webpack 4 源码主流程分析(一):前言及总流程概览

原文首发于 blog.flqin.com。若有错误,请联系笔者。分析码字不易,转载请代表出处,谢谢!html

前言

此系列文章做为笔记,用于记录分析 webpack 源码主流程的过程。node

概览

目录

根据 webpack 构建流程及相关,本系列文章一共分为如下章节:webpack

  1. 配置初始化
  2. 编译前的准备
  3. reslove 前的准备
  4. reslove 流程
  5. 构建 module(上)
  6. 构建 module(下)
  7. 生成 chunk
  8. 优化 chunk
  9. 资源的构建
  10. 文件的生成
  11. 打包后文件解析
  12. watch
  13. webpack 优化

流程图

webpack 构建流程图:git

webpack 构建流程

本系列代码环境

"devDependencies": {
    "@babel/core": "^7.7.5",
    "@babel/preset-env": "^7.7.6",
    "@fe_korey/test-loader": "^1.0.0",
    "babel-loader": "^8.0.6",
    "html-webpack-plugin": "^3.2.0"
  },
  "dependencies": {
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.10"
  }
复制代码

版本不一样,源码略微有差别。github

本项目 demo 开源在github,欢迎交流学习。web

分析源码前的一系列准备工做

采用 vscode 来打断点调试分析。npm

配置 vscode

//launch.json
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "runtimeExecutable": "npm",
      "runtimeArgs": ["run", "debug"],
      "port": 5858,
      "console": "externalTerminal",
      "skipFiles": ["<node_internals>/**/*.js"]
    }
  ]
复制代码

这些配置是怎么来的?json

配置 npm script

"scripts": {
    "debug": "node --inspect-brk=5858 ./node_modules/.bin/webpack"
  },
复制代码

了解 webpack 的插件架构

webpack 从配置初始化到打包完成定义了一个生命周期,在这个生命周期中的每个阶段定义一些不一样的功能。webpack 的流程一样也是一个事件驱动的架构,利用插件系统 tabpable,经过 发布订阅事件 来实现全部内部的,外部扩展的功能。bash

了解 webpack 的核心模块

webpack 的构建是经过 Compiler 控制构建流程,Compilation 解析,ModuleFactory 生成模块,Parser 解析源码,Template 渲染代码,最后输出打包后的文件。babel

了解 tapable

tabpable 本质就是一个事件发布订阅机制,支持同步异步,使用xxx.tap之类的来事件订阅,使用xxx.call之类的来进行事件发布。 相关文档查阅:

demo 准备

npm 安装

npm i webpack-cli webpack
npm i @babel/core @babel/preset-env babel-loader -D
npm i @fe_korey/test-loader -D
复制代码

demo 文件

咱们以 development 模式为例,暂时忽略支线剧情,只分析探索 webpack 的打包主流程。

//src/a.js
import { add } from 'Src/b';
import('./c.js').then(m => m.sub(2, 1));
const a = 1;
add(3, 2 + a);
复制代码
//src/b.js
import { mul } from '@fe_korey/test-loader?number=20!Src/e';
export function add(a, b) {
  return a + b + mul(10, 5);
}
export function addddd(a, b) {
  return a + b * b;
}
复制代码
//src/c.js
import { mul } from 'Src/d';
import('./b.js').then(m => m.add(200, 100));
export function sub(a, b) {
  return a - b + mul(100, 50);
}
复制代码
//src/d.js
export function mul(a, b) {
  const d = 10000;
  return a * b + d;
}
复制代码
//webpack.config.js
var path = require('path');

module.exports = {
  entry: {
    bundle: './src/a.js'
  },
  devtool: 'none',
  output: {
    path: __dirname + '/dist',
    filename: '[name].[chunkhash:4].js',
    chunkFilename: '[name].[chunkhash:8].js'
  },
  mode: 'development',
  resolve: {
    alias: {
      Src: path.resolve(__dirname, 'src/')
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      }
    ]
  }
};
复制代码
//babel.config.js
module.exports = {
  presets: ['@babel/env']
};
复制代码

一颗坚决且耐操的心

为何要阅读它?

  • 由于可让咱们更好的理解海量配置,知道每个配置在打包的具体哪一个环节
  • 在对构建流程进行优化时能更清楚的根据过程思考优化点
  • 还能够学习下在这种大型项目里,如何实现稳定的架构和良好的扩展性
  • 对自定义开发一些 pluginloader 有更深入的理解
  • 了解它的一些代码设计方式能给咱们的平常搬砖带来一些新的启发

最重要的仍是想知足本身的好奇欲,想知道在这犀利的打包背后,究竟是怎么实现的。

webpack 里包含数不清的变量和钩子,海量插件,这些足以让你怀疑人生,请务必保持一颗耐操的心。 一切准备就绪后,进入 vscode 的调试模式!

相关文章
相关标签/搜索