模块化import与require及区别

本节主要介绍webpack中的模块方法,包括ES6的import以及CommonJS的require等。

Webpack是一个模块打包工具,对一切文件都视为模块。它本身支持非常多的模块化方法,包括本节中出现的所有模块化方法。

下一节我们将要学习Webpack资源入口,有必要先了解一些模块知识。

一、JavaScript模块化历史

在JavaScript这门语言最初的阶段,是没有模块化方法的,因为这门语言设计出来的初衷是作为web小脚本使用的。后来随着其在web应用的增长,不能模块化开始限制了其应用。

这个时候社区出现了一些模块化规范,比较著名的有CommonJS、AMD和CMD等。

社区的模块化规范可以解决一些JS模块化的问题,但各种模块化规范还是不统一的,有学习和兼容成本。

于是,JavaScript在制订ES6语言标准的时候,提出了自己的模块化,也就是我们现在一般叫做的ES6 Module(ES6模块化)。

ES6 Module经过五年的发展后,已经广泛应用在JS开发领域。目前,JS模块化使用的主要是ES6 Module和CommonJS这两种。

二、ES6 Module

ES6的模块化语法主要用import进行模块导入,export进行模块导出。

1.export模块导出

  // 导出的模块有两个变量name和age,一个函数add
  // a.js
  export var name = 'Jack';
  export var age = 18;
  export function add(a, b) {
    return a + b;
  }

上面的导出也可以换一个写法

  // 导出的模块有两个变量name和age,一个函数add
  // b.js
  var name = 'Jack';
  var age = 18;
  function add(a, b) {
    return a + b;
  }

  export { name, age, add };

export还可以导出匿名模块,方便在导入的时候使用

  // 使用匿名(default)导出模块,这里导出的是一个对象
  // c.js
  export default {
    price: 285,
    id: 12,
  }

2.import模块导入

我们使用import … from '…'方式导入模块。对于匿名(default)导出的模块,我们自定义一个变量代表其导出值。

  // 对于匿名(default)导出的模块c.js,我们自定义一个变量moduleC代表其导出值
  // d.js
  import moduleC from './c.js'
  console.log(moduleC)   // 控制台输出一个对象{price: 285, id: 12}

对于非default导出的模块,我们可以使用大括号方式导出模块

  // 对于模块a.js或b.js,我们使用大括号方式导出模块
  // e.js
  import { name, age, add } from './b.js'
  console.log(name, age);   // 控制台输出'Jack'和18
  console.log(add(1, 8));   // 控制台输出9

除了使用import … from '…'方式导入模块,也可以使用import '…'。使用这种方式,导入模块后会执行模块内容,但是并不使用其对外提供的接口。

3.import()函数

注意import()函数与上面的import模块导入语法的区别。

import()函数是ES2020提案里提出来的。它与普通的import模块导入语法的区别,外观上是它的import后面跟的是一个括号(),而普通的import最后是一个引号''。

import()函数虽然是ES2020提案里的,但Webpack早已经支持该模块导入语法了。

  // import()函数导入模块
  import('./f.js')

除了外观上的区别,import()与引号形式import的核心区别是,import()导入模块是异步的,而引号形式import导入的模块是同步的。

在Vue-Router的路由懒加载中,我们就是通过使用import()来实现的,下图是Vue官方文档的截图。

vue路由懒加载 Webpack教程 姜瑞涛的官方网站

简单解释一下import()的原理。Webpack在打包的时候,碰到import()引入的模块的时候并不会立刻把该模块内容打包到当前文件里。Webpack会使用动态生成JS的方式,在运行代码的时候生成script标签,script标签引入的就是import()里导入的内容。import()导入模块后是一个Promise对象,我们可以通过import().then()的方式来处理后续异步的工作。

三、CommonJS

CommonJS是目前比较流行的JS模块化规范,它主要在Node.js中使用。Node.js对CommonJS的实现并不完全与其规范一致,教程不会涉及这些细微差别。

CommonJS主要使用module.exports导出模块,require('…')导入模块。

  // g.js
  module.exports = {
    name: 'Gola',
    age: 25
  }
  // h.js
  var person = require('./g.js')
  console.log(person)  // 输出{name: 'Gola',age: 25}

Webpack对CommonJS也支持异步模块。如果你用过旧版本的Webpack,可以发现require.ensure异步导入模块的语法。注意该语法是Webpack特有的,现在推荐使用import()函数做异步导入模块。

  // dependencies是一个数组,数组项是需要导入的模块;callback是成功回调函数;errorCallback是失败回调函数;chunkName是自定义的chunk名;
  require.ensure(dependencies, callback, errorCallback, chunkName)

小结

  1. Webpack支持ES6 Module、CommonJS和AMD等模块化方法,目前常用的是ES6 Module和CommonJS。ES6 Module和CommonJS都支持同步和异步导入模块。
  2. ES6 Module通过export导出模块,import … from '…'或import '…'同步导入模块。
  3. CommonJS通过module.exports导出模块,require('…')同步导入模块。
  4. ES6 Module通过import()函数异步导入模块,CommonJS通过require.ensure异步导入模块,现在推荐使用import()函数异步导入模块。

笔记与思考

发表评论

邮箱地址不会被公开。 必填项已用*标注