[原文链接]http://feclub.cn/post/content/20180403

概念

webpack可以看做是模块打包机。它通过分析项目结构,找到 js、css、图片等模块或资源,并将其打包为合适的格式以供浏览器使用。

功能

  • 代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等。
  • 文件优化/压缩:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。
  • 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。
  • 模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
    等等...

webpack4主要变化

  • 环境支持:官方宣布不在支持Node 4
  • mode 属性:webpack需要设置mode属性,可以是 development 或 production。

    通过mode, 你可以轻松设置打包环境。

    • 如果你将 mode 设置成 development,你将获得最好的开发阶段体验。这得益于webpack针对开发模式提供的特性:
      • 浏览器调试工具
      • 注释、开发阶段的详细错误日志和提示
      • 快速和优化的增量构建机制
    • 如果你将mode设置成了 production, webpack将会专注项目的部署,包括以下特性:
      • 开启所有的优化代码
      • 更小的bundle大小
      • 去除掉只在开发阶段运行的代码
      • 可以开启Scope hoisting和Tree-shaking
  • 插件和优化:webpack4删除了CommonsChunkPlugin插件,它使用内置API optimization.splitChunks

优化

  • 优化loader配置(缩小文件搜索范围)

    • include & exclude
    • resolve.alias(配置项通过别名来把原导入路径映射成一个新的导入路径 ,此优化方法会影响使用Tree-Shaking去除无效代码)
    • resolve.modules
    • resolve.extensions
    • module.noParse(module.noParse 配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析处理)

      module: {
       noParse: [/react\.min\.js/]
      }
      
  • .dll 为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据。

    • DllPlugin插件: 用于打包出一个个动态链接库

      module.exports = {
        entry: {
            react: ['react'] //react模块打包到一个动态链接库
        },
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: '[name].dll.js', //输出动态链接库的文件名称
            library: '_dll_[name]' //全局变量名称
        },
        plugins: [
            new webpack.DllPlugin({
                name: '_dll_[name]', //和output.library中一致,值就是输出的manifest.json中的 name值
                path: path.join(__dirname, 'dist', '[name].manifest.json')
            })
        ]
      }
      
    • DllReferencePlugin: 在配置文件中引入DllPlugin插件打包好的动态链接库

        plugins: [
           new webpack.DllReferencePlugin({
           manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')),
           })
        ]
      
  • HappyPack针对loader解析过程,能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。

  • ParallelUglifyPlugin可以把对JS文件的串行压缩变为开启多个子进程并行执行

  • 区分环境:通过环境变量区分,用 webpack-merge覆盖相应配置

  • CDN:配置publicPath

    • 静态资源的URL变成指向CDN服务器的地址
    • 把不同的静态资源分配到不同的CDN服务器上
  • Tree Shaking(ES6模块静态解析)
    Tree Shaking 可以用来剔除JavaScript中用不上的死代码。它依赖静态的ES6模块化语法,例如通过import和export导入导出。

  • 开启 Scope Hoisting:参考以下文章

    https://webpack.js.org/plugins/module-concatenation-plugin/#src/components/Sidebar/Sidebar.jsx
    https://segmentfault.com/a/1190000012600832

    通过分析出模块之间的依赖关系,尽可能的把打散的模块合并到一个函数中去,但前提是不能造成代码冗余。 因此只有那些被引用了一次的模块才能被合并。

          const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
          module.exports = {
               plugins: [
                   // 开启 Scope Hoisting
                   new ModuleConcatenationPlugin(),
               ]
          };
    
  • 提取公共代码
    使用 common-chunk-and-vendor-chunk(用法待官方文档更新)

    optimization: {
          splitChunks: {
              cacheGroups: {
                  commons: {
                      chunks: "initial",
                      minChunks: 2,
                      maxInitialRequests: 5, // The default limit is too small to showcase the effect
                      minSize: 0 // This is example is too small to create commons chunks
                  },
                  vendor: {
                      test: /node_modules/,
                      chunks: "initial",
                      name: "vendor",
                      priority: 10,
                      enforce: true
                  }
              }
          }
      }
    
  • 代码分离

    • 入口起点:使用 entry 配置手动地分离代码。

        entry: {
            index: './src/index.js',
            another: './src/another-module.js'
        }
      
    • 防止重复:使用 splitChunks 去重和分离 chunk。

    • 动态导入:通过模块的内联函数调用来分离代码。