雖然webpack已經升級到了4,但網上大量webpack配置的博文依舊是2/3,按照2/3的一些方法去配置webpack4會出現不少問題,很是不利於學習(挫敗感)。
你們調侃webpack配置複雜,有各類像webpack配置工程師這樣的段子。認真梳理起來其實並不難懂。
本文中Webpack4項目工程化構建配置簡單,註釋詳細,且很是實用,附有github源碼,利於學習。引伸到新的概念都有拓展閱讀,不會讓那你一臉懵逼!
github webpack4配置源碼
但願本文能幫你點亮webpack配置技能點,歡迎評論提問題和star。javascript
npm init
複製代碼
一路回車就ok了:css
package name: (test) test
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
...
複製代碼
cnpm i --save-dev webpack
複製代碼
新建文件,webpack.config.js
會最終暴露出一個配置對象。html
const config = {};
module.exports = config;
複製代碼
webpcak4新增了mode,用於根據環境選用對應配置,不設置會warning: The 'mode' option has not been set, webpack will fallback to 'production' for this value...
vue
const config = {
mode: "production" // none/development/production 有三個值
}
複製代碼
定義webpack入口和輸出。
entry/output
是一個對象,能夠定義多個入口。配置output,使其根據入口加上hash動態生成打包後的名稱:java
const path = require("path");
// __dirname爲當前絕對路徑
console.log("__dirname ===>", __dirname);
// __dirname ===> D:\github\Personal-site
const config = {
entry: {
index: "./src/index.js"
// 能夠添加多個入口
// app: "./src/app.js"
},
output: {
filename: "[name].[hash].js",
// 生成絕對路徑
// D:\github\Personal-site\dist
path: path.resolve(__dirname, "dist"),
publicPath: "./"
}
}
複製代碼
以上用了path
作了路徑處理,path
是node.js
內置的package
,用來處理路徑。path.resolve(__dirname, "dist")
會生成返回一個絕對路徑,以儲存生成的文件。
publicPath
並不會對生成文件的路徑形成影響,主要是對頁面裏面引入的資源的路徑作對應的補全。如publicPath: "/"
後,生成的頁面引入js的路徑爲src="/[name].[hash].js"
,本地預覽會報錯,設置成publicPath: "./"
===> src="./[name].[hash].js"
則能夠解決問題。node
指定sourceMap模式。
sourceMap模式有不少種,具體可看:webpack——devtool裏的7種SourceMap模式
vue-cli的webpack.dev.conf.js使用了cheap-module-eval-source-map
。
生產環境這裏使用hidden-source-map
。android
const config = {
// cheap-module-eval-source-map is faster for development
devtool: "cheap-module-eval-source-map"
}
複製代碼
cnpm i --save-dev webpack-dev-server
複製代碼
const config = {
devSever: {
contentBase: './dist',
hot: true,
host: 'localhost'
}
}
複製代碼
可參考:官方文檔 、 segmentfault。webpack
這裏咱們將開發的devServer單獨分爲一個js文件,並經過node運行文件從而跑起服務器。
安裝依賴:ios
cnpm i --save-dev opn webpack-dev-server
複製代碼
新建: /build/dev-server.jsgit
const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');
// 使用opn打開瀏覽器(解決devServer.open無效)
const opn = require("opn");
// 引入配置
const config = require('../webpack.config.js');
// devServer配置
const options = {
contentBase: './dist',
hot: true,
host: 'localhost'
};
// 將devServer加入webpack配置
webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
// 新建devServer
const server = new webpackDevServer(compiler, options);
// 監聽、打開端口
server.listen(5000, 'localhost', () => {
console.log('dev server listening on port 5000');
opn(`http://127.0.0.1:5000`);
});
複製代碼
在package.json
中添加腳本命令:
{
scripts: {
"dev": "node ./build/dev-server.js"
}
}
複製代碼
註釋掉webpack.config.js
中配置的devServer
:
const config = {
// devSever: {
// contentBase: './dist',
// hot: true,
// host: 'localhost'
// }
}
複製代碼
執行npm run dev
便可開啓服務。(別急着運行,繼續配置)
plugins
選項用於以各類方式自定義 webpack
構建過程。webpack
附帶了各類內置插件,能夠經過webpack.[plugin-name]
或者直接引入require([plugin-name])
訪問這些插件。 自帶插件
自動生成html,插入script。
更多: 官方配置、html-minifier配置、html-minifier中文文檔
const HtmlWebpackPlugin = require("html-webpack-plugin");
const config = {
entry: {
index: "./src/index.js"
},
plugins: [
new HtmlWebpackPlugin({
// html模板文件(在文件中寫好title、meta等)
template: "src/index.html",
// 輸出的路徑(包含文件名)
filename: "./index.html",
//自動插入js腳本
// true body head false 默認爲true:script標籤位於html文件的 body 底部
inject: true,
// chunks主要用於多入口文件,當你有多個入口文件,那就回編譯後生成多個打包後的文件,那麼chunks 就能選擇你要使用那些js文件
chunks: ["index"],
// 壓縮html
minify: {
// 移除註釋
removeComments: true,
// 不要留下任何空格
collapseWhitespace: true,
// 當值匹配默認值時刪除屬性
removeRedundantAttributes: true,
// 使用短的doctype替代doctype
useShortDoctype: true,
// 移除空屬性
removeEmptyAttributes: true,
// 從style和link標籤中刪除type="text/css"
removeStyleLinkTypeAttributes: true,
// 保留單例元素的末尾斜槓。
keepClosingSlash: true,
// 在腳本元素和事件屬性中縮小JavaScript(使用UglifyJS)
minifyJS: true,
// 縮小CSS樣式元素和樣式屬性
minifyCSS: true,
// 在各類屬性中縮小url
minifyURLs: true
}
})
]
}
複製代碼
自帶插件,爲每一個引入 css 的 JS 文件建立一個 css 文件,css抽離,並寫入html。
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const config = {
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[hash].css",
})
]
};
複製代碼
刪除文件夾,避免由於生成的文件帶hash,而一直存在。
cnpm i --save-dev clean-webpack-plugin
複製代碼
const CleanWebpackPlugin = require("clean-webpack-plugin");
const config = {
plugins: [
new CleanWebpackPlugin(["dist"])
]
};
複製代碼
啓用熱替換模式。
在控制檯中輸出可讀的模塊名。
文件未變更時,保持build出來的文件hash不變。
// 三種插件webpack自帶
const config = {
plugins: [
// 啓用 HMR
new webpack.HotModuleReplacementPlugin(),
// 在控制檯中輸出可讀的模塊名
new webpack.NamedModulesPlugin(),
// 不作改動hash保持不變
new webpack.HashedModuleIdsPlugin()
]
};
複製代碼
配置如何展現性能提示。
默認不配置下開啓devServer時,會提示:
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
vendor.256a0afe197a0724d634.js (1.67 MiB)
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
index (1.8 MiB)
vendor.256a0afe197a0724d634.js
index.256a0afe197a0724d634.css
index.256a0afe197a0724d634.js
WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
複製代碼
由於限制了文件大小爲250kb,若是超過就會提示
避免提示設置以下:
const config = {
performance: {
// false | "error" | "warning" // 不顯示性能提示 | 以錯誤形式提示 | 以警告...
hints: "warning",
// 開發環境設置較大防止警告
// 根據入口起點的最大致積,控制webpack什麼時候生成性能提示,整數類型,以字節爲單位
maxEntrypointSize: 5000000,
// 最大單個資源體積,默認250000 (bytes)
maxAssetSize: 3000000
}
}
複製代碼
loader 用於對模塊的源代碼進行轉換。咱們可使用loader將less/sass/scss/stylus轉爲css並壓縮、兼容處理等,能夠將js es6/7語法轉爲es5等等。
安裝:
cnpm i --save-dev less css-loader postcss-loader less-loader autoprefixer mini-css-extract-plugin
複製代碼
// css抽離
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 使用mini-css-extract-plugin則不能用style-loader
// 前者是抽離css,後者將全部css插入html,故衝突
const config = {
module: {
rules: [
{
test: /\.less$/,
// 只解析改目錄的文件
include: path.resolve(__dirname, "src"),
use: [
MiniCssExtractPlugin.loader,
// "style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
plugins: [
require("autoprefixer")({
browsers: [
"ie >= 11",
"ff >= 30",
"chrome >= 34",
"safari >= 7",
"opera >= 23",
"ios >= 7",
"android >= 4.4",
"bb >= 10"
]
})
]
}
},
"less-loader"
]
}
]
}
}
複製代碼
使用mini-css-extract-plugin
會將js中的css抽離出來,打包成單獨的文件,從而避免默認狀況下,打包後,因爲css經過js動態插入到html中,致使頁面閃動。
使用css-loder
可以解析js中引入的css:import "main.less"
。
使用style-loader
把加載的css做爲style標籤內容插入到html中。
使用postcss-loader autoprefixer
可以將css代碼自動加兼容性前綴,配置如上代碼。
使用less-loader
將less代碼轉爲css。
Babel是編寫下一代JavaScript的編譯器,能夠將當前運行平臺(瀏覽器、node服務器)尚不支持的下一代或幾代js語法編譯爲當前支持的js語法版本。
使用babel-loader將es6/7語法轉爲es5瀏覽器可執行代碼。
這裏安裝了babel-loader@7.1.5,不注意會有大坑,緣由見註釋:
// babel-loader已經升級到了8,須要裝@babel/core,可是仍是有問題,因此這裏安裝@7.1.5
cnpm i --save-dev babel-loader@7.1.5 babel-core babel-preset-env babel-polyfill
複製代碼
const config = {
module: {
rules: [{
test: /\.js$/,
// 只解析include文件夾內的
include: path.resolve(__dirname, "src"),
// 排除node_modules文件夾
exclude: /node_modules/,
use: [{
// cacheDirectory = true 使用緩存,提升性能,將 babel-loader 提速至少兩倍
loader: "babel-loader?cacheDirectory",
options: {
presets: [
[
"env",
{
"modules": false
}
],
// 包含stage-1, stage-2以及stage-3的全部功能,我的開發就直接上最新的了,爽
"stage-0"
],
plugins: [
"transform-es2015-modules-commonjs"
]
}
}]
}]
}
};
複製代碼
babel-preset-env
是一個新的 preset,(presets是一系列plugin的集合)能夠根據配置的目標運行環境,自動啓用須要的 babel 插件,因爲Preset 的執行順序時從最後一個逆序執行,因此env
寫在最前,就當是保底... 可是使用preset依然不會解析Set/Map這樣的,這時候就要用babel-polyfill
了。
babel-polyfill
簡單描述就是只要引入了babel-polyfill
你能夠大膽的用ES6,可參考ES6和Babel你不知道的事兒,可是使用後會使代碼體積增大,視需求而定。在文件入口引入babel-polyfill
便可使用: import "babel-polyfill"
.
stage-0
是對ES7一些提案的支持,Babel
經過插件的方式引入,讓Babel能夠編譯ES7代碼。固然因爲ES7沒有定下來,因此這些功能隨時肯能被廢棄掉的。參考:如何區分Babel中的stage-0,stage-1,stage-2以及stage-3,其經過插件方式引入,因此須要安裝:
cnpm i --save-dev babel-preset-stage-0
複製代碼
使用url-loader而非file-loader,由於前者包含了後者,提供了更爲強大的功能。他能夠解決css樣式中引入的圖片文件等打包後路徑指向不正確和將圖片轉爲DataURL模式(base64編碼的字符串形式,More:DATA URL簡介及DATA URL的利弊)從而提升網站的加載速度。更多參考:file-loader 和 url-loader
cnpm i --save-dev url-loader file-loader
複製代碼
const config = {
module: {
rules: [{
// 處理引入的圖片視頻字體等文件的loader
// 將小於10k的圖片文件轉爲DataURL,而且設置默認的dist中存放方式
test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif|mp4|webm)(\?\S*)?$/,
loader: "url-loader?limit=10240&name=assets/img/[name]_[hash].[ext]",
// 同樣的做用
// loader: "url-loader?limit=102400&name=[name]_[hash].[ext]&outputPath=assets/img/"
}]
}
};
複製代碼
優化。
// css優化壓縮
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const config = {
optimization: {
// 公共代碼抽取
// CommonsChunkPlugin 已棄用,使用optimization.splitChunks代替
// 提取被重複引入的文件,單獨生成一個或多個文件,這樣避免在多入口重複打包文件
splitChunks: {
cacheGroups: {
commons: {
// 選擇所有chunk
chunks: "all",
// 生成的公共代碼文件名,慣用vendor
name: "vendor",
// 做用於
test: /[\\/]node_modules[\\/]/
}
}
},
// 壓縮代碼,默認開啓
// minimize: true,
// 壓縮配置
minimizer: [
// 優化壓縮css
new OptimizeCSSAssetsPlugin({}),
// 壓縮js配置
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
})
]
}
}
複製代碼
使用webpack
命令便可開始構建,也能夠自定義命令npm run build
:
package.json:
{
"scripts": {
"build": "webpack"
}
}
複製代碼
github webpack4配置源碼
但願本文能幫你點亮webpack配置技能點,歡迎評論提問題和star。
原文發表於本人blog : 柴犬工做室 CQ STUDIO