今天浅整理一下webpack的打包过程

一、初始化过程

1、读参:从配置文件和Shell语句读取与合并参数,得出webpack的配置参数

  • 配置文件默认下为webpack.config.js(可以通过命令的形式指定配置文件)
  • webpack将各个配置项拷贝到options对象中,然后加载用户配置的**plugins**
var path = require('path');
var node_modules = path.resolve(__dirname, 'node_modules');
var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');
 
module.exports = {
  // 入口文件,是模块构建的起点
  entry: './path/to/my/entry/file.js',
  // 文件路径指向(可加快打包过程)。
  resolve: {
    alias: {
      'react': pathToReact
    }
  },
  // 生成文件,是模块构建的终点,包括输出文件与输出路径。
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: '[name].js'
  },
  // 这里配置了处理各模块的 loader
  module: {
    loaders: [
      {
        test: /.js$/,
        loader: 'babel',
        query: {
          presets: ['es2015', 'react']
        }
      }
    ],
    noParse: [pathToReact]
  },
  // webpack 各插件对象,在 webpack 的事件流中执行对应的方法。
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
};

二、编译构建过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iJMuYVDx-1661479557701)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/54f3adf173c9423aa5e3f74d6bb22647~tplv-k3u1fbpfcp-watermark.image?)]

2、创建Compiler对象: 启动webpack,创建Compiler对象(通过上述参数初始化)

  • Compiler对象是一个单局全例,负责把控整个webpack打包的构建流程,负责文件监听和启动编译
  • 每次热更新和重新构建,compiler都会重新生成一个新的compilation对象,负责此次更新的构建过程
  • compilation对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息

调用Compilerrun来真正启动webpack编译构建流程

3、从入口文件(entry)开始解析

  • entry可以有三种不同形式: string | object | array,分别对应: 一对一(一个入口一个打包文件),多对一(多个入口,一个打包文件),多对多(多个入口,多个打包文件)

4、make编译模块:

  • 一个新的 Compilation 创建完毕主开始编译 完毕主开始编译this.hooks.make.callAsync

5、build module模块:

  • 对不同文件类型的依赖模块文件使用对应的**Loader**进行编译,最终转为Javascript文件(编译)

  • loader的执行顺序是从右向左执行的

    module.exports = {
      //...
      module: {
        rules: [
          {
            test: /.(le|c)ss$/,
            use: ['style-loader', 'css-loader', 'less-loader'],
            exclude: /node_modules/,
          },
        ],
      },
    };
    // 这样的话就是先处理less-loader,再css-loader,再style-loader
    
  • 常见loader

    • file-loader: 可以解析项目中URL的引入,将文件拷贝到相应的路径,并修改打包后文件的引入路径,让其指向正确的文件

    • tslint-loader:通过 TSLint 检查 TypeScript 代码

    • ts-loader:将 TypeScript 转换成 JavaScript

    • eslint-loader:通过 ESLint 检查 JavaScript 代码

    • style-loader:动态创建 style 标签,将 CSS 代码插入到 head

    • css-loader:负责处理 @importurl 等语句。例如 import css from ‘file.css’url(image.png)`

    • less-loader:将 .less 文件内容转换成 CSS

    • sass-loader:将 .sass 文件内容转换成 CSS

  • 在用loader对一个模块转换后,使用acorn解析转换后的内容输出对应的抽象语法树(AST),从配置的入口模块开始,分析其AST,当遇到require等导入其它模块语句时,便将其加入到依赖的模块列表,同时对新找出的依赖模块递归分析,最终搞清所有模块的依赖关系

三、输出流程

  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk(配置在entry的模块,或者是动态引入的模块),再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

四、上述过程简而言之

  • 初始化参数: 从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。

  • 开始编译: 根据我们的webpack配置注册好对应的插件调用 compile.run 进入编译阶段,在编译的第一阶段是 compilation,他会注册好不同类型的module对应的 factory

  • 编译模块: 进入 make 阶段,会从 entry 开始进行两步操作:

    • 第一步是调用 loaders 对模块的原始代码进行编译,转换成标准的JS代码,
    • 第二步是调用 acorn 对JS代码进行语法分析,然后收集其中的依赖关系。每个模块都会记录自己的依赖关系,从而形成一颗关系树。
  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表

  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐