升级 webpack 到 4.x 版本

升级 webpack 到 4.x 版本

说明

webpack 4 可以零配置启动,也支持通过配置文件进行更细致的配置,相比于上一个版本,配置已经简化了很多

webpack 4 引入了 mode 用来设置开发环境,同时也可以简化配置项,不同的 mode 会携带不同的默认配置

  • --mode development 开发模式更关注开发体验:编译速度、报错信息
  • --mode production 生产模式更关注用户体验:文件大小、运行性能、打包速度

webpack 4 的 plugin 插件体系较之前版本改动较大,一些插件已经不能使用

项目代码

1. 零配置启动

安装

# webpack-cli CLI 工具被拆分为单独的包了
sudo yarn add webpack webpack-cli --dev

package.json 中添加脚本,通过 --mode 定义环境变量

  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },

文件组织

零配置启动的默认入口文件是 /src/index.js 输出文件为 /dist/main.js 如果需要自定义还是使用 webapck 配置文件吧

├── dist
│   └── main.js # index.js 和 bd.js 被打包到 一个文件了
├── index.html
├── package.json
├── src
│   ├── bd.js
│   └── index.js
└── yarn.lock

结果

  • yarn run build webpack --mode production 生产环境默认会压缩

2. 配置文件启动

1. 添加 package.json scripts

"scripts": {
    "dev": "webpack-dev-server --config build/webpack.dev.config.js",
    "start": "yarn run dev",
    "build": "webpack --colors --config build/webpack.prod.config.js",
    "report": "webpack --colors --env.REPORT --config build/webpack.prod.config.js",
    "server": "nodemon server/index.js"
},

2. 公用的配置

// webpack.base.config.js 与在 webpack 3.x 下的配置基本没有变化

module.exports = {
   context: common.context,
   entry: utils.computeEntry(config, packageConfig), 
   output: utils.computeOutput(config),
   cache: true,
   resolve: {
      extensions: ['.js', '.json', '.jsx', '.css'],
      modules: ['node_modules', common.sourceCode]
   },
   module: {
      rules: [
         {
            test: /\.(js|jsx)$/,
            loader: 'eslint-loader',
            enforce: 'pre',
            include: common.sourceCode,
            options: {
               formatter: require('eslint-friendly-formatter')
            }
         },
         {
            test: /\.(js|jsx)$/,
            loader: 'babel-loader',
            include: common.sourceCode
         },
         {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader',
            options: {
               limit: 10000,
               name: namedAssets(current.env !== 'production' ? 'imgs/[name].[ext]' : 'imgs/[name].[hash:10].[ext]')
            }
         },
         {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            loader: 'url-loader',
            options: {
               limit: 10000,
               name: namedAssets(current.env !== 'production' ? 'media/[name].[ext]' : 'media/[name].[hash:10].[ext]')
            }
         },
         {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: 'url-loader',
            options: {
               limit: 10000,
               name: namedAssets(current.env !== 'production' ? 'fonts/[name].[ext]' : 'fonts/[name].[hash:10].[ext]')
            }
         },
         {
            test: require.resolve(common.requestModule),
            loader: 'imports-loader?basicRequestLink=>' + JSON.stringify(current.conf.basicRequestLink)
         },
         {
            test: require.resolve(utils.resolve(common.sourceCode)('index.js')),
            loader: 'imports-loader?assetsPublicPath=>' + JSON.stringify(current.conf.assetsPublicPath)
         }
      ]
   },
   plugins: [
      new HtmlWebpackPlugin({
         template: utils.resolve(common.sourceCode)('index.html'),
         filename: 'index.html',
         inject: 'body',
         minify: false,
         xhtml: true,
         cache: false
         // favicon: ''
      })
   ]
};

3. 开发环境配置

// webpack.dev.config.js
module.exports = merge(baseWebpackConfig, {
   mode: 'development', // 通过 mode 声明开发环境
   devtool: '#cheap-module-eval-source-map',
   module: {
      rules: [
         {
            test: /\.(scss|sass|css)$/,
            include: common.sourceCode,
            use: utils.computeStyleLoader(false, ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'])
         }
      ]
   },
   // optimization 代替 webpack 3.x 中 webpack.optimize.CommonsChunkPlugin 分离模块
   optimization: { 
      splitChunks: {
         cacheGroups:{
            commons: {
               chunks: 'initial',
               minChunks: 2,
               maxInitialRequests: 5,
               minSize: 0
            },
            vendor: {
               test: /node_modules/,
               chunks: 'initial',
               name: 'vendor',
               priority: 10,
               enforce: true,
            }
         }
      },
      runtimeChunk: {
         name: 'runtime'
      }
   },
   plugins: [
      new CleanWebpackPlugin(['dev'], { root: common.context }),
      new webpack.NamedModulesPlugin(),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NoEmitOnErrorsPlugin(),
      new FriendlyErrorsPlugin()
   ],
   devServer: { // webpack-dev-server 的配置没有大的变化
      contentBase: currentConfig.assetsRoot,
      publicPath: currentConfig.assetsPublicPath,
      historyApiFallback: true,
//    clientLogLevel: 'none',
      hot: true,
      inline: true,
      compress: true,
      open: true,
      openPage: 'index.html',
      port: currentConfig.port,
      host: currentConfig.devServerIp,
      stats: {
         colors: true,
         errors: true,
         warnings: true,
         modules: false,
         chunks: false
      }
   }
});

4. 生产环境配置

extract-text-webpack-plugin 不在适用 webpack 4.x,改用 mini-css-extract-plugin 代替

'use strict';
/* eslint-disable */

const utils = require('./utils');
const config = require('../config/index');
const common = config.common;
const currentConfig = config.production;

// 设置环境变量
if (!process.env.NODE_ENV) {
   process.env.NODE_ENV = JSON.parse(currentConfig.env.NODE_ENV);
}

/*
   production 环境下 webpack 配置文件,安装 plugins
*/
const webpack = require('webpack');
const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const baseWebpackConfig = require('./webpack.base.config');

// 打包信息展示插件
let reportPlugin = [];

if (currentConfig.bundleAnalyzerReport) {
   const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

   reportPlugin.push(new BundleAnalyzerPlugin());
}

// workbox 插件
let workboxPlugin = [];

if (currentConfig.needWorkboxSW) {
   const WorkboxPlugin = require('workbox-webpack-plugin');
   const defaultConfig = {
      cacheId: 'webpack-pwa',
      skipWaiting: true,
      clientsClaim: true,
      swDest: 'service-wroker.js',
      // 一下两个配置不在需要
      // globPatterns: ['**/*.{html,js,css,png.jpg}'],
      // globIgnores: [ 'service-wroker.js' ],
      runtimeCaching: [
         {
            urlPattern: /.*\.js/,
            handler: 'networkFirst', // 网络优先
         }
      ]
   };
   workboxPlugin.push(new WorkboxPlugin.GenerateSW(currentConfig.workboxConfig || defaultConfig));
}

module.exports = merge(baseWebpackConfig, {
    // mode 声明生产环境,生产环境下回默认压缩文件
   mode: 'production', 
   devtool: currentConfig.productionSourceMap ? '#source-map' : false,
   module: {
      rules: [
         {
            // 使用 mini-css-extract-plugin 插件来分离出 css 文件
            test: /\.(scss|sass|css)$/,
            include: common.sourceCode,
            use: [
               MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'
            ]
         }
      ]
   },
   // optimization 配置模块分离,代替 webpack.optimize.CommonsChunkPlugin
   optimization: {
      splitChunks: {
         cacheGroups:{
            commons: {
               chunks: 'initial',
               minChunks: 2,
               maxInitialRequests: 5,
               minSize: 0
            },
            vendor: {
               test: /node_modules/,
               chunks: 'initial',
               name: 'vendor',
               priority: 10,
               enforce: true,
            },
            styles: {
               name: 'styles',
               test: /\.scss$/,
               chunks: 'all',
               enforce: true,
            }
         }
      },
      runtimeChunk: {
         name: 'runtime'
      },
   },
   plugins: [
      new CleanWebpackPlugin(['dist'], { root: common.context }),
      new webpack.HashedModuleIdsPlugin(),
      new webpack.optimize.ModuleConcatenationPlugin(),
      new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }),
      new MiniCssExtractPlugin({
         filename: utils.resolve(currentConfig.assetsSubDirectory)('css/[name].[contenthash].css')
      }),
      new CopyWebpackPlugin([
         {
            from: 'src/manifest.json',
            to: 'manifest.json'
         },
         {
            from: 'src/icon.png',
            to: 'static/imgs/icon.png'
         }
      ]),
      ...workboxPlugin,
      ...reportPlugin
   ]
});

5. 更多配置

更多配置可以查看源码 需要切换到 webpack-v4-template 分支

猜你喜欢

转载自blog.csdn.net/mjzhang1993/article/details/79850235