前言
大家好,之前出了一篇面試篇webpack入門,這篇文章繼續介紹接下來更深入東西。
概覽
- 如何載入自己的loader
- 使用loader-utils,schema-utils
- 編寫自己的loader
- 擴充套件
如何載入自己的loader
講道理大家都是直接import一個loader或者使用webpack內建的loader的。
如果除錯自己的loader,應該如下寫法:
//webpack.config.js
const path = require("path");
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: path.resolve("loader.js"),
options: {
test: 'apple'
}
}
]
}
]
}
};
複製程式碼
其實和正常載入loader一樣,只是這裡指向的是本地檔案的路徑。
path.resolve('loader.js') 得出路徑
/Users/kev1nzh/Desktop/my/webpack/loader.js
使用單個loader
在使用一個loader的時候,loader會接收你正則匹配的資原始檔(如上,所有js檔案)的字串。
loader通過程式碼轉化模組後,最後返回傳遞出去。
複製程式碼
使用多個loader
-
當使用多個loader的時候,從傳入loader陣列的最後一個開始反向傳入資原始檔字串。
-
最後一個loader接收最原始的資原始檔字串,轉化後傳入下一個lodaer。
-
中間的loader接收上一個loader,轉化後傳入下一個。
-
第一個loader最後接收轉化,並傳出所有loader處理完的資原始檔字串。
{
test: /\.css$/,
use: [
{
loader: 'css-loader'
},
{
loader: 'style-loader'
},
]
}
//style-loader接收所有css的檔案,轉化完再傳給css-loader,轉化完後再懟出來。
複製程式碼
使用loader-utils,schema-utils
loader-utils, schema-utils是webpack的loader工具庫,有很多便捷的方法可以呼叫。
const { getOptions,stringifyRequest, parseQuery } = require("loader-utils");
const validateOptions = require("schema-utils");
const schema = {
type: "object",
properties: {
test: {
type: "string"
}
}
};
module.exports = function(source) {
//getOptions 用於在loader裡獲取傳入的options,返回的是物件值。
const options = getOptions(this);
// stringifyRequest轉換路徑,避免require()或impot時使用的絕對路徑
stringifyRequest(this, "./test.js"); // Result => "\"./test.js\""
//parseQuery獲取query引數的,這個很簡單就不說啦
parseQuery('?name=kev&age=14') // Result => {name: 'kev', age: '14'}
//驗證引數的型別是否正確。
validateOptions(schema, options, "loader");
};
複製程式碼
編寫自己的loader
總算到手寫環節了!!!!
//webapck.config.js
const path = require("path");
module.exports = {
entry: "./src",
output: {
path: path.resolve(__dirname, "dist"),
filename: "package.js"
},
mode: "production",
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: path.resolve("loader.js"),
options: {
work: '996',
sick: 'ICU',
}
}
]
}
]
}
};
複製程式碼
首先載入工具庫,為了後續使用。
第一步先驗證options是否符合型別,
第二步獲取引數,然後替換傳入的資原始檔字串。
//loader.js
const { getOptions } = require("loader-utils");
const validateOptions = require("schema-utils");
const schema = {
type: "object",
properties: {
work: {
type: 'String'
},
sick: {
type: 'String'
}
}
};
module.exports = function(source) {
const options = getOptions(this);
validateOptions(schema, options, 'loader');
const {work, sick} = options;
source = source.replace(/\[work\]/g, work).replace(/\[sick\]/g, sick);
return `export default ${JSON.stringify(source)}`;
};
複製程式碼
展示下要轉換的js。
// src/index.js
console.log('工作[work] 生病[sick] 加班不規範 親人兩行淚');
複製程式碼
最後在命令列,webpack!!!!!
擴充套件
webpack是如何執行的?
const index = require('./index');
const console = require('./console');
//index.js
const axios = require('./scripts/debounce.js'');
const moment = require('moment');
// do something
複製程式碼
- webpack會解析所有模組,如果模組中有依賴其他檔案,那就繼續解析依賴的模組。直到檔案沒有依賴為止。
- 解析結束後,webpack會把所有模組封裝在一個函式裡,並放入一個名為modules的陣列裡。
- 將modules傳入一個自執行函式中,自執行函式包含一個installedModules物件,已經執行的程式碼模組會儲存在此物件中。
- 最後自執行函式中載入函式(webpack__require)載入模組。
分離程式碼
// ./src/moment.js
const moment = require('moment');
console.log(moment().format('MMMM Do YYYY, h:mm:ss a'))
// ./index.js
const momentJs = require('./src/moment');
console.log(123);
複製程式碼
如上程式碼,我們打包一下試試看。
兩個檔案有依賴關係,所以打包後,都會把moment模組打包進去。SplitChunksPlugin
webpack4.x的分離程式碼方法,之前的CommonsChunkPlugin外掛已被移除。 此模組開箱即用,預設情況下,它僅影響按需塊,因為更改初始塊會影響HTML檔案應包含的指令碼標記以執行專案。
webpack將根據以下條件自動拆分塊:
- 可以共享新塊或來自該node_modules資料夾的模組
- 新塊將大於30kb(在min + gz之前)
- 根據需要載入塊時的最大並行請求數將小於或等於5
- 初始頁面載入時的最大並行請求數將小於或等於3
- 當試圖滿足最後兩個條件時,首選更大的塊。
讓我們看下程式碼如何實現!
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'initial', //選擇哪些模組需要優化, 引數為 all、async、initial
minSize: 30000, // 要生成的塊的最小數
maxSize: 0, //要生成的塊的最大數
minChunks: 2, // 分割前共享模組的最小塊數
maxAsyncRequests: 5, //按需載入時的最大並行請求數
maxInitialRequests: 3, // 入口的最大並行請求數
automaticNameDelimiter: '~', //指定生成檔名當中的分隔符
name: true, //拆分塊的名稱
cacheGroups: { //快取組
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};
複製程式碼
好了這篇需要講的東西已經結束了。
面試系列第一篇: 面試官:你知道Callback Hell(回撥地獄)嗎?
面試系列第二篇: 面試官:react和vue有什麼區別嗎?
面試系列第三篇: 面試官:你瞭解es6的知識嗎?
面試系列第四篇: 面試官:你瞭解Webpack嗎?