前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >人人都看得懂的 webpack 源码 (1)-环境准备

人人都看得懂的 webpack 源码 (1)-环境准备

作者头像
用户6256742
发布2024-05-17 09:37:47
1040
发布2024-05-17 09:37:47
举报
文章被收录于专栏:网络日志网络日志

一、为什么要写这个系列?

谨以此专栏向我的老板以及像他一样致力于开源繁荣的大佬致敬!

首先排除摸鱼,因为最近忙死,几乎无鱼可摸。主要两点原因吧,说来有趣:

1. 致敬我的老板

如果你有个框架作者的老板是种什么感觉?是的,我的老板就是框架作者!要说周会唯一开心的事儿莫过于他第一个汇报工作,他的汇报总是带着技术分享的,他总是说就是随便讲讲,你会发现他讲的都是思考,都是原理,都是源码,甚至会分析这么干的优劣,还会带着更好的实现思路。

每次请教问题,他都能非常流利的回答,甚至一些官网文档都没提及的特性,它都能如数家珍般的娓娓道来。佩服之余,我觉得我也应该再进一步!

来了我司之后是我的老板让我看到确实有一大帮人在看源码、写源码,并且将技术付诸于业务实践,并非无效卷!g

2. 总结+鞭策

我在动笔之前,webpack v4 的前半部分源码我看了大概有5/6遍了,持续时长超过2年,中间因为种种原因被打断过好几次,看了忘,忘了看,反反复复的。此外,在 buildModule 递归收集依赖的地方总是会卡住,上周末我看了一个下午,终于递归收集依赖的部分攻克了。

看了很多很多文章,好多文章把关键点都省略掉了,这部分关键点省略之后是看不懂的,同时为了给自己定个目标也是为了好好的梳理,我决定动笔写个专栏,秉持着写只要看就能懂的源码分享文章,把自己遇到的问题平铺直叙的写出来。

立个 FLAG,2024年内完成这个专栏,我预计应该会在 100 篇左右,预祝各位看官老爷早日成为尊贵的奥迪车主!!!

二、Demo 准备

本专栏讲述的是 webpack v5.x 的源码,至于为啥不讲 webpack v4,答案很简单:我的 webpack 4 没看完😂

2.1 demo 仓库地址

github 示例代码仓库

2.2 demo 依赖信息

上 package.json 文件:

代码语言:javascript
复制
{
  "name": "w5-itm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "build": "webpack",
    "watch": "webpack --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.20.2",
    "@babel/plugin-transform-runtime": "^7.19.6",
    "@babel/preset-env": "^7.20.2",
    "babel-loader": "^9.1.0",
    "clean-webpack-plugin": "^4.0.0",
    "html-webpack-plugin": "^5.5.0",
    "webpack": "^5.75.0",
    "webpack-cli": "^4.10.0",
    "webpack-virtual-modules": "^0.5.0"
  }
}

2.2 webpack.config.js 配置

这里提一点,我们的配置是个动态的过程,我们以打包一个 bundle 为例子开始,主要分析 webpack 如何从模块变成 bundle 的过程。

在这个过程中,后面这个配置文件是会成长的,最初的配置就是下面这个样子,其中 loader 部分我们只配置了 babel-loader 和 一个我们自己写的测试 loader!

代码语言:javascript
复制
module.exports = {
  entry: {
    bundle1: './src/index.js',
    // bundle2: './src/a/d.js'
  },
  cache: {
    type: 'filesystem',
    cacheDirectory: path.join(__dirname, './.cache'),
    buildDependencies: {
      config: [__filename]
    }
  },
 
  // mode: 'development',
  mode: 'production', 
  devtool: 'source-map',
  output: {
    filename: 'bundle.[chunkhash:4].js',
    path: path.resolve(__dirname, './dist')
  },
  recordsPath: path.join(__dirname, 'records.json'),
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env'],
              plugins: [
                [ // babel transform-runtime 暂时屏蔽,会额外多处很多模块,不利于看到现状
                 '@babel/plugin-transform-runtime',
                //   {
                //     corejs: 3
                //   }
                // ]
              ]
            }
          }
        ]
      }
    ]
  },
  resolve: {
    alias: {
      Src: path.resolve(__dirname, './src')
    },
    extensions: ['.js', '.jsx', '.json'],
    fallback: {
      assert: require.resolve('assert'),
      buffer: require.resolve('buffer')
    },
 
  },
  plugins: [
    new CleanWebpackPlugin()
  ]
}

2.3 src 目录结构

src 下的目录结构如下,index.js 是整个构建的主入口!

代码语言:javascript
复制
.
├── index.css
├── index.html
├── index.js
├── ok.js
└── some-dir
    ├── a.js
    ├── b.js
    ├── c.js
    ├── d.js
    ├── e.js
    └── f.js

三、调试环境准备

调试环境依旧使用我的 Webstorm 调试环境,不需要配置,开箱即用,如果你 vsc 用户,自己搜一下 vscode 配置 node.js 断点调试(我一直用 webstorm,因为真的太好用了)

3.1 在 Webstorm 中加入断点

你只需要在要调试的代码行号处点击一下即可,点击后行号处出现一个红点,表示断点已经生成:

人人都看得懂的 webpack 源码 (1)-环境准备
人人都看得懂的 webpack 源码 (1)-环境准备

3.2 启动调试

webpack 调试不能通过右键 debugger 调试某个文件,因为这个文件不是入口,我们需要调试整个构建流程,因此需要以调试方式运行构建命令,你需要在 package.json 中加入 webpack 命令:

代码语言:javascript
复制
"scripts": {
  "test": "echo "Error: no test specified" && exit 1",
  "build": "webpack",
  "watch": "webpack --watch"
},

我们接下来要调试 build 这个命令,你会发现 webstorm 在 build 行号处有个绿色小三角,点击这个三角,在弹出菜单中选择 Debug 'build'

人人都看得懂的 webpack 源码 (1)-环境准备
人人都看得懂的 webpack 源码 (1)-环境准备

当代码运行到断点处就会停住,如下图:

人人都看得懂的 webpack 源码 (1)-环境准备
人人都看得懂的 webpack 源码 (1)-环境准备

四、webpack 基础知识

在开启正式的代码阅读之前,我们需要你有以下基础知识,相信这一波就够劝退一大票人的:

4.1 Tapable 和 Hook

Tapable个发布订阅的事件库。与 event-emitter 不同的是,这个库提供了一种钩子机制(Hook),相当于是个事件名。这些 hook 有的是同步的(SyncHook),有的是异步的(SsyncHook),有的是串行的(SeriesHook),有的是并行(ParallelHook)的,有的有返回(WaterfallHook)值,有的是有熔断(BailHook)的....

关于 Tapable 已经有很多文章再说了,虽然这里不再赘述,但是我们希望你有这部分基础!

4.1 webpack 中的常用名词及含义

  1. webpack 生命周期webpack 基于 Tapable 库实现,webpack 中设计了很多 hook,这些钩子可以被任意订阅,而 webpack 的核心工作流也是通过指定的节点去触发指定 hook 来推进的。这些 hook 被称为 webpack 生命周期 hook。
  2. plugin:插件,上面介绍 hook 的时候说了,webpack 内部注册了很多 hook 供订阅,那么订阅这些钩子的一方实现某些固定的功能的就是一个 webpack 插件了。订阅某个流程节点钩子,webpack 当执行流推进到这个节点时,就会触发这个钩子并且传入一些重要的对象如 Compiler/Compilation/NormalModuleFactory/Parser...
  3. Compiler: 编译器,由 webpack 创建的编译器对象,继承自 Tapable,整个构建声明周期之后一份,负责调度 webpack 顶层的生命周期 hook:beforeRun,run,compilation,thisCompilation,compile,make,emit....(这些钩子有个印象就行,后面会细讲)
  4. Compilation: 由 Compiler 创建,同样继承自 Tapable,负责具体的构建工作,比如创建 Module,生成 Module Graph,Seal,Render 这些具体的构建工作细节。
  5. Resolver:资源(loader、代码模块)路径解析器,继承自 Tapable,负责解析被引用到代码模块、loader 模块的资源路径,webpack 的 Resolver 基于 enhanced-resolve 这个库创建
  6. ModduleFactory:模块工厂类,继承自 Tapable,用于创建模块对象,我们手写的 js 模块是文本文件,webpack 通过 ModuleFactory 提供的工厂函数将我们写的 js 代码变成 Module 对象,期间会调用对应的 loader 进行预处理。这里我们主要讨论 NormalModuleFactory(NMF);
  7. Parser:代码转 AST 的解析器,webpack 使用的是 acorn,Parser 同样继承自 Tapable。解析的重要意义在于通过分析 AST 找到这个模块依赖的其他模块,进行依赖收集。当然,不同的 AST 解析目的不一,这里强调的是 webpack 的 AST 解析,如果是 Babel 的 AST 解析自然是为了转义!

4.2 webpack 构建流程

  1. 首先 webpack 通过 webpack-cli 启动,期间会整合命令行参数;
  2. 然后通过 webpack 创建 Compiler 对象(这个过程伴随着 Compiler 的顶层生命周期 hook 的注册);
  3. Compiler 创建 Compilation 对象(这个过程伴随着 Compilation 生命周期 hook 的注册);
  4. 接着通过 Compilation 的生命周期开启构建流程,直到最后生成 bundle 文件!

五、总结

本文详述了后续代码的 demo 和 webpack 源码阅读的基础:

  1. Tapable 库及 hook 机制;
  2. webpack 基础概念及作用;
  3. webpack 整个运行流程;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么要写这个系列?
    • 1. 致敬我的老板
      • 2. 总结+鞭策
      • 二、Demo 准备
        • 2.1 demo 仓库地址
          • 2.2 demo 依赖信息
            • 2.2 webpack.config.js 配置
              • 2.3 src 目录结构
              • 三、调试环境准备
                • 3.1 在 Webstorm 中加入断点
                  • 3.2 启动调试
                  • 四、webpack 基础知识
                    • 4.1 Tapable 和 Hook
                      • 4.1 webpack 中的常用名词及含义
                        • 4.2 webpack 构建流程
                        • 五、总结
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档