Dynamic imports with webpack

问题

使用 webpack 构建, 动态去加载 css 时,为什么使用 import() 会报错,使用 System.import() 可以?

$ webpack => 2.6.1

dynamic-load-css-file
dynamic-load-css-file-error


原因

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

模块化的实现对比

CommonJSAMDCMDES6 Module
解决的问题模块化开发模块化开发模块化开发模块化开发
适用环境服务端浏览器浏览器浏览器/服务端
加载方式同步加载/异步加载异步加载异步加载同步加载/异步加载
模块定义module.exportsdefine(id?,dependencies?,factory)define(function(require,exports,module){ })export
模块加载require()/require.ensure()require([module], callback)require(module)import / import()
执行时机 提前执行延迟执行
依赖原则 依赖前置依赖就近
规范化的实现 require.jsSeaJS
webpack 的支持require.ensure()require() import / import()

参考

推荐阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值