webpack external模塊的具體使用
這篇文章討論Webpack打包library時經(jīng)常需要用到的一個選項external,它用于避免將一些很通用的模塊打包進你發(fā)布的library里,而是選擇把它們聲明成external的模塊,在你的library被上層使用后,在最后階段由Webpack統(tǒng)一把這個external的依賴模塊打包進來。
external選項一般都是用在打包library上面,如果不是library而是一個最終的app的發(fā)布JS文件,那external也沒有什么意義。關(guān)于Webpack打包library的分析和一些選項的作用,我在前一篇文章做了討論。
external選項
我們?nèi)匀皇褂们耙黄恼碌睦?,定義一個庫util.js:
import $ from 'jquery' function hideImages() { $('img').hide(); } export default { "hideImages": hideImages }
我們使用Webpack打包發(fā)布這個庫:
// 入口文件 entry: { util: './util.js', } // 輸出文件 output: { path: './dist', filename: '[name].dist.js' library: 'util', libraryTarget: commonjs2, targetExport: 'default' }
這樣打包出來的util.dist.js文件會把jquery的代碼完整地注入進去,因為你的源代碼使用到了它。但是這往往并不是我們希望的,因為jquery是很通用的模塊,在一個app中,很可能其它的庫也會用到它,最頂層的入口文件app也可能用到它,如果每一個庫模塊的發(fā)布版本都將jquery原封不動地打包進了自己的bundle,最后拼到一起,在最終的app發(fā)布代碼里就會有很多份jquery的復(fù)制,當然這可能并不會影響它的正常功能,但是會占據(jù)很大的代碼體積。
所以通常情況下當你的庫需要依賴到例如jquery,bootstrap這樣的通用JS模塊時,我們可以不將它打包進bundle,而是在Webpack的配置中聲明external:
externals: { jquery: { root: 'jquery', commonjs: 'jquery', commonjs2: 'jquery', amd: 'jquery', }, },
這就是在告訴Webpack:請不要將這個模塊注入編譯后的JS文件里,對于我源代碼里出現(xiàn)的任何import/require這個模塊的語句,請將它保留。
我們可以看一下編譯后的bundle文件的結(jié)構(gòu):
module.exports = (function(modules) { var installedModules = {}; function webpack_require(moduleId) { // ... } return webpack_require('./util.js'); }) ({ './util.js': generated_util, // '/path/to/jquery.js': generated_jquery 原本有這一行,現(xiàn)在被刪去。 });
可以看到j(luò)query模塊沒有被打包進bundle文件,而對于util,它的生成代碼即generated_util函數(shù)中關(guān)于import jquery相關(guān)的語句也被保留了原意:
function generated_util(module, exports, webpack_require) { var $ = require('jquery'); // util的其它源代碼 // ... }
當然也并非完全沒有修改,例如將import的改回了傳統(tǒng)的require關(guān)鍵詞,因為我們這里用的是CommonJS風(fēng)格的打包方式。不過這些都是次要的,關(guān)鍵是它保留了require這個關(guān)鍵詞,而沒有使用webpack_require將jquery真的引入進來。這就是說,當前的這個JS文件的模塊管理系統(tǒng)中是沒有jquery的,它是一個external的模塊,需要在這個JS文件被其它人引用并且在上層編譯時,jquery才可能被真的引入進來,到那個時候這里的require關(guān)鍵詞才會被替換為webpack_require。
對于external的依賴模塊,通常你可以這樣做,例如你使用npm發(fā)布你的庫,你可以將jquery在package.json文件中添加到dependencies,這樣別人npm install你發(fā)布的庫時,jquery也會被自動下載到node_modules供別人打包使用。
umd格式下的打包
如果我們使用umd格式打包,我們可以看到在不同環(huán)境中,external模塊是如何發(fā)揮作用的:
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') // commonjs2 module.exports = factory(require('jquery')); else if(typeof define === 'function' && define.amd) define("util", ['jquery'], factory); // amd else if(typeof exports === 'object') exports["util"] = factory(require('jquery')); // commonjs else root["util"] = factory(root['jquery']); // var }) (window, function(__webpack_external_module_jquery__) { return (function(modules) { var installedModules = {}; function webpack_require(moduleId) { // ... } return webpack_require('./util.js'); }) ({ './util.js': generated_util, }); }
而generated_util也相應(yīng)地增加一個參數(shù)__webpack_external_module_jquery__:
function generated_util(module, exports, webpack_require, __webpack_external_module_jquery__) { var $ = __webpack_external_module_jquery__; // util的其它源代碼 // ... }
這樣的寫法似乎結(jié)構(gòu)和上面的CommonJS的編譯版本不太一樣,但實際上本質(zhì)是一樣的。因為現(xiàn)在umd要照顧到不同的運行環(huán)境,所以它把require('jquery')提前了,作為factory的參數(shù)傳入。對于每種運行環(huán)境,各有各的做法:
- CommonJS:保留require('jquery')語句。
- AMD:在define中將jquery定義為依賴模塊。
- Var:從全局域中取出jquery變量,這需要jquery在該模塊之前就已經(jīng)被加載。
然后不管是哪種情況,它們都將載入后的jquery模塊作為參數(shù)傳入factory函數(shù),這樣就能正確加載util模塊了。
以上涉及到Webpack生成代碼的部分可能有點繞,需要你比較了解Webpack打包模塊的機制和原理,關(guān)于這部分我在這篇文章里做了詳細討論。
總結(jié)
以上就是關(guān)于Webpack的external選項的使用,并且從編譯后的JS代碼分析了它到底是如何起作用的。我想閱讀Webpack相關(guān)的生成代碼還是很重要的,這樣才算是真正地理解了external的機制,在碰到一些坑時才能知道怎么去debug。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用JavaScript開發(fā)跨平臺的桌面應(yīng)用詳解
下面小編就為大家?guī)硪黄褂肑avaScript開發(fā)跨平臺的桌面應(yīng)用詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07JavaScript HTML DOM 元素 (節(jié)點)新增,編輯,刪除操作實例分析
這篇文章主要介紹了JavaScript HTML DOM 元素 (節(jié)點)新增,編輯,刪除操作,結(jié)合實例形式分析了JavaScript針對HTML DOM 元素 (節(jié)點)的新增,編輯,刪除相關(guān)操作技巧與使用注意事項,需要的朋友可以參考下2020-03-03