最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Webpack打包慢問題的完美解決方法

 更新時(shí)間:2017年03月16日 09:37:37   作者:王偉嘉  
這篇文章主要給大家介紹了關(guān)于Webpack打包慢問題的完美解決方法,文中通過示例代碼介紹的非常詳細(xì),相信對大家的學(xué)習(xí)或者工作能帶來一定的幫助,需要的朋友們下面來一起看看吧。

前言

這幾天寫騰訊實(shí)習(xí)生 Mini 項(xiàng)目的時(shí)候用上了 React 全家桶,當(dāng)然同時(shí)引入了 Webpack 作為打包工具。但是開發(fā)過程中遇到一個(gè)很棘手的問題就是,React 加上 React-Router、superagent、eventproxy 這些第三方輪子一共有好幾百個(gè) module,Webpack 的打包速度極慢。這對于開發(fā)是非常不好的體驗(yàn),同時(shí)效率也極低。

問題分析

我們先來看一下完全沒有任何優(yōu)化的時(shí)候,Webpack 的打包速度(使用了jsx和babel的loader)。

下面是我們的測試文件:

//test.js
var react = require('react');
var ReactAddonsCssTransitionGroup = require('react-addons-css-transition-group');
var reactDOM = require('react-dom');
var reactRouter = require('react-router');
var superagent = require("superagent");
var eventproxy = require("eventproxy");

運(yùn)行

webpack test.js

在我的2015款RMBP13,i5處理器,全SSD下,性能是這樣的:

沒錯(cuò)你沒有看錯(cuò),這幾個(gè)第三方輪子加起來有整整668個(gè)模塊,全部打包需要20多秒。

這意味著什么呢?你每次對業(yè)務(wù)代碼的修改,gulp 或者 Webpack 監(jiān)測到后都會(huì)重新打包,你要足足等20秒才能看到自己的修改結(jié)果。

但是需要重新打包的只有你的業(yè)務(wù)代碼,這些第三方庫是完全不用重新打包的,它們的存在只會(huì)拖累打包性能。所以我們要找一些方法來優(yōu)化這個(gè)過程。

配置externals

Webpack 可以配置 externals 來將依賴的庫指向全局變量,從而不再打包這個(gè)庫,比如對于這樣一個(gè)文件:

import React from 'react';
console.log(React);

如果你在 Webpack.config.js 中配置了externals:

module.exports = {
 externals: {
  'react': 'window.React'
 }
 //其它配置忽略...... 
};

等于讓 Webpack 知道,對于 react 這個(gè)模塊就不要打包啦,直接指向 window.React 就好。不過別忘了加載 react.min.js,讓全局中有 React 這個(gè)變量。

我們來看看性能,因?yàn)椴挥么虬?React 了所以速度自然超級(jí)快,包也很?。?/p>

配置externals的缺陷

問題如果就這么簡單地解決了的話,那我就沒必要寫這篇文章了,下面我們加一個(gè) react 的動(dòng)畫庫 react-addons-css-transition-group 來試一試:

import React from 'react';
import ReactAddonsCssTransitionGroup from 'react-addons-css-transition-group';
console.log(React);

對,你沒有看錯(cuò),我也沒有截錯(cuò)圖,新加了一個(gè)很小很小的動(dòng)畫庫之后,性能又爆炸了。從模塊數(shù)來看,一定是 Webpack 又把 react 重新打包了一遍。

我們來看一下為什么一個(gè)很小很小的動(dòng)畫庫會(huì)導(dǎo)致 Webpack 又傻傻地把 react 重新打包了一遍。找到 react-addons-css-transition-group 這個(gè)模塊,然后看看它是怎么寫的:

// react-addons-css-transition-group模塊
// 入口文件 index.js
module.exports = require('react/lib/ReactCSSTransitionGroup');

這個(gè)動(dòng)畫模塊就只有一行代碼,唯一的作用就是指向 react 下面的一個(gè)子模塊,我們再來看看這個(gè)子模塊是怎么寫的:

// react模塊
// react/lib/ReactCSSTransitionGroup.js
var React = require('./React');
var ReactTransitionGroup = require('./ReactTransitionGroup');
var ReactCSSTransitionGroupChild = require('./ReactCSSTransitionGroupChild');
//....剩余代碼忽略

這個(gè)子模塊又反回去依賴了 react 整個(gè)庫的入口,這就是拖累 Webpack 的罪魁禍?zhǔn)住?/p>

總而言之,問題是這樣產(chǎn)生的:

  1. Webpack 發(fā)現(xiàn)我們依賴了 react-addons-css-transition-group
  2. Webpack 去打包 react-addons-css-transition-group 的時(shí)候發(fā)現(xiàn)它依賴了 react 模塊下的一個(gè)叫 ReactTransitionGroup.js 的文件,于是 Webpack 去打包這個(gè)文件。
  3. ReactTransitionGroup.js 依賴了整個(gè) react 的入口文件 React.js,雖然我們設(shè)置了 externals ,但是 Webpack 不知道這個(gè)入口文件等效于 react 模塊本身,于是我們可愛又敬業(yè)的 Webpack 就把整個(gè) react 又重新打包了一遍。

讀到這里你可能會(huì)有疑問,為什么不能把這個(gè)動(dòng)畫庫也設(shè)置到 externals 里,這樣不是就不用打包了嗎?

問題就在于,這個(gè)動(dòng)畫庫并沒有提供生產(chǎn)環(huán)境的文件,或者說這個(gè)庫根本沒有提供 react-addons-css-transition-group.min.js 這個(gè)文件。

這個(gè)問題不只存在于 react-addons-css-transition-group 中,對于 react 的大多數(shù)現(xiàn)有庫來說都有這個(gè)依賴關(guān)系復(fù)雜的問題。

初級(jí)解決方法

所以對于這個(gè)問題的解決方法就是,手工打包這些 module,然后設(shè)置 externals ,讓 Webpack 不再打包它們。

我們需要這樣一個(gè) lib-bundle.js 文件:

window.__LIB["react"] = require("react");
window.__LIB["react-addons-css-transition-group"] = require("react-addons-css-transition-group");
// ...其它依賴包

我們在這里把一些第三方庫注冊到了 window.__LIB 下,這些庫可以作為底層的基礎(chǔ)庫,免于重復(fù)打包。

然后執(zhí)行 webpack lib-bundle.js lib.js,得到打包好的 lib.js。然后去設(shè)置我們的 externals :

var webpack = require('webpack');
module.exports = {
 externals: {
  'react': 'window.__LIB["react"]',
  'react-addons-css-transition-group': 'window.__LIB["react-addons-css-transition-group"]',
  // 其它庫
 }
 //其它配置忽略...... 
};

這時(shí)由于 externals 的存在,Webpack 打包的時(shí)候就會(huì)避開這些模塊超多,依賴關(guān)系復(fù)雜的庫,把這些第三方 module 的入口指向預(yù)先打包好的 lib.js 的入口 window.__LIB,從而只打包我們的業(yè)務(wù)代碼。

終極解決方法

上面我們提到的方法本質(zhì)上就是一種動(dòng)態(tài)鏈接庫(dll)”的思想,這在 windows 系統(tǒng)下面是一種很常見的思想。一個(gè)dll包,就是一個(gè)很純凈的依賴庫,它本身不能運(yùn)行,是用來給你的 app 或者業(yè)務(wù)代碼引用的。

同樣的 Webpack 最近也新加入了這個(gè)功能:webpack.DllPlugin。使用這個(gè)功能需要把打包過程分成兩步:

  1. 打包ddl包
  2. 引用ddl包,打包業(yè)務(wù)代碼

首先我們來打包ddl包,首先配置一個(gè)這樣的 ddl.config.js:

const webpack = require('webpack');

const vendors = [
 'react',
 'react-dom',
 'react-router',
 // ...其它庫
];

module.exports = {
 output: {
  path: 'build',
  filename: '[name].js',
  library: '[name]',
 },
 entry: {
  "lib": vendors,
 },
 plugins: [
  new webpack.DllPlugin({
   path: 'manifest.json',
   name: '[name]',
   context: __dirname,
  }),
 ],
};

webpack.DllPlugin 的選項(xiàng)中:

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

運(yùn)行Webpack,會(huì)輸出兩個(gè)文件一個(gè)是打包好的 lib.js,一個(gè)就是 manifest.json,它里面的內(nèi)容大概是這樣的:

{
 "name": "vendor_ac51ba426d4f259b8b18",
 "content": {
  "./node_modules/react/react.js": 1,
  "./node_modules/react/lib/React.js": 2,
  "./node_modules/react/node_modules/object-assign/index.js": 3,
  "./node_modules/react/lib/ReactChildren.js": 4,
  "./node_modules/react/lib/PooledClass.js": 5,
  "./node_modules/react/lib/reactProdInvariant.js": 6,
  // ............
 }
}

接下來我們就可以快樂地打包業(yè)務(wù)代碼啦,首先寫好打包配置文件 webpack.config.js:

const webpack = require('webpack');
module.exports = {
 output: {
  path: 'build',
  filename: '[name].js',
 },
 entry: {
  app: './src/index.js',
 },
 plugins: [
  new webpack.DllReferencePlugin({
   context: __dirname,
   manifest: require('./manifest.json'),
  }),
 ],
};

webpack.DllReferencePlugin 的選項(xiàng)中:

  1. context 需要跟之前保持一致,這個(gè)用來指導(dǎo) Webpack 匹配 manifest 中庫的路徑;
  2. manifest 用來引入剛才輸出的 manifest.json 文件。

DllPlugin 本質(zhì)上的做法和我們手動(dòng)分離這些第三方庫是一樣的,但是對于包極多的應(yīng)用來說,自動(dòng)化明顯加快了生產(chǎn)效率。

總結(jié)

以上就是關(guān)于徹底解決Webpack打包慢問題的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 微信小程序刪除處理詳解

    微信小程序刪除處理詳解

    這篇文章主要為大家詳細(xì)介紹了微信小程序刪除處理的相關(guān)代碼,用小程序里的模態(tài)框?qū)崿F(xiàn)刪除,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • webpack前端應(yīng)用之基礎(chǔ)打包實(shí)現(xiàn)

    webpack前端應(yīng)用之基礎(chǔ)打包實(shí)現(xiàn)

    本文主要介紹了webpack前端應(yīng)用之基礎(chǔ)打包實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • JavaScript獲取時(shí)間戳的方法總結(jié)

    JavaScript獲取時(shí)間戳的方法總結(jié)

    JavaScript獲得時(shí)間戳的方法有五種,后四種都是通過實(shí)例化時(shí)間對象new Date() 來進(jìn)一步獲取當(dāng)前的時(shí)間戳,下面我們就一起學(xué)習(xí)一下具體獲取的方法吧
    2023-09-09
  • Echarts.js實(shí)現(xiàn)水滴球和海洋效果

    Echarts.js實(shí)現(xiàn)水滴球和海洋效果

    這篇文章介紹了Echarts.js實(shí)現(xiàn)水滴球和海洋效果的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • js實(shí)現(xiàn)開啟密碼大寫提示

    js實(shí)現(xiàn)開啟密碼大寫提示

    本文主要分享了js實(shí)現(xiàn)開啟密碼大寫提示的實(shí)例,代碼簡單易懂。需要的朋友一起來看下吧
    2016-12-12
  • JS實(shí)現(xiàn)遮罩層效果的簡單實(shí)例

    JS實(shí)現(xiàn)遮罩層效果的簡單實(shí)例

    這篇文章介紹了JS實(shí)現(xiàn)遮罩層效果的簡單實(shí)例,有需要的朋友可以參考一下
    2013-11-11
  • 將字符串轉(zhuǎn)換成gb2312或者utf-8編碼的參數(shù)(js版)

    將字符串轉(zhuǎn)換成gb2312或者utf-8編碼的參數(shù)(js版)

    直接在url中傳遞中文參數(shù)時(shí),讀到的中文都是亂碼,那么我們應(yīng)該怎么將這些參數(shù)轉(zhuǎn)換呢,接下來與大家分享下將字符串轉(zhuǎn)換成utf-8或者gb2312編碼的參數(shù)的技巧
    2013-04-04
  • 通過location.replace禁止瀏覽器后退防止重復(fù)提交

    通過location.replace禁止瀏覽器后退防止重復(fù)提交

    如果用戶重復(fù)提交事件,然后又后退,這樣可能會(huì)對某些數(shù)據(jù)產(chǎn)生災(zāi)難性的問題。所以今天就向大家介紹一種通過location.replace禁止瀏覽器后退按鈕的方法
    2014-09-09
  • JsRender for index循環(huán)索引用法詳解

    JsRender for index循環(huán)索引用法詳解

    這篇文章主要介紹了JsRender for index循環(huán)索引用法,以實(shí)例形式詳細(xì)分析了JsRender中循環(huán)的用法,需要的朋友可以參考下
    2014-10-10
  • JavaScript如何借用構(gòu)造函數(shù)繼承

    JavaScript如何借用構(gòu)造函數(shù)繼承

    這篇文章主要介紹了JavaScript如何借用構(gòu)造函數(shù)繼承,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評(píng)論

古田县| 青田县| 修文县| 汝南县| 万山特区| 珠海市| 正宁县| 自治县| 施甸县| 城固县| 个旧市| 鹤峰县| 广安市| 新野县| 敦化市| 宜城市| 随州市| 赤峰市| 丹巴县| 新野县| 琼中| 陆河县| 广河县| 平顶山市| 中牟县| 望江县| 成安县| 冀州市| 新邵县| 曲麻莱县| 天峻县| 凤阳县| 称多县| 建湖县| 六盘水市| 政和县| 织金县| 双城市| 舞阳县| 天水市| 靖西县|