GithubHelp home page GithubHelp logo

my-webpack's Introduction

Hi there 👋

I am qixuan, a FE developer

TypeScript & Rust Lover

my-webpack's People

Contributors

giveme-a-name avatar

Watchers

 avatar

my-webpack's Issues

[RFC]: 实现Tree-Shaking功能

理论基础

在 CommonJs、AMD、CMD 等旧版本的 JavaScript 模块化方案中,导入导出行为是高度动态,难以预测的;

if (process.env.NODE_ENV === "development") {
  // 我们可以在条件判断中进行 require()
  // 其实这跟 nodejs 的 require 实现相关
  // nodejs require 是在运行时进行依赖模块处理的。它将依赖模块处理成一个 module 对象。
  // docs: https://juejin.cn/post/7111928640572489742#heading-13
  require("./bar");
  exports.foo = "foo";
}

而 ESM 方案则从规范层面规避这一行为,它要求所有的导入导出语句只能出现在模块顶层,且导入导出的模块名必须为字符串常量。

所以,ESM 下模块之间的依赖关系是高度确定的,与运行状态无关,编译工具只需要对 ESM 模块做 AST 等静态分析,在编译阶段判断出哪些模块值是没有被使用过的。

实现原理

Webpack 中,Tree-shaking 的实现一是先标记出模块导出值中哪些没有被用过,二是使用 Terser 删掉这些没被用到的导出语句。标记过程大致可划分为三个步骤:

  • Make 阶段,收集模块导出变量并记录到模块依赖关系图 ModuleGraph 变量中
  • Seal 阶段,遍历 ModuleGraph 标记模块导出变量有没有被使用
  • 生成产物时,若变量没有被其它模块使用则删除对应的导出语句

其中 Make 阶段和 Seal 阶段是在 Webpack 中进行处理的。我们主要实现的就是这一部分。

// src/index.js
import { add } from "./utils.js";

// src/utils.js
export function add() {}
export function sub() {}

比如上面在没有 tree-shaking 代码,Webpack 会将它打包成类似这样

// src/utils.js
Object.defineProperty(exports, "__esModule", { value: true });
exports.add = add;
exports.sub = sub;

实际上,我们的预期效果是这样

Object.defineProperty(exports, "__esModule", { value: true });
exports.add = add;

sub 变量对应的导出语句就被删除了

如何实现?

我们通过分析 AST 可以分析出在模块依赖和引入变量之间的关系。

我们将该模块导入依赖的变量记录下来,在依赖模块 AST 分析时记录下它到处的变量。

在构建依赖图时进行对依赖模块导出变量和被导入变量进行一一对比。这样可以删除掉依赖。

// src/index.js
import { add } from "./utils.js";

// index.js 的dependency对象如下:
//
// {
//   "./utils": {
//     path: "/xxx/.utils.js",
//     imports: ["add"],
//   }
// }

// src/utils.js
export function add() {}
export function sub() {}

// utils 导出的 moduleInfo 新增 exports 信息,记录导出的变量。
// const utils-ModuleInfo = {
//   filename: "utils.js",
//   dependencies: [],
//   ...,
//   exports: ["add", "sub"]
// }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.