webpack-module-chunk-bundle

module、chunk、bundle

module

  • 对于webpack来说,所有的资源(.js.css.png)都是module
  • .js文件webpack原生可以处理,其他类型文件,需要通过loader进行转换,然后交给webpack处理
  • webpack配置中,可以通过module字段,对不同module使用不同的rule处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    module: {
    rules: [
    {
    test: /\.css$/,
    use: [
    { loader: "style-loader" },
    { loader: "css-loader" }
    ]
    }, ...
    ]
    },

entry-point

  • 生成依赖图(dependency graph)的入口;
  • webpack只能以.js文件做为生成依赖图的入口;parcel能使用其他模块(.html)做为入口,生成依赖图

chunk

  • webpack内部处理时的概念;
  • 一个chunk是对依赖图的部分(子图)进行封装的结果Chunk the class is the encapsulation for parts of your dependency graph
  • 可以说一个chunk是一堆module的集合
  • 可以通过多个entry-point来生成一个chunk

chunk分类

  • entry chunk
    • 包含webpack runtime code并且是最先执行的chunk
  • initial chunk
    • 包含同步加载进来的module且不包含runtime codechunk
    • entry chunk执行后再执行
  • normal chunk
    • 使用require.ensureSystem.importimport()异步加载进来的module,会被放到normal chunk
    • 一般normal chunk(异步chunk),会单独生成一个bundle,其名称一般通过webpackChunkName魔法注释output.chunkFilename来指定
      • webpackChunkName魔法注释中指定的name可以在output.chunkFilename中使用[name]取到

bundle

  • 最终输出的chunk在用户端,被称之为bundle
  • 正常情况下,可以将chunkbundle当成一个概念,只不过是不同时间的同一个东西
    • chunk和bundle的区别,可以理解为chunk是过程中的代码块(给webpack处理的),bundle是结果的代码块(展现给用户的)
  • 一般一个chunk对应一个bundle,只有在配置了sourcemap时,才会出现一个chunk对应多个bundle的情况;

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// other.js
import(/*webpackChunkName: "lodash */ 'lodash').then(_ => {
  console.log(_)
})


// webpack.config.js
entry:{
main:['./src/main.js','./src/test.js'],
other:['./src.other.js']
},
output:{
path:path.resolve(__dirname,'./dist'),
filename:"[name].bundle.js", // 正常生成的bundle名称
chunkFileName:"[name].async.bundle.js" // normalChunk的名称,也即最终生成的异步bundle的名称
}
  • main.js中引入了gloabl.css
  • other.js中异步导入了lodash并使用了webpackChunkName魔法注释

  • module

    • main.js、test.js、other.js、global.css都是module
  • entry-point
    • main.js、test.js、other.js
  • chunk
    • main
    • other
  • bundle

    • main.bundle.js
    • other.bundle.js
    • lodash.async.bundle.js
  • entry的两个key指定了两个chunk(bundle),名称分别为mianother,最终会输出两个bundle

  • main.js、test.js、other.js都是entry-point
  • 因为没有抽取css,所以没单独生成一个css文件global.css的内容内联main.bundle.js中的

loader

  • webpack loaderwebpack 为了处理各种类型文件的一个中间层,webpack 本质上就是一个 node 模块,它不能处理js 以外的文件,那么 loader 就帮助webpack 做了一层转换,将所有文件都转成字符串,你可以对字符串进行任意操作/修改,然后返回给 webpack 一个包含这个字符串的对象,让 webpack 进行后面的处理。如果把 webpack 当成一个垃圾工厂的话,那么 loader 就是这个工厂的垃圾分类

plugin

  • 如果把 webpack 当成一个垃圾工厂,loader 就是垃圾分类,将所有垃圾整理好交给 webpackplugin 就是如何去处理这些垃圾。

核心流程

  • webpack 启动后会从 entry-point 开始递归解析 entry-point 依赖的所有 module
  • 每找到一个 module, 就会根据配置的 loader 去找出对应的转换规则,对 module 进行转换后,再解析出当前 module 依赖的 module
  • 这些模块会以 entry字段配置的key(chunk name)为单位进行分组,一个 entry 和其所有依赖的 module 被分到一个组也就是一个 chunk
  • 最后 webpack 会把所有 chunk 转换成文件输出为bundle
  • 在整个流程中 webpack 会在恰当的时机执行 plugin 里定义的逻辑,在plugin执行逻辑中,可能会再抽取其他bundle(例如从js bundle中再单独抽取出一个css bundle文件),但这不属于webpack主逻辑,属于plugin附加的能力
  • 正常情况下,webpack是一个js entry-point对应一个js chunk对应生成一个js bundle(除非配置了sourcemap,会单独再生成一个sourcemap bundle);
  • plugin属于增强webpack功能,loaderwebpack提供非js文件的转换能力;

相关项目

参考

https://github.com/webpack/webpack.js.org/issues/970
https://juejin.im/post/5cede821f265da1bbd4b5630
https://juejin.im/post/5d2b300de51d45775b419c76