当import/export、require/module.exports 混用时, 你能分清吗?

ES6的模块化: import export defaultnode

common.js的模块化: require module.exports node.js使用该规范webpack

为何有模块概念

理想状况下,开发者只须要实现核心的业务逻辑,其余均可以加载别人已经写好的模块。es6

可是,Javascript不是一种模块化编程语言,在es6之前,它是不支持”类”(class),因此也就没有”模块”(module)了。同时之前也没有webpack这样的工具,可使用node去操做文件,读取文件内容, 而后达到引入文件内容的目的.(也就是模块化)--在不一样的文件中放着不一样的功能模块web

Common.js

首先须要明白的在node中每一个文件都是一个自执行函数(只不过咱们肉眼凡胎看不出来,哈啊哈)编程

(function (exports, require, module, __filename, __dirname) {
    module.exports = exports = this
    return module.exports
})()
复制代码

为了说明module.exports = exports = this请看下面例子element-ui

a.jsbabel

this.a = 123  // 第一种
exports.a = 123   //第二种
module.exports.a = 123  // 第三种
复制代码

b.js框架

let a = require('./a')
console.log(a)
复制代码

效果: 编程语言

ES6中的模块化

import/export模块化

export defaultexport 的区别

  1. 在一个文件或模块中 export 能够有多个,但 export default 仅有一个
  2. 经过 export 方式导出,在导入时要加 { },而 export default 则不须要
1.export
//a.js
export const str = "小生方勤";
//b.js
import { str } from 'a';   // 导入的时候须要花括号

2.export default
//a.js
const str = "小生方勤";
export default str;
//b.js
import str from 'a';      // 导入的时候无需花括号
复制代码

export default const a = 1; 这样写是会报错的哟。

es6 的导出模块写法有

export default 123;

export const a = 123;

const b = 3;
const c = 4;
export { b, c };
复制代码

虽然咱们通常在像Vue一些框架中均可以使用Es6的语法进行导入导出,可是babel 会将这些通通转换成 commonjs 的 exports。

exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.c = 4;
exports.__esModule = true;
复制代码

babel 转换 es6 的模块输出逻辑很是简单,即将全部输出都赋值给 exports,并带上一个标志 __esModule 代表这是个由 es6 转换来的 commonjs 输出。

babel将模块的导出转换为commonjs规范后,也会将引入 import 也转换为 commonjs 规范。即采用 require 去引用模块,再加以必定的处理,符合es6的使用意图。

也就是全部最后经过webpack打包后都将转化为common.js的规范

引入 default

对于最多见的

import a from './a.js';
复制代码

在es6中 import a from './a.js' 的本意是想去引入一个 es6 模块中的 default 输出。

经过babel转换后获得 var a = require(./a.js) 获得的对象倒是整个对象,确定不是 es6 语句的本意,因此须要对 a 作些改变。

咱们在导出提到,default 输出会赋值给导出对象的default属性。

exports.default = 123;
复制代码

因此这里最后的 a 变量就是 require 的值的 default 属性。若是原先就是commonjs规范的模块,那么就是那个模块的导出对象。

引入 * 通配符

咱们使用 import * as a from './a.js' es6语法的本意是想将 es6 模块的全部命名输出以及defalut输出打包成一个对象赋值给a变量。

已知以 commonjs 规范导出:

exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.__esModule = true;
复制代码

那么对于 es6 转换来的输出经过 var a = require('./a.js') 导入这个对象就已经符合意图。

import { a } from './a.js'

import { a } from './a.js' 直接转换成 require('./a.js').a 便可。

总结

通过上面的转换分析,咱们得知即便咱们使用了 es6 的模块系统,若是借助 babel 的转换,es6 的模块系统最终仍是会转换成 commonjs 的规范。因此咱们若是是使用 babel 转换 es6 模块,混合使用 es6 的模块和 commonjs 的规范是没有问题的,由于最终都会转换成 commonjs。

问题

为什么有的地方使用 require 去引用一个模块时须要加上 default?

require('xx').default

咱们在上文 babel 对导出模块的转换提到,es6 的 export default 都会被转换成 exports.default,即便这个模块只有这一个输出。

咱们常常会使用 es6 的 export default 来输出模块,并且这个输出是这个模块的惟一输出,咱们会误觉得这种写法输出的是模块的默认输出。

// a.js

export default 123;
复制代码
// b.js 错误

var foo = require('./a.js')
复制代码

在使用 require 进行引用时,咱们也会误觉得引入的是a文件的默认输出。

结果这里须要改为 var foo = require('./a.js').default

这个场景在写 webpack 代码分割逻辑时常常会遇到。

require.ensure([], (require) => {
   callback(null, [
     require('./src/pages/profitList').default,
   ]);
 });
复制代码

模块依赖的优化


模块依赖的优化

咱们在使用各大 UI 组件库时都会被介绍到为了不引入所有文件,请使用 babel-plugin-component 等babel 插件。

import { Button, Select } from 'element-ui'
复制代码

由前文可知 import 会先转换为 commonjs, 即

var a = require('element-ui');
var Button = a.Button;
var Select = a.Select;
复制代码

var a = require('element-ui'); 这个过程就会将全部组件都引入进来了。

因此 babel-plugin-component就作了一件事,将 import { Button, Select } from 'element-ui' 转换成了

import Button from 'element-ui/lib/button'
import Select from 'element-ui/lib/select'
复制代码

即便转换成了 commonjs 规范,也只是引入本身这个组件的js,将引入量减小到最低。

因此咱们会看到几乎全部的UI组件库的目录形式都是

|-lib
||--component1
||--component2
||--component3
|-index.common.js
复制代码

index.common.jsimport element from 'element-ui' 这种形式调用所有组件

给个element的连接去看看吧 :element.eleme.cn/#/zh-CN/com…

相关文章
相关标签/搜索