參考地址-官網javascript
啓用此功能須要更新 webpack-dev-server 的配置,和使用 webpack 內置的 HMR 插件。css
webpack.config.jshtml
module.exports = {
// ...
devServer: {
// ...
hot: true
}
};
複製代碼
worker.js前端
if (module.hot) {
module.hot.accept('./print.js', function() {
console.log('Accepting the updated printMe module!');
printMe();
})
}
複製代碼
注意點vue
CSS 的模塊熱更新,藉助於 style-loader
。java
false
,全部文件代碼都沒有反作用「反作用」的定義是,在導入時會執行特殊行爲的代碼,而不是僅僅暴露一個 export 或多個 export。舉例說明,例如 polyfill,它影響全局做用域,而且一般不提供 export。有反作用的不能tree sharking!webpack
注意,任何導入的文件都會受到 tree shaking 的影響。這意味着,若是在項目中使用相似 css-loader
並導入 CSS 文件,則須要將其添加到 side effect 列表中,以避免在生產模式中無心中將它刪除。git
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js",
"*.css"
]
}
複製代碼
還能夠在
module.rules
配置選項 中設置"sideEffects"
es6
從 webpack 4 開始,也能夠經過 "mode"
配置選項輕鬆切換到壓縮輸出,只需設置爲 "production"
。
webpack.config.js
module.exports = {
// ...
mode: "production"
};
複製代碼
import
和 export
)package.json
文件中,添加一個 sideEffects
入口UglifyJSPlugin
, webpack4 開始能夠設置 mode
: "production"
來代替)生產環境,在使用
uglifyjs-webpack-plugin
時,你必須提供sourceMap:true
選項來啓用 source map 支持。鼓勵你在生產環境中啓用 source map,由於它們對調試源碼(debug)和運行基準測試(benchmark tests)頗有幫助。
eval
- 映射到轉換後的代碼eval-source-map
- 行數可以正確映射,會映射到原始代碼中。cheap-eval-source-map
- 相似 eval-source-map
,每一個模塊使用 eval()
執行。這是 "cheap(低開銷)" 的 source map,由於它沒有生成列映射(column mapping),只是**映射行數。它會忽略源自 loader 的 source map,**而且僅顯示轉譯後的代碼,就像 eval
devtool。cheap-module-eval-source-map
- 相似 cheap-eval-source-map
,而且,在這種狀況下,源自 loader 的 source map 會獲得更好的處理結果。然而,loader source map 會被簡化爲每行一個映射(mapping)。這些選項一般用於生產環境中:
(none)
(省略 devtool
選項) - 不生成 source map。這是一個不錯的選擇。
source-map
- 整個 source map 做爲一個單獨的文件生成。它爲 bundle 添加了一個引用註釋,以便開發工具知道在哪裏能夠找到它。
你應該將你的服務器配置爲,不容許普通用戶訪問 source map 文件!
hidden-source-map
- 與 source-map
相同,但不會爲 bundle 添加引用註釋。若是你只想 source map 映射那些源自錯誤報告的錯誤堆棧跟蹤信息,但不想爲瀏覽器開發工具暴露你的 source map,這個選項會頗有用。
你不該將 source map 文件部署到 web 服務器。而是隻將其用於錯誤報告工具。
nosources-source-map
- 建立的 source map 不包含 sourcesContent(源代碼內容)
。它能夠用來映射客戶端上的堆棧跟蹤,而無須暴露全部的源代碼。你能夠將 source map 文件部署到 web 服務器。
這仍然會暴露反編譯後的文件名和結構,但它不會暴露原始代碼。
如下選項對於開發環境和生產環境並不理想。他們是一些特定場景下須要的,例如,針對一些第三方工具。
inline-source-map
- source map 轉換爲 DataUrl 後添加到 bundle 中。cheap-source-map
- 沒有列映射(column mapping)的 source map,忽略 loader source map。inline-cheap-source-map
- 相似 cheap-source-map
,可是 source map 轉換爲 DataUrl 後添加到 bundle 中。cheap-module-source-map
- 沒有列映射(column mapping)的 source map,將 loader source map 簡化爲每行一個映射(mapping)。inline-cheap-module-source-map
- 相似 cheap-module-source-map
,可是 source mapp 轉換爲 DataUrl 添加到 bundle 中。許多 library 將經過與 process.env.NODE_ENV
環境變量關聯,以決定 library 中應該引用哪些內容。例如,當不處於生產環境中時,某些 library 爲了使調試變得容易,可能會添加額外的日誌記錄(log)和測試(test)。其實,**當使用 process.env.NODE_ENV === 'production'
時,一些 library 可能針對具體用戶的環境進行代碼優化,從而刪除或添加一些重要代碼。**咱們可使用 webpack 內置的 DefinePlugin
爲全部的依賴定義這個變量:
NODE_ENV 屬性:
- 這個變量並非 pocess.env 直接就有的,而是經過設置獲得的。
- 能夠經過判斷這個變量區分開發環境或生產環境。
webpack.prod.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
});
複製代碼
技術上講,NODE_ENV
是一個由 Node.js 暴露給執行腳本的系統環境變量。一般用於決定在開發環境與生產環境(dev-vs-prod)下,服務器工具、構建腳本和客戶端 library 的行爲。然而,與預期不一樣的是,沒法在構建腳本 webpack.config.js
中,將 process.env.NODE_ENV
設置爲 "production"
,請查看 #2537。
例如 process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js'
這樣的條件語句,在 webpack 配置文件中,沒法按照預期運行。
任何位於
/src
的本地代碼均可以關聯到 process.env.NODE_ENV 環境變量,因此如下檢查也是有效的:
src/worker.js
import { cube } from './math.js';
if (process.env.NODE_ENV !== 'production') {
console.log('Looks like we are in development mode!');
}
複製代碼
爲何 webpack官網 裏面說:
process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js'`這樣的條件語句,在 webpack 配置文件中,沒法按照預期運行。
可是 MiniCssExtractPlugin 官網 裏面能夠以下使用:
const devMode = process.env.NODE_ENV !== 'production'
複製代碼
process.env.NODE_ENV
值都是 undefined
。// 方式一
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
// 方式二
{
mode: 'production'
}
複製代碼
只設置
NODE_ENV
,則會自動設置mode
。
webpack
配置文件裏獲取NODE_ENV
的值呢,這樣就能夠根據不一樣的值定義相關的參數了,如上所述,答案是:corss-env
,在package.json裏增長以下配置:"scripts": {
"build-cross-env":"cross-env NODE_ENV=production webpack"
}
複製代碼
經過
cross-env NODE_ENV=production
,信息傳遞給了webpack的配置文件, src文件下面不能訪問。
把代碼分離到不一樣的 bundle 中,而後能夠按需加載或並行加載這些文件。代碼分離能夠用於獲取更小的 bundle,以及控制資源加載優先級,若是使用合理,會極大影響加載時間。
有三種經常使用的代碼分離方法:
entry
配置手動地分離代碼。CommonsChunkPlugin
去重和分離 chunk。當涉及到動態代碼拆分時,webpack 提供了兩個相似的技術。對於動態導入,第一種,也是優先選擇的方式是,使用符合 ECMAScript 提案 的 import()
語法。第二種,則是使用 webpack 特定的 require.ensure
。讓咱們先嚐試使用第一種……
import()
調用會在內部用到 promises。若是在舊有版本瀏覽器中使用import()
,記得使用 一個 polyfill 庫(例如 es6-promise 或 promise-polyfill),來 shimPromise
。
worker.js
// 方式一
const _ = await import(/* webpackChunkName: "lodash" */ 'lodash');
// 方式二
import(/* webpackChunkName: "print" */ './print').then(module => {
var print = module.default;
print();
});
複製代碼
注意當調用 ES6 模塊的
import()
方法(引入模塊)時,必須指向模塊的.default
值,由於**它纔是 promise 被處理後返回的實際的module
對象*。*
webpack.config.js
output: {
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
複製代碼
跟整個webpack構建項目相關的,每次項目構建hash對應的值都是不一樣的,即便項目文件沒有作**「任何修改」**。
實際上是有修改的,由於每次webpack打包編譯都會注入webpack的運行時代碼,致使整個項目有變化,因此每次hash值都會變化的。
**根據不一樣的入口文件(Entry)進行依賴文件解析、構建對應的chunk,生成對應的hash值。**在生產環境裏把一些公共庫和程序入口文件區分開,單獨打包構建,採用chunkhash的方式生成hash值,那麼只要不改動公共庫的代碼,就能夠保證其hash值不會受影響。
對css使用了chunkhash以後,它與依賴它的chunk共用chunkhash,測試後會發現,css與js文件名的chunkhash值是同樣的,JS
和 CSS
相互影響。
css文件最好使用contenthash。
contenthash表示由文件內容產生的hash值,內容不一樣產生的contenthash值也不同。
對於圖片、字體等靜態資源,生成對應的文件hash值是由對應的file-loader
來計算的。
那麼這些靜態文件的hash值使用的是什麼hash值呢?
其實就是hash
屬性值。此hash非webpack每次項目構建的hash,它是***由file-loader根據文件內容計算出來的,不是webpack構建的hash***。
module.exports = function(env, argv) {
return {
mode: env.production ? 'production' : 'development',
devtool: env.production ? 'source-maps' : 'eval',
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: argv['optimize-minimize'] // 只有傳入 -p 或 --optimize-minimize
})
]
};
};
複製代碼
當 webpack 配置對象導出爲一個函數時,能夠向起傳入一個"環境對象(environment)"。也能夠經過 [指定環境變量](#4. 指定環境變量) 中的 cross-env NODE_ENV=production webpack"
配置
webpack --env.NODE_ENV=local --env.production --progress
複製代碼
若是設置
env
變量,卻沒有賦值,--env.production
默認將--env.production
設置爲true
。還有其餘可使用的語法。有關詳細信息,請查看 webpack CLI 文檔。
webpack 將運行由配置文件導出的函數,而且等待 Promise 返回。便於須要異步地加載所需的配置變量。
module.exports = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
entry: './app.js',
/* ... */
})
}, 5000)
})
}
複製代碼
iframe
iframe
,將咱們本身的應用注入到這個iframe
當中去。live.bundle.js
文件,其不但建立了iframe
標籤,同時包含socket.io
的client
代碼,以和webpack-dev-server
進行websocket
通信,從而完成自動編譯打包、頁面自動刷新的功能。inline
socket.io
的client
代碼被打包進了你的包(bundle
)中,以此來與webpack-dev-server
進行websocket
通信,從而完成自動編譯打包、頁面自動刷新的功能。bundle
文件很臃腫。總結
Iframe mode
和Inline mode
最後達到的效果都是同樣的,都是監聽文件的變化,而後再將編譯後的文件推送到前端,完成頁面的reload
的。devServer.inline
切換兩種模式,默認爲inline
模式。inline mode
。記住,只設置
NODE_ENV
,則不會自動設置mode
。
只在配置中提供 mode
選項:
module.exports = {
mode: 'production'
};
複製代碼
或者從 CLI 參數中傳遞:
webpack --mode=production
複製代碼
會將
process.env.NODE_ENV
的值設爲production
。啓用FlagDependencyUsagePlugin
,FlagIncludedChunksPlugin
,ModuleConcatenationPlugin
,NoEmitOnErrorsPlugin
,OccurrenceOrderPlugin
,SideEffectsFlagPlugin
和UglifyJsPlugin
.
mode: production
// webpack.production.config.js
module.exports = {
+ mode: 'production',
- plugins: [
- new UglifyJsPlugin(/* ... */),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
- new webpack.optimize.ModuleConcatenationPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ]
}
複製代碼
會將
process.env.NODE_ENV
的值設爲development
。啓用NamedChunksPlugin
和NamedModulesPlugin
。
mode: development
// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
- new webpack.NamedModulesPlugin(),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
複製代碼
對於用途普遍的 library,咱們但願它可以兼容不一樣的環境,例如 CommonJS,AMD,Node.js 或者做爲一個全局變量。爲了讓你的 library 可以在各類用戶環境(consumption)中可用,須要在 output
中添加 library
屬性。
爲了讓 library 和其餘環境兼容,還須要在配置文件中添加 libraryTarget
屬性。這是能夠控制 library 如何以不一樣方式暴露的選項,output.libraryTarget
的默認選項是 var
。
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
library: 'webpackNumbers'
library: 'webpackNumbers',
libraryTarget: 'umd'
},
複製代碼
output.publicPath 和 devServer.publicPath 的區別
devServer.publicPath 的意義就是決定外部能以怎樣的路徑經過 devServer來訪問構建在內存中的文件,這個字段未顯式設定時,則會去沿用 output.publicPath
字段的顯式值(若是output.publicPath有值的話,不然就用本身的 default
值)。output.publicPath 的意義是用來爲構建的文件生成知足特定需求的前綴,並將這個前綴提供給須要的 resolver、plugin 或者其餘的配置字段。
HtmlWebpackPlugin 中的filename 也會依賴於public.publicPath
參考博客-你必定能看懂的關於 devServer.publicPath、output.publicPath 和 output.path 的意義的闡述
這個字段只在 production
配置下有效,若是你去試一下的話,你會發如今 development
配置下,不管你給把它配置成什麼值(前提必須是一個合規的絕對地址),它都不會對你訪問開發時構建在內存中的文件產生影響,因此 development
配置下,直接忽略就行了。另外,它的 default
值是 `path.resolve(__dirname, './dist')
過去 webpack 打包時的一個取捨是將 bundle 中各個模塊單獨***打包成閉包***。這些打包函數使你的 JavaScript 在瀏覽器中***處理的更慢***。相比之下,一些工具像 Closure Compiler 和 RollupJS 能夠提高(hoist)或者***預編譯全部模塊到一個閉包中***,提高你的代碼在瀏覽器中的執行速度。這個插件會在 webpack 中實現以上的預編譯功能。
devServer
構建的文件是在內存裏的,而非你電腦的磁盤上,可是若是內存中找不到想要的文件時,devServer
會根據文件的路徑嘗試去電腦的磁盤上找,若是這樣還找不到纔會404
。開發時在內存和
contentBase
下真實的磁盤路徑中存在着一樣文件名的文件,那麼devServer
返回的是內存的那個
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(devConfig.assetsPublicPath, 'index.html') },
],
},
複製代碼
當使用 HTML5 History API 時,任意的 404
響應均可能須要被替代爲 index.html
。經過傳入如下啓用:
historyApiFallback: true
複製代碼
經過傳入一個對象,好比使用 rewrites
這個選項,此行爲可進一步地控制:
historyApiFallback: {
rewrites: [
{ from: /^\/$/, to: '/views/landing.html' },
{ from: /^\/subpage/, to: '/views/subpage.html' },
{ from: /./, to: '/views/404.html' }
]
}
複製代碼
決定外部可以以什麼樣的路徑訪問到構建的文件。
與 output.publicPath 的關係 [查看](#10.2 output.publicPath 和 devServer.publicPath)
這個文件放在根目錄下面設置轉碼規則的。例如要想在代碼中使用es6,就要在這個文件中配置"presets": ["es2015"]
。在項目代碼中要使用jsx語法除了安裝babel-plugin-transform-vue-jsx插件以外,還要配置"plugins": ["transform-runtime", "transform-vue-jsx"]
。
這個文件配置編輯器的編碼風格
配置 ESLint
能夠經過如下三種方式配置 ESLint:
.eslintrc 文件示例:
{
"env": {
"browser": true,
},
"globals": {
"angular": true,
},
"rules": {
"camelcase": 2,
"curly": 2,
"brace-style": [2, "1tbs"],
"quotes": [2, "single"],
"semi": [2, "always"],
"space-in-brackets": [2, "never"],
"space-infix-ops": 2,
}
}
複製代碼
放在項目根目錄,則會應用到整個項目;若是子目錄中也包含 .eslintrc 文件,則子目錄會忽略根目錄的配置文件,應用該目錄中的配置文件。這樣能夠方便地對不一樣環境的代碼應用不一樣的規則。
想要引入三方js庫,可是這些庫不符合eslint規範,能夠在這個文件裏忽略掉,例如:
build/*.js
config/*.js
static
複製代碼
這個文件用於配置不須要加入版本管理的文件,例如:
.DS_Store
node_modules/
npm-debug.log
test/unit/coverage
test/e2e/reports
selenium-debug.log
.idea
/clear
/src/modules/cache.js
複製代碼
在不一樣前端工具之間共享目標瀏覽器和Node.js版本的配置。
使用方法
(1) package.json (推薦)
{
"browserslist": [
"last 1 version",
"> 1%",
"maintained node versions",
"not dead"
]
}
複製代碼
(2) .browserslistrc
# Browsers that we support
last 1 version
> 1%
maintained node versions
not dead
複製代碼
Browserslist 的數據都是來自Can I Use的。若是你想知道配置語句的查詢結果可使用online demo
只是多種配置方式的一種
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}
複製代碼
webpack-dev-server 和 webpack-dev-middleware 裏 Watch 模式默認開啓。
默認配置便是咱們推薦的web最佳實踐,可是你項目的最佳策略根據項目類型可能會有所不一樣
默認將全部來源於node_modules
的模塊分配到叫作venders
的緩存組,全部引用超過兩次的模塊分配到default
緩存組.