1. 程式人生 > >打包js

打包js

來源 完全 ren 訪問 class content rip () 配置

參考來源:https://github.com/ruanyf/webpack-demos#demo01-entry-file-source

後面的代碼:https://github.com/947133297/lwj-webpack-demo

打包AMD和commonJS模塊

webpack默認支持這兩種模塊的打包

amd.js

define(‘amd‘,function(){
    return {
       data:‘content from amd module‘
    }
});

commonJS.js

module.exports = {
    data:‘content from commonjs module‘
}

配置文件

module.exports = {
  entry: ‘./main.js‘,
  output: {
    filename: ‘bundle.js‘
  }
};

入口文件

var amd = require(‘./js-module/amd‘);
var com = require(‘./js-module/commomJS‘);

console.log(amd);
console.log(com);

運行結果:可正常輸出這兩個模塊,網絡請求只有一個bundle.js,可見這兩個模塊的內容都打包進了一個js文件中

技術分享

chunk(這裏的理解偏頗)

entry chunk :包含了 webpackJsonp、__webpack_require__ 的定義 ,__webpack_require__.e用於以promise方式加載依賴後執行組件的代碼(入口文件的代碼),如:

技術分享

normal chunk:包含了入口文件所需的模塊的代碼,裏面調用了webpackJsonp來註冊依賴,如:

技術分享

多組件代碼抽取

如果多個組件中有相同的代碼,每個組件都都像上個例子那樣完全打包一份,那雖然減少了網絡訪問次數,但可能導致無謂的流量消耗,因為多個模塊是可以共用代碼的

全局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可以實現模塊的不打包,從而達到復用的目的

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 ,語法不同但效果一樣就不再舉例了

源碼分析:

  bundle1、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不會額外生成文件,而是復用之前的

CommonsChunkPlugin

代碼抽取還可以用這個插件來實現,測試代碼如下:

抽取依賴

// 配置文件
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中可能同時出現出現被依賴的模塊代碼以及對應的入口文件的代碼

使用jquery

回顧以下: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‘);
});

運行結果正常。

打包js