webpack es六、commonjs模塊混合打包分析

前言

本文着重介紹import、require混用的狀況下打包結果有何不一樣,以及webpack打包出的js運行機制。webpack負責將commonjs和es6模塊轉化爲瀏覽器認識的語句。javascript

babel配置

{
  "presets": [
    ["es2015", {"modules": false}],
    "stage-2"
  ]
}
複製代碼

各模塊均爲es6模塊的狀況

項目結構:

app.js(entry):html

import c from './c';
import {c1,c2} from './c'
console.log(c,c1,c2)
export default '我是a';
複製代碼

c.jsjava

import b from './b'
export let c1 = '我是c111'
export let c2 = '我是c222'
export default '我是c';
複製代碼

b.jswebpack

export default 'bbb';
複製代碼

htmlgit

<script src='./app.js'></script>
<script type="text/javascript">
    console.log(app)
</script>
複製代碼

結果解析:

此種狀況app.js、b.js、c.js都是es6模塊。es6

  1. html控制檯輸出github

    我是c 我是c111 我是c222
    {default: "我是a", __esModule: true}
    複製代碼
  2. 打包出的app.js以下:web

    Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
    /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
    console.log(__WEBPACK_IMPORTED_MODULE_0__c__["c" /* default */], __WEBPACK_IMPORTED_MODULE_0__c__["a" /* c1 */], __WEBPACK_IMPORTED_MODULE_0__c__["b" /* c2 */]);
    /* harmony default export */ __webpack_exports__["default"] = ('我是a');
    複製代碼

    app暴露出的是一個對象,而且增長了default和__esModule屬性。瀏覽器

  3. c.js以下bash

    /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return c1; });
    /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return c2; });
    /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__b__ = __webpack_require__(4);
    var c1 = '我是c111';
    var c2 = '我是c222';
    /* harmony default export */ __webpack_exports__["c"] = ('我是c');
    複製代碼

    c.js暴露了三個屬性。而且c將export default轉化爲了"c"屬性,而後會經過調用__WEBPACK_IMPORTED_MODULE_0__c__["c"]來獲取c的default值。

  4. b.js

    /* unused harmony default export */ var _unused_webpack_default_export = ('bbb');
    複製代碼

    因爲b.js雖然被c.js import了,可是沒有使用,因此b.js並無export出去。壓縮模式下b.js會被刪除。這就是webpack tree-shaking功能

結論:

若是入口模塊是es6模塊,並且引用的模塊也是es6模塊,那麼引用編譯後不會添加{__esModule:true},只有入口模塊纔會添加{__esModule:true},若是入口模塊有export default的值,那麼default會轉化爲暴露對象的default屬性。

引入的模塊爲commonjs模塊的狀況:

項目結構:

將案例一的c.js改成:

let c1 = 'c1'
let c2 = 'c2'
module.exports = {
	c1,
	c2,
}
複製代碼

結果解析:

此種狀況app.js、b.js是es6模塊,c.js是commonjs模塊

  1. c.js以下:

    var c1 = 'c1';
    var c2 = 'c2';
    module.exports = {
    	c1: c1,
    	c2: c2
    };
    複製代碼

結論:

若是入口模塊是es6模塊,引入的模塊是commonjs模塊,那麼引入的模塊會原樣輸出,而且引入的模塊將不會有default屬性。

引入的模塊爲commonjs模塊但未使用的狀況:

項目結構:

將案例一的b.js改成:

module.exports = 'bbb'
複製代碼

結果解析:

此種狀況app.js、c.js是es6模塊,b.js是commonjs模塊,但b只是import了並未使用

  1. b.js以下:

    module.exports = 'bbb'
    複製代碼

結論:

若是入口模塊是es6模塊,引入的模塊是commonjs模塊但並未使用,那麼webpack的tree-shaking功能不會生效,將打包的js壓縮後仍是會存在b.js
複製代碼

入口模塊爲commonjs模塊,引入的模塊爲es6模塊:

項目結構:

將案例一的app.js改成:

var b = require('./b')
var c = require('./c')
console.log(b.default)
console.log(c)
module.exports = {
	a:'我是a'
}
複製代碼

結果解析:

此種狀況b.js、c.js是es6模塊,app.js是commonjs模塊

  1. app.js以下:

    var b = __webpack_require__(3);
    var c = __webpack_require__(0);
    console.log(b.default);
    console.log(c);
    module.exports = {
    	a: '我是a'
    }
    複製代碼
  2. b.js以下

    Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
    /* harmony default export */ __webpack_exports__["default"] = ('bbb');
    複製代碼

結論:

若是入口模塊是commonjs模塊,引入的模塊是es6模塊,那麼es6模塊編譯後會添加{__esModule:true}。若是被調用的es6模塊中剛好有export default語句,那麼編譯後的es6模塊將會添加.default = ...。這時候若是入口commonjs模塊想調用es6模塊的default值,就須要手動添加b.default。例如:var b = require('./b').default console.log(b)。另:commonjs模塊中不能使用import語句,會報錯!

入口模塊和引入的模塊爲commonjs模塊的狀況

結論:

模塊所有原樣輸出。沒有export default的狀況了。

綜上

  1. es6模塊調用commonjs模塊,能夠直接使用commonjs模塊,commonjs模塊將不會被webpack的模塊系統編譯而是會原樣輸出,而且commonjs模塊沒有.default屬性

  2. es6模塊調用es6模塊,被調用的es6模塊不會添加{__esModule:true},只有調用者纔會添加{__esModule:true};而且能夠進行tree-shaking操做,若是被調用的es6模塊只是import進來,可是並無被用到,那麼被調用的es6模塊將會被標記爲/* unused harmony default export */,在壓縮時此模塊將會被刪除(例外:若是被調用的es6模塊裏有當即執行語句,那麼這些語句將會被保留)。

  3. 若是是commonjs模塊引用了es6模塊,那麼es6模塊編譯後會添加{__esModule:true}。若是被調用的es6模塊中剛好有export default語句,那麼編譯後的es6模塊將會添加.default = ...,這時調用require進來的es6模塊默認值,就須要例如:var b = require('./b').default console.log(b)

  4. 若是commonjs模塊調用commonjs模塊,那麼commonjs模塊會原樣輸出。

  5. commonjs模塊中不能使用import語句,會報錯

  6. webpakc的output設置會設置模塊的打包格式和保留變量,若是設置library = 'test',那麼打包後的js執行完成後全部的模塊將會掛到window.test上

項目地址

相關文章
相關標籤/搜索