打包格式
rollup输出格式
rollup支持的打包输出格式:
- es,
- amd
- cjs
- iife
- umd
- system
cjs/CommonJs
一种 JavaScript 语言的模块化规范,它通常会在服务端的 Nodejs 上使用。项目是由多个模块组成的,使用
require("module")
读取并加载模块在 CommonJs 的模块化规范中,每一个文件就是一个模块,拥有自己独立的作用域、变量、以及方法等,对其他的模块都不可见。CommonJS规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性
module.exports
是对外的接口。加载某个模块,其实是加载该模块的module.exports
属性。require
方法用于加载模块缺点:不能在浏览器中直接运行,执行后才能拿到依赖信息,由于用户可以动态 require(例如 react 根据开发和生产环境导出不同代码 的写法),无法做到提前分析依赖以及 Tree-Shaking
//moudle-a.js
moudle.exports = {
a: 1
};
//moudle-b.js
var ma = require('./moudle-a');
var b = ma.a + 2;
module.exports ={
b: b
};
//moudle-a.js
moudle.exports = {
a: 1
};
//moudle-b.js
var ma = require('./moudle-a');
var b = ma.a + 2;
module.exports ={
b: b
};
模块化规范给项目带来极大的好处,在业务复杂,模块众多的大型项目中,开发者都遵循相同的规则来开发各自的模块,他们通过规范来约束模块的定义,大家不需要太多的沟通或者大量的文档来说明自己的模块使用规则,成千上万的模块就这样生产,并能够容易的使用。它的意义不仅是让模块看起来很规范,在合作开发、社区中传播中也起到了重大的作用
CMD
通用模块定义规范(Common Module Definiton),它是类似于 CommonJs 模块化规范,但是运行于浏览器之上的
CMD 规范尽量保持简单,并与 CommonJS 的 Modules 规范保持了很大的兼容性。通过 CMD 规范书写的模块,可以很容易在 Node.js 中运行。在 CMD 规范中,一个模块就是一个文件
格式如下:
define(factory);
define(factory);
具体用法如下:
// moudle-a.js
define(function(require, exports, module) {
module.exports = {
a: 1
};
});
// moudle-b.js
define(function(require, exports, module) {
var ma = require('./moudle-a');
var b = ma.a + 2;
module.exports = {
b: b
};
});
// moudle-a.js
define(function(require, exports, module) {
module.exports = {
a: 1
};
});
// moudle-b.js
define(function(require, exports, module) {
var ma = require('./moudle-a');
var b = ma.a + 2;
module.exports = {
b: b
};
});
CMD 规范拥有简单、异步加载脚本、友好的调试并且兼容 Nodejs,它的确在开发过程中给我们提供了较好的模块管理方式
AMD
异步模块定义规范(Asynchronous Module Definition),它是 CommonJs 模块化规范的超集,但是运行于浏览器之上的,AMD 的特点就和它的名字一样,模块的加载过程是异步的,它大大的利用了浏览器的并发请求能力,让模块的依赖过程的阻塞变得更少了。requireJs 就是 AMD 模块化规范的实现
AMD 作为一个规范,只需定义其语法 API,而不关心其实现。AMD 规范简单到只有一个 API,即 define 函数:
define(id?, dependencies?, factory);
define(id?, dependencies?, factory);
具体用法如下:
// moudle-a.js
define('moudleA', function() {
return {
a: 1
}
});
// moudle-b.js
define(['moudleA'], function(ma) {
var b = ma.a + 2;
return {
b: b
}
});
// moudle-a.js
define('moudleA', function() {
return {
a: 1
}
});
// moudle-b.js
define(['moudleA'], function(ma) {
var b = ma.a + 2;
return {
b: b
}
});
UMD
通用模块定义规范(Universal Module Definition)。也是随着大前端的趋势所诞生,它可以通过运行时或者编译时让同一个代码模块在使用 CommonJs、CMD 甚至是 AMD 的项目中运行。未来同一个 JavaScript 包运行在浏览器端、服务区端甚至是 APP 端都只需要遵守同一个写法就行了
它没有自己专有的规范,是集结了 CommonJs、CMD、AMD 的规范于一身
ESM
ECMAScript Module,现在最流行的模块方案,使用
import
export
来管理依赖。由于它们只能写在所有表达式外面,所以打包器可以轻易做到分析依赖以及 Tree-Shaking。当然他也支持动态加载(import()
)。浏览器直接通过
<script type="module">
即可使用该写法。NodeJS 可以通过使用 mjs 后缀或者在 package.json 添加"type": "module"
来使用,注意他还有一些 实验性的功能 没有正式开启。考虑到大量 cjs 库没有支持,如果要发布 esm 版的库还是通过 rollup 打包一下比较好(同时相关依赖可以放到 devDependencies 里)
IIFE
Immediately Invoked Function Expression,只是一种写法,可以隐藏一些局部变量,可以用来代替 UMD 作为纯粹给前端使用的写法
systemjs
systemjs 是一个最小系统加载工具,用来创建插件来处理可替代的场景加载过程,包括加载 CSS 场景和图片,主要运行在浏览器和 NodeJS 中。它是 ES6 浏览器加载程序的的扩展,将应用在本地浏览器中。通常创建的插件名称是模块本身,要是没有特意指定用途,则默认插件名是模块的扩展名称 缺点:版本兼容性差,对开发者体验不好
格式选择
只支持 NodeJS 的 require 写法
package.json:"main": "index.js"
其中 index.js 使用 cjs 写法(module.exports = xxx;
)
只支持 NodeJS 的 import 写法
package.json:"main": "index.mjs"
或 "type": "module", "main": "index.js"
其中 index.mjs 或 index.js 使用 esm 写法(export default xxx
)
同时支持 NodeJS 的 require 和 import 写法
利用 条件 export,直接看文档里面有例子。
支持浏览器直接通过 <script>
引入的写法
package.json:"browser": "index.global.js"
,然后 jsDelivr 等 cdn 会自动使用这个文件,具体到 cdn 上还有 "jsdelivr": "index.jsdelivr.js"
等配置写法,权重更高。
这里可以试试 esbuild 输出 iife 格式的包,比 webpack/babel 更快,除了对 cjs 的库不太友好(可以配合下面 rollup/commonjs 插件使用)。
浏览器直接支持 type="module"
引入 esm 写法的文件,但是这对于 cdn 来说并不友好:cdn 看到 import "xxx"
并不知道如何找到 xxx 模块,所以这种写法建议只在本地使用。另外也可以通过 vite,让它使用 rollup 和 esbuild 帮你引入这些外部模块。
支持现代打包器 rollup 和 webpack2+ 通过 import 引入的写法
package.json:"module": "index.esm.js"
如果某些库没有写这个选项,那么可以借助 rollup 的 commonjs 插件转译到可用,具体做法可以参考 rollup 文档
浏览器支持
浏览器格式
- 浏览器不支持
require
,即commonjs
- 浏览器也不支持
import
,即esm
babel对import和require的处理
babel
对require
是不做处理的,就加了一个严格模式babel
会对import
进行处理,转化为commonjs
规范。export default
被转换成exports["default"]
,同时还加了一个标记变量__esModule
来描述这个exports
是由es6 export
转换过来的
webpack是如何处理import和require
虽然 babel
将 import
转换成 CommonJS
规范形式的,但是浏览器本身没有 module
export
require
global
这些变量,并没有原生的支持CommonJS
规范,所以需要一些库来做这些支持
在webpack
打包中就会有一套自己的loader
专门来处理这些
总结
1、浏览器不支持import
和require
2、babel
会将esModule
规范转化成commonjs
规范 3、webpack、gulp
以及其他构建工具会对commonjs
进行处理,使之支持浏览器环境