本文項目代碼位置: 源碼地址javascript
webpack 能幹什麼?css
module.exports = {
entry: '', // 指定入口文件
output: '', // 指定輸出目錄和輸出文件名
mode: '', // 環境
module: {
rules: [ // loader配置
{test: '', use: ''}
]
},
plugins: [ // 插件配置
new xxxPlugin()
]
}
複製代碼
爲何須要 loader ?html
webpack 原生只支持 js、json 兩種模塊類型,因此須要 loader 把其餘類型的文件轉化成有效的模塊,並能夠添加到依賴圖中。vue
loader 自己是一個函數,接受源文件做爲參數,返回轉換的結果html5
功能 | loader | 說明 |
---|---|---|
解析es6 | babel-loader | 配合.babelrc使用 |
解析vue | vue-loader | |
解析css | css-loader | 用於加載.css文件,並轉換成commonjs對象 |
style-loader | 將樣式經過<style> 標籤插入到head中 |
|
解析less | less-loader | 將less轉換成css |
解析圖片和字體 | file-loader | 用於處理文件(圖片、字體) |
url-loader | 也能夠處理圖片和字體,和file-loader功能相似,但它還能夠設置較小資源自動轉base64(內部用了file-loader),使用options:{limit: xxx} |
插件用於 bundle 文件的優化、資源管理和環境變量注入,它做用於整個構建過程java
style-loader
功能互斥,不能同時使用JS文件的壓縮 :默認開啓了內置的 terser-webpack-plugin
,webpack 在打包時會自動壓縮 js 代碼
css文件的壓縮 :使用 optimize-css-assets-webpack-plugin
,同時使用 cssnano
(處理器)node
plugins: [
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
})
]
複製代碼
html文件的壓縮:修改 html-webpack-plugin
,設置壓縮參數react
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['main', 'other'], //要包含哪些chunk
inject: true, //將chunks自動注入html
minify: { // 壓縮相關
html5: true,
collapseWhitespace: true, //壓縮空白字符
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: true
}
})
]
複製代碼
開啓 dev-server
後默認只要有一個文件變化,會從新構建,刷新瀏覽器頁面。jquery
模塊熱替換: 只從新打包變動的模塊,局部刷新,保留數據狀態,(而不是將全部模塊從新打包,刷新頁面)提高構建速度,使開發更加方便webpack
經過 devServer.hot
啓用,其內部依賴 webpack.HotModuleReplacementPlugin
實現,HotModuleReplacementPlugin
會在 hot: true
時自動被引入,能夠不寫
style-loader
內部實現了if(module.hot){ // 若是開啓了HMR功能
// 監聽xxx.js文件的變化,一旦發生變化,其餘模塊不會從新打包,會執行回調函數
module.hot.accept('./xxx.js', function(){
fn()
})
}
複製代碼
因爲通過 webpack
打包後的代碼是通過各類 loaders
,plugins
轉換事後的一個大的js文件,開發過程當中沒法調試。source-map
是一種提供源代碼到構建後代碼映射的技術,報錯時經過 source map
能夠定位到源代碼。
啓用方式:
module.exports = {
devtool: 'source-map'
}
複製代碼
選項:
[inline- | hidden- | eval-] [nosources- ] [cheap- [module- ]]source-map
.map
文件,提供錯誤代碼準確信息和源代碼的錯誤位置.map
做爲 DataURI
嵌入,不單獨生成 .map
文件,構建速度更快eval
包裹模塊代碼,指定模塊對應文件loader
的 sourcemap
推薦組合:
eval-source-map
(eval
速度最快,source-map
調試最友好)
1.考慮是否要隱藏源代碼?
nosources-source-map
---所有隱藏
hidden-source-map
---只隱藏源代碼,會提示構建後代碼錯誤信息
2.考慮是否要調試友好?
source-map
當設置了 http 強緩存,好比有效期爲一天,若是不使用 hash,當這個文件改變了,由於文件名沒變,因此客戶端使用的仍是舊的緩存;若是使用了 hash,這時文件名就改變了,就會請求新的資源,而沒有更改過的文件繼續使用緩存
hash
,每次構建都會改變,不建議使用webpack
打包的 chunk
有關,不一樣的 entry
會生成不一樣的 chunkhash
值contenthash
不變,推薦在 css
文件上使用js 文件的指紋設置:
//設置 output 的 filename,使用 [chunkhash]
module.exports = {
output: {
filename: '[name][chunkhash:8].js',
path:__dirname+'/dist'
}
}
複製代碼
css 文件的指紋設置:
使用 MiniCssExtractPlugin
將 css
從 js
中提出來,而後使用 [contenthash]
plugins: [
new MiniCssExtractPlugin({
filename: '[name][contenthash:8].css'
})
]
複製代碼
補充:
module、chunk、bundle的區別
chunk
,能夠理解爲一個 entry
對應一個 chunk
chunk
就對應一個 bundle
,但也能夠經過一些插件進行拆包,把一個大chunk
拆分爲多個 bundle
,好比 MiniCssExtractPlugin
tree shaking
(搖樹優化):一個模塊可能有多個方法,只要其中的某個方法使用到了,則整個文件都會被打到 bundle
裏面去,tree shaking
就是隻把用到的方法打入bundle
,沒用到的方法會在 uglify
階段被擦除掉。
使用:webpack
默認支持,在 .babelrc
裏設置 module:false
便可
webpack
會在 production mode
的狀況下默認開啓 tree shaking
要求:必須是 es6 語法,cjs 的方式不支持
tree shaking 原理
DCE:永遠不會被用到的代碼,好比引入了一個方法可是沒調用 或者 if(false){xxx}
利用 ES6 模塊的特色:
import
的模塊名只能是字符串常量import binding
是immutable
的在打包以前靜態的分析文件,在uglify階段刪除無用代碼
將一個大bundle文件拆包,拆包的方案能夠在cacheGroups裏配置
// splitChunks默認配置
optimization: {
splitChunks: {
chunks: 'all', // 不管同步引入仍是異步引入
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/, // 匹配node_modules目錄下的文件
priority: -10 // 優先級配置項
},
default: {
minChunks: 2, // 至少引用了2次
priority: -20, // 優先級配置項
reuseExistingChunk: true
}
}
}
}
複製代碼
在默認設置中
node_mudules
文件夾中的模塊打包進一個叫 vendors
的 bundle
中default bundle
中 ,能夠經過 priority
來設置優先級。將第三方庫和業務基礎包單獨打成一個文件,只在第一次打,或者須要更新依賴的時候打,此後每次就能夠只打本身的源代碼,加快了構建速度。
方法:使用 DLLPlugin
進行分包,DllReferencePlugin
對 manifest.json
引用
分包須要單獨的配置文件:
// webpack.dll.js
module.exports={
entry: {
lib: [
'lodash',
'jquery'
]
},
output: {
filename: '[name]_[chunkhash].dll.js',
path: path.join(__dirname, 'build/lib'),
library: '[name]' // 打包後對外暴露的全局變量名稱
},
plugins: [
new webpack.DllPlugin({
name: '[name]', // manifest.json中的name,要與ouput.library名一致
path: path.join(__dirname, 'build/lib/manifest.json'),
})
]
}
複製代碼
在 package.json
中添加命令對 dll
單獨打包:
"scripts": {
"dll": "webpack --config webpack.dll.js"
},
複製代碼
使用 DllReferencePlugin
對 manifest.json
進行引用,告訴 webpack
使用了哪些動態連接庫,不用再打包這裏面的東西
// webpack.prod.js
new webpack.DllReferencePlugin({
manifest: require('./build/lib/manifest.json')
}),
複製代碼
使用 addAssetHtmlWebpackPlugin
將 dll
資源插到 html
裏
// webpack.prod.js
new addAssetHtmlWebpackPlugin([
{
filepath: path.resolve(__dirname, './build/lib/*.dll.js'),
outputPath: 'static', // 將*.dll.js拷貝後的輸出路徑,相對於html文件
publicPath: 'static'
}
])
複製代碼
demo 地址: webpack實踐-dll-plugin分支
使用先後對比:
使用 dllplugin
前,基礎庫打到了 main.js
裏,佔了 160kb
: 使用後:
main.js
只剩 1.23kb
splitChunks
是在構建時拆包,dll
是提早構建好基礎庫,打包的時候就不須要打基礎庫了,時間上 dll
比 splitChunks
快一點dll
須要多配置一個 webpack.dll.config.js
,並且一旦 dll
中的依賴有更新,得走兩遍打包,比 splitChunks
麻煩一些splitChunks
去提取頁面間的公共 js
文件。DllPlugin
用於基礎包(框架包、業務包)的分離。使用 thread-loader
開啓多進程打包,加快打包速度!
注意:啓動進程須要大概 600ms
,進程間通訊也有花銷,項目小的話開啓多進程得不償失,因此只有當項目比較大,打包耗時較長的時候才適合使用多進程。
module: {
rules: [
{
test: /.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: 2 //開啓兩個進程
}
},
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true
}
}
]
},
]
}
複製代碼
多頁面打包須要多個入口文件,多個 HtmlWebpackPlugin
產生多個 html
。咱們不可能去手寫不少個入口和 HtmlWebpackPlugin
方案: 動態獲取 entry
和設置 html-webpack-plugin
數量
// 核心方法
const setMPA = () => {
const entry = {};
const htmlWebpackPlugins = [];
const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));
entryFiles.forEach(entryFile => {
const match = entryFile.match(/src\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = entryFile;
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
template: path.join(__dirname, `src/${pageName}/index.html`),
filename: `${pageName}.html`,
chunks: [pageName], //要包含哪些chunk
inject: true, //將chunks自動注入html
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
)
})
return {
entry,
htmlWebpackPlugins
}
}
複製代碼
其餘具體配置見 webpack實踐-mpa-build分支