国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

開發(fā)工具心得:如何 10 倍提高你的 Webpack 構(gòu)建效率

用戶83 / 915人閱讀

摘要:在項目架構(gòu)中這兩個東西基本成為了標配,但的模塊必須在使用前經(jīng)過的構(gòu)建后文稱為才能在瀏覽器端使用,而每次修改也都需要重新構(gòu)建后文稱為才能生效,如何提高的構(gòu)建效率成為了提高開發(fā)效率的關(guān)鍵之一。

0. 前言

圖1:ES6 + Webpack + React + Babel

webpack 是個好東西,和 NPM 搭配起來使用管理模塊實在非常方便。而 Babel 更是神一般的存在,讓我們在這個瀏覽器尚未全面普及 ES6 語法的時代可以先一步體驗到新的語法帶來的便利和效率上的提升。在 React 項目架構(gòu)中這兩個東西基本成為了標配,但 commonjs 的模塊必須在使用前經(jīng)過 webpack 的構(gòu)建(后文稱為 build)才能在瀏覽器端使用,而每次修改也都需要重新構(gòu)建(后文稱為 rebuild)才能生效,如何提高 webpack 的構(gòu)建效率成為了提高開發(fā)效率的關(guān)鍵之一。

1. Webpack 的構(gòu)建流程

在開始正式的優(yōu)化之前,讓我們先回顧一下 Webpack 的構(gòu)建流程,有哪些關(guān)鍵步驟,只有了解了這些,我們才能分析出哪些地方有優(yōu)化的可能性。

圖2:webpack is a module bundler.

首先,我們來看看官方對于 Webpack 的理念闡釋,webapck 把所有的靜態(tài)資源都看做是一個 module,通過 webpack,將這些 module 組成到一個 bundle 中去,從而實現(xiàn)在頁面上引入一個 bundle.js,來實現(xiàn)所有靜態(tài)資源的加載。所以詳細一點看,webpack 應(yīng)該是這樣的:

圖3:Every static asset should be able to be a module --webpack

通過 loader,webpack 可以把各種非原生 js 的靜態(tài)資源轉(zhuǎn)換成 JavaScript,所以理論上任何一種靜態(tài)資源都可以成為一個 module。
當然 webpack 還有很多其他好玩的特性,但不是本文的重點因此不鋪開進行說明了。了解了上述的過程,我們就可以根據(jù)這些過程的前后處理進行對應(yīng)的優(yōu)化,接下來我們會針對 build 和 rebuild 的過程給與相應(yīng)的意見。

2. RESOLVE

我們先從解析模塊路徑和分析依賴講起,有人可能覺得這無所謂,但當項目應(yīng)用依賴的模塊越來越多,越來越重時,項目越來越大,文件和文件夾越來越多時,這個過程就變得越來越關(guān)乎性能。

2.1 減小 Webpack 覆蓋的范圍

build +, rebuild +

webpack 默認會去尋找所有 resolve.root 下的模塊,但是有些目錄我們是可以明確告知 webpack 不要管這里,從而減輕 webpack 的工作量。這時會用到 module.noParse 參數(shù)。

2.2 Resolove.root VS Resolove.moduledirectories

build +, rebuild +

rootmoduledirectories 如果只從用法上來看,似乎是可以互相替代的。但因為 moduledirectories 從設(shè)計上是取相對路徑,所以比起 root ,所以會多 parse 很多路徑。

resolve: {
    root: path.resolve("src/node_modules"),
    extensions: ["", ".js", ".jsx"]
},
resolve: {
    modulesDirectories: ["node_modules", "./src"],
    extensions: ["", ".js", ".jsx"]
},

上面的配置,只會解析

./src/node_modules/a

==== 此處有修改 2016/09/10 感謝 @lili_21 ====

而下面的配置會解析

/some/folder/structure/node_modules/a
/some/folder/structure/src/a
/some/folder/node_modules/a
/some/folder/src/a
/some/node_modules/a
/some/src/a
/node_modules/a
/src/a 

大部分的情況下使用 root 即可,只有在有很復雜的路徑下,才考慮使用 moduledirectories,這可以明顯提高 webpack 的構(gòu)建性能。這個 issue 也很詳細地討論了這個問題。

3. LOADERS

webpack 官方和社區(qū)為我們提供了各種各樣 loader 來處理各種類型的文件,這些 loader 的配置也直接影響了構(gòu)建的性能。

3.1 Babel-loader: 能者少勞

build ++, rebuild ++

以 babel-loader 為例,我們在開發(fā) React 項目時很可能會使用到了 ES6 或者 jsx 的語法,因此使用到 babel-loader 的情況很多,最簡單的情況下我們可以這樣配置,讓所有的 js/jsx 通過 babel-loader:

module: {
    loaders: [
      {
          test: /.js(x)*$/,
          loader: "babel-loader",
          query: {
              presets: ["react", "es2015-ie", "stage-1"]
          }
      }
    ]
}

上面這樣的做法當然是 ok 的,但是對于很多的 npm 包來說,他們完全沒有經(jīng)過 babel 的必要(成熟的 npm 包會在發(fā)布前將自己 es5,甚至 es3 化),讓這些包通過 babel 會帶來巨大的性能負擔,畢竟 babel6 要經(jīng)過幾十個插件的處理,雖然 babel-loader 強大,但能者多勞的這種保守的想法卻使得 babel-loader 成為了整個構(gòu)建的性能瓶頸。所以我們可以使用 exclude,大膽地屏蔽掉 npm 里的包,從而使整包的構(gòu)建效率飛速提高。

module: {
    loaders: [
      {
          test: /.js(x)*$/,
          loader: "babel-loader",
          exclude: function(path) {
              // 路徑中含有 node_modules 的就不去解析。
              var isNpmModule = !!path.match(/node_modules/);
              return isNpmModule;
          },
          query: {
              presets: ["react", "es2015-ie", "stage-1"]
          }
      }
    ]
}

甚至,在我們十分確信的情況下,使用 include 來限定 babel 的使用范圍,進一步提高效率。

var path = require("path");
module.exports = {
    module: {
        loaders: [
          {
              test: /.js(x)*$/,
              loader: "babel-loader",
              include: [
                // 只去解析運行目錄下的 src 和 demo 文件夾
                path.join(process.cwd(), "./src"),
                path.join(process.cwd(), "./demo")
              ],
              query: {
                  presets: ["react", "es2015-ie", "stage-1"]
              }
          }
        ]
    }
}
4. PLUGINS

webpack 官方和社區(qū)為我們提供了很多方便的插件,有些插件為我們開發(fā)和生產(chǎn)帶來了很多的便利,但是不合適地使用插件也會拖慢 webpack 的構(gòu)建效率,而有些插件雖然不會為我們的開發(fā)上直接提供便利,但使用他們卻可以幫助我們提高 webpack 的構(gòu)建效率,這也是本文會提到的。

4.1 SourceMaps

build +

SourceMaps 是一個非常實用的功能,可以讓我們在 chrome debug 時可以不用直接看已經(jīng) bundle 過的 js,而是直接在源代碼上進行查看和調(diào)試,但完美的 SourceMaps 是很慢的,webpack 官方提供了七種 sourceMap 模式共大家選擇,性能對比如下:

devtool build speed rebuild speed production supported quality
eval +++ +++ no generated code
cheap-eval-source-map + ++ no transformed code (lines only)
cheap-source-map + o yes transformed code (lines only)
cheap-module-eval-source-map o ++ no original source (lines only)
cheap-module-source-map o - yes original source (lines only)
eval-source-map -- + no original source
source-map -- -- yes original source

具體各自的區(qū)別請參考 https://github.com/webpack/do... ,我們這里推薦使用 cheap-source-map,也就是去掉了column mapping 和 loader-sourceMap(例如 jsx to js) 的 sourceMap,雖然帶上 eval 參數(shù)的可以快更多,但是這種 sourceMap 只能看,不能調(diào)試,得不償失。

4.2 OPTIMIZATION

build ++,rebuild ++

webpack 提供了一些可以優(yōu)化瀏覽器端性能的優(yōu)化插件,如UglifyJsPlugin,OccurrenceOrderPlugin 和 DedupePlugin,都很實用,也都在消耗構(gòu)建性能(UglifyJsPlugin 非常耗性能),如果你是在開發(fā)環(huán)境下,這些插件最好都不要使用,畢竟腳本大一些,跑的慢一些這些比起每次構(gòu)建要耗費更多時間來說,顯然還是后者更會消磨開發(fā)者的耐心,因此,只在正產(chǎn)環(huán)境中使用 OPTIMIZATION。

4.3 CommonsChunk

rebuild +

當你的 webpack 構(gòu)建任務(wù)中有多個入口文件,而這些文件都 require 了相同的模塊,如果你不做任何事情,webpack 會為每個入口文件引入一份相同的模塊,顯然這樣做,會使得相同模塊變化時,所有引入的 entry 都需要一次 rebuild,造成了性能的浪費,CommonsChunkPlugin 可以將相同的模塊提取出來多帶帶打包,進而減小 rebuild 時的性能消耗。這里有一篇很通俗易懂的使用方法:http://webpack.toobug.net/zh-... ,感興趣的朋友不妨一試。

4.4 DLL & DllReference

build +++, rebuild +++

除了正在開發(fā)的源代碼之外,通常還會引入很多第三方 NPM 包,這些包我們不會進行修改,但是仍然需要在每次 build 的過程中消耗構(gòu)建性能,那有沒有什么辦法可以減少這些消耗呢?DLLPlugin 就是一個解決方案,他通過前置這些依賴包的構(gòu)建,來提高真正的 build 和 rebuild 的構(gòu)建效率。
鑒于現(xiàn)有的資料對于這兩個插件的解釋都不是很清楚,筆者這里翻譯了一篇日本同學的文章,通過一個簡單的例子來說明一下這兩個插件的用法。我們舉例,把 react 和 react-dom 打包成為 dll bundle。
首先,我們來寫一個 DLLPlugin 的 config 文件。

webpack.dll.config.js

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: {
    vendor: ["react", "react-dom"]
  },
  output: {
    path: path.join(__dirname, "dist"),
    filename: "[name].dll.js",
    /**
     * output.library
     * 將會定義為 window.${output.library}
     * 在這次的例子中,將會定義為`window.vendor_library`
     */
    library: "[name]_library"
  },
  plugins: [
    new webpack.DllPlugin({
      /**
       * path
       * 定義 manifest 文件生成的位置
       * [name]的部分由entry的名字替換
       */
      path: path.join(__dirname, "dist", "[name]-manifest.json"),
      /**
       * name
       * dll bundle 輸出到那個全局變量上
       * 和 output.library 一樣即可。 
       */
      name: "[name]_library"
    })
  ]
};

執(zhí)行 webpack 后,就會在 dist 目錄下生成 dll bundle 和對應(yīng)的 manifest 文件

$ ./node_modules/.bin/webpack --config webpack.dll.config.js
Hash: 36187493b1d9a06b228d
Version: webpack 1.13.1
Time: 860ms
        Asset    Size  Chunks             Chunk Names
vendor.dll.js  699 kB       0  [emitted]  vendor
   [0] dll vendor 12 bytes {0} [built]
    + 167 hidden modules

$ ls dist
./                    vendor-manifest.json
../                   vendor.dll.js

manifest 文件的格式大致如下,由包含的 module 和對應(yīng)的 id 的鍵值對構(gòu)成。

cat dist/vendor-manifest.json
{
  "name": "vendor_library",
  "content": {
    "./node_modules/react/react.js": 1,
    "./node_modules/react/lib/React.js": 2,
    "./node_modules/process/browser.js": 3,
    "./node_modules/object-assign/index.js": 4,
    "./node_modules/react/lib/ReactChildren.js": 5,
    "./node_modules/react/lib/PooledClass.js": 6,
    "./node_modules/fbjs/lib/invariant.js": 7,
...

好,接下來我們通過 DLLReferencePlugin 來使用剛才生成的 DLL Bundle。

首先我們寫一個只去 require react,并通過 console.log 吐出的 index.js

var React = require("react");
var ReactDOM = require("react-dom");
console.log("dll"s React:", React);
console.log("dll"s ReactDOM:", ReactDOM);

再寫一個不參考 Dll Bundle 的普通 webpack config 文件。

webpack.conf.js

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: {
    "dll-user": ["./index.js"]
  },
  output: {
    path: path.join(__dirname, "dist"),
    filename: "[name].bundle.js"
  }
};

執(zhí)行 webpack,會在 dist 下生成 dll-user.bundle.js,約 700K,耗時 801ms。

$ ./node_modules/.bin/webpack
Hash: d8cab39e58c13b9713a6
Version: webpack 1.13.1
Time: 801ms
             Asset    Size  Chunks             Chunk Names
dll-user.bundle.js  700 kB       0  [emitted]  dll-user
   [0] multi dll-user 28 bytes {0} [built]
   [1] ./index.js 145 bytes {0} [built]
    + 167 hidden modules

接下來,我們加入 DLLReferencePlugin

webpack.conf.js

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: {
    "dll-user": ["./index.js"]
  },
  output: {
    path: path.join(__dirname, "dist"),
    filename: "[name].bundle.js"
  },
  // ----在這里追加----
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      /**
       * 在這里引入 manifest 文件
       */
      manifest: require("./dist/vendor-manifest.json")
    })
  ]
  // ----在這里追加----
};
./node_modules/.bin/webpack
Hash: 3bc7bf760779b4ca8523
Version: webpack 1.13.1
Time: 70ms
             Asset     Size  Chunks             Chunk Names
dll-user.bundle.js  2.01 kB       0  [emitted]  dll-user
   [0] multi dll-user 28 bytes {0} [built]
   [1] ./index.js 145 bytes {0} [built]
    + 3 hidden modules

結(jié)果是非常驚人的,只有2.01K,耗時 70 ms,無疑大大提高了 build 和 rebuild 的效率。實際放到頁面上看下是否可行。


  
  

因為 Dll bundle 在依賴安裝完畢后就可以進行了,我們可以在第一次執(zhí)行 dev server 前執(zhí)行一次 dll bundle 的 webapck 任務(wù)。

4.4.1 和 external 的比較

有人會說,這個和 用 webpackexternals 配置把 require 的 module 指向全局變量有點像啊。

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: {
    "ex": ["./index.js"]
  },
  output: {
    path: path.join(__dirname, "dist"),
    filename: "[name].bundle.js"
  },
  externals: {
    // require("react")はwindow.Reactを使う
    "react": "React",
    // require("react-dom")はwindow.ReactDOMを使う
    "react-dom": "ReactDOM"
  }
};

  
  
  

這里有兩個主要的區(qū)別:

像是 react 這種已經(jīng)打好了生產(chǎn)包的使用 externals 很方便,但是也有很多 npm 包是沒有提供的,這種情況下 DLLBundle 仍可以使用。

如果只是引入 npm 包一部分的功能,比如 require("react/lib/React") 或者 require("lodash/fp/extend") ,這種情況下 DLLBundle 仍可以使用。

當然如果只是引用了 react 這類的話,externals 因為配置簡單所以也推薦使用。

4.5 HappyPack

build +, rebuild +

webpack 的長時間構(gòu)建搞的大家都很 unhappy。于是 @amireh 想到了一個點子,既然 loader 默認都是一個進程在跑,那是否可以讓 loader 多進程去處理文件呢?

happyPack 的文檔寫的很易懂,這里就不再贅述,happyPack 不僅利用了多進程,同時還利用緩存來使得 rebuild 更快。下面是插件作者給出的性能數(shù)據(jù):

For the main repository I tested on, which had around 3067 modules, the build time went down from 39 seconds to a whopping ~10 seconds when there was yet no

Successive builds now take between 6 and 7 seconds.

Here"s a rundown of the various states the build was performed in:

Elapsed (ms) Happy? Cache enabled? Cache present? Using DLLs?
39851 NO N/A N/A NO
37393 NO N/A N/A YES
14605 YES NO N/A NO
13925 YES YES NO NO
11877 YES YES YES NO
9228 YES NO N/A YES
9597 YES YES NO YES
6975 YES YES YES YES

The builds above were run on Linux over a machine with 12 cores.

5. 其他

上面我們針對 webpack 的 resolve、loader 和 plugin 的過程給出了相應(yīng)的優(yōu)化意見,除了這些哪些優(yōu)化點呢?其實有些優(yōu)化貫穿在這個流程中,比如緩存和文件 IO。

5.1 Cache

無論在何種性能優(yōu)化中,緩存總是必不可少的一部分,畢竟每次變動都只影響很小的一部分,如果能夠緩存住那些沒有變動的部分,直接拿來使用,自然會事半功倍,在 webpack 的整個構(gòu)建過程中,有多個地方提供了緩存的機會,如果我們打開了這些緩存,會大大加速我們的構(gòu)建,尤其是 rebuild 的效率。

5.1.1 webpack.cache

rebuild +

webpack 自身就有 cache 的配置,并且在 watch 模式下自動開啟,雖然效果不是最明顯的,但卻對所有的 module 都有效。

5.1.2 babel-loader.cacheDirectory

rebuild ++

babel-loader 可以利用系統(tǒng)的臨時文件夾緩存經(jīng)過 babel 處理好的模塊,對于 rebuild js 有著非常大的性能提升。

5.1.3 HappyPack.cache

build +, rebuild +

上面提到的 happyPack 插件也同樣提供了 cache 功能,默認是以 .happypack/cache--[id].json 的路徑進行緩存。因為是緩存在當前目錄下,所以他也可以輔助下次 build 時的效率。

5.2 FileSystem

默認的情況下,構(gòu)建好的目錄一定要輸出到某個目錄下面才能使用,但 webpack 提供了一種很棒的讀寫機制,使得我們可以直接在內(nèi)存中進行讀寫,從而極大地提高 IO 的效率,開啟的方法也很簡單。

var MemoryFS = require("memory-fs");
var webpack = require("webpack");

var fs = new MemoryFS();
var compiler = webpack({ ... });
compiler.outputFileSystem = fs;
compiler.run(function(err, stats) {
  // ...
  var fileContent = fs.readFileSync("...");
});

當然,我們還可以通過 webpackDevMiddleware 更加無縫地就接入到 dev server 中,例如我們以 express 作為靜態(tài) server 的例子。

var compiler = webpack(webpackCfg);

var webpackDevMiddlewareInstance = webpackDevMiddleware(compiler, {
   // webpackDevMiddleware 默認使用了 memory-fs
   publicPath: "/dist",
   aggregateTimeout: 300, // wait so long for more changes
   poll: true, // use polling instead of native watchers
   stats: {
       chunks: false
   }
});

var app = express();
app.use(webpackDevMiddlewareInstance);
app.listen(xxxx, function(err) {
   console.log(colors.info("dev server start: listening at " + xxxx));
   if (err) {
     console.error(err);
   }
}
6. 總結(jié)

上面我們從 webpack 構(gòu)建的各個部分,給出了相應(yīng)的優(yōu)化策略,如果你的項目中能夠?qū)⑵渫耆瀼仄饋恚?0 倍提速不是夢想。這些優(yōu)化也同樣應(yīng)用到了我們團隊的 react 項目中,https://github.com/uxcore/uxcore ,歡迎一起來討論 webpack 的效率優(yōu)化方案。

7. 參考文章

webpack build performance:http://webpack.github.io/docs...

webpackのDLLバンドルを使ってビルドを速くする:http://qiita.com/pirosikick/i...

How to make your Webpack builds 10x faster:http://www.slideshare.net/tru...

本文作者 eternalsky,始發(fā)于團隊微信公眾號 猿猿相抱 和個人博客 空の屋敷,轉(zhuǎn)載請保留作者信息。

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/79738.html

相關(guān)文章

  • webpack 教程資源收集

    學習的過程中收藏了這些優(yōu)秀教程和的項目,希望對你有幫助。 github地址, 有不錯的就更新 官方文檔 中文指南 初級教程 webpack-howto 作者:Pete Hunt Webpack 入門指迷 作者:題葉   webpack-demos 作者:ruanyf 一小時包教會 —— webpack 入門指南 作者:VaJoy Larn   webpack 入門及實踐 作者:...

    Backache 評論0 收藏0
  • 7 天 600 stars, Mobi.css 是如何誕生的

    摘要:發(fā)布一周以來,獲得了,登上了,在上進入了前三。為什么要創(chuàng)造當我在設(shè)計一個新的移動端用戶的網(wǎng)站比如面向微信用戶的網(wǎng)站的時候,調(diào)研了一些現(xiàn)有的框架,應(yīng)用比較廣泛的有等。否則只能有中國人來關(guān)注你的項目了。要知道,外國開發(fā)者比中國開發(fā)者多很多倍的。 受邀寫一篇 Mobi.css 的誕生歷程,請原諒我吸引眼球的標題,我會努力把這篇文章寫得有一些干貨的。 GitHub Repo | Homepag...

    CoderStudy 評論0 收藏0
  • webpack打包分析與性能優(yōu)化

    摘要:打包分析與性能優(yōu)化背景在去年年末參與的一個項目中,項目技術(shù)棧使用,生產(chǎn)環(huán)境全量構(gòu)建將近三分鐘,項目業(yè)務(wù)模塊多達數(shù)百個,項目依賴數(shù)千個,并且該項目協(xié)同前后端開發(fā)人員較多,提高構(gòu)建效率,成為了改善團隊開發(fā)效率的關(guān)鍵之一。 webpack打包分析與性能優(yōu)化 背景 在去年年末參與的一個項目中,項目技術(shù)棧使用react+es6+ant-design+webpack+babel,生產(chǎn)環(huán)境全量構(gòu)建將...

    joy968 評論0 收藏0
  • 個人分享--web前端學習資源分享

    摘要:前言月份開始出沒社區(qū),現(xiàn)在差不多月了,按照工作的說法,就是差不多過了三個月的試用期,準備轉(zhuǎn)正了一般來說,差不多到了轉(zhuǎn)正的時候,會進行總結(jié)或者分享會議那么今天我就把看過的一些學習資源主要是博客,博文推薦分享給大家。 1.前言 6月份開始出沒社區(qū),現(xiàn)在差不多9月了,按照工作的說法,就是差不多過了三個月的試用期,準備轉(zhuǎn)正了!一般來說,差不多到了轉(zhuǎn)正的時候,會進行總結(jié)或者分享會議!那么今天我就...

    sherlock221 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<