Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

splitChunks与source-map

1. splitChunks

  • 原理

    • 把要打包的所有代码,按照路径匹配规则,分为多个包
  • 在 json 中配置

    optimization: {
        splitChunks: {
            chunks: "all",
            minSize: 30000,
            minChunks: 2,
            name: true,
            cacheGroups: {
              antd: {
                name: "antd",
                test({ resource }: any) {
                  return  /[\\/]node_modules[\\/](antd|@antv|@ant-design)[\\/]/.test(resource);
                },
                filename: "[name].[chunkhash:8].js",
                priority: 10,
                enforce: true
              },
              vendors: {
                name: "vendors",
                test({ resource }: any) {
                  return  /[\\/]node_modules[\\/]/.test(resource);
                },
                filename: "[name].[chunkhash:8].js",
                priority: -10,
                enforce: true
              }
            }
        }
    }
    
  • 在 chain 中配置

    config.optimization.splitChunks({
      chunks: "all",
      minSize: 30000,
      minChunks: 2,
      name: true,
      cacheGroups: {
        antd: {
          name: "antd",
          test({ resource }: any) {
            return /[\\/]node_modules[\\/](antd|@antv|@ant-design)[\\/]/.test(
              resource
            );
          },
          filename: "[name].[chunkhash:8].js",
          priority: 10,
          enforce: true,
        },
        vendors: {
          name: "vendors",
          test({ resource }: any) {
            return /[\\/]node_modules[\\/]/.test(resource);
          },
          filename: "[name].[chunkhash:8].js",
          priority: -10,
          enforce: true,
        },
      },
    });
    
    • 这里在主包之外,额外分出两个包
      • 一个是antd,对 UI 组件库进行单独文件打包
      • 一个是vendors,对剩下的模块依赖进行单独打包
  • 参数解释

    • chunks: "all"

      • 表示对所有 chunks 生效
      • 默认值是"async",只对异步资源生效,这时候生成的 chunk 会带有数字 id,比如 0.js、1.js 等等
      • webpack 规定通过下面方式引入的就是异步资源
        import("./bar.js");
        或者;
        import("./func.js").then(({ add }) => {
          console.log(add(2, 3));
        });
        
        • 这跟 ES6 的 import 区分开来,特别是这里不用必须出现在顶层作用域
      • 不想要数字 id 的话,可以用注释自己指定
        import(/* webpackChunkName: "func" */ "./func.js").then(({ add }) => {
          console.log(add(2, 3));
        });
        
        • 需要结合 output 选项的chunkFilename: "[name].js"使用
    • minChunks: 2

      • 只有该模块被 2 个入口以上同时引用才会进行提取
      • 默认值是 1,只要被 1 个入口使用,就会提取
    • cacheGroups

      • 指定分离 chunks 的规则,一个数组项代表一个规则
      • 默认有两种规则: vendors 和 default
      • 规则内通过 priority 指定优先级,enforce 指定强制生效
  • 在 webpack4 之前,这种功能需要内部自带的插件 webpack.optimize.CommonsChunkPlugin 来实现

    • 原理是提取多个入口文件中的公共部分
    • 对于单入口文件也可以通过修改 entry 添加一个 vendor 数组提取想要的部分

2. source-map

  • 原理

    • 打包的同时生成.map 文件,可被开发者工具加载,逆向还原出源代码,便于 debug
  • 在 json 中配置

    devtool: "source-map";
    
    • 只对 js 生效,而对于 css,需要在对应 css-loader 下的 options 中添加一项sourceMap: true
    • 会延长构建的时间,因为会生成完整文件,如果想生成简略版本,可以改为cheap-source-map或者cheap-module-eval-source-map
  • 安全问题

    • 虽然 debug 方便了,但如果传到生产环境,就容易被用户逆向看到源代码

    • 【解决办法 1】使用hidden-source-map

      • 仍会产出完整 map 文件,但不会在 bundle 中添加引用,这样用户就看不到
      • 然后要借助第三方的错误跟踪平台,比如 Sentry,自己把 map 文件传上去,然后在平台里面查看
    • 【解决办法 2】使用nosources-source-map

      • 只能让用户看到源码的目录结构,看不到文件内容,debug 时也可以看到源代码的错误栈,一般够用
    • 【解决办法 3】ngnix 配置对 map 文件的白名单访问权限