极客时间返利平台,你可以在上边通过山月的链接购买课程,并添加我的微信 (shanyue94) 领取返现。

# 前端打包时 cjs、es、umd 模块有何不同

Issue

欢迎在 Gtihub Issue 中回答此问题: Issue 475 (opens new window)

# cjs (commonjs)

commonjs 是 Node 中的模块规范,通过 requireexports 进行导入导出 (进一步延伸的话,module.exports 属于 commonjs2)

同时,webpack 也对 cjs 模块得以解析,因此 cjs 模块可以运行在 node 环境及 webpack 环境下的,但不能在浏览器中直接使用。但如果你写前端项目在 webpack 中,也可以理解为它在浏览器和 Node 都支持。

比如,著名的全球下载量前十 10 的模块 ms (opens new window) 只支持 commonjs,但并不影响它在前端项目中使用(通过 webpack),但是你想通过 cdn 的方式直接在浏览器中引入,估计就会出问题了

// sum.js
exports.sum = (x, y) => x + y;

// index.js
const { sum } = require("./sum.js");

由于 cjs 为动态加载,可直接 require 一个变量

require(`./${a}`);

# esm (es module)

esm 是 tc39 对于 ESMAScript 的模块话规范,正因是语言层规范,因此在 Node 及 浏览器中均会支持

它使用 import/export 进行模块导入导出.

// sum.js
export const sum = (x, y) => x + y;

// index.js
import { sum } from "./sum";

esm 为静态导入,正因如此,可在编译期进行 Tree Shaking,减少 js 体积。

如果需要动态导入,tc39 为动态加载模块定义了 API: import(module) 。可将以下代码粘贴到控制台执行

const ms = await import("https://cdn.skypack.dev/ms@latest");

ms.default(1000);

esm 是未来的趋势,目前一些 CDN 厂商,前端构建工具均致力于 cjs 模块向 esm 的转化,比如 skypacksnowpackvite 等。

目前,在浏览器与 node.js 中均原生支持 esm。

  • cjs 模块输出的是一个值的拷贝,esm 输出的是值的引用
  • cjs 模块是运行时加载,esm 是编译时加载

示例: array-uniq (opens new window)

# umd

一种兼容 cjsamd 的模块,既可以在 node/webpack 环境中被 require 引用,也可以在浏览器中直接用 CDN 被 script.src 引入。

(function (root, factory) {
  if (typeof define === "function" && define.amd) {
    // AMD
    define(["jquery"], factory);
  } else if (typeof exports === "object") {
    // CommonJS
    module.exports = factory(require("jquery"));
  } else {
    // 全局变量
    root.returnExports = factory(root.jQuery);
  }
})(this, function ($) {
  // ...
});

示例: react-table (opens new window), antd (opens new window)

这三种模块方案大致如此,部分 npm package 也会同时打包出 commonjs/esm/umd 三种模块化格式,供不同需求的业务使用,比如 antd (opens new window)

webpack 打包使用的是 cjs, vite 使用的是 esm,这样理解对吗 rollup 使用的是啥模块化方案?

webpack 也有 tree-shaking 吗和 rollup 的有啥不同

Author

回答者: songcee (opens new window)

已收到你的邮件,谢谢~~~

Last Updated: 12/8/2021, 9:06:07 PM