Webpack笔记

160 阅读12分钟

1. Webpack简介

Nodejs 10版本以上,Webpack 4.26版本以上

1.1 webpack是什么

webpack是一种前端资源构建工具,一个静态模块打包器(module bundler)。

在webpack看来,前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。

它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundler)。

浏览器不能识别less文件,我们需要借助工具将less编译成css ,这里需要一个工具叫XXX

构建工具将前端一系列的小操作整成大的

静态模块打包器

告诉webpack入口文件index.js ,引入各种资源,把各种依赖都记录好,形成依赖关系图,然后把各种资源引进来,叫做chunk(块), 再对chunk各种处理比方所less编译成css,js编译成浏览器能识别的js ...最后把打包文件输出出去叫bundle 。

1.2 webpack的五个核心概念

1.2.1 Entry

入口(Entry)表示Webpack打包后以哪个文件为入口起点开始打包,分析建构内部依赖图

1.2.2 Output

输出(output)指示Webpack打包后的资源bundles 输出到哪里去,以及如何命名。

1.2.3 Loader

Loader让Webpack能够去处理那些非JavaScript文件(webpack自身只理解JavaScript)

1.2.4 Plugins

插件(Plugins)可以用于执行范围更广的任务。 插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。

1.2.5 Mode

模式Mode指示Webpack使用相应模式的配置。

选项描述特点
development会将process.env.NODE_ENV的值设为development。启用NamedChunksPlugin 和 NamedModulesPlugin能让代码本地调试运行的环境
production会将process.env.NODE_ENV的值设为production。启用FlagDependencyUsagePlugin,FlagIncludeedChunksPlugin,ModuleConcatenationPlugin,SideEffectsFlagPlugin 和 UglifyJsPlugin能让代码优化上线运行的环境

2. Webpack的初体验

npm init 

npm i webpack webpack-cli -g

npm i webpack webpack-cli -D

index.js: webpack入口起点文件

  1. 运行指令

开发环境: webpack ./src/index.js -o ./build/built.js --mode=development

     webpack会以./src/index.js为入口文件开始打包,打包后输出到./build/built.js 整体打包环境,是开发环境

生产环境: webpack ./src/index.js -o ./bulid/bulit.js --mode=production

      webpack会以./src/index.js为入口文件开始打包,打包后输出到./bulid/bulit.js整体打包环境,是生产环境

2. 结论

  • webpack能处理js/json资源,不能处理css/img等其他资源
  • 生产环境比开发环境多一个压缩js代码
  • 生产环境和开发环境将ES6模块编译成浏览器能识别的模块化

3. 打包样式资源

webpack.config.js : webpack的配置文件

作用: 指示webpack干哪些活(当你运行webpack指令时,会加载里面的配置)

所有构建工具都是基于node.js平台的,模块化默认采用commonjs

// resolve用来拼接绝对路径的方法
const { resolve } = require('path')
module.exports = {
    // webpack配置
   // 入口起点
   entry: './src/index.js',
   // 输出
   output: {
     // 输出文件名
     filename: 'built.js',
     // 输出路径
     // __dirname nodejs的变量,代表当前文件的目录绝对路径
     path: resolve(__dirname,'build')

   },
   // loader的配置
   modules: {
     rules: [
       // 详细loader配置
      //  不同文件必须配置不同loader处理
       {
        //  匹配哪些文件
         test: /\.css$/,
        //  使用哪些loader进行处理
         use: [
          //  use数组中loader执行顺序: 从右到左,从下到上 依次执行
           // 创建style标签,将js中的样式资源插入进行,添加到head中生效
           'style-loader',
           // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
           'css-loader'
         ]

       },{
         test: /\.less$/,
         use: [
           'style-loader',
           'css-loader',
           // 将less文件编译成css文件
          //  需要下载less-loader和less 
           'less-loader'
         ]
       }
     ]
   },
   // plugins的配置
   plugins: [
     // 详细plugins的配置
   ],
   // 模式
   mode: 'development', // 开发模式
  //  mode: 'production'
}


4. 打包html资源

webpack.config.js : webpack的配置文件

loader: 1. 下载 2. 使用(配置loader)

plugins: 1. 下载 2. 引入 3. 使用

// resolve用来拼接绝对路径的方法
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    // webpack配置
   // 入口起点
   entry: './src/index.js',
   // 输出
   output: {
     // 输出文件名
     filename: 'built.js',
     // 输出路径
     // __dirname nodejs的变量,代表当前文件的目录绝对路径
     path: resolve(__dirname,'build')

   },
   // loader的配置
   modules: {
     rules: [
       // 详细loader配置
      //  不同文件必须配置不同loader处理
       {
        //  匹配哪些文件
         test: /\.css$/,
        //  使用哪些loader进行处理
         use: [
          //  use数组中loader执行顺序: 从右到左,从下到上 依次执行
           // 创建style标签,将js中的样式资源插入进行,添加到head中生效
           'style-loader',
           // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
           'css-loader'
         ]

       },{
         test: /\.less$/,
         use: [
           'style-loader',
           'css-loader',
           // 将less文件编译成css文件
          //  需要下载less-loader和less 
           'less-loader'
         ]
       }
     ]
   },
   // plugins的配置
   plugins: [
     // 详细plugins的配置
     //html-webpack-plugin npm i html-webpack-plugin -D
     // 功能: 默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
     // 需求: 需要有结构的HTML文件
     new HtmlWebpakcPlugin({
       // 赋值'./src/index.html'文件,并自动引入打包输出的所有资源(JS/CSS)
       template: './src/index.html'
     })
 
   ],
   // 模式
   mode: 'development', // 开发模式
  //  mode: 'production'
}

5. 打包图片资源

// resolve用来拼接绝对路径的方法
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    // webpack配置
   // 入口起点
   entry: './src/index.js',
   // 输出
   output: {
     // 输出文件名
     filename: 'built.js',
     // 输出路径
     // __dirname nodejs的变量,代表当前文件的目录绝对路径
     path: resolve(__dirname,'build')

   },
   // loader的配置
   modules: {
     rules: [
       // 详细loader配置
      //  不同文件必须配置不同loader处理
       {
        //  匹配哪些文件
         test: /\.css$/,
        //  使用哪些loader进行处理,要使用多个loader处理用use
         use: [
          //  use数组中loader执行顺序: 从右到左,从下到上 依次执行
           // 创建style标签,将js中的样式资源插入进行,添加到head中生效
           'style-loader',
           // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
           'css-loader'
         ]

       }, {
         test: /\.less$/,
         use: [
           'style-loader',
           'css-loader',
           // 将less文件编译成css文件
          //  需要下载less-loader和less 
           'less-loader'
         ]
       }, {
         //处理图片资源
         test: /\.(jpg|png|gif)$/,
        //  下载url-loader file-loader npm i url-loader file-loader -D
         loader: 'url-loader', // 使用一个loader
         options: {
           // 图片大小小于8拷贝,就会被base64处理
          //  优点: 减少请求时数量(减轻服务器压力)
          //  缺点: 图片体积会更大(文件请求速度更慢)
           limit: 8 * 1024,
           // 问题: 因为rul-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
          //  解析时会出问题: [object Module]
          // 解决: 关闭url-loader的es6模块化,使用commonjs去解析
          esModule: false,
          // 给图片进行重命名 
          // [hash:10]取图片的hash的前10位
          // [ext] 取文件原来扩展名
          name: '[hash:10].[ext]'
         }

       }, {
         test: /\.html$/,
         //html-loader处理html文件的img图片(负责引入img, 从而能被url-loader打包处理) 
         //  npm i html-loader -D 
         loader: 'html-loader',

       }
     ]
   },
   // plugins的配置
   plugins: [
     // 详细plugins的配置
     //html-webpack-plugin npm i html-webpack-plugin -D
     // 功能: 默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
     // 需求: 需要有结构的HTML文件
     new HtmlWebpakcPlugin({
       // 赋值'./src/index.html'文件,并自动引入打包输出的所有资源(JS/CSS)
       template: './src/index.html'
     })
 
   ],
   // 模式
   mode: 'development', // 开发模式
  //  mode: 'production'
}

6. 打包其他资源

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
   entry: './src/index.js',
   output: {
     filename: 'built.js',
     path: resolve(__dirname,'build')
   },
   modules: {
     rules: [
       {
         test: /\.css$/,
         use: [
           'style-loader',
           'css-loader'
         ]
       }, {
         // 打包其他资源(除了html/js/css资源以外的资源)
         exclude: /\.(css|js|html)$/, //排除css,js,html
         loader: 'file-loader',
         options: {
            name: '[hash:10].[ext]'
         }

       }
     ]
   },
   plugins: [
     new HtmlWebpakcPlugin({
       template: './src/index.html'
     })
   ],
   mode: 'development', // 开发模式
}

7. devServer

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
   entry: './src/index.js',
   output: {
     filename: 'built.js',
     path: resolve(__dirname,'build')
   },
   modules: {
     rules: [
       {
         test: /\.css$/,
         use: [
           'style-loader',
           'css-loader'
         ]
       }, {
         exclude: /\.(css|js|html)$/, 
         loader: 'file-loader',
         options: {
            name: '[hash:10].[ext]'
         }
       }
     ]
   },
   plugins: [
     new HtmlWebpakcPlugin({
       template: './src/index.html'
     })
   ],
   mode: 'development', // 开发模式
  //  开发服务器devServer,用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
  // 特点: 只会在内存中编译打包,不会有任务输出
  // 启动devServer指令为: npx webpack-dev-server 
  // 安装 npm i webpack-dev-server -D
  devServer: {
     // 项目构建后的路径
    contentBase: resolve(__dirname,'build'),
    // 启动gzip压缩
    compress: true,
    // 端口号
    port: 3000,
    // 自动打开本地默认浏览器
    open: true
  }
}

8. 开发环境配置

开发环境配置: 能让代码运行

运行项目指令:

webpack: 会将打包结果输出出去

npx webpack-dev-server: 只会在内存中编译打包,没有输出

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
   entry: './src/js/index.js',
   output: {
     filename: 'js/built.js',
     path: resolve(__dirname,'build')
   },
   modules: {
     // loader的配置
     rules: [
       {
        // 处理less资源
         test: /\.less$/,
         use: ['style-loader','css-loader','less-loader']
       },
       {
        //  处理css资源
         test: /\.css$/,
         use: ['style-loader','css-loader']
       }, {
         //处理图片资源
         test: /\.(jpg|png|gif)$/,
         loader: 'url-loader', 
         options: {
            limit: 8 * 1024,
            esModule: false,
            name: '[hash:10].[ext]',
            outputPath: 'imgs'
         }
       }, {
         // 处理html中img资源
         test: /\.html$/,
         loader: 'html-loader',
       }, {
        //  处理其他资源
         exclude: /\.(css|less|js|html|jpg|png|gif)$/, 
         loader: 'file-loader',
         options: {
            name: '[hash:10].[ext]'
         },
          outputPath: 'media'
       }
     ]
   },
   plugins: [
    //  plugins配置
     new HtmlWebpakcPlugin({
       template: './src/index.html'
     })
   ],
   mode: 'development',
   devServer: {
    contentBase: resolve(__dirname,'build'),
    compress: true,
    port: 3000,
    open: true
  }
}

9. 生产环境配置

const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';

// 复用loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader',
  {
    // 还需要在package.json中定义browserslist
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]
    }
  }
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [...commonCssLoader]
      },
      {
        test: /\.less$/,
        use: [...commonCssLoader, 'less-loader']
      },
      /*
        正常来讲,一个文件只能被一个loader处理。
        当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
          先执行eslint 在执行babel
      */
      {
        // 在package.json中eslintConfig --> airbnb
        test: /\.js$/,
        exclude: /node_modules/,
        // 优先执行
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env',
              {
                useBuiltIns: 'usage',
                corejs: {version: 3},
                targets: {
                  chrome: '60',
                  firefox: '50'
                }
              }
            ]
          ]
        }
      },
      {
        test: /\.(jpg|png|gif)/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          outputPath: 'imgs',
          esModule: false
        }
      },
      {
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        exclude: /\.(js|css|less|html|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production'
};

10. 性能优化配置

开发环境性能优化

  • 优化打包构建速度
  • 优化代码调试

生产环境性能优化

  • 优化打包构建速度
  • 优化代码运行的性能

HMR: hot module replacement 热模块替换 / 模块热替换

作用: 一个模块发生变化,只会重新打包这一个模块,而不是打包所有,这样会极大的提升构建速度

devServer: {
  hot: true // 开启HMR功能。 当修改了webpack配置,新配置要想生效,必须重启服务
}

样式文件:可以使用HMR功能:因为style-loader内部实现了~

js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码

注意:HMR功能对js的处理,只能处理非入口js文件的其他文件

html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了~ (不用做HMR功能)

解决:修改entry入口,将html文件引入

  1. oneOf

loader只会匹配一个

注意: 不能有两个配置处理同一种文件,提升构建速度 优化生产环境的打包速度

  1. 缓存

babel缓存 和 文件资源缓存

  • babel缓存 cacheDirectory: true

作用: 让第二次打包构建速度更快

  • 文件资源缓存

hash: 每次webpack构建时会生成一个唯一的hash值。

问题: 因为js和css同时使用一个hash值。

如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)

chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样

问题: js和css的hash值还是一样的

因为css是在js中被引入的,所以同属于一个chunk

contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样

作用: 让代码上线运行缓存更好使用

  1. tree shaking

tree shaking:去除无用代码

前提:(1). 必须使用ES6模块化 (2). 开启production环境

作用: 减少代码体积

在package.json中配置 :

"sideEffects": false 所有代码都没有副作用(都可以进行tree shaking

问题:可能会把css / @babel/polyfill (副作用)文件干掉

"sideEffects": ["*.css", "*.less"] 这些文件不再进行tree shaking

  1. code split (代码分割) Demo1:

// 通过单入口和多入口的方式拆分

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 单入口
  // entry: './src/js/index.js',
  entry: {
    // 多入口:有一个入口,最终输出就有一个bundle
    index: './src/js/index.js',
    test: './src/js/test.js'
  },
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production'
};
// 缺点: 我们很难有多个入口文件要改,改起来很麻烦,所以不推荐

Demo2:


const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 单入口
  // entry: './src/js/index.js',
  entry: {
    index: './src/js/index.js',
    test: './src/js/test.js'
  },
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  /*
    optimization的作用: 
    1. 可以将node_modules中代码单独打包一个chunk最终输出
    2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
  */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  mode: 'production'
};
// 这种方式用的也比较少

Demo3:


const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 单入口
  entry: './src/js/index.js',
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  /*
    1. 可以将node_modules中代码单独打包一个chunk最终输出
    2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
  */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  mode: 'production'
};

// 通过js代码,让某个文件被单独打包成一个chunk 
// import动态导入语法: 能将某个文件单独打包 
// 第三种方法: 通过import动态导入语法+ optimizaiton配置来完成所有的代码分割,
//从而让我们的代码不是一个巨大的js文件,而是拆分成多个小的js文件,从而能实现并行加载,速度更快(推荐)
  1. lazy loading
document.getElementById('btn').onclick = function() {
    // 懒加载~:当文件需要使用时才加载~
    // 预加载 prefetch:会在使用之前,提前加载js文件 
    // 正常加载可以认为是并行加载(同一时间加载多个文件)  
    // 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源

    import ( /* webpackChunkName: 'test', webpackPrefetch: true */ './test').then(({ mul }) => {
        console.log(mul(4, 5));
    });
};

总结: 懒加载就是利用代码分割的思路, 将代码分割的import语法, 放到异步回调函数中, 当触发异步回调的函数时, 再去懒加载这个代码。 预加载 webpackPrefetch: true

  1. pwa

const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

/*
  PWA: 渐进式网络开发应用程序(离线可访问)
    workbox --> workbox-webpack-plugin
*/

// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';

// 复用loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader',
  {
    // 还需要在package.json中定义browserslist
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]
    }
  }
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        // 在package.json中eslintConfig --> airbnb
        test: /\.js$/,
        exclude: /node_modules/,
        // 优先执行
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      },
      {
        // 以下loader只会匹配一个
        // 注意:不能有两个配置处理同一种类型文件
        oneOf: [
          {
            test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']
          },
          /*
            正常来讲,一个文件只能被一个loader处理。
            当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
              先执行eslint 在执行babel
          */
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'usage',
                    corejs: { version: 3 },
                    targets: {
                      chrome: '60',
                      firefox: '50'
                    }
                  }
                ]
              ],
              // 开启babel缓存
              // 第二次构建时,会读取之前的缓存
              cacheDirectory: true
            }
          },
          {
            test: /\.(jpg|png|gif)/,
            loader: 'url-loader',
            options: {
              limit: 8 * 1024,
              name: '[hash:10].[ext]',
              outputPath: 'imgs',
              esModule: false
            }
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            exclude: /\.(js|css|less|html|jpg|png|gif)/,
            loader: 'file-loader',
            options: {
              outputPath: 'media'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.[contenthash:10].css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    }),
    new WorkboxWebpackPlugin.GenerateSW({
      /*
        1. 帮助serviceworker快速启动
        2. 删除旧的 serviceworker

        生成一个 serviceworker 配置文件~
      */
      clientsClaim: true,
      skipWaiting: true
    })
  ],
  mode: 'production',
  devtool: 'source-map'
};

在入口文件index.js中注册serviceworker

注意:

  1. eslint不认识 window、navigator全局变量 解决:需要修改package.json中eslintConfig配置
  "env": {
    "browser": true // 支持浏览器端全局变量
  }
  1. sw代码必须运行在服务器上
nodejs
  npm i serve -g
  serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去

// 注册serviceWorker

// 处理兼容性问题
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(() => {
        console.log('sw注册成功了~');
      })
      .catch(() => {
        console.log('sw注册失败了~');
      });
  });
}
  1. 多进程打包
/*
  正常来讲,一个文件只能被一个loader处理。
  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
    先执行eslint 在执行babel
*/
...
{
  test: /\.js$/,
  exclude: /node_modules/,
  use: [
    /* 
      开启多进程打包。 
      进程启动大概为600ms,进程通信也有开销。
      只有工作消耗时间比较长,才需要多进程打包
    */
    {
      loader: 'thread-loader',
      options: {
        workers: 2 // 进程2个
      }
    },
    {
      loader: 'babel-loader',
      options: {
        presets: [
          [
            '@babel/preset-env',
            {
              useBuiltIns: 'usage',
              corejs: { version: 3 },
              targets: {
                chrome: '60',
                firefox: '50'
              }
            }
          ]
        ],
        // 开启babel缓存
        // 第二次构建时,会读取之前的缓存
        cacheDirectory: true
      }
    }
  ]
},
...
  1. externals

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'production',
  externals: {
    // 拒绝jQuery被打包进来
    // 忽略库名 -- npm 包名
    jquery: 'jQuery'
  }
};

  1. dll

webpack.config.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    // 告诉webpack哪些库不参与打包,同时使用时的名称也得变~
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname, 'dll/manifest.json')
    }),
    // 将某个文件打包输出去,并在html中自动引入该资源
    new AddAssetHtmlWebpackPlugin({
      filepath: resolve(__dirname, 'dll/jquery.js')
    })
  ],
  mode: 'production'
};


webpack.dll.js

/*
  使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
    当你运行 webpack 时,默认查找 webpack.config.js 配置文件
    需求:需要运行 webpack.dll.js 文件
      --> webpack --config webpack.dll.js
*/

const { resolve } = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    // 最终打包生成的[name] --> jquery
    // ['jquery'] --> 要打包的库是jquery
    jquery: ['jquery'],
  },
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'dll'),
    library: '[name]_[hash]' // 打包的库里面向外暴露出去的内容叫什么名字
  },
  plugins: [
    // 打包生成一个 manifest.json --> 提供和jquery映射
    new webpack.DllPlugin({
      name: '[name]_[hash]', // 映射库的暴露的内容名称
      path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径
    })
  ],
  mode: 'production'
};


总结

webpack性能优化

  • 开发环境性能优化
  • 生产环境性能优化

开发环境性能优化

  • 优化打包构建速度
    • HMR
  • 优化代码调试
    • source-map

生产环境性能优化

  • 优化打包构建速度
    • oneOf
    • babel缓存
    • 多进程打包
    • externals
    • dll
  • 优化代码运行的性能
    • 缓存(hash-chunkhash-contenthash)
    • tree shaking
    • code split
    • 懒加载/预加载
    • pwa

11. webpack配置详解

待更新...