webpack代碼拆分的示例分析-創(chuàng)新互聯(lián)

這篇文章主要介紹webpack代碼拆分的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

楊浦ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!

如果利用 webpack 將項(xiàng)目中的所有代碼打包在一起,很多時(shí)候是不適用的,因?yàn)榇a中有些東西我們總是希望將其拆分出來(lái)。比如:

  1. 樣式表,希望利用 link 標(biāo)簽引入

  2. 使用概率較低的模塊,希望后期需要的時(shí)候異步加載

  3. 框架代碼,希望能利用瀏覽器緩存下部分不易變動(dòng)的代碼

下面是我在閱讀 webpack 的官方文檔時(shí)候,記錄的一些筆記,部分地方使用了自己的話來(lái)講,力圖讓它顯得更易懂。

按需加載拆分

webpack 可以幫助我們將代碼分成不同的邏輯塊,在需要的時(shí)候加載這些代碼。

使用require.ensure()來(lái)拆分代碼

require.ensure()是一種使用 CommonJS 的形式來(lái)異步加載模塊的策略。在代碼中通過require.ensure([<fileurl>])引用模塊,其使用方法如下:

require.ensure(dependencies: String[], callback: function(require), chunkName: String)

第一個(gè)參數(shù)指定依賴的模塊,第二個(gè)參數(shù)是一個(gè)函數(shù),在這個(gè)函數(shù)里面你可以使用 require 來(lái)加載其他的模塊,webpack 會(huì)收集 ensure 中的依賴,將其打包在一個(gè)單獨(dú)的文件中,在后續(xù)用到的時(shí)候使用 jsonp 異步地加載進(jìn)去。

require.ensure(['./a'], function(require){
  let b = require('./b');
  let a = require('./a');
  console.log(a+b)
});

以上代碼,a 和 b 會(huì)被打包在一起,在代碼中執(zhí)行到這段代碼的時(shí)候,會(huì)異步地去加載,加載完成后執(zhí)行函數(shù)里面的邏輯。

let a = require('./a');
require.ensure(['./a'], function(require){
  let b = require('./b');
  console.log(a+b)
});

如果這樣寫,那么 a 不會(huì)和 b 打包在一起,因?yàn)?a 已經(jīng)被打包在主代碼中了。

require.ensure(['./c'], function(require){
  let a = require('./a');
  console.log(a)
});

require.ensure(['./c'], function(require){
  let b = require('./b');
  console.log(b)
});

以上代碼中兩個(gè)模塊都依賴了 c 模塊,這個(gè)時(shí)候會(huì)拆分出兩個(gè)模塊,其中都包含了 c 模塊,因?yàn)樵趯?shí)際運(yùn)用中,以上兩個(gè)require.ensure的執(zhí)行順序不確定,執(zhí)行與否也不確定,因此需要將 c 模塊都打包進(jìn)去。

require.ensure還可以傳入第三個(gè)參數(shù),這個(gè)參數(shù)用來(lái)指定打包的包名,對(duì)于上面這種情況,c 模塊被打包入了兩個(gè)包中,如果事先明確這兩個(gè)包都會(huì)被使用,那么不妨將這兩個(gè)包合并為一個(gè),這樣就不會(huì)有 c 模塊被打包兩次的問題了,所以可以將 chunkName 指定為同一個(gè)名字。

require.ensure(['./c'], function(require){
  let a = require('./a');
  console.log(a)
}, 'd');

require.ensure(['./c'], function(require){
  let b = require('./b');
  console.log(b)
}, 'd');

ok,這樣以上兩個(gè)require.ensure拆出來(lái)的包就合并為同一個(gè)了。

CSS 拆分

開發(fā)者,可能希望能將工程中的所有引入的 CSS 拆分為單個(gè)文件,這樣可以利用緩存,且利用 CSS 和 JavaScript 并行加載,來(lái)加速 web 應(yīng)用。

使用css-loader

為了加載 css,這里需要用到 css-loader,配置方法如下:

module: {
  loaders: [{
    test: /\.css$/,
    exclude: /node_modules/,
    loader: 'css-loader'
  }]
}

這樣在代碼中就可以寫如下代碼:

let css = require('./main.css');
console.log('' + css);

通過 require 一個(gè) css 得到其內(nèi)容,當(dāng)然了這里 require('./main.css') 實(shí)際得到的是一個(gè)對(duì)象,需要調(diào)用其 toString 方法將其轉(zhuǎn)換為字符串。在代碼中引用一段 css,這常常不是我們想要的。為此可以使用 style-loader 在代碼執(zhí)行起來(lái)的時(shí)候,會(huì)將這些 css 插入到 style 標(biāo)簽中,只是這里 css 還是存在于 js 中的,是后來(lái)動(dòng)態(tài)插入到頁(yè)面中的:

module: {
  loaders: [{
    test: /\.css$/,
    exclude: /node_modules/,
    loader: 'style-loader!css-loader'
  }]
}

更多時(shí)候,是希望將 css 拆分為單個(gè)文件,然后使用 link 標(biāo)簽嵌入到 html 中,CSS 和 JavaScript 可以并行加載,css 還可以被緩存下來(lái)。

使用extract-text-webpack-plugin來(lái)拆分 css

為了使用這個(gè)插件首先需要通過 npm 來(lái)安裝它:

npm i --save-dev extract-text-webpack-plugin

然后在 webpack 的配置文件中使用該插件:

var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = function () {
  return {
    entry: './index.js',
    output: {
      path: './build',
      filename: 'bundle.js'
    },
    module: {
      loaders: [{
        test: /\.css$/,
        exclude: /node_modules/,
        // 在 loader 中使用該插件
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
      }]
    },
    plugins: [
      // 將其添加在插件中
      new ExtractTextPlugin({ filename: 'bundle.css', disable: false, allChunks: true })
    ]
  }
}

需要注意的是,對(duì)于 webpack1 和 webpack2 這個(gè)插件的配置方法是不同的,差別比較細(xì)微,詳情請(qǐng)看官方文檔 extract text plugin for webpack 2

拆分業(yè)務(wù)代碼與框架代碼

通常一個(gè) web 應(yīng)用都會(huì)引用若干第三方庫(kù),這些第三方庫(kù)通常比較穩(wěn)定不會(huì)經(jīng)常變動(dòng),但是如果將業(yè)務(wù)代碼和框架代碼打包在了一起,這樣業(yè)務(wù)代碼每次變動(dòng)打包得到的結(jié)果都會(huì)變動(dòng),及時(shí)只改變了一個(gè)字符,瀏覽器也無(wú)法利用緩存,必須全部重新加載。因此,何不將第三方庫(kù)單獨(dú)打包在一起呢?

這里舉個(gè)案例,一個(gè) react 項(xiàng)目中使用了reactreact-dom這兩個(gè)包,我希望將他們打包在一起,將業(yè)務(wù)代碼打包在一起。

下面一步一步來(lái):

1. 安裝 react 和 react-dom:

npm i react react-dom --save

2. 配置 entry,output 和 loader

先使用單入口,讓代碼工作起來(lái)。另外因?yàn)槭褂昧?react 所以要使用babel-loader來(lái)加載 js

// webpack.config.js

module.exports = {
  entry: 'index.js',
  output: {
    path: 'build/',
    filname: '[name]@[chunkhash].js'
  },
  module:{
    loaders:[{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel'
    }]
  }
}

3. 編寫業(yè)務(wù)代碼

index.js:

import React from 'react';
import ReactDOM from 'react-dom';


var Hello = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

ReactDOM.render(<Hello name={'world'} />, document.getElementById('app'));

index.html:

<div id="app"></div>
<!--entry 為一個(gè)字符串,這個(gè) chunk 的名字會(huì)是 main, 因此這里引入 main.js -->
<script src="build/main.js"></script>

啟動(dòng)webpack-dev-server,打開瀏覽器這個(gè)時(shí)候應(yīng)該能在頁(yè)面上看到 hello world,這說明工作正常。

4. 拆分框架代碼

為了拆分框架代碼,我們需要增加一個(gè)入口,在這個(gè)入口中要包含reactreact-dom

module.exports = {
  entry: {
    main: 'index.js',
    vendor: ['react', 'react-dom']
  }
  //...
}

單單像上面這樣配置,打包后會(huì)得到 main.js 和 vendor.js,但會(huì)發(fā)現(xiàn)在 main.js 中依然包含了 react 和 react-dom 的代碼,這是因?yàn)橹付巳肟诤?,webpack 就會(huì)從入口文件開始講整個(gè)依賴打包進(jìn)來(lái),index.js 中引用了 react 和 react-dom 自然會(huì)被打包進(jìn)去。要想達(dá)到之前所說的那個(gè)效果,還需要借助一個(gè)插件 —— CommonsChunkPlugin

5. 使用 CommonsChunkPlugin

這個(gè)插件的功能是將多個(gè)打包結(jié)果中公共的部分抽取出來(lái),作為一個(gè)單獨(dú)的文件。它符合目前的場(chǎng)景,因?yàn)?code>main.js和vendor.js中存在一份公共的代碼,那就是vendor.js中的內(nèi)容。(這個(gè)說法并不準(zhǔn)確,這里只是指 react 和 react-dom 都被打包進(jìn)了這兩個(gè)文件)

let webpack = require('webpack');

module.exports = {
  entry: {
    main: 'index.js',
    vendor: ['react', 'react-dom']
  },
  //...

  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor' // 指定一個(gè)希望作為公共包的入口
    })
  ]
}

再進(jìn)行打包,這個(gè)時(shí)候會(huì)發(fā)現(xiàn)main.js中的代碼不在包含 react 的代碼了。看似實(shí)現(xiàn)了我們的需求,但真實(shí)應(yīng)用下并沒有這么簡(jiǎn)單,在實(shí)際項(xiàng)目中 js 腳本通常都會(huì)給添加一個(gè) MD5 的 hash 在后面,形如app@709d9850745a4c8ba1d4.js 這樣每次打包后,如果文件內(nèi)容變了,后面的 hash 也會(huì)變動(dòng)。就以上場(chǎng)景,會(huì)發(fā)現(xiàn)當(dāng)我們修改了業(yè)務(wù)代碼后,得到的 hash 是不同的,因此每次都會(huì)得到兩個(gè)不同的打包結(jié)果。業(yè)務(wù)代碼改變了,拆分出來(lái)的框架包也變了,這顯然不符合初衷 —— 利用瀏覽器緩存。

這是因?yàn)?webpack 在打包的時(shí)候會(huì)產(chǎn)生一些運(yùn)行時(shí)代碼,比如__webpack_require__、webpackJsonp等等,這些函數(shù)是用來(lái)幫助 webpack 完成模塊加載等功能的,業(yè)務(wù)代碼的改變會(huì)導(dǎo)致業(yè)務(wù)代碼打包后的 hash 值改變,而在 webpack 的運(yùn)行時(shí)代碼中實(shí)際上是保存了打包后的結(jié)果的文件名的,因?yàn)樗诋惒郊虞d模塊的時(shí)候需要用到。因此,下面需要做的是將 webpack 的運(yùn)行時(shí)代碼拆分出來(lái)。

修改 plugins 如下,將 name 修改為 names,并增加一個(gè) init 的包名,執(zhí)行打包,會(huì)發(fā)現(xiàn) webpack 的運(yùn)行時(shí)代碼都被入該包內(nèi)。

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    names: ['vendor', 'init']
  })
]

這樣以來(lái),修改了業(yè)務(wù)代碼后,vendor 因?yàn)橹灰昧?react 和 react-dom 因此,業(yè)務(wù)代碼的改變不會(huì)改變 vendor 這個(gè)包的內(nèi)容,hash 也保持不變。但,也僅僅如此 如果你引用了其他模塊,webpack 收集依賴的時(shí)候會(huì)給每個(gè)模塊編一個(gè)號(hào),引入其他模塊會(huì)導(dǎo)致模塊數(shù)改變,也就會(huì)導(dǎo)致編號(hào)改變,這個(gè)時(shí)候打包出來(lái)的 vendor 還是會(huì)改變。

以上是“webpack代碼拆分的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司行業(yè)資訊頻道!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站muchs.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

分享名稱:webpack代碼拆分的示例分析-創(chuàng)新互聯(lián)
文章路徑:http://muchs.cn/article2/ddosic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、定制開發(fā)、電子商務(wù)營(yíng)銷型網(wǎng)站建設(shè)、動(dòng)態(tài)網(wǎng)站、定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)