參考來源:https://github.com/ruanyf/webpack-demos#demo01-entry-file-sourcejavascript
後面的代碼:https://github.com/947133297/lwj-webpack-demohtml
webpack默認支持這兩種模塊的打包java
amd.jsjquery
define('amd',function(){ return { data:'content from amd module' } });
commonJS.jswebpack
module.exports = { data:'content from commonjs module' }
配置文件git
module.exports = { entry: './main.js', output: { filename: 'bundle.js' } };
入口文件github
var amd = require('./js-module/amd'); var com = require('./js-module/commomJS'); console.log(amd); console.log(com);
運行結果:可正常輸出這兩個模塊,網絡請求只有一個bundle.js,可見這兩個模塊的內容都打包進了一個js文件中web
entry chunk :包含了 webpackJsonp、__webpack_require__ 的定義 ,__webpack_require__.e用於以promise方式加載依賴後執行組件的代碼(入口文件的代碼),如:json
normal chunk:包含了入口文件所需的模塊的代碼,裏面調用了webpackJsonp來註冊依賴,如:promise
若是多個組件中有相同的代碼,每一個組件都都像上個例子那樣徹底打包一份,那雖然減小了網絡訪問次數,但可能致使無謂的流量消耗,由於多個模塊是能夠共用代碼的
全局JS:
把要複用的部分抽取到一個額外的全局js中,而後手動引入這個js,其餘組件中直接使用這個js便可,如:
module.exports = { entry: { bundle1:'./main1.js', bundle2:'./main2.js' }, output: { filename: '[name].js' } }; // main1.js console.log('組件1獲取數據' + data); //main2.js console.log('組件2獲取數據' + data); //commonData.js: var data = 'this is common data'; index.html: <html> <script src="commonData.js"></script> <body> <script type="text/javascript" src="bundle1.js"></script> <script type="text/javascript" src="bundle2.js"></script> </body> </html>
有沒有辦法不全局,並且可使多個組件共用呢?這個需求可惟一推測出只能使用js模塊,可是以上測試中,發現使用模塊的話,會徹底打包進去,以致於不能實現代碼複用。其餘webpack提供一個require.ensure能夠實現模塊的不打包,從而達到複用的目的
對以上代碼進行改造:
// commonData.js exports.data = 'this is common data'; // mian1.js require.ensure(['./commonData'], function(require) { var m = require('./commonData'); console.log('組件1獲取數據' + m.data); }); //main2.js require.ensure(['./commonData'], function(require) { var m = require('./commonData'); console.log('組件2獲取數據' + m.data); }); //index.html <html> <body> <script type="text/javascript" src="bundle1.js"></script> <script type="text/javascript" src="bundle2.js"></script> </body> </html>
運行結果同樣。只不過此次實現了代碼複用:
以上效果的另一種實現方式,是使用 bundle-loader ,語法不一樣但效果同樣就再也不舉例了
源碼分析:
bundle一、2.js中包含了webpackJsonp、__webpack_require__以及這個函數對象的一系列方法,以及對應入口文件的執行代碼
__webpack_require__.e 函數:用於根據模塊id來獲取模塊,返回一個promise。往header上寫一個script標籤,這個標籤onload的時候,也就是這個新增script中的webpackJsonp函數執行完了,就觸發promise的resolve方法(執行了對應入口文件的代碼)
補充測試:
模塊1和2ensure了一個文件,模塊3ensure了另外一個文件。則會額外生成0.js和1.js。也就是說多少個文件被ensure,就會額外生成多少個文件(名字從0開始計算),重複ensure不會額外生成文件,而是複用以前的
與ensure具備相同功能的是import。這二者都用於動態代碼分割,若是使用import的話須要注意promise的兼容,可使用響應的墊片庫來處理,簡單的import使用,能夠參考倉庫中的demo5
代碼抽取還能夠用這個插件來實現,測試代碼以下:
抽取依賴
// 配置文件 var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin"); module.exports = { entry: { bundle1: './main1.js', bundle2: './main2.js' }, output: { filename: '[name].js' }, plugins: [ new CommonsChunkPlugin('chunkInit') ] } // main1.js require('./com'); require('./comm2'); var data = 'this is differenet1 '; //main2.js require('./com'); require('./comm2'); var data = 'this is differenet2 '; //com.js exports.data = '這裏存放的是公共代碼' //comm2.js exports.data = '這裏存放的是公共代碼2' //index.html <html> <body> <script src="chunkInit.js"></script> <script src="bundle1.js"></script> <script src="bundle2.js"></script> </body> </html>
運行結果:
會生成一個chunkinit.js文件(這個名字是咱們在new 插件的時候指定的),這個文件中包含了webpackJsonp、__webpack_require__以及這個函數對象的一系列方法以及被依賴的模塊的代碼,也就是說require進來的東西並非動態加載的,並且直接寫到了這個chunkinit.js文件中。而兩個bundle文件調用了webpackjsonP函數,裏面的回調函數中執行了對應入口文件的代碼
可見,這個插件實現的功能和require.ensure都是代碼抽取,但二者本質上不一樣:
組件的初始化定義:包含了webpackJsonp、__webpack_require__以及這個函數對象的一系列方法
ensure:動態加載代碼,抽取的是被依賴的代碼,多個組件的初始化定義也仍是重複的
插件:非動態加載代碼,抽取的是多個組件的初始化定義到一個文件中,而且裏面寫好了被依賴的模塊代碼
以上兩個組件都引用了兩個相同的依賴,因此這兩個依賴都放到了chuninit中。測試發現,多個組件中相同的依賴會被放到chunkinti中,而差別的部分則放到對應的bundle中,也就是說bundle中可能同時出現出現被依賴的模塊代碼以及對應的入口文件的代碼
回顧如下:jq這個庫兼容amd和commonJS的導入方式,require.ensure能夠以不打包的形式導入一個庫
有了以上的理解,怎麼使用jq就很好想象了,如下使用ensure來導入,一樣的理解使用上面的插件來導入應該也是可行的
require.ensure(['./jquery-3.2.1.min'], function(require) { var jq = require('./jquery-3.2.1.min'); jq('body').attr('c2','true'); });
運行結果正常。