成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

webpack 填坑之路--提取獨(dú)立文件(模塊)

ZweiZhao / 1289人閱讀

摘要:前言最近重新看了一遍提取公共文件的配置。這篇文章將以解決實(shí)際開發(fā)遇到的問題為核心,悉數(shù)利用提取獨(dú)立文件模塊的應(yīng)用。利用插件是專門用來(lái)提取獨(dú)立文件的,它主要是提取多個(gè)入口的公共模塊。插入標(biāo)簽的這一步可以在打包好獨(dú)立文件之前,就在模板中插入。

前言

最近重新看了一遍 webpack 提取公共文件的配置。原來(lái)覺得這東西是個(gè)玄學(xué),都是 “憑感覺” 配置。這篇文章將以解決實(shí)際開發(fā)遇到的問題為核心,悉數(shù)利用 webpack 提取獨(dú)立文件(模塊)的應(yīng)用。

獨(dú)立文件在實(shí)際開發(fā)中一般有兩種:

第三方模塊 如 Vue React jQuery 等

項(xiàng)目開發(fā)編寫的獨(dú)立模塊(模塊),對(duì)于 MPA 多頁(yè)面開發(fā)來(lái)說是封裝出的一些方法庫(kù)比如 utils.getQueryString() 或者是每個(gè)頁(yè)面的共同操作;對(duì)于SPA 應(yīng)用來(lái)說沒有特別的需要分離出模塊,但是針對(duì)首屏渲染速度的提升,可以將 某些獨(dú)立模塊分離出來(lái)實(shí)現(xiàn)按需加載。

分離出獨(dú)立文件的目的:

獨(dú)立文件一般很少更改或者不會(huì)更改,webpack 沒必要每次打包進(jìn)一個(gè)文件中,獨(dú)立文件提取出可以長(zhǎng)期緩存。

提升 webpack 打包速度

提取第三方模塊

配置externals
Webpack 可以配置 externals 來(lái)將依賴的庫(kù)指向全局變量,從而不再打包這個(gè)庫(kù)。

// webpack.config.js 中
module.exports = {
  entry: {
    app: __direname +"/app/index.js"
  }
  externals: {
    jquery: "window.jQuery"
  }
  ...
}

// 模板 html 中
...

...

// 入口文件  index.js
import $ from "jquery"

其實(shí)就是 script 標(biāo)簽引入的jquery 掛載在window下 其他類型 externals 的配置可以去官網(wǎng)查看,這種方法不算是打包提取第三方模塊,只是一個(gè)變量引入,不是本文討論的重點(diǎn)。

利用CommonsChunkPlugin
CommonsChunkPlugin 插件是專門用來(lái)提取獨(dú)立文件的,它主要是提取多個(gè)入口 chunk 的公共模塊。他的配置介紹如下:

配置屬性 配置介紹
name 或者 names chunk 的名稱 如果是names數(shù)組 相當(dāng)于對(duì)每個(gè)name進(jìn)行插件實(shí)例化
filename 這個(gè)common chunk 的文件輸出名
minChunks 通常情況為一個(gè)整數(shù),至少有minChunks個(gè)chunk使用了該模塊,該模塊才會(huì)被移入[common chunk]里 minChunks 還可以是Infinity意思為沒有任何模塊被移入,只是創(chuàng)建當(dāng)前這個(gè) chunk,這通常用來(lái)生成 jquery 等第三方代碼庫(kù)。minChunks還可以是一個(gè)返回布爾值的函數(shù),返回 true 該模塊會(huì)被移入 common chunk,否則不會(huì)。默認(rèn)值是 chunks 的長(zhǎng)度。
chunks 元素為chunk名稱的數(shù)組,插件將從該數(shù)組中提取common chunk 可見 minChunks 應(yīng)該小予chunks的長(zhǎng)度,且大于1。如果沒有 所有的入口chunks 會(huì)被選中
children 默認(rèn)為false 如果為true 相當(dāng)于為上一項(xiàng)chunks配置為chunk的子chunk 用于代碼分割code split
async 默認(rèn)為false 如果為true 生成的common chunk 為異步加載,這個(gè)異步的 common chunk 是 name 這個(gè) chunk 的子 chunk,而且跟 chunks 一起并行加載
minSize 如果有指定大小,那么 common chunk 的文件大小至少有 minSize 才會(huì)被創(chuàng)建。非必填項(xiàng)。

創(chuàng)建一個(gè)如下圖的目錄

package.json 如下

{
  "name": "webpacktest",
  "version": "1.0.0",
  "description": "",
  "directories": {
    "doc": "doc"
  },
  "scripts": {
    "start": "webpack"
  },
  "author": "abzerolee",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^2.30.1",
    "webpack": "^3.8.1"
  },
  "dependencies": {
    "underscore": "^1.8.3",
  }
}

a.js 引入了 underscore 需要進(jìn)行了數(shù)組去重操作,現(xiàn)在需要將underscore分離為獨(dú)立文件。

// webpack.config.js
entry: {
  a: __dirname +"/app/a.js",
  vendor: ["underscore"]
},
output: {
  path: __dirname +"/dist",
  filename: "[name].[chunkhash:6].js",       
  chunkFilename: "[name].[id].[chunkhash:6].js"
},
plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: "vendor",
  }),
  new HtmlWebpackPlugin({
    template: __dirname +"/app/index.html"
  })
]
// a.js
let _ = require("underscore");

let arr = _.filter([1,2,3,2,3,3,5,5], (v, i, self) => self.indexOf(v) === i);
console.log("unique:" +arr);

這樣underscore就分離進(jìn)了 vendor 塊,注意的是需要在入口定義 要輸出的 [ 獨(dú)立文件名 ]: [ 需要分離的模塊數(shù)組 ], 然后在CommonsChunkPlugin中配置 name : [獨(dú)立文件名]。

當(dāng)然也可以不用在入口定義,如vue-cli 就是在 在CommonsChunk中配置了minChunks。我們的第三方模塊都是通過npm 安裝在node_modules 目錄下,我們可以通過minChunks 判斷模塊路徑是否含有node_module 來(lái)返回true 或 false,前文有介紹minChunks的含義。配置如下:

entry: {
    a: __dirname +"/app/a.js", // **注意** 入口沒定義vendor 
  },
  output: {
    path: __dirname +"/dist",
    filename: "[name].[chunkhash:6].js",
    chunkFilename: "[name].[id].[chunkhash:6].js"
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      minChunks: function(module) {
        let flag =  module.context && module.context.indexOf("node_modules") !== -1;
        console.log(module.context, flag);
        return flag;
      }
    }),
    new HtmlWebpackPlugin({
      template: __dirname +"/app/index.html"
    })
  ]

上述兩種方式,對(duì)于多頁(yè)面還是單頁(yè)面都是可應(yīng)用的。但是現(xiàn)在的問題是每次入口文件 a.js 修改之后都會(huì)造成 vendor重新打包。那么如何解決這個(gè)問題呢。

manifest 處理第三方模塊應(yīng)用

我們將 a.js 做一個(gè)簡(jiǎn)單修改:

// 原來(lái)
-  console.log("unique:" +arr);
// 修改后
+   console.log(arr);

重新打包發(fā)現(xiàn)vendor的hash變化了相當(dāng)于重新打包了underscore,解決的方法是利用一個(gè) manifest 來(lái)記錄 vendor 的 id ,如果vendor沒改變,則不需要重新打包。這就有兩種解決方式 :

1. 利用manifest.js

利用CommonsChunkPlugin的chunks特性,提取出 webpack定義的異步加載代碼,配置如下:

entry: {
  a: __dirname +"/app/a.js",
},
output: {
  path: __dirname +"/dist",
  filename: "[name].[chunkhash:6].js",
  chunkFilename: "[name].[id].[chunkhash:6].js"
},
plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: "vendor",
    minChunks: function(module) {
      let flag =  module.context && module.context.indexOf("node_modules") !== -1;
      console.log(module.context, flag);
      return flag;
    }
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: "manifest",
    chunks: ["vendor"],
  }),
  new HtmlWebpackPlugin({
    template: __dirname +"/app/index.html"
  })
]

還是修改了 a.js 之后發(fā)現(xiàn) vendor的 hash 值沒有變化,如下圖:

這里要注意的是chunks: [ 獨(dú)立文件名 ]。但是,又有但是,要是這么就配置沒問題了,就不能叫做玄學(xué)了,修改 a.js 的內(nèi)部代碼沒問題,如果修改了 require 的模塊引入,vendor的hash又有變化了,當(dāng)然我們可以盡量避免修改文件的依賴引入,但是終歸不是最完美的方式。那么終極解決方法是什么呢?DllReferencePlugin,DllPlugin。

2. 利用DllReferencePlugin,DllPlugin

既然動(dòng)態(tài)打包的時(shí)候建立 manifest 不行,那么能不能直接把他打包成一個(gè)純凈的依賴庫(kù),本身無(wú)法運(yùn)行,只是讓我們的app 來(lái)引入。

那么我們需要完成兩步,先webpack.DllPlugin打包dll(純凈的第三方獨(dú)立文件),然后用DllReferencePlugin 在我們的應(yīng)用中引用,這樣的好處是如果下一個(gè)項(xiàng)目還是使用一樣的依賴比如react react-dom react-router,可以直接引入這個(gè)dll。

配置文件如下:

  entry: {
    vendor: ["underscore"]
  },
  output: {
    path: __dirname +"/dist",
    filename: "[name].js",
    library: "[name]",
  },
  plugins: [
    new webpack.DllPlugin({
      path: __dirname +"/dist/manifest.json",
      name: "[name]",
      context: __dirname,
    }),
  ],

根據(jù)上述配置打包結(jié)果如上圖,dist目錄下現(xiàn)在有一個(gè)vender.js 和 manifest.json 注意這里輸出的路徑配置。DllPlugin配置介紹如下:

配置項(xiàng) 介紹
path path 是 manifest.json 文件的輸出路徑,這個(gè)文件會(huì)用于后續(xù)的業(yè)務(wù)代碼打包;
name name 是 dll 暴露的對(duì)象名,要跟 output.library 保持一致;
context context 是解析包路徑的上下文,這個(gè)要跟接下來(lái)配置的 webpack.config.js 一致。

之后在我們的應(yīng)用中引入中,配置如下:

  entry: {
    a: __dirname +"/app/a.js",
  },
  output: {
    path: __dirname +"/dist",
    filename: "[name].[chunkhash:6].js",
    chunkFilename: "[name].[id].[chunkhash:6].js"
  },
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require("./dist/manifest.json"),
    }),
    new HtmlWebpackPlugin({
      template: __dirname +"/app/index.html"
    })
  ]

根據(jù)上述配置打包得到a.3e6285.js index.html 如上圖,瀏覽器中打開index.html會(huì)顯示
Uncaught ReferenceError: vendor is not defined

這里需要在 index.html 中 a.3e6285.js 插入 script 標(biāo)簽


再打開index.html 可以控制臺(tái)打印出了數(shù)組去重的結(jié)果。插入標(biāo)簽的這一步可以在打包好獨(dú)立文件之前,就在模板html 中插入。

到了這里,提取第三方模塊的方法,避免重復(fù)打包的方法都介紹完畢了。接下來(lái)是配置提取自己編寫的公共模塊方法。

提取項(xiàng)目公共模塊

單頁(yè)面應(yīng)用的公共模塊沒有必要提取出多帶帶的文件,因?yàn)椴槐乜紤]復(fù)用的情況。但是對(duì)于打包生成的文件過大,我們又想分離出幾個(gè)模塊有需要的時(shí)候才加載,其實(shí)這并不是提取公共模塊,而是代碼分割,通過:

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

在callback中定義的 require的模塊將會(huì)獨(dú)立打包,并且插入在 html 的head標(biāo)簽,這里就不做更多介紹了。

多頁(yè)面應(yīng)用是有必要抽取公共模塊的,比如a.js 引用了lib1, b.js 也引用了 lib1 那么lib1,那么我們肯定希望在提取出 lib1 同時(shí)還可以提取出第三方庫(kù),配置文件如下:

// a.js 
let _ = require("underscore");
let lib1 = require("./lib1");
console.log("this is entry_a import lib1");

let arr = _.filter([1,2,3,2,3,3,5,5], (v, i, self) => self.indexOf(v) === i);
console.log(arr);

// b.js
require("./lib1");
var b = "b";

console.log("this is entry_b import lib1");

// webpack.config.js
  entry: {
    a: __dirname +"/app/a.js",
    b: __dirname +"/app/b.js",
    vendor: ["underscore"],
  },
  output: {
    path: __dirname +"/dist",
    filename: "[name].[chunkhash:6].js",
    chunkFilename: "[name].[id].[chunkhash:6].js"
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: ["chunk", "vendor"],
      minChunks: 2,
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: "manifest",
      chunks: ["vendor"]
    }),
    new HtmlWebpackPlugin({
      template: __dirname +"/app/index.html",
      filename: __dirname +"/dist/a.html",
      chunks: ["a", "chunk", "vendor", "manifest"],
    }),
    new HtmlWebpackPlugin({
      template: __dirname +"/app/index.html",
      filename: __dirname +"/dist/b.html",
      chunks: ["b", "chunk", "vendor", "manifest"],
    }),
  ]
}

通過打包后發(fā)現(xiàn)生成了如下文件:

可以明確看出生成了chunk.d09623.js 而且 其中就是我們的lib1.js 的庫(kù)的代碼。這里要注意的是Commons.ChunkPlugin的配置 當(dāng)name 給定數(shù)組之后從入口文件中選取 共同引用超過 minChunks 次數(shù)的模塊打包進(jìn)name 數(shù)組的第一個(gè)模塊,然后name 數(shù)組后面的塊 "vendor" 依次打包(查找entry里的key,沒有找到相關(guān)的key就生成一個(gè)空的塊),最后一個(gè)塊包含webpack生成的在瀏覽器上使用各個(gè)塊的加載代碼,所以插入到頁(yè)面中最后一個(gè)塊要最先加載,加載順序由name數(shù)組自右向左。

這里我們使用manifest 去提取了 webpackJsonp 的加載代碼,為了防止重復(fù)打包庫(kù)文件,這在前文已經(jīng)提到過。所以vendor中的加載代碼在mainfest.js 中,修改a.js 的console.log, 重新打包后的文件可以發(fā)現(xiàn)chunk.d0962e.js, vendor.98054b.js都沒有重新打包

所以總結(jié)來(lái)講就是多入口配置CommonsChunk

    new webpack.optimize.CommonsChunkPlugin({
      name: ["生成的項(xiàng)目公共模塊文件名", "第三方模塊文件名"],
      minChunks: 2,
    }),

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89601.html

相關(guān)文章

  • webpack4配置之分享幾個(gè)常用插件

    摘要:去做想做的事,去愛值得的人去成為自己喜歡的模樣,去讓自己發(fā)光渾身充滿力量,充實(shí)的日子最美好各位早安,這里是平頭哥聯(lián)盟,我是首席填坑官蘇南,用心分享一起成長(zhǎng)做有溫度的攻城獅。 showImg(https://segmentfault.com/img/bVbjIcs?w=1008&h=298); 前言   繼上一次webpack的基礎(chǔ)配置分享之后,本次將分享一些工作中項(xiàng)目常用的配置插件、也...

    Jackwoo 評(píng)論0 收藏0
  • React 歷史項(xiàng)目維護(hù)與優(yōu)化實(shí)踐

    摘要:本文介紹了作者接手維護(hù)一個(gè)中型歷史項(xiàng)目時(shí)的一系列改進(jìn)實(shí)踐,包括模塊結(jié)構(gòu)拆分業(yè)務(wù)邏輯梳理打包優(yōu)化等。代碼中如菜單名稱結(jié)構(gòu)表單字段名等的各種硬編碼配置分散在各處。最后,在提升面向開發(fā)者的打包體驗(yàn)方面,本次優(yōu)化中主要實(shí)現(xiàn)的是與的解耦。 本文介紹了作者接手維護(hù)一個(gè)中型 React 歷史項(xiàng)目時(shí)的一系列改進(jìn)實(shí)踐,包括模塊結(jié)構(gòu)拆分、業(yè)務(wù)邏輯梳理、Webpack 打包優(yōu)化等。 背景 這是一個(gè) PC 的...

    toddmark 評(píng)論0 收藏0
  • webpack4配置詳解之逐行分析

    摘要:今天就嘗試著一起來(lái)聊聊吧,旨在幫大家加深理解新手更容易上路,都能從到搭建配置自定屬于自己的腳手架,或?qū)σ逊庋b好的腳手架有進(jìn)一步的鞏固,接下來(lái)蘇南會(huì)詳細(xì)講解中的每一個(gè)配置字段的作用部分為新增。 showImg(https://segmentfault.com/img/bVbjmMV?w=1008&h=298); 前言   經(jīng)常會(huì)有群友問起webpack、react、redux、甚至cre...

    dkzwm 評(píng)論0 收藏0
  • Reactjs、redux的從入門到放棄、刪庫(kù)跑路示例

    摘要:我的入門到放棄之路最近看到很多相關(guān)的問題跟討論,越來(lái)越多的小伙伴喜歡這個(gè)框架了,同時(shí)也在看到了有些入門的小伙伴遇到了各種各樣的問題,本人也是框架使用都一枚,公司是騰訊阿里平安三巨頭合資的一家公司,分別上海深圳杭州北京廣州等多個(gè)分部,前端人員 showImg(https://segmentfault.com/img/bVbhonB?w=1278&h=722); 我的react入門到放棄之...

    Miracle 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<