问题
使用 webpack 构建, 动态去加载 css 时,为什么使用 import()
会报错,使用 System.import()
可以?
$ webpack => 2.6.1
原因
require.ensure()
在 webpack1.x 中提供了 require.ensure()
方法动态导入文件,其函数签名如下:
require.ensure(dependencies, callback, chunkName)
简单示例:
require.ensure([], function(require) {
const foo = require("./module");
});
注:require.ensure()
出自 CommonJS 中有一个 Modules/Async/A 规范,该规范定义了 require.ensure
语法。webpack 基于此基础,在打包的时候根据 require.ensure()
进行代码切分,并异步加载切分后的代码。
System.import()
ES6 Loader 规范定义了 System.import 方法,用于在运行时动态加载 ES6 模块,Webpack 把 System.import 作为拆分点;所以也可以通过 System.import()
方法实现动态引入,与 require.ensure()
不同的是 System.import()
返回的是一个 Promise,如:
System.import("./module")
.then(module => console.log(module))
.catch(err => console.log(Chunk loading failed))
import()
而在 webpack v2 (v2.1.0-beta.28) 废弃了 System.import()
方法,在 webpack v3 会完全删除System.import()
方法, 进而支持 ECMAScript State 3 草案阶段的原生 import()
方法来替代 System.import()
方法。
import("./module").then(module => {
return module.default;
}).catch(err => {
console.log("Chunk loading failed");
});
import
ES6 模块与 CommonJS 模块的差异 ,自行理解:
-
CommonJS
CommonJS 和 AMD 模块是运行时加载
CommonJS 模块就是对象,输入时必须查找对象属性
CommonJS 模块输出的是值的缓存,不存在动态更新
-
ES6 Module
ES6 模块是编译时加载
ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,再通过 import 命令输入
ES6 export 语句输出的接口,与其对应的值是动态绑定关系
由于 ES6 中的模块是编译时加载,import
命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行。所以,下面的代码会报错:
// 报错
if (x === 2) {
import MyModual from './myModual';
}
注:在 Webpack 2(v2.2.0-rc.5) 中增加对 ES6 模块的原生支持。这意味着 Webpack 现在可以识别 import 和 export,不需要先把它们转换成 CommonJS 模块的格式。
require()、import、import()
require()
是 CommonJS 的实现,用于运行时加载,推荐阅读 require() 源码解读
import
是 ECMAScript 6 Module 的语法,import 是静态执行,推荐阅读 import 命令
import()
函数是 ECMAScript Stage 3 草案阶段的语法;用于完成动态加载即运行时加载,可以用在任何地方。import()
函数 返回的是一个 Promise。类似于 CommonJs 的 require()
,区别主要是前者是异步加载,后者是同步加载,推荐阅读 proposal-dynamic-import
import()
的适用场景:
按需加载
条件加载
动态的模块路径
结论
webpack 的 Dynamic Imports 实现主要是利用 ECMAScript的 import()
动态加载特性,而 import()
目前只是一个草案,如果需要用此方法,需要引入对应的转换器,如 babel-plugin-syntax-dynamic-import。
模块化的实现对比
CommonJS | AMD | CMD | ES6 Module | |
---|---|---|---|---|
解决的问题 | 模块化开发 | 模块化开发 | 模块化开发 | 模块化开发 |
适用环境 | 服务端 | 浏览器 | 浏览器 | 浏览器/服务端 |
加载方式 | 同步加载/异步加载 | 异步加载 | 异步加载 | 同步加载/异步加载 |
模块定义 | module.exports | define(id?,dependencies?,factory) | define(function(require,exports,module){ }) | export |
模块加载 | require()/require.ensure() | require([module], callback) | require(module) | import / import() |
执行时机 | 提前执行 | 延迟执行 | ||
依赖原则 | 依赖前置 | 依赖就近 | ||
规范化的实现 | require.js | SeaJS | ||
webpack 的支持 | require.ensure() | require() | import / import() |