webpack4.0各個擊破(5)—— Module篇

來源:互聯網
上載者:User

標籤:text   參與   icloud   打包   配置   term   行合并   col   call   

webpack4.0各個擊破(5)—— Module篇

webpack作為前端最火的構建工具,是前端自動化工具鏈最重要的部分,使用門檻較高。本系列是筆者自己的學習記錄,比較基礎,希望通過問題 + 解決方式的模式,以前端構建中遇到的具體需求為出發點,學習webpack工具中相應的處理辦法。(本篇中的參數配置及使用方式均基於webpack4.0版本

使用webpack對指令碼進行合并是非常方便的,因為webpack實現了對各種不同模組規範的相容處理,對前端開發人員來說,理解這種實現方式比學習如何配置webpack更為重要,本節的內容實用性較低。

一. 模組化亂燉

指令碼合并是基於模組化規範的,javascript模組化是一個非常混亂的話題,各種**【*MD】**規範亂飛還要外加一堆【*.js】的規範實現。現代化前端項目多基於架構進行開發,較為流行的架構內部基本已經統一遵循ES6的模組化標準,儘管支援度不一,但通過構建工具可以解決瀏覽器支援滯後的問題;基於nodejs的服務端項目原生支援CommonJs標準;而開發中引入的一些工具類的庫,熱門的工具類庫為了能同時相容瀏覽器和node環境,通常會使用UMD標準(Universal Module Definition) 來實現模組化,對UMD範式不瞭解的讀者可以先閱讀《javascript基礎修鍊(4)——UMD規範的代碼推演》一文,甚至有些第三方庫並沒有遵循任何模組化方案。如果不藉助構建工具,想要對各類方案實現相容是非常複雜的。

二. webpack與模組化

webpack預設支援的是CommonJs規範,畢竟它是nodejs支援的模組管理方式,而沒有node哪來的webpack。但同時為了擴充其使用情境,webpack在版本迭代中也加入了對ES harmony規範和AMD規範的相容。

webpack如何識別CommonJs模組

webpack打包後輸出檔案的基本結構是下面這個樣子的:

(function(modules) { // webpackBootstrap    // 模組緩衝對象    var installedModules = {};    // webpack內部的模組引用函數    function __webpack_require__(moduleId) {        // 載入入口JS        // 輸出        return module.exports;    }    // 掛載模組數組    __webpack_require__.m = modules;    // ...    // 在__webpack_require__掛載多個屬性    // 傳入入口JS模組ID執行函數並輸出模組    return __webpack_require__(__webpack_require__.s = 0);});// 包含所有模組的數組([    /* id為0 */    (function(module, exports) {        console.log(‘1‘)    })]);

簡化以後實際上就是一個自執行函數:

(function(modules){    return __webpack_require__(0);}([Module0,Module1...]))

可以看到__webpack_reqruie__( )這個方法的參數就是模組的唯一ID標識,傳回值就是module.exports,所以webpack對於CommonJs規範是原生支援的。

webpack如何識別ES Harmony模組

對於ES Harmony規範不熟悉的可以查看《ES6 Module文法》一文。

先使用import命令載入一個CommonJs規範匯出的模組,查看打包後的代碼可以看到模組引用的部分被轉換成了下面這樣:

__webpack_require__.r(__webpack_exports__);/* harmony import */ var _components_component10k_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./components/component10k.js");/* harmony import */var _components_component10k_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_components_component10k_js__WEBPACK_IMPORTED_MODULE_0__);

簡化一下再來看:

__webpack_require__.r(__webpack_exports__);var a = __webpack_require__("./components/component10k.js");var b = __webpack_require__.n(a);

這裡涉及到兩個工具函數:

這個方法是給模組的exports對象加上ES Harmony規範的標記,如果支援Symbol對象,則為exports對象的Symbol.toStringTag屬性賦值Module,這樣做的結果是exports對象在調用toString方法時會返回‘Module‘(筆者並沒有查到這種寫法的緣由);如果不支援Symbol對象,則將exports.__esModule賦值為true。

另一個工具函數是:

傳入了一個模組,返回一個getter方法,此處是一個高階函數的應用,實現的功能是當模組的__esModule屬性為真時,返回一個getDefault( )方法,否則返回getModuleExports( )方法.

回過頭再來看上面的簡化代碼:

// 添加ES Harmony規範模組標記__webpack_require__.r(__webpack_exports__);// a實際上得到了模組通過module.exports輸出的對象var a = __webpack_require__("./components/component10k.js");// 根據a的模組化規範類型返回不同的getter函數,當getter函數執行時才會真正得到模組對象var b = __webpack_require__.n(a);

總結一下,webpack所做的處理相當於對模組增加了代理,如果被載入模組符合ES Harmony規範,則返回module[‘default‘],否則返回module。這裡的module泛指模組輸出的對象。

再使用import載入一個使用export文法輸出的ES Harmony模組,查看打包結果中的模組檔案可以看到:

//component10k.js模組檔案在main.bundle.js中的內容__webpack_require__.r(__webpack_exports__);__webpack_exports__["default"] = (function(){    Array.from(‘component10k‘);})

可以看到輸出的內容直接綁定到了輸出模組的default屬性上,由於這個模組被打上了__esModule的標記,所以引用它的模組會通過module[‘default‘]來取用其內容,也就正好命中了模組的輸出內容。

webpack如何識別AMD模組

我們將component10k.js模組改為用AMD規範定義:

define(function(){    console.log(‘test‘);})

查看經過webpack打包後,這個模組變成了如下的樣子:

var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(){    console.log(‘test‘);}).call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));

簡化一下:

var result;!(result=(function(){}).call(...),result!==undefined && module.exports = result);

抽象一下:

var result;!(expression1,expression2 && expression3)

這裡涉及的javascript的基本知識較多,逗號運算式的優先順序最低,所以最後參與運算,逗號運算式會從左至右依次執行語句,並返回最後一個運算式的結果,&&為短路運算文法,即前一個條件成立時才計算後面的運算式,指派陳述式執行完後會將所賦的值返回。此處外層的!(expression )文法起了什麼作用,筆者也沒看懂,希望瞭解的讀者多多指教。

所以,webpack對於AMD模組的處理,實際上是加了一層封裝,將模組啟動並執行結果掛載到了webpack模組的module.exports對象上。

webpack4.0各個擊破(5)—— Module篇

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.