1、Webpack 简介

从本质上讲,webpack 是现代 JavaScript 应用程序的静态模块打包器。 当 webpack 处理您的应用程序时,它会在内部从一个或多个入口点构建一个依赖关系图,然后将您项目所需的每个模块组合成一个或多个包,这些包是静态资产,用于为您的内容提供服务。

1.1 核心概念

Entry

  • 入口点指示 webpack 应该使用哪个模块来开始构建其内部依赖关系图。 Webpack 将确定入口点依赖于哪些其他模块和库(直接或间接)。
  • 默认情况下,它的值为 ./src/index.js,但您可以通过在 webpack 配置中设置 entry 属性来指定不同的(或多个入口点)

    Output

  • output 属性告诉 webpack 在哪里发出它创建的包以及如何命名这些文件。 对于主输出文件,它默认为 ./dist/main.js,对于任何其他生成的文件,默认为 ./dist 文件夹。

    Loaders

  • webpack 默认只理解 JavaScript 和 JSON 文件加载器 loaders 允许 webpack 处理其他类型的文件,并将它们转换为可以被你的应用程序使用并添加到依赖关系图中的有效模块

  • 在高层次上,加载器在你的 webpack 配置中有两个属性:

    • test 属性标识应该转换哪个或哪些文件。
    • use 属性指示应该使用哪个加载器来进行转换。

      Plugins

  • 虽然加载器用于转换某些类型的模块,但可以利用插件来执行更广泛的任务,如包优化、资产管理和环境变量注入

  • 为了使用插件,您需要 require() 并将其添加到 plugins 数组中。 大多数插件都可以通过选项进行定制。 由于您可以在一个配置中多次使用一个插件用于不同的目的,您需要通过使用 new 运算符调用它来创建它的一个实例。

    Mode

  • 通过将 mode 参数设置为 development、production 或 none,您可以启用 webpack 与每个环境对应的内置优化。 默认值为生产 production 。

    Browser Compatibility

  • Webpack 支持所有符合 ES5 标准的浏览器(不支持 IE8 及以下)。 Webpack 需要为 import() 和 require.ensure() 提供 Promise。 如果你想支持旧浏览器,你需要在使用这些表达式之前加载一个 polyfill

    2、Webpack 配置

    代码必须使用 webpack 之类的打包器进行打包,并使用 Babel 之类的编译器进行转换。生产环境代码需要进行生产优化,例如代码拆分。

2.1 初始化项目

  • 创建 package.json 项目描述文件(默认选择yes):yarn init -y 或 npm init -y

2.2 安装webpack

  1. yarn add webpack webpack-cli --dev
  • 带 -D(—save-dev)后缀安装的包会记录在 package.json 文件”devDependencies”下
  • 带 -S (—save)后缀安装的包会记录在 package.json 文件 “dependencies”下
  • devDependencies:dev开发时的依赖包
  • dependencies:程序运行时的依赖包

2.3 初始化配置

  • 创建html:index.html——项目首页
  • 创建src文件夹存放项目源代码:index.js——项目js入口文件
  • 移除package.json 中的 main属性,添加 “private”: true ```json { “name”: “webpack-demo”, “version”: “1.0.0”, “description”: “”,
  • “private”: true,
  • “main”: “index.js”, “scripts”: { “test”: “echo \”Error: no test specified\” && exit 1” }, “keywords”: [], “author”: “”, “license”: “ISC”, “devDependencies”: { “webpack”: “^4.20.2”, “webpack-cli”: “^3.1.2” }, “dependencies”: {} } ```

  • webpack基本配置:在根目录或build文件下新建 webpack.config.js 文件

    • 入口 entry
      • 单文件入口:entry: './src/index.js'
      • 多文件入口代码分割entry: { app: './src/app.js', vendors: './src/vendors.js' }
        • 多个文件完全分离,互相独立(每个bundle中都有一个webpack引导),常见单入口单页面应用
    • 输出 output
      • filename :输出的文件名称;
      • path :输出的目录绝对路径;
      • chunkFilename:决定 non-entry chunk(非入口 chunk) 的名称
  1. const path=require('path')
  2. module.exports={
  3. mode:'development',//开发环境
  4. entry:{
  5. main:path.resolve(__dirname, './src/index.js'),
  6. //向 entry 属性传入「(file path)数组」将创建“多个主入口(multi-main entry)”
  7. },
  8. output:{
  9. path:path.resolve(__dirname,'dist'),
  10. filename:'js/[name].[hash:8].js',//根据入口起点定义的名称,动态地产生 bundle 名称
  11. chunkFilename:'js/[name].[hash:8].js', //[name]代表原js文件名,[hash]代表本次生成的哈希值
  12. publicPath:'./'
  13. //如果编译时不知道最终文件的 publicPath ,可以留空,并在入口文件中动态设置。
  14. //或者在入口起点设置 __webpack_public_path__ 来忽略它
  15. //__webpack_public_path__ = myRuntimePublicPath
  16. }
  17. }
  • loader:对模块的源代码转换。允许打包除 JavaScript 外的任何静态资源。类似其他构建工具中“task”
    • test 属性:用来标识出应该被对应的 loader 进行转换的某个或多个文件;
    • use 属性:表示转换时要用哪个 loader;
  • plugins:解决 loader 无法实现的其他事,从优化和压缩,到重新定义环境中的变量等等
    • 使用:只需要 require 它,并添加到 plugins 数组,通过 new 实例化(携带参数/选项)即可
  • 模块 module:模块化编程中,开发者将程序分解为功能离散的 chunk,并称之为模块
    • 修改package.json 文件指定配置路径:
  1. "scripts":{"serve": "webpack ./src/index.js --config ./build/webpack.config.js"}

2.4 babel-loader转译ESNext

babel-loader则是帮我们把不同的文件转化成我们想要的格式输出,或者说就是将我们的经过babel处理后的代码进行输出成浏览器可以识别的文件

将ES6以上的语法转译为ES5

  • 安装babel-loader及相关依赖:yarn add babel-loader @babel/core @babel/preset-env --dev
    • babel-loader 使用 Babel 加载 ES2015+ 代码并将其转换为 ES5
    • @babel/core Babel 编译的核心包
    • @babel/preset-env Babel 编译的预设,可以理解为 Babel 插件的超集。常见 Babel 预设还有:
      • @babel/preset-react则是帮我们识别JSX语法
      • @babel/preset-typescript 识别ts、tsx语法
  • 修改webpack.config.js配置

    1. const path=require('path')
    2. module.exports = {
    3. module: {
    4. rules: [
    5. {
    6. test: /\.js$/,
    7. exclude: /(node_modules|bower_components)/,//exclude表示排除掉的文件正则表达式
    8. use: [{
    9. loader: 'babel-loader',
    10. options: {
    11. presets: ['@babel/preset-env'],
    12. }]
    13. }
    14. ]
    15. }
    16. }
  • 为了避免 webpack.config.js 太臃肿,建议将 Babel 配置文件提取出来。根目录下新增 .babelrc.js ```javascript // ./babelrc.js

module.exports = { presets: [ [ “@babel/preset-env”, { // useBuiltIns: false 默认值,无视浏览器兼容配置,引入所有 polyfill // useBuiltIns: entry 根据配置的浏览器兼容,引入浏览器不兼容的 polyfill // useBuiltIns: usage 会根据配置的浏览器兼容, // 以及你代码中用到的 API 来进行 polyfill,实现了按需添加 useBuiltIns: “entry”, corejs: “3.9.1”, // 是 core-js 版本号 targets: { chrome: “58”, ie: “11”, }, }, ], ], };

  1. <a name="hh0qc"></a>
  2. ### 2.5 html-webpack-plugin自动引入打包后js至html
  3. 创建html页面并自动引入打包生成的js文件
  4. - 插件的安装:`yarn add html-webpack-plugin --dev`
  5. - 修改配置 webpack.config.js:
  6. ```javascript
  7. const HtmlWebpackPlugin = require('html-webpack-plugin');
  8. module.exports = {
  9. plugins: [
  10. new HtmlWebpackPlugin({
  11. filename: 'index.html',
  12. template: path.resolve(__dirname, 'src/index.html'),
  13. minify: {
  14. collapseWhitespace: true,
  15. removeComments: true,
  16. removeAttributeQuotes: true,
  17. },
  18. })
  19. ]
  20. }

2.6 clean-webpack-plugin 清除上次构建

打包前自动删除输出目录,webpack 5 直接添加 output:{clean: true},不用再下载

  • 安装:yarn add clean-webpack-plugin --dev
  • 配置:

    1. const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    2. const HtmlWebpackPlugin = require('html-webpack-plugin');
    3. module.exports={
    4. plugins: [
    5. new HtmlWebpackPlugin({
    6. filename: 'index.html',
    7. template: path.resolve(__dirname, 'src/index.html'),
    8. minify: {
    9. collapseWhitespace: true,
    10. removeComments: true,
    11. removeAttributeQuotes: true,
    12. },
    13. }),
    14. new CleanWebpackPlugin(),
    15. ],
    16. }

    2.7 url-loader、file-loader打包资源文件

  • 安装:yarn add file-loader url-loader --dev

    • file-loader 解析文件url,并将文件复制到输出的目录中(打包资源图片,修复引入路径)
    • url-loader 功能与 file-loader 类似,如果文件小于限制的大小,则会返回 base64 编码(对于小图片等资源,好处是减少资源的请求次数)
  • 修改 webpack.config.js 配置 添加 rules 配置,分别对 图片,媒体,字体文件进行配置:
    1. module.exports = {
    2. module: {
    3. rules: [
    4. {
    5. test: /\.(jpe?g|png|gif|svg)$/i,
    6. use: [{
    7. loader: 'url-loader',
    8. options: {
    9. limit: 4096, //limit是文件大小阈值,这里设置为4k
    10. fallback: {
    11. loader: 'file-loader',
    12. options: {
    13. name: 'img/[name].[hash:8].[ext]'
    14. }
    15. }
    16. }
    17. }]
    18. },
    19. {
    20. test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
    21. use: [{
    22. loader: 'url-loader',
    23. options: {
    24. limit: 4096,
    25. fallback: {
    26. loader: 'file-loader',
    27. options: {
    28. name: 'fonts/[name].[hash:8].[ext]'
    29. }
    30. }
    31. }
    32. }]
    33. },
    34. {
    35. test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
    36. use: [{
    37. loader: 'url-loader',
    38. options: {
    39. limit: 4096,
    40. fallback: {
    41. loader: 'file-loader',
    42. options: {
    43. name: 'media/[name].[hash:8].[ext]'
    44. }
    45. }
    46. }
    47. }]
    48. },
    49. ]
    50. },
    51. };

    2.8 html-loader打包html

解析html中引用的资源文件,复制到输出目录

  • 安装:yarn add html-loader --dev
  • 配置:

    1. module.exports = {
    2. module: {
    3. rules: [
    4. {
    5. test: /\.html$/,
    6. use:[{
    7. loader: 'html-loader',
    8. options: {
    9. attrs: [
    10. 'img:src',
    11. 'link:href',
    12. 'video:src',
    13. 'video:poster'
    14. ]
    15. }
    16. }]
    17. },
    18. ]
    19. }
    20. }

    2.9 eslint-loader代码检测、路由懒加载

  • eslint——良好的代码检测工具。standard为eslint一种标准样式

    • 安装:yarn add eslint eslint-loader babel-eslint standard --dev
  • babel-plugin-syntax-dynamic-import——配置路由懒加载
    • 安装:yarn add babel-plugin-syntax-dynamic-import --dev
  • 配置:

    • 修改webpack.config.js

      1. module.exports={
      2. module: {
      3. rules: [
      4. {
      5. test: /\.js$/,
      6. exclude: /(node_modules|bower_components)/,
      7. use: [
      8. {
      9. loader: 'babel-loader',
      10. options: {
      11. presets: ['@babel/preset-env'],
      12. plugins: ['@babel/plugin-syntax-dynamic-import'],
      13. }
      14. },
      15. {
      16. loader: 'eslint-loader',
      17. options: {
      18. // eslint options (if necessary)
      19. fix: true
      20. }
      21. }
      22. ]
      23. },
      24. }
    • 修改.eslintrc.js文件,添加以下配置

      1. module.exports = {
      2. root: true,
      3. parserOptions: {
      4. ecmaVersion: 6,
      5. sourceType: 'module',
      6. parser: 'babel-eslint'
      7. },
      8. env: {
      9. browser: true,
      10. node: true,
      11. es6: true
      12. },
      13. extends: [
      14. // https://github.com/standard/standard/blob/master/docs/RULES-en.md
      15. 'standard'
      16. ],
      17. globals: {
      18. NODE_ENV: false
      19. },
      20. rules: {
      21. // allow async-await
      22. 'generator-star-spacing': 'off',
      23. // allow debugger during development
      24. 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
      25. // semicolon分号
      26. 'semi': ['error', 'always'],
      27. 'no-unexpected-multiline': 'off',
      28. 'space-before-function-paren': ['error', 'never'],
      29. 'quotes': ['error', 'single', { 'avoidEscape': true }]
      30. }
      31. };

      2.10 scss、postcss、css配置

2.10.1 通用样式处理

  • 通用安装:yarn add sass-loader node-sass postcss-loader autoprefixer css-loader --dev
    • sass-loader,node-sass:加载和转译 SASS/SCSS 文件。也可使用 Less loader
    • postcss-loader:css样式后处理工具。css压缩、合并、自动兼容浏览器
    • autoprefixer :自动添加css3前缀
    • css-loader:解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
  • 通用配置:autoprefixer新版本推荐在package.json中添加”browserslist”选项调用

    1. "browserslist": [
    2. "last 1 version",
    3. "> 0.15% in CN",
    4. "maintained node versions",
    5. "not dead"
    6. ]

    2.10.2 样式提取导出——生产环境

  • 生产环境安装 :yarn add mini-css-extract-plugin --dev

    • mini-css-extract-plugin:为每个引入 CSS 的 JS 文件创建一个 CSS 文件
  • 生产环境配置:

    1. const autoprefixer = require('autoprefixer');
    2. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    3. module.exports={
    4. module: {
    5. rules: [
    6. {
    7. test: /\.(sa|sc|c)ss$/,
    8. exclude: /node_modules/,
    9. use: [
    10. MiniCssExtractPlugin.loader,
    11. {
    12. loader: 'css-loader',
    13. options: {
    14. sourceMap: true,
    15. }
    16. },
    17. {
    18. loader: 'postcss-loader',
    19. options: {
    20. ident: 'postcss',
    21. sourceMap: true,
    22. /* eslint-disable */
    23. plugins: loader => [autoprefixer()]
    24. /* eslint-enable */
    25. }
    26. },
    27. {
    28. loader: 'sass-loader',
    29. options: {
    30. sourceMap: true,
    31. }
    32. }
    33. ]
    34. }
    35. ]
    36. },
    37. plugins: [
    38. new MiniCssExtractPlugin({
    39. filename: '[name].[hash:8].css', // 设置最终输出的文件名
    40. chunkFilename: '[id].[hash:8].css'
    41. }),
    42. ],
    43. }

    2.10.3 样式添加到DOM——开发环境

  • 开发环境安装:yarn add style-loader --dev

    • style-loader:将模块的导出作为样式添加到 DOM 中
    • vue-style-loader:可选
  • 开发环境配置:
    1. const autoprefixer = require('autoprefixer');
    2. module.exports={
    3. module: {
    4. rules: [
    5. {
    6. test: /\.(sa|sc|c)ss$/,
    7. exclude: /node_modules/,
    8. use: [
    9. 'style-loader',
    10. {
    11. loader: 'css-loader',
    12. options: {
    13. sourceMap: true,
    14. }
    15. },
    16. {
    17. loader: 'postcss-loader',
    18. options: {
    19. ident: 'postcss',
    20. sourceMap: true,
    21. /* eslint-disable */
    22. plugins: loader => [autoprefixer()]
    23. /* eslint-enable */
    24. }
    25. },
    26. {
    27. loader: 'sass-loader',
    28. options: {
    29. sourceMap: true,
    30. }
    31. }
    32. ]
    33. }
    34. ]
    35. }
    36. }

2.11 uglifyjs、terser、optimize-css-assets压缩插件

  • uglifyjs-webpack-plugin:实现js代码压缩、混淆、tree-shaking(不支持es6!)
  • terser-webpack-plugin:适用于ES6 +的JavaScript解析器,压缩器工具包
  • optimize-css-assets-webpack-plugin:优化压缩css,有一些压缩规则带来问题(属性、选择器合并)
  • 安装:
    • yarn add uglifyjs-webpack-plugin optimize-css-assets-webpack-plugin --dev
    • yarn add terser-webpack-plugin --dev
  • 配置:
    1. const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
    2. const TerserPlugin = require('terser-webpack-plugin');
    3. const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    4. module.exports = {
    5. optimization: {
    6. minimize: true,
    7. minimizer: [
    8. new TerserPlugin({
    9. terserOptions: {
    10. parse: {
    11. ecma: 8,
    12. },
    13. compress: {
    14. ecma: 5,
    15. warnings: false,
    16. comparisons: false,
    17. inline: 2,
    18. drop_console: true,//清除 console 函数
    19. drop_debugger: true,
    20. pure_funcs: ['console.log'],
    21. },
    22. mangle: {
    23. safari10: true,
    24. },
    25. output: {
    26. ecma: 5,
    27. comments: false,
    28. // Turned on because emoji and regex is not minified properly using default
    29. // https://github.com/facebook/create-react-app/issues/2488
    30. ascii_only: true,
    31. },
    32. sourceMap: true
    33. },
    34. }),
    35. new UglifyJsPlugin({
    36. cache: true, //启用文件缓存
    37. parallel: true, // 并行化处理,多进程压缩
    38. sourceMap: true // 输出对应的map文件(这会减慢编译速度)
    39. }),
    40. new OptimizeCSSAssetsPlugin({}) // 优化压缩css
    41. ],
    42. }
    43. }

2.12 webpack-dev-server 配置热更新开发

  • 安装:yarn add webpack-dev-server --dev
  • 配置:通过配置 devServerHotModuleReplacementPlugin (aka HMR)插件来实现热更新
    • 开发环境时,以webpack-dev-server替换 webpack 来执行webpack配置文件
    • webpack输出真实的文件,而webpack-dev-server输出的文件只存在于内存中,输出目录找不到相关文件
    • devServer 主要就是启动了一个静态服务器,让开发者可以方便的预览自己工程构建的webApp
      1. const path = require('path');
      2. const webpack = require('webpack');
      3. module.exports={
      4. //将 dist 目录下的文件 serve 到 localhost:3000 下
      5. devServer: {
      6. hot: true,
      7. port: 3000,
      8. contentBase: path.join(__dirname, 'dist')
      9. },
      10. plugins: [
      11. new webpack.NamedModulesPlugin(),
      12. new webpack.HotModuleReplacementPlugin(),
      13. ]
      14. }

2.13 webpack-bundle-analyzer 打包分析

提供可视化的界面,以用来分析webpack构建后的打包情况

  • 安装:yarn add webpack-bundle-analyzer --dev
  • 配置
    1. const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    2. module.exports = {
    3. plugins: [
    4. new BundleAnalyzerPlugin()
    5. ]
    6. }

    2.14 定义环境变量

DefinePlugin,允许在编译时(compile time)配置的全局常量

  1. const webpack = require('webpack');
  2. module.exports={
  3. plugins: [
  4. new webpack.DefinePlugin({
  5. 'process.env': {
  6. VUE_APP_BASE_URL: JSON.stringify('http://localhost:3000'),
  7. NODE_ENV: JSON.stringify(process.env.NODE_ENV)
  8. }
  9. }),
  10. ]
  11. }

2.15 webpack-merge 合并 webpack 配置

  • 安装:yarn add webpack-merge - D
  • 配置:webpack.config.js 拆分为 webpack.common.js、webpack.dev.js、webpack.prod.js三个配置文件
    • webpack.common.js ```javascript const path = require(‘path’); const HtmlWebpackPlugin = require(‘html-webpack-plugin’); const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’); const webpack = require(‘webpack’);

module.exports = { entry: ‘./src/index.js’, output: { filename: ‘js/[name].[hash:8].js’, path: path.resolve(dirname, ‘dist’), publicPath: ‘./‘ }, module: { rules: [ { test: /.js$/, exclude: /(node_modules|bower_components)/, use: [{ loader: ‘babel-loader’, options: { presets: [‘@babel/preset-env’], plugins: [‘@babel/plugin-syntax-dynamic-import’], } }, { loader: ‘eslint-loader’, options: { // eslint options (if necessary) fix: true } }] }, { test: /.(jpe?g|png|gif|svg)$/i, use: [{ loader: ‘url-loader’, options: { limit: 4096, //limit是文件大小阈值,这里设置为4k fallback: { loader: ‘file-loader’, options: { name: ‘img/[name].[hash:8].[ext]’ } } } }] }, { test: /.(woff2?|eot|ttf|otf)(\?.)?$/i, use: [{ loader: ‘url-loader’, options: { limit: 4096, fallback: { loader: ‘file-loader’, options: { name: ‘fonts/[name].[hash:8].[ext]’ } } } }] }, { test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.)?$/, use: [{ loader: ‘url-loader’, options: { limit: 4096, fallback: { loader: ‘file-loader’, options: { name: ‘media/[name].[hash:8].[ext]’ } } } }] }, ] }, plugins: [ new HtmlWebpackPlugin({ filename: ‘index.html’, template: path.resolve(dirname, ‘src/index.html’), minify: { collapseWhitespace: true, removeComments: true, removeAttributeQuotes: true, }, }), new webpack.DefinePlugin({ ‘process.env’: { VUE_APP_BASE_URL: JSON.stringify(‘http://localhost:3000‘), NODE_ENV: JSON.stringify(process.env.NODE_ENV) } }), new CleanWebpackPlugin(), ], };

  1. - webpack.dev.js
  2. ```javascript
  3. const path = require('path');
  4. const autoprefixer = require('autoprefixer');
  5. const webpack = require('webpack');
  6. const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
  7. const merge = require('webpack-merge');
  8. const common = require('./webpack.common.js');
  9. let devConfig = {
  10. mode: 'development',
  11. output: {
  12. filename: 'js/[name].[hash:8].js',
  13. path: path.resolve(__dirname, 'dist')
  14. },
  15. devtool: 'inline-source-map',//配置source map
  16. devServer: {
  17. hot: true,
  18. port: 3000,
  19. contentBase: path.join(__dirname, 'dist')
  20. },
  21. module: {
  22. rules: [
  23. {
  24. test: /\.(sa|sc|c)ss$/,
  25. exclude: /node_modules/,
  26. use: [
  27. 'style-loader',
  28. {
  29. loader: 'css-loader',
  30. options: {
  31. sourceMap: true,
  32. }
  33. },
  34. {
  35. loader: 'postcss-loader',
  36. options: {
  37. ident: 'postcss',
  38. sourceMap: true,
  39. /* eslint-disable */
  40. plugins: loader => [autoprefixer()]
  41. /* eslint-enable */
  42. }
  43. },
  44. {
  45. loader: 'sass-loader',
  46. options: {
  47. sourceMap: true,
  48. }
  49. }
  50. ]
  51. }
  52. ]
  53. },
  54. plugins: [
  55. new webpack.NamedModulesPlugin(),
  56. new webpack.HotModuleReplacementPlugin(),
  57. new BundleAnalyzerPlugin(),
  58. ]
  59. };
  60. module.exports = merge(common, devConfig);
  • webpack.prod.js ```javascript const path = require(‘path’); const autoprefixer = require(‘autoprefixer’); const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’); const OptimizeCSSAssetsPlugin = require(‘optimize-css-assets-webpack-plugin’); const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin’); const merge = require(‘webpack-merge’); const common = require(‘./webpack.common.js’);

let prodConfig = { mode: ‘production’, output: { filename: ‘js/[name].[hash:8].js’, path: path.resolve(__dirname, ‘dist’) }, module: { rules: [ { test: /.(sa|sc|c)ss$/, exclude: /node_modules/, use: [ MiniCssExtractPlugin.loader, { loader: ‘css-loader’, options: { sourceMap: true, } }, { loader: ‘postcss-loader’, options: { ident: ‘postcss’, sourceMap: true, / eslint-disable / plugins: loader => [autoprefixer()] / eslint-enable / } }, { loader: ‘sass-loader’, options: { sourceMap: true, } } ] }] }, plugins: [ new MiniCssExtractPlugin({ filename: ‘[name].[hash:8].css’, // 设置最终输出的文件名 chunkFilename: ‘[id].[hash:8].css’ }), ], optimization: { minimizer: [ new UglifyJsPlugin({ cache: true, //启用文件缓存 parallel: true, // 并行化处理,多进程压缩 sourceMap: true }), new OptimizeCSSAssetsPlugin({}), ] } };

module.exports = merge(common, prodConfig);

  1. <a name="Kz5iT"></a>
  2. ### 2.16 package.json配置
  3. ```json
  4. "scripts": {
  5. "build": " npx webpack --config webpack.prod.js",
  6. "serve": " npx webpack-dev-server --open --config webpack.dev.js"
  7. },

2.17 manifest 配置

webpack 通过 manifest,可以追踪所有模块到输出 bundle 之间的映射,来控制 webpack 输出。通过 [WebpackManifestPlugin](https://github.com/danethurber/webpack-manifest-plugin) 插件,可以将 manifest 数据提取为一个容易使用的 json 文件。

  • 安装:npm install webpack-manifest-plugin -D
  • 使用 ```javascript const ManifestPlugin = require(‘webpack-manifest-plugin’);

module.exports = { // … plugins: [ new ManifestPlugin() ] };

  1. <a name="1Kpqr"></a>
  2. ### 2.18 SplitChunksPlugin
  3. SplitChunksPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。如插件将 lodash 分离到单独的 chunk,并且将其从 main bundle 中移除,减轻大小
  4. ```javascript
  5. const path = require('path');
  6. module.exports = {
  7. mode: 'development',
  8. entry: {
  9. index: './src/index.js',
  10. another: './src/another-module.js',
  11. },
  12. output: {
  13. filename: '[name].bundle.js',
  14. path: path.resolve(__dirname, 'dist'),
  15. },
  16. + optimization: {
  17. + splitChunks: {
  18. + chunks: 'all',
  19. + },
  20. + },
  21. };

2.19 prefetch/preload

预获取和预加载。在声明 import 时,使用下面这些内置指令,可以让 webpack 输出 “resource hint(资源提示)”,来告知浏览器:

  • prefetch(预获取):将来某些导航下可能需要的资源
    • prefetch chunk 会在父 chunk 加载结束后开始加载
    • prefetch chunk 在浏览器闲置时下载
  • preload(预加载):当前导航下可能需要资源
    • preload chunk 会在父 chunk 加载时,以并行方式开始加载
    • preload chunk 具有中等优先级,并立即下载
    • 不正确地使用 webpackPreload 会有损性能,请谨慎使用

3、总结常用配置

3.1 常用loaders

webpack 默认支持处理 js、json 文件,其他类型都处理不了,这里必须借助 Loader 来对不同类型的文件的进行处理

3.1.1 babel-loader

3.1.2 html-loader

3.1.3 eslint-loader

3.1.4 style-loader

3.1.5 css-loader

3.1.6 postcss-loader

3.1.7 less-loader/sass-loader

3.1.8 url-loader/file-loader

webpack5 新增资源模块(asset module),允许使用资源文件(字体,图标等)而无需配置额外的 loader,因此 file-loader 和 url-loader 都可以不用安装

  • asset/resource 将资源分割为单独的文件,并导出 url,类似之前的 file-loader 的功能.
  • asset/inline 将资源导出为 dataUrl 的形式,类似之前的 url-loader 的小于 limit 参数时功能.
  • asset/source 将资源导出为源码(source code),类似的 raw-loader 功能.
  • asset 会根据文件大小来选择使用哪种类型,当文件小于 8 KB(默认) 的时候会使用 asset/inline,否则会使用 asset/resource

3.2 常用plugins

插件(Plugin)可以贯穿 Webpack 打包的生命周期,执行不同的任务

3.2.1 html-webpack-plugin

创建html页面并自动引入打包生成的js文件

3.2.2 clean-webpack-plugin

打包前自动删除上次构建输出目录,webpack 5 可配置 output:{clean: true},不用下载

3.2.3 mini-css-extract-plugin

3.2.4 hard-source-webpack-plugin

hard-source-webpack-plugin 为模块提供了中间缓存,重复构建时间大约可以减少 80%,但是在 webpack5 中已经内置了模块缓存,不需要再使用此插件

3.2.5 optimize-css-assets-webpack-plugin

压缩css

3.2.6 terser-webpack-plugin

压缩js,因为 webpack5 内置了terser-webpack-plugin 插件,所以我们不需重复安装

3.3 其他配置

3.3.1 cross-env 环境配置

3.3.2 webpack-dev-server 本地服务配置

devServer 主要就是启动了一个静态服务器,让开发者可以方便的预览自己工程构建的webApp。通过配置 devServer 和 HotModuleReplacementPlugin (aka HMR)插件来实现热更新

3.3.3 sourcemap 配置

devtool build rebuild 显示代码 SourceMap 文件 描述
(none) 很快 很快 无法定位错误
eval 很快(cache) 编译后 定位到文件
source-map 很慢 很慢 源代码 定位到行列
eval-source-map 很慢 一般(cache) 编译后 有(dataUrl) 定位到行列
eval-cheap-source-map 一般 快(cache) 编译后 有(dataUrl) 定位到行
eval-cheap-module-source-map 快(cache) 源代码 有(dataUrl) 定位到行
inline-source-map 很慢 很慢 源代码 有(dataUrl) 定位到行列
hidden-source-map 很慢 很慢 源代码 无法定位错误
nosource-source-map 很慢 很慢 源代码 定位到文件
关键字 描述
inline 代码内通过 dataUrl 形式引入 SourceMap
hidden 生成 SourceMap 文件,但不使用
eval eval(…) 形式执行代码,通过 dataUrl 形式引入 SourceMap
nosources 不生成 SourceMap
cheap 只需要定位到行信息,不需要列信息
module 展示源代码中的错误位置
  • 开发环境推荐:eval-cheap-module-source-map
  • 生产环境推荐:none

3.3.4 webpack-bundle-analyzer 打包体积分析

3.3.5 speed-measure-webpack-plugin 打包速度分析

3.3.6 tree-shaking 配置

  • Tree-shaking 可以使得项目最终构建(Bundle)结果中只包含你实际需要的代码

webpack 默认支持,需要在 .bablerc 里面设置 model:false,即可在生产环境下默认开启

  1. // ./babelrc.js
  2. module.exports = {
  3. presets: [
  4. [
  5. "@babel/preset-env",
  6. {
  7. module: false,
  8. useBuiltIns: "entry",
  9. corejs: "3.9.1",
  10. targets: {
  11. chrome: "58",
  12. ie: "11",
  13. },
  14. },
  15. ],
  16. ],
  17. plugins: [
  18. ["@babel/plugin-proposal-decorators", { legacy: true }],
  19. ["@babel/plugin-proposal-class-properties", { loose: true }],
  20. ]
  21. };

参考资料