本節咱們將深刻了解一些應用於構建網站和應用的最佳實踐和工具。css
開發環境和生產環境的構建目標差別很大。在開發環境中咱們須要具備強大的實時從新加載和模塊熱替換功能的source map和localhost server 。而在生產環境中,咱們的目標變成了更小的輸出包、更輕量的source map和更好的資源優化來減小加載時間。遵循邏輯分離咱們推薦爲每一個環境編寫獨立的webpack配置。html
雖然咱們對生產環境和開發環境作了略微區分,可是遵循不重複原則DRY(don't repeat yourself)仍是保留一個通用配置。爲了整合這些配置咱們須要一個webpack-merge插件。有了通用配置咱們就不用在特定環境的配置中重複代碼了。node
安裝webpack-merge插件並把以前成型了的代碼分離:react
npm install --save-dev webpack-merge
projectwebpack
webpack-demo |- package.json - |- webpack.config.js + |- webpack.common.js + |- webpack.dev.js + |- webpack.prod.js |- /dist |- /src |- index.js |- math.js |- /node_modules
webpack.common.jsweb
+ const path = require('path'); + const CleanWebpackPlugin = require('clean-webpack-plugin'); + const HtmlWebpackPlugin = require('html-webpack-plugin'); + + module.exports = { + entry: { + app: './src/index.js' + }, + plugins: [ + new CleanWebpackPlugin(['dist']), + new HtmlWebpackPlugin({ + title: 'Production' + }) + ], + output: { + filename: '[name].bundle.js', + path: path.resolve(__dirname, 'dist') + } + };
webpack.dev.jsexpress
+ const merge = require('webpack-merge'); + const common = require('./webpack.common.js'); + + module.exports = merge(common, { + mode: 'development', + devtool: 'inline-source-map', + devServer: { + contentBase: './dist' + } + });
webpack.prod.jsnpm
+ const merge = require('webpack-merge'); + const common = require('./webpack.common.js'); + + module.exports = merge(common, { + mode: 'production', + });
在webpack.common.js中咱們配置了input和output並引入了兩種環境都須要的插件。在webpack.dev.s中咱們把mode設置爲了開發模式,同時添加了推薦的開發模式調試工具(強大的 source mapping)以及簡單的devServer配置。最後在webpack.prod.js中咱們把模式設置爲了會使用UglifyJSPlugin的生產模式。json
如今根據新的配置修改一下啓動腳本。咱們將使用npm start做爲開發環境腳本,npm run build做爲生產環境腳本。服務器
package.json
{ "name": "development", "version": "1.0.0", "description": "", "main": "src/index.js", "scripts": { - "start": "webpack-dev-server --open", + "start": "webpack-dev-server --open --config webpack.dev.js", - "build": "webpack" + "build": "webpack --config webpack.prod.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "clean-webpack-plugin": "^0.1.17", "css-loader": "^0.28.4", "csv-loader": "^2.1.1", "express": "^4.15.3", "file-loader": "^0.11.2", "html-webpack-plugin": "^2.29.0", "style-loader": "^0.18.2", "webpack": "^3.0.0", "webpack-dev-middleware": "^1.12.0", "webpack-dev-server": "^2.9.1", "webpack-merge": "^4.1.0", "xml-loader": "^1.2.1" } }
許多引用庫會根據process.env.NODE_ENV來決定包含什麼。在非生產模式下許多庫會添加一些額外的日誌和測試來使調試更加簡單。而在process.env.NODE_ENV==="production"時它們可能會刪除或加入一部分重要的代碼來提升真實用戶運行你的代碼時的性能。webpack v4及之後明確mode屬性會自動幫你配置DefinePlugin插件:
webpack.prod.js
const merge = require('webpack-merge'); const common = require('./webpack.common.js'); module.exports = merge(common, { mode: 'production', });
ps:技術上講,NODE_ENV
是一個由 Node.js 暴露給執行腳本的系統環境變量。一般用於決定在開發環境與生產環境(dev-vs-prod)下,服務器工具、構建腳本和客戶端 library 的行爲。然而,與預期不一樣的是,沒法在構建腳本 webpack.config.js
中,將 process.env.NODE_ENV
設置爲 "production"
。所以,例如 process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js'
這樣的條件語句,在 webpack 配置文件中,沒法按照預期運行。
若是你使用了像react這樣的庫,那你添加完這個插件後應該能發現輸出包的大小減少了很是多。並且本地src文件夾下的文件都會識別這個變量,因此如下檢查會有效:
src/index.js
import { cube } from './math.js'; + + if (process.env.NODE_ENV !== 'production') { + console.log('Looks like we are in development mode!'); + } function component() { var element = document.createElement('pre'); element.innerHTML = [ 'Hello webpack!', '5 cubed is equal to ' + cube(5) ].join('\n\n'); return element; } document.body.appendChild(component());
注意,雖然UglifyJSPlugin 是代碼壓縮方面比較好的選擇,可是還有一些其餘可選擇項。如下有幾個一樣很受歡迎的插件:
BabelMinifyWebpackPlugin
ClosureCompilerPlugin
若是決定嘗試以上這些,只要確保新插件也會按照Tree Shaking指南中所陳述的,具備刪除未引用代碼(dead code)的能力足矣。
咱們鼓勵你在生產環境中啓用 source map,由於它們對調試源碼(debug)和運行基準測試(benchmark tests)頗有幫助。也就是說,你應該選擇一個針對生產環境的構建速度較快的配置。對於本指南,咱們將在生產環境中使用 source-map
選項,而不是咱們在開發環境中用到的 inline-source-map
:
webpack.prod.js
const merge = require('webpack-merge'); const common = require('./webpack.common.js'); module.exports = merge(common, { mode: 'production', + devtool: 'source-map' });
ps:避免在生產中使用 inline-***
和 eval-***
,由於它們能夠增長 bundle 大小,並下降總體性能。
正如在管理資源中最後的 加載CSS小節中所提到的,一般最好的作法是使用 ExtractTextPlugin
將 CSS 分離成單獨的文件。在插件文檔中有一些很好的實現例子。disable
選項能夠和 --env
標記結合使用,以容許在開發中進行內聯加載,推薦用於熱模塊替換和構建速度。
以上描述也能夠經過命令行實現。例如,--optimize-minimize
標記將在後臺引用 UglifyJSPlugin
。和以上描述的 DefinePlugin
實例相同,--define process.env.NODE_ENV="'production'"
也會作一樣的事情。而且,webpack -p
將自動地調用上述這些標記,從而調用須要引入的插件。
這些簡便方式雖然都很不錯,可是咱們一般建議只使用配置方式,由於在這兩種場景中下,配置方式可以更好地幫助你瞭解本身正在作的事情。配置方式還可讓你更方便地控制這兩個插件中的其餘選項。