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 的調試模式!

相關文章
相關標籤/搜索