模块化演变
CommonJS规范
- 一个文件就是一个模块
- 每个模块都有单独的作用域
- 通过module.exports导出成员
- 通过require函数载入模块
- 同步模式加载模块
因为同步模式加载模块,不适用浏览器,于是出现了
AMD(Asynchronous Module Definition异步模块定义规范)并出现了Require.js,实现了AMD规范,用define
定义。但是使用起来相对复杂,模块JS文件请求频繁
EsModule
特性
1,通过给 script 添加 type = module
的属性,就可以以 ES Module 的标准执行其中的 JS 代码了
2,ESM 自动采用严格模式,忽略 'use strict'
3,每个 ES Module 都是运行在单独的私有作用域中
4,ESM 是通过 CORS 的方式请求外部 JS 模块的
5,ESM 的 script 标签会延迟执行脚本
导出
导出的只是一个引用,导出的是存放值得地址
export {name,age}
导入
导入中的from
不能省略掉.js
文件名,需要填写完整文件路径名。也可以使用完整URL来加载文件.import
不能放在类似if
这种嵌套语法中,需要放在文件顶层。如果需要动态加载,使用import()
函数,返回一个promise
。
import('./module.js').then(function(module){
console.log(module) // 返回对象在module中
})
如果导出内容很多,有多个对象,还有一个default
。导入的时候其他对象可以正常导入,如果想导入import
成员,需要重命名
export {a,b}
export default "c";
//---------------------
import {a,b default as c} from "module.js"
//或者如下,tilte可以随意命名
import title,{a,b} from "module.js"
导出导入成员
项目中经常会出现一些公用模块,比如component
,business
,page
等类似的公众区域,
使用的时候挨个导入会很麻烦,可以新建一个index.js
文件,统一导出
import {comA} from "./comA.js
import {comB} from "./comB.js"
export {comA,comB}
ESM兼容性问题
因为市面上存在一些浏览器不兼容ESM,除了webpack打包编译转换为ES5等方式外,有一个浏览器环境polyfill。直接引入unpkg
网站的两个cdn
链接,IE不支持promise,还需要引入promise的polyfill
如果在script
标签中加入module
属性,只会在不兼容ESM规范的浏览器中运行
Es Module和Node.js交互
Node.js 8.5版本之后,开始实验性使用ESM。
结论:
- ES Module 中可以导入 CommonJS 模块
- CommonJS 模块始终只会导出一个默认成员
- ESM中不能直接提取CMS成员,注意 import 不是解构导出对象
- 不能在 CommonJS 模块中通过 require 载入 ES Module
ESM in Node.js与CMS模块差异
- ESM中没有CommonJS中那些模块全局成员(require, module, exports,__filename,__dirname)
- require, module, exports 可以通过 import 和 export 代替
__filename 和 __dirname 在ESM中可以通过 import 对象的 meta 属性获取
// 通过 url 模块的 fileURLToPath 方法转换为路径 import { fileURLToPath } from 'url' import { dirname } from 'path' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) console.log(__filename) console.log(__dirname)
注意事项
如果需要在type=module
的情况下继续使用 CommonJS,
需要将文件扩展名修改为.cjs