webpack--代码分片

webpack--代码分片,第1张

一、代码分片

(1)代码分片是webpack作为打包工具所特有的一项技术,通过这项技术我们可以把代码按照特定的形式进行拆分,使用户不必一次全部加载,而是按需加载

(2)代码分片可以有效降低首屏加载资源的大小。

二、通过入口划分代码

(1)webpack中每个入口(entry)都将生成一个对应的资源文件,通过入口的配置我们可以进行一些简单有效的代码划分。

(2)对于web应用来说通常会有一些库和工具是不常变动的,我们可以把它们放在一个单独的入口,由该入口产生的资源不会经常更新,因此可以有效地利用客户端缓存,让用户不必在每次请求页面时都重新加载。

//webpack.config.js
entry: {
  app: './app.js',
    lib: ['lib-a', 'lib-b', 'lib-c']
}
//index.html

(3)这种拆分方法主要适合于那些将接口绑定在全局对象上的库,因为业务代码中的模块无法直接引用库中的模块,二者属于不同的依赖树

三、CommonsChunkPlugin

(1) CommonsChunkPlugin是webpack4之前内部自带的插件(webpack4之后替换为SplitChunks)。它可以将多个Chunk中公共的部分提取出来。

(2)公共模块的提取可以为项目带来几个收益

1、开发过程中减少了重复模块打包,可以提升开发速度。

2、减小整体资源体积。

3、合理分片后的代码可以更有效地利用客户端缓存。

(3)配置 

const webpack = require('webpack')
module.exports = {
  entry: {
    index: './src/index.js',
    lib: './src/lib.js'
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "commons",//对应于上面的entry的key
      filename: 'commons.js'
    })
  ]
}

插件配置项:

name:用于指定公共chunk的名字。

filename:提取后的资源文件名。

记得在页面中添加一个scrcipt标签来引入common.js,并且注意,该JS一定要在其他JS之前引入。

(4)虽然CommonsChunkPlugin主要用于提取多入口之间公共模块,但这不代表对于单入口应用就无法使用。我们仍然可以用它来提取第三方类库及业务中不常更新的模块,只要单独为它们创建一个入口即可。

const webpack = require('webpack')
module.exports = {
  entry: {
    app: './app.js',
    vendor: ['react']
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      filename: 'vendor.js'
    })
  ]
}

(5)设置提取范围

配置项 chunks 可以规定从那些入口中提取公共模块。

const webpack = require('webpack')
module.exports = {
  entry: {
    a: './a.js',
    b: './b.js',
    c: './c.js',
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "commons",
      filename: 'commons.js',
      chunks: ['a', 'b']
    })
  ]
}

(6)设置提取规则

1、默认的规则是只要一个模块被两个入口chunk所引用就会被提取出来。

2、使用配置项:minChunks(可为数字、Infinity、函数)

  • 数字

(1)为n时,只有该模块被n个入口同时引用才会进行提取。另外,这个阈值不会影响通过数组形式传入模块的提取。

  • Infinity

(1)设置为无穷代表提起的阈值无限高,也就是说所有模块都不会被提取。

(2)配置项的意义

1、只想让webpack提取特定的几个模块,并将这些模块通过数组型入口传入,这样做的好处是提取那些模块是完全可控的。

2、为了生成一个没有任何模块而仅仅包含webpack初始化环境的文件,这个文件我们通常称为mainifest。 

  • 函数

(1)可以让我们更细粒度地控制公共模块。

(2)webpack打包过程中地每个模块都会经过这个函数地处理,当函数地返回值是true时进行提取。

new webpack.optimize.CommonsChunkPlugin({
  name: "vendor",
  filename: 'vendor.js',
  minChunks: function (module, count) {
    //module.context模块目录路径
    if (module.context && module.context.includes('node_modules')) {
      return true
    }
    //module.resource包含模块名的完整路径
    if (module.resource && module.resource.endsWith('util.js')) {
      return true
    }
    //count为模块的引用次数
    if (count > 5) {
      return true
    }
  }
})

(7)hash与长效缓存

1、当我们用这个插件提取公共模块时,提取后的资源内部不仅仅是模块的代码,往往还包括webpack的运行时。webpack运行时指的是初始化环境的代码,如创建模块缓存对象、声明模块加载函数等。

2、问题:运行时包含模块id,id改变会导致运行时的代码发生变动,进一步影响chunk hash 的生成。其改变会导致用户频繁地更新资源。

解决方案:将运行时的代码单独提取出来。

const webpack = require('webpack')
module.exports = {
  entry: {
    app: './app.js',
    vendor: ['react']
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: "manifest",
    }),
  ]
}

注意:

1、manifest必须出现在最后,否则webpack将无法正常提取模块。

2、在页面中manifest.js应该最先被引入,用来初始化webpack环境。

(8)CommonsChunkPlugin的不足

1、一个CommonsChunkPlugin只能提取一个vendor。提取多个要配置多个插件。

2、manifest实际上上会使浏览器多加载一个资源,这对于页面渲染速度是不友好的。

3、由于内部设计的缺陷,在提取公共模块的时候会破坏掉原有Chunk中模块的依赖,导致难以进行更多的优化。比如在异步chunk的场景下,其并不会按照我们预期正常工作。

四、optimization.SplitChunks
module.exports = {
  entry: { app: "./src/index.js" },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  mode:'development',
  optimization: {
    splitChunks: {
    //对所有的chunks生效(默认情况下,只对异步chunks生效,并且不需要配置)
      chunks: "all"
    }
  },
};

 mode是webpack4中新增的配置项,可以针对当前是开发环境还是生成环境自动添加对应的一些webpack配置。

(1)SplitChunks默认情形下的提取条件

1、提取后的chunk可被共享或者来自node_modules目录。

2、提取后的JavaScript chunk体积大于30KB(压缩和gzip之前),CSS chunk 体积大于50KB。

3、在按需加载过程中,并行请求的资源最大值小于等于5。

4、在首次加载时,并行请求的资源数最大值小于等于3.

 (2)配置

  • chunks 选项,决定要提取哪些模块
    1、默认是 async :只提取异步加载的模块出来打包到一个文件中。
    异步加载的模块:通过 import(‘xxx’) 或 require([‘xxx’],() =>{}) 加载的模块。

        2、initial:只对入口chunk生效;

        3、all:不管异步加载还是同步加载的模块都提取出来,打包到一个文件中;

  • minSize 选项:规定被提取的模块在压缩前的大小最小值,单位为字节;
    默认为30000,只有超过了30000字节才会被提取。

  • maxSize 选项:把提取出来的模块打包生成的文件大小不能超过maxSize值;
    如果超过了,要对其进行分割并打包生成新的文件。
    单位为字节,默认为0,表示不限制大小。

  • minChunks 选项:表示要被提取的模块最小被引用次数,引用次数超过或等于minChunks值,才能被提取。

  • maxAsyncRequests 选项:最大的按需(异步)加载次数,默认为 6;

  • maxInitialRequests 选项:打包后的入口文件加载时,还能同时加载js文件的数量(包括入口文件),默认为4。

    优先级 :maxInitialRequests / maxAsyncRequests < maxSize < minSize;

  • automaticNameDelimiter 选项:打包生成的js文件名的分割符,默认为:~

  • name选项:打包生成 js 文件的名称;

  • cacheGroups 选项,核心重点,配置提取模块的方案,里面每一项代表一个提取模块的方案。
    下面是 cacheGroups 每项中特有的选项,其余选项和外面一致,若 cacheGroups 每项中有,就按配置的,没有就使用外面配置的;

    • test 选项:用来匹配要提取的模块的资源路径或名称,值是正则或函数;

    • priority 选项:方案的优先级,值越大表示提取模块时优先采用此方案,默认值为0;

    • reuseExistingChunk 选项:true / false。
      为true时,如果当前要提取的模块,在已经在打包生成的js文件中存在,则将重用该模块,而不是把当前要提取的模块打包生成新的 js 文件。

    • enforce选项:true / false。
      为true时,忽略minSize,minChunks,maxAsyncRequests和maxInitialRequests外面选项

(3)资源异步加载(按需加载)

1、webpack中有两种异步加载的方式:import函数和require.ensure(webpack1中支持的)。

2、与正常ES6中的import语法不同,通过import函数加载的模块及其依赖会被异步地进行加载,并返回一个promise对象。

import('./bar.js').then(({ add }) => {
  console.log(add(2, 3));

})
export function add(a, b) {
  return a + b;
}

3、原理

通过javacript在页面地head标签里插入一个script标签/dist/0.js。

4、ES6中的import必须出现在代码的顶层作用域,而webpack的import函数则可以在任何我们希望的时候调用。

(5)异步chunk的配置

output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist"),
    //指定异步chunk的文件名。命名规则与filename一致,
    //异步chunk默认有名字,其默认值为[id].js
    chunkFilename: '[name].js'
},

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/876342.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存