react webpack 實踐與解說

目前寫 react 最常用的工具是 webpack,它是模組的打包工具,可將多種不同類型的檔案打包成一支 js 擋,除了能將語言打包,也可同時進行編譯與壓縮。隨著可進行的配置種類繁多,所以在剛入門時很難知道有哪些設定或是哪些 plugin,以及該如何挑選與使用。雖然選擇多可以更客製化自己所需要的最佳環境,但這也就相對的製造了門檻。

詳細介紹網路上很多,這裡就不多作介紹。因為 webpack 能講的東西太多了,本篇會著重在解說我使用的 react 環境中 webpack 的各項設定功能為何。我使用的 react 環境設定有以下功能:

  1. source map。
  2. hmr (hot module replacement)。
  3. 提出 vendor。
  4. 支援 jsx。
  5. sass 編譯及提出為獨立檔案。
  6. 設定 react 執行環境 (development/production)。
  7. ES6 編譯。
  8. import js/jsx 時省略副檔名。

詳細程式碼可參考 Github

webpack 設定

使用 webpack 時主要會在 project 的根目錄下建立一名為 webpack.config.js 的檔案,此檔案會匯出一個物件讓 webpack 來執行,以下為我所使用的設定,接下來會根據各項設定做解說。

devtool

用來選擇來幫助 debug 的開發工具(develop tool),這項設定牽扯到在 debug 時 source map 的顯示方式。

因為透過 webpack 編譯或壓縮甚至打包程式後,在瀏覽器上跑的程式的長相已經跟當初寫的樣子差異很大,source map 就是對應這些檔案還原成當初寫的樣子,來方便 debug。

devtool: 'eval'

在官方文件中建議在 develop 環境時使用 ‘eval’,而在 production 環境下使用 ‘cheap-module-source-map’。以下為 webpack 所列出的可用設定與比較。

來源:https://webpack.github.io/docs/configuration.html

entry

欲執行打包程式的進入點,可以同時有多個進入點。

‘webpack-hot-middleware/client?reload=true’

這裡的設定是在觸發瀏覽器的重載,在一般情況下使用 ‘webpack-hot-middleware/client’ 即可達到,但當 sass 透過 extract-text-webpack-plugin 提出為外部檔案時,sass 的改動並不會觸發瀏覽器的重載,此時在後面加入參數 ‘reload=true’,即可讓 sass 再編譯成獨立外部檔案時,也觸發瀏覽器的重載。

path.join(__dirname, 'src/app/index')

欲執行打包程式的檔案路徑。

vendor: ['react', 'react-dom']

將常用的 react 與 react-dom 提出,另外打包成一支檔案。因為這些套件不會在你開發的時候做修改,這樣做的好處是在開發時若有使用到 hmr,則會只重新載入修改到的檔案,而不會連套件的部分也一併重新載入,可加快 hmr 的時間。

output

處理過的檔案的相關設定。

path: path.join(__dirname, 'dist')

處理過的檔案所要放置的路徑。

filename: '[name].js'

處理過的檔案的命名。

publicPath: '/'

在開發時並未真的產生一個檔案放在上面 path 所設定的地方,而是藉由設定 publicPath 來將處理過的檔案所要存放對應瀏覽器的路徑。

chunkFilename: '[name].js'

在 entry 中可有多個入口,可以打包成多支 js 檔,若當通通打包成一支 js 會使檔案過大時,將檔案拆分批次載入可以達到優化的效果。若在 entry 中已設了多個入口,這裡則會產生對應的檔案。

上圖是處理完所 output 的檔案,publicPath 路徑下放了依 entry 路徑所打包的檔案,而 source map 的檔案則放在 webpack://. 的下面。

module

裡面主要包含 loaders 來解析不同類型的檔案並做相對應的處理。

test: /\.sass$/
loader: ExtractTextPlugin.extract('style-loader', ['css-loader?minimize', 'sass-loader'])

test:使用正規表達式來過濾副檔名為 sass 的檔案。

loader:將所過濾出來的檔案來做對應的處理,有 import 的 sass 檔案解析及處理,其中 ‘css-loader?minimize’ 會將 css 檔案再做壓縮。

未使用 extract-text-webpack-plugin 的話所 import 的 csss 會在 header 的 style 中。

使用 extract-text-webpack-plugin 可將 import 的 css 提出成外部的檔案。

兩種做法其實沒有孰優孰劣,可依自己的需求做設定。

test: /\.js[x]?$/
include: path.resolve(__dirname, ‘src’)
exclude: /node_modules/
loader: 'babel-loader'

test:使用正規表達式來過濾副檔名為 js 與 jsx 的檔案。

include:欲處理檔案的資料夾。

exclude:排除不做處理的資料夾。

loader:透過 babel 來處理 js 與 jsx 以及 ES6。

plugins

在 module 的 loader 處理過後的檔案,可在 plugin 中在做額外的處理。

new webpack.optimize.OccurrenceOrderPlugin()

載入的模組的會給模組一個 id,這 id 會根據模組調用的次數來排序,調用頻繁的模組會分配到更短的 id,讓 id 是可預測的,可以加快 hmr的速度。

new webpack.HotModuleReplacementPlugin()

做 hot reload。

new webpack.NoErrorsPlugin()

讓重新編譯程式出錯時不重載畫面,等到程式修正後再做重載。

new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  filename: '[name].js'
})

可以把共用且不會變動的 import 提取出來成一支檔案,像是在 react component 中都會需要 import react,這樣可以再重新編譯時減少要編譯的程式大小,縮短編譯時間。

new ExtractTextPlugin('main.css')

一般 import 的 sass 會在 html 中把 sass 編譯的結果寫在 header 的 style 中,這樣的處理會將 import 提出為一支 css 檔案。

new webpack.DefinePlugin({
  'process.env': {
    'NODE_ENV': JSON.stringify('development')
  }
})

設定 react 執行環境,若是 production 環境直接將 development 改為 production 即可,production 環境下的執行效率比 development 下的好很多。

resolve

extensions: ['', '.js', '.jsx']

用來處理可省略的副檔名名稱。

參考:

webpack configuration

入门 Webpack,看这篇就够了

webpack学习实践系列(一)

[webpack] devtool配置对比

從頭建立一套 web-based 服務架構 (5) Tuning Webpack

JavaScript Source Map 详解

Like what you read? Give Kinvil Hsiao a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.