携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情 >>
最近在写单包的sdk时用到了rollup打包,于是必然的注意到了配置项中的format这一栏:
Specifies the format of the generated bundle. One of the following:
amd– Asynchronous Module Definition, used with module loaders like RequireJS
cjs– CommonJS, suitable for Node and other bundlers (alias:commonjs)
es– Keep the bundle as an ES module file, suitable for other bundlers and inclusion as a<script type=module>tag in modern browsers (alias:esm,module)
iife– A self-executing function, suitable for inclusion as a<script>tag. (If you want to create a bundle for your application, you probably want to use this.). "iife" stands for "immediately-invoked Function Expression"
umd– Universal Module Definition, works asamd,cjsandiifeall in one
于是温故一下js的几种模块类型。
我的未打包代码为:
// log.js
export const log = (params) => {
console.log(params);
};
// main.js
import chalk from "chalk";
import { log } from "./utils/log";
let a = "a1";
setTimeout(() => {
a = "a2";
log(a);
}, 1000);
console.log(chalk.green("hello " + a));
1.1 AMD
Asynchronous Module Definition, used with module loaders like RequireJS
amd指异步模块定义,一般用于requirejs,
amd代码形如:
define(['chalk'], (function (chalk) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
const log = (params) => {
console.log(params);
};
let a = "a1";
setTimeout(() => {
a = "a2";
log(a);
}, 1000);
console.log(chalk__default["default"].green("hello " + a));
}));
AMD一般是配合requirejs使用。
AMD 是异步(asynchronously)导入模块的(因此得名),但是这个例子里看不出来,如果是异步导入,会如下:
define(['dep1', 'dep2'], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});
// 或者
// "simplified CommonJS wrapping" https://requirejs.org/docs/whyamd.html
define(function (require) {
var dep1 = require('dep1'),
dep2 = require('dep2');
return function () {};
});
1.2 CJS
CommonJS, suitable for Node and other bundlers (alias:
commonjs)CommonJS,为Node或其他模块使用。
CJS的代码形如:
'use strict';
var chalk = require('chalk');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
const log = (params) => {
console.log(params);
};
let a = "a1";
setTimeout(() => {
a = "a2";
log(a);
}, 1000);
console.log(chalk__default["default"].green("hello " + a));
- 也就是我们在node中最常见的使用方式,require 导入模块。
- 与AMD相比,CJS 不可以在浏览器中直接使用,并且是同步导入,是现在最常用的模块化方法之一。
- 当
CJS导入时,它会给你一个导入对象的副本,具体看下面与ES的对比部分。
1.3 ES
es– Keep the bundle as an ES module file, suitable for other bundlers and inclusion as a<script type=module>tag in modern browsers (alias:esm,module)
- 简单来说,保持import的方式不变,可以通过
<script type=module>的方式直接运行在浏览器中。
import chalk from 'chalk';
const log = (params) => {
console.log(params);
};
let a = "a1";
setTimeout(() => {
a = "a2";
log(a);
}, 1000);
console.log(chalk.green("hello " + a));
1.4 ES与CJS的对比
| 模块依赖关系建立的阶段 | 引入 | 导出 | |
|---|---|---|---|
| CommonJS | 动态 —— 代码运行阶段 | require —— 表达式,可以动态指定 | 导出本身值的拷贝,可被修改,不会影响原文件 |
| ES6 module | 静态 —— 代码编译阶段 | import —— 声明式,必须位于顶层作用域 | 导出值的动态映射,只读 |
本质区别
两者的本质区别是:前者对模块依赖的解决是“动态的”,模块依赖关系的建立发生在代码运行阶段;而后者是“静态的”,模块依赖关系的建立发生在代码编译阶段。
在CommonJS中,require是一个表达式,并且可以接受动态指定,require 甚至可以写在if语句里,因此在代码运行到之前,没有办法确定明确的依赖关系。
在ES6 module中,导入、导出语句都是声明式的,它不支持导入的路径是一个表达式,并且导入、导出语句必须位于模块的顶层作用域(比如不能放在if语句中),这让他的依赖关系在代码的编译阶段就比较明了。
相比CommonJS,ES6 module的好处是:
-
死代码检测和排除。我们可以用静态分析工具检测出哪些模块没有被调用过。
- 比如,在引入工具类库时,工程中往往只用到了其中一部分组件或接口,但有可能会将其代码完整地加载进来。未被调用到的模块代码永远不会被执行,也就成为了死代码。通过静态分析可以在打包时去掉这些未曾使用过的模块,以减小打包资源体积。
- 模块变量类型检查。JavaScript属于动态类型语言,不会在代码执行前检查类型错误(比如对一个字符串类型的值进行函数调用)。ES6 Module的静态模块结构有助于确保模块之间传递的值或接口类型是正确的。
- 编译器优化。在CommonJS等动态模块系统中,无论采用哪种方式,本质上导入的都是一个对象,而ES6 Module支持直接导入变量,减少了引用层级,程序效率更高。
\
1.4 IIFE
iife– A self-executing function, suitable for inclusion as a<script>tag. (If you want to create a bundle for your application, you probably want to use this.). "iife" stands for "immediately-invoked Function Expression"
- 简单来说,生成一个立即执行函数,将外在的依赖作为参数传入这个函数,这样可以获得一个纯净的function包。
- 应该是rollup特有的?他可以最大程度上减少包本身的体积。
(function (chalk) {
'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
const log = (params) => {
console.log(params);
};
let a = "a1";
setTimeout(() => {
a = "a2";
log(a);
}, 1000);
console.log(chalk__default["default"].green("hello " + a));
})(chalk);
1.5 UMD
umd– Universal Module Definition, works asamd,cjsandiifeall in one
- 最具兼容性的模块管理格式,正如它官方文档的介绍:UMD模式通常试图与当天最受欢迎的脚本加载程序(例如Requirej等)提供兼容性。在许多情况下,它将AMD用作基础,并添加了特殊评估来处理commonjs兼容性。
- 展开说包含的内容就很多了,可以看一下 juejin.cn/post/684490… 这篇文章。
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('chalk')) :
typeof define === 'function' && define.amd ? define(['chalk'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.chalk));
})(this, (function (chalk) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
const log = (params) => {
console.log(params);
};
let a = "a1";
setTimeout(() => {
a = "a2";
log(a);
}, 1000);
console.log(chalk__default["default"].green("hello " + a));
}));