有了vue-cli的幫助,我們建立vue的專案非常的方便,使用vue create
然後選擇些需要的設定項就能自動幫我們建立設定好的webpack專案腳手架了,實在是‘居家旅行’必備良藥。這次藉著學習webpack的機會,不用vue-cli
搭建一個vue專案。
注:基於webpack5,其執行於 Node.js v10.13.0+ 的版本。
完整程式碼:https://github.com/mashiro-cat/learn_webpack
webpack官網:https://webpack.js.org/
webpack中文官網:https://webpack.docschina.org/
安裝:
npm i webpack webpack-cli -D
執行:
npx webpack ./src/main.js --mode=development
# 根目錄有組態檔
npx webpack
開啟檔案就能看到五個核心設定點:
webpack本身只提供了對js中ES Module
和壓縮的支援,很多功能都要通過使用loader
或者plugin
拓展。
webpack.config.js組態檔編寫:
module.exports = {
// 入口 多入口則設定成物件形式
entry:"",
// 輸出 需使用絕對路徑
output:{},
// loader
module:{
rules:[]
},
// 外掛
plugins:[],
// development 或者 production
// 生產模式預設開啟js和html壓縮
mode:"development"
}
輸出:
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'static/js/main.js' // 將js輸出到 static/js 目錄中
}
module中:
generator: {
// 將圖片檔案輸出到 static/imgs 目錄中
// 將圖片檔案命名 [hash:8][ext][query]
// [hash:8]: hash值取8位元 直接[hash]則不擷取
// [ext]: 使用之前的副檔名
// [name]: 會使用之前的名字
// [query]: 新增之前的query引數
filename: "static/imgs/[hash:8][ext][query]",
},
安裝兩個loader,其使用順序是css-loader會處理css,而將編譯的css經style-loader後會動態建立style
標籤。
css-loader
# 安裝
npm i css-loader style-loader -D
rules: [
// 兩個loader順序按此 它會先使用後面的
{ test: /\.css$/i, use: ["style-loader", "css-loader"] }
]
現在是css全部是打包到js中,然後動態插入的。若需要提取到單獨檔案,則可以藉助外掛。
// 安裝外掛
npm i mini-css-extract-plugin -D
// 設定外掛
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 將styel-loader改為MiniCssExtractPlugin.loader
{
// 用來匹配 .css 結尾的檔案
test: /\.css$/,
// use 陣列裡面 Loader 執行順序是從右到左
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
plugins:[
new MiniCssExtractPlugin({
// 定義輸出檔名和目錄
filename: "static/css/main.css",
}),
]
// 安裝
npm i postcss-loader postcss postcss-preset-env -D
// 設定
{
// 用來匹配 .css 結尾的檔案
test: /\.css$/,
// use 陣列裡面 Loader 執行順序是從右到左
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{ // 在css-loader之後,前處理器loader之前
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解決大多數樣式相容性問題
],
},
},
},
],
},
控制相容性:
package.json 檔案中新增 browserslist 來控制樣式的相容性的程度:
{
// 其他省略
//"browserslist": ["ie >= 8"]
// 實際開發中我們一般不考慮舊版本瀏覽器了,所以我們可以這樣設定:
// 所有瀏覽器的最新兩個版本 支援市面上99%瀏覽器 還沒死的瀏覽器
"browserslist": ["last 2 version", "> 1%", "not dead"]
}
安裝外掛:
npm i css-minimizer-webpack-plugin -D
webpack設定:
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
plugins:[
// css壓縮
new CssMinimizerPlugin(),
]
使用less,scss等預處理都要安裝對應的loader進行編譯,webpack才能識別處理。
less的使用:
// 安裝less-loader
npm i less-loader -D
// 設定
// less-loader將less轉為css後還是要交給css-loader處理的
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"]
}
scss, sass的使用:
// 安裝
npm i sass-loader sass -D
// 設定
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
const path = require('path')
module.exports = {
// 入口 多入口則設定成物件形式
entry: "./src/main.js",
// 輸出 需使用絕對路徑
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
// loader
module: {
rules: [
// 兩個loader順序按此 它會先使用後面的
{ test: /\.css$/i, use: ["style-loader", "css-loader"] },
// less-loader將less轉為css後還是要交給css-loader處理的
{ test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] },
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
]
},
// 外掛
plugins: [],
// development 或者 production
mode: "development"
}
Webpack4使用file-loader 和 url-loader處理圖片資源,而webpack5將那倆都內建了,直接設定開啟就可。
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
},
將小於某個大小的圖片轉化成Base64可新增此設定:
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小於10kb的圖片會被base64處理
}
}
},
const path = require('path')
module.exports = {
// 入口 多入口則設定成物件形式
entry: "./src/main.js",
// 輸出 需使用絕對路徑
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
// loader
module: {
rules: [
// 兩個loader順序按此 它會先使用後面的
{ test: /\.css$/i, use: ["style-loader", "css-loader"] },
// less-loader將less轉為css後還是要交給css-loader處理的
{ test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] },
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小於10kb的圖片會被base64處理
}
}
},
]
},
// 外掛
plugins: [],
// development 或者 production
mode: "development"
}
若專案中參照了字型,視訊等資源,則是希望不要處理它,直接輸出就好了。設定為type: "asset/resource"
它就會原封不動的輸出了。
{
// 處理字型圖示或者視訊等其它資源
test: /\.(ttf|woff2?|map4|map3)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
}
const path = require('path')
module.exports = {
// 入口 多入口則設定成物件形式
entry: "./src/main.js",
// 輸出 需使用絕對路徑
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'static/js/main.js', // 將js輸出到 static/js 目錄中
clean: true
},
// loader
module: {
rules: [
// 兩個loader順序按此 它會先使用後面的
{ test: /\.css$/i, use: ["style-loader", "css-loader"] },
// less-loader將less轉為css後還是要交給css-loader處理的
{ test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] },
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小於10kb的圖片會被base64處理
}
},
generator: {
// 將圖片檔案輸出到 static/imgs 目錄中
// 將圖片檔案命名 [hash:8][ext][query]
// [hash:6]: hash值取6位
// [ext]: 使用之前的副檔名
// [query]: 新增之前的query引數
filename: "static/imgs/[hash:6][ext][query]",
},
},
{
// 處理字型圖示或者視訊等其它資源
test: /\.(ttf|woff2?|map4|map3)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
]
},
// 外掛
plugins: [],
// development 或者 production
mode: "development"
}
安裝:
npm i eslint-webpack-plugin eslint -D
在webpack設定中使用eslint外掛
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
plugins: [
new ESLintWebpackPlugin({
// 指定檢查檔案的根目錄
context: path.resolve(__dirname, "src"),
}),
],
編寫設定:
組態檔由很多種寫法:.eslintrc.*:新建檔案,位於專案根目錄
區別在於設定格式不一樣package.json 中 eslintConfig:不需要建立檔案,在原有檔案基礎上寫,ESLint 會查詢和自動讀取它們,所以以上組態檔只需要存在一個即可
根目錄建立.eslintrc.js
組態檔
// .eslintrc.js
module.exports = {
// 解析設定項
parserOptions: {
ecmaVersion: 6, // ES 語法版本
sourceType: "module", // ES 模組化
},
env: {
node: true, // 啟用node中全域性變數
browser: true, // 啟用瀏覽器中全域性變數 不開啟則像 console Math 等全域性變數無法使用
},
// 繼承規則
extends: ['eslint:recommended'],
// 檢測規則
// 自定義的規則會覆蓋繼承的規則
// "off" 或 0 - 關閉規則
// "warn" 或 1 - 開啟規則,使用警告級別的錯誤:warn (不會導致程式退出)
// "error" 或 2 - 開啟規則,使用錯誤級別的錯誤:error (當被觸發的時候,程式會退出)
rules: {
semi: "off", // 禁止使用分號
'array-callback-return': 'warn', // 強制陣列方法的回撥函數中有 return 語句,否則警告
'default-case': [
'warn', // 要求 switch 語句中有 default 分支,否則警告
{ commentPattern: '^no default$' } // 允許在最後註釋 no default, 就不會有警告了
],
eqeqeq: [
'warn', // 強制使用 === 和 !==,否則警告
'smart' // https://eslint.bootcss.com/docs/rules/eqeqeq#smart 除了少數情況下不會有警告
],
},
}
安裝:
npm i babel-loader @babel/core @babel/preset-env -D
babel設定編寫:
組態檔由很多種寫法:
package.json 中 babel:不需要建立檔案,在原有檔案基礎上寫
presets 預設:
簡單理解:就是一組 Babel 外掛, 擴充套件 Babel 功能
@babel/preset-env: 一個智慧預設,允許您使用最新的 JavaScript。
@babel/preset-react:一個用來編譯 React jsx 語法的預設
@babel/preset-typescript:一個用來編譯 TypeScript 語法的預設
// 建立.babelrc.js
module.exports = {
presets: ["@babel/preset-env"],
};
webpack增加babel
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules程式碼不編譯
loader: "babel-loader",
},
安裝html-webpack-plugin
npm i html-webpack-plugin -D
webpack設定, 設定好後就會自動的引入所需的js了。
const HtmlWebpackPlugin = require("html-webpack-plugin");
plugins: [
new HtmlWebpackPlugin({
// 以 public/index.html 為模板建立檔案
// 新的html檔案有兩個特點:1. 內容和原始檔一致 2. 自動引入打包生成的js等資源
template: path.resolve(__dirname, "public/index.html"),
}),
]
使用webpacksever後,在開發時就能自動檢測檔案變化,並實時編譯展示出來了。
// 安裝
npm i webpack-dev-server -D
// 設定
devServer: {
host: "localhost", // 啟動伺服器域名
port: "3000", // 啟動伺服器埠號
open: true, // 是否自動開啟瀏覽器
},
執行:
// 此時不會打包生成檔案,都是在記憶體中進行編譯的
npx webpack serve
const path = require('path')
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// 入口 多入口則設定成物件形式
entry: "./src/main.js",
// 輸出 需使用絕對路徑
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'static/js/main.js', // 將js輸出到 static/js 目錄中
clean: true
},
// loader
module: {
rules: [
// 兩個loader順序按此 它會先使用後面的
{ test: /\.css$/i, use: ["style-loader", "css-loader"] },
// less-loader將less轉為css後還是要交給css-loader處理的
{ test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] },
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小於10kb的圖片會被base64處理
}
},
generator: {
// 將圖片檔案輸出到 static/imgs 目錄中
// 將圖片檔案命名 [hash:8][ext][query]
// [hash:6]: hash值取6位
// [ext]: 使用之前的副檔名
// [query]: 新增之前的query引數
filename: "static/imgs/[hash:6][ext][query]",
},
},
{
// 處理字型圖示或者視訊等其它資源
test: /\.(ttf|woff2?|map4|map3)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{ // babel設定
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules程式碼不編譯
loader: "babel-loader",
},
]
},
// 外掛
plugins: [
new ESLintWebpackPlugin({
// 指定檢查檔案的根目錄
context: path.resolve(__dirname, "src"),
}),
new HtmlWebpackPlugin({ // html處理的外掛
// 以 public/index.html 為模板建立檔案
// 新的html檔案有兩個特點:1. 內容和原始檔一致 2. 自動引入打包生成的js等資源
template: path.resolve(__dirname, "public/index.html")
})
],
devServer: {
host: "localhost", // 啟動伺服器域名
port: "666", // 啟動伺服器埠號
open: true, // 是否自動開啟瀏覽器
},
// development 或者 production
mode: "development"
}
SourceMap(原始碼對映)是一個用來生成原始碼與構建後程式碼一一對映的檔案的方案。
通過檢視Webpack DevTool檔案可知,SourceMap 的值有很多種情況.
開發時我們只需要關注兩種情況即可:
開發模式:cheap-module-source-map,優點:打包編譯速度快,只包含行對映,缺點:沒有列對映
生產模式:source-map,優點:包含行/列對映,缺點:打包編譯速度更慢。
設定:
devtool: "cheap-module-source-map",
HotModuleReplacement:它(HMR/熱模組替換):在程式執行中,替換、新增或刪除模組,而無需重新載入整個頁面。
module.exports = {
// 其他省略
devServer: {
host: "localhost", // 啟動伺服器域名
port: "3000", // 啟動伺服器埠號
open: true, // 是否自動開啟瀏覽器
hot: true, // 開啟HMR功能(只能用於開發環境,生產環境不需要了)
},
};
此時 css 樣式經過 style-loader 處理,已經具備 HMR 功能了。 但是 js 可以使用vue-loader, react-hot-loader實現。
OneOf設定(開發和正式都能用):
匹配到一條規則就不繼續匹配了
module: {
rules: [
{
oneOf: [
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
.........
]
}
]
}
Include/Exclude
如在設定babel排除node_moudels
資料夾
使用快取Cache
每次打包時 js 檔案都要經過 Eslint 檢查 和 Babel 編譯,速度比較慢。我們可以快取之前的 Eslint 檢查 和 Babel 編譯結果,這樣第二次打包時速度就會更快了
// babel
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules程式碼不編譯
include: path.resolve(__dirname, "../src"), // 也可以用包含
loader: "babel-loader",
options: {
cacheDirectory: true, // 開啟babel編譯快取
cacheCompression: false, // 快取檔案不要壓縮
},
},
// Eslint
new ESLintWebpackPlugin({
// 指定檢查檔案的根目錄
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 預設值
cache: true, // 開啟快取
// 快取目錄
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
})
打包啟用多執行緒:
開啟執行緒也需要時間,小專案可能提升不明顯。
npm i thread-loader -D
安裝loader,然後設定:
// nodejs核心模組,直接使用
const os = require("os");
const TerserPlugin = require("terser-webpack-plugin"); // webpack自帶的js壓縮模組
// cpu核數
const threads = os.cpus().length;
// babel使用多執行緒
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules程式碼不編譯
include: path.resolve(__dirname, "../src"), // 也可以用包含
use: [
{
loader: "thread-loader", // 開啟多程序
options: {
workers: threads, // 數量
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 開啟babel編譯快取
},
},
],
},
// Eslint使用多執行緒
new ESLintWebpackPlugin({
// 指定檢查檔案的根目錄
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 預設值
cache: true, // 開啟快取
// 快取目錄
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
threads, // 開啟多程序
}),
// js壓縮使用多執行緒
optimization: {
minimize: true,
minimizer: [
// css壓縮也可以寫到optimization.minimizer裡面,效果一樣的
new CssMinimizerPlugin(),
// 當生產模式會預設開啟TerserPlugin,但是我們需要進行其他設定,就要重新寫了
new TerserPlugin({
parallel: threads // 開啟多程序
})
],
},
Tree Shaking: 預設開啟,通常用於描述移除 JavaScript 中的沒有使用上的程式碼。
Babel優化:
@babel/plugin-transform-runtime: 禁用了 Babel 自動對每個檔案的 runtime 注入,而是引入 @babel/plugin-transform-runtime 並且使所有輔助程式碼從這裡參照。
// 安裝
npm i @babel/plugin-transform-runtime -D
// 設定
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 開啟babel編譯快取
cacheCompression: false, // 快取檔案不要壓縮
plugins: ["@babel/plugin-transform-runtime"], // 減少程式碼體積
},
},
打包程式碼分塊
Preload / prefetch
使用Core-js
使用PWA
使用的庫:
設定環境變數:
https://www.npmjs.com/package/cross-env
// 安裝
npm install --save-dev cross-env
// package.json
vue-loder檔案: https://vue-loader.vuejs.org/zh/
安裝vue-loader
npm i vue
npm install -D vue-loader vue-template-compiler
module: {
rules: [
// ... 其它規則
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// 請確保引入這個外掛!
new VueLoaderPlugin()
]
style-loader 替換為 vue-style-loader,並安裝前處理器loader
npm i -D css-loader vue-style-loader less-loader less-loader sass-loader stylus-loader
設定拓展名自動佈局
resolve: {
extensions: [".vue", ".js", ".json"], // 自動補全副檔名,讓vue可以使用
},
Eslint設定指定為vue的
npm i -D @babel/eslint-parser
// .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended"],
parserOptions: {
parser: "@babel/eslint-parser",
},
};
Bable設定
npm i -D @vue/cli-plugin-babel
// babel.config.js
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
};
提供對js的變數,解決頁面警告
// 解決頁面警告
new DefinePlugin({
__VUE_OPTIONS_API__: "true",
__VUE_PROD_DEVTOOLS__: "false",
}),
除了以上vue中專用的設定,然後加上less,scss的loader,把前面的html外掛加上去。就是一個基本的vue-cli了。完整的設定可以看最前面的倉庫連結。
如 elment plus 按需引入可參照其官網進行設定
https://yk2012.github.io/sgg_webpack5/
https://vue-loader.vuejs.org/zh/
https://webpack.docschina.org/