當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…

相關文章
相關標籤/搜索