ES6的模塊化: import export default
common.js的模塊化: require module.exports node.js使用該規(guī)范
為什么有模塊概念
理想情況下,開發(fā)者只需要實現(xiàn)核心的業(yè)務邏輯,其他都可以加載別人已經(jīng)寫好的模塊。
但是,Javascript不是一種模塊化編程語言,在es6以前,它是不支持”類”(class),所以也就沒有”模塊”(module)了。同時以前也沒有webpack這樣的工具,可以使用node去操作文件,讀取文件內容, 然后達到引入文件內容的目的.(也就是模塊化)--在不同的文件中放著不同的功能模塊
Common.js
首先需要明白的在node中每個文件都是一個自執(zhí)行函數(shù)(只不過我們肉眼凡胎看不出來,哈啊哈)
(function (exports, require, module, __filename, __dirname) {
module.exports = exports = this
return module.exports
})()
為了說明module.exports = exports = this請看下面例子
a.js
this.a = 123 // 第一種
exports.a = 123 //第二種
module.exports.a = 123 // 第三種
b.js
let a = require('./a')
console.log(a)
效果:
ES6中的模塊化
import/export
export default 和 export 的區(qū)別
- 在一個文件或模塊中
export可以有多個,但export default僅有一個 - 通過 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 會將這些統(tǒng)統(tǒng)轉換成 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規(guī)范后,也會將引入 import 也轉換為 commonjs 規(guī)范。即采用 require 去引用模塊,再加以一定的處理,符合es6的使用意圖。
也就是所有最后通過webpack打包后都將轉化為common.js的規(guī)范
引入 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規(guī)范的模塊,那么就是那個模塊的導出對象。
引入 * 通配符
我們使用 import * as a from './a.js' es6語法的本意是想將 es6 模塊的所有命名輸出以及defalut輸出打包成一個對象賦值給a變量。
已知以 commonjs 規(guī)范導出:
exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.__esModule = true;
那么對于 es6 轉換來的輸出通過 var a = require('./a.js') 導入這個對象就已經(jīng)符合意圖。
import { a } from './a.js'
import { a } from './a.js'
直接轉換成 require('./a.js').a 即可。
總結
經(jīng)過上面的轉換分析,我們得知即使我們使用了 es6 的模塊系統(tǒng),如果借助 babel 的轉換,es6 的模塊系統(tǒng)最終還是會轉換成 commonjs 的規(guī)范。所以我們如果是使用 babel 轉換 es6 模塊,混合使用 es6 的模塊和 commonjs 的規(guī)范是沒有問題的,因為最終都會轉換成 commonjs。
問題
為何有的地方使用 require 去引用一個模塊時需要加上 default?
require('xx').default
我們在上文 babel 對導出模塊的轉換提到,es6 的 export default 都會被轉換成 exports.default,即使這個模塊只有這一個輸出。
我們經(jīng)常會使用 es6 的 export default 來輸出模塊,而且這個輸出是這個模塊的唯一輸出,我們會誤以為這種寫法輸出的是模塊的默認輸出。
// a.js
export default 123;
// b.js 錯誤
var foo = require('./a.js')
在使用 require 進行引用時,我們也會誤以為引入的是a文件的默認輸出。
結果這里需要改成 var foo = require('./a.js').default
這個場景在寫 webpack 代碼分割邏輯時經(jīng)常會遇到。
require.ensure([], (require) => {
callback(null, [
require('./src/pages/profitList').default,
]);
});
模塊依賴的優(yōu)化
模塊依賴的優(yōu)化
我們在使用各大 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 規(guī)范,也只是引入自己這個組件的js,將引入量減少到最低。
所以我們會看到幾乎所有的UI組件庫的目錄形式都是
|-lib
||--component1
||--component2
||--component3
|-index.common.js
index.common.js 給 import element from 'element-ui' 這種形式調用全部組件
給個element的鏈接去看看吧 :https://element.eleme.cn/#/zh-CN/component/quickstart