写在前面

在上篇博客中,我们介绍了 webpack 基本配置 js、html、css 的方法和本地预览 webpack-dev-server 的使用。经过上篇博客的配置,我们已经可以使用 webpack 打包只含有 html+css+js 的前端项目了。

但是我们在日常开发中,使用的功能远不止于此,因此在项目中使用更高级的语言和功能时要手动配置相关编译出口和规则。

1. 使用两个 webpack.config.js

在上述引入 css 的配置过程中,有两种引入方式,一种是生成 <style> 标签的形式,一种是抽离成 css 文件的形式。抽离成 css 文件的方式肯定要比 <style> 标签的形式要加载地慢些。在我们使用 webpack-dev-server 预览时,肯定希望越快越好,因此,在开发过程中使用 <style> 标签的形式更好些。但是在项目打包时,反到是抽离成 css 文件的方式要更好些。

由于开发环境和生产环境对 webpack 的配置有不同的要求,因此就产生了使用两个 webpack.config.js 来满足不同的需求的开发模式。

webpack 和 webpack-dev-server 的打包和运行都依赖 webpack.cofig.js 文件。这两个命令在运行时都默认调用 webpack.config.js 或 webpackfile.js(详可使用 webpack —help查看)。webpack 允许我们使用 —config 来手动设置调用的配置文件的信息。

1.1 手动拆分 webpack.config.js

将默认的 webpack.config.js 复制一份命名为 webpack.config.prod.js ,用于生产环境的配置。默认的是开发环境下的配置,也可以改名为 webpack.config.dev.js。然后将二者的 mode 模式修改成对应的模式,并且,在开发模式中使用 <style> 标签的配置,在生产模式中使用抽离 css 文件的配置。

上述方式虽然手动划分成了两个 webpack.config.js 文件,但是二者有很多重复的部分,如入口、出口的配置等。因此可以简化一下,再抽离出一个 webpack.config.base.js 文件进行继承和引入。

webpack 的配置文件本质就是 js 文件,因此就是按照 js 的方式继承。如下:

webpack.config.base.js

  1. const HtmlWebpackPlugin = require('html-webpack-plugin');
  2. const path = require('path');
  3. module.exports = {
  4. entry: './src/index.js',
  5. output: {
  6. filename: '[name].[contenthash].js'
  7. },
  8. plugins: [
  9. new HtmlWebpackPlugin({
  10. title: 'My App',
  11. template: 'src/assets/index.html'
  12. })
  13. ]
  14. };

webpack.config.dev.js

  1. const path = require('path');
  2. const base = require('./webpack.config.base')
  3. module.exports = {
  4. ...base,
  5. mode: 'development',
  6. devServer: {
  7. contentBase: './dist',
  8. },
  9. module: {
  10. rules: [
  11. {
  12. test: /\.css$/i,
  13. use: ['style-loader', 'css-loader']
  14. },
  15. ],
  16. }
  17. };

webpack.config.prod.js

  1. const path = require('path');
  2. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  3. const base = require('./webpack.config.base')
  4. module.exports = {
  5. ...base,
  6. mode: 'production',
  7. plugins: [
  8. ...base.plugins,
  9. new MiniCssExtractPlugin({
  10. filename: '[name].[contenthash].css',
  11. chunkFilename: '[id].[contenthash].css',
  12. ignoreOrder: false,
  13. })
  14. ],
  15. module: {
  16. rules: [
  17. {
  18. test: /\.css$/i,
  19. use: [
  20. {
  21. loader: MiniCssExtractPlugin.loader,
  22. options: {
  23. publicPath: '../'
  24. }
  25. },
  26. 'css-loader'
  27. ]
  28. },
  29. ],
  30. }
  31. };

package.json

  1. "scripts": {
  2. "build": "rm -rf dist && webpack --config config/webpack.prod.js",
  3. "start": "webpack-dev-server --config config/webpack.dev.js",
  4. "test": "echo \"Error: no test specified\" && exit 1"
  5. },

1.2 使用 webpack-merge 工具

也可以使用 webpack config merge 相关的工具 webpack-merge 来进行生产环境和开发环境配置文件的分离。详看 webpack-merge

拆分原理是一样的,也是分成基本、开发、生产三个配置文件,只不过 webpack-merge 提供了 merge 方法,用于合并配置对象。

安装 webpack-merge

  1. yarn add webpack-merge --dev
  2. //npm install webpack-merge --save-dev

将上述改成使用 webpack-merge 的方法如下:

config / webpack.common.js

  1. const HtmlWebpackPlugin = require('html-webpack-plugin');
  2. const path = require('path');
  3. module.exports = {
  4. entry: './src/index.js',
  5. output: {
  6. filename: '[name].[contenthash].js'
  7. },
  8. plugins: [
  9. new HtmlWebpackPlugin({
  10. title: 'My App',
  11. template: 'src/assets/index.html'
  12. })
  13. ]
  14. };

config / webpack.dev.js

  1. const path = require('path');
  2. const common = require('./webpack.common');
  3. const { merge } = require('webpack-merge');
  4. module.exports = merge(common,{
  5. mode: 'development',
  6. devServer: {
  7. contentBase: './dist',
  8. },
  9. module: {
  10. rules: [
  11. {
  12. test: /\.css$/i,
  13. use: ['style-loader', 'css-loader']
  14. },
  15. ],
  16. }
  17. });

config / webpack.prod.js

  1. const path = require('path');
  2. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  3. const common = require('./webpack.common');
  4. const { merge } = require('webpack-merge');
  5. module.exports = merge(common,{
  6. mode: 'production',
  7. plugins: [
  8. new MiniCssExtractPlugin({
  9. filename: '[name].[contenthash].css',
  10. chunkFilename: '[id].[contenthash].css',
  11. ignoreOrder: false,
  12. })
  13. ],
  14. module: {
  15. rules: [
  16. {
  17. test: /\.css$/i,
  18. use: [
  19. {
  20. loader: MiniCssExtractPlugin.loader,
  21. options: {
  22. publicPath: '../'
  23. }
  24. },
  25. 'css-loader'
  26. ]
  27. },
  28. ],
  29. }
  30. });

package.json

  1. "scripts": {
  2. "build": "rm -rf dist && webpack --config config/webpack.prod.js",
  3. "start": "webpack-dev-server --config config/webpack.dev.js",
  4. "test": "echo \"Error: no test specified\" && exit 1"
  5. },

以上只是 webpack-merge 的基本用法,更多用法待解锁。

2. loader 和 plugin 的区别

  1. loader 是加载器,plugin 是插件
  2. loader 是用来加载某些资源文件的,比如 babel-loader 会将 js 转化为所有浏览器都支持的 js 文件格式,style-loader 会将 css 文件加载成 <style> 标签放在 html 里
  3. plugin 插件是用来扩展那 webpack 功能的,比如 HtmlWebpackPlugin 是用来自动生成 html 文件的,MiniCssExtractPlugin 是用来抽取出单独的 css 文件的