❝最近看一下webpack相關的內容,談一下如何編寫loader和plugincss
❞
相信你們對webpack也有必定的瞭解,其實深刻淺出webpack這本書也看了不少遍,每一次看都會有一些細節以前沒有注意到,我以爲其實能夠把它當成是一本工具書來看,以前我也是隻看配置都有點讓你看不過來,更別說其餘的了。html
因此今天我就說一下如何編寫一個loader與plugin,以及它們之間有什麼卻別等。vue
Loader其實就是一個轉換器,把你輸入的內容翻譯一遍,本質上是沒有什麼變化的,就像中文翻譯成英文同樣。咱們其實在不知不覺當中也使用了不少的Loader,可是咱們沒有過多關注而已。經常使用的Loader有如下幾類:node
「語言轉換類」webpack
babel-loader
:把ES6轉成ES5
ts-loader
:把TypeScript轉成JavaScript
sass-loader
:把scss/sass轉成css
less-loader
:把less代碼轉成css
css-loader
:加載css,文件導入等
「文件加載類」git
raw-loader
:把文本文件加載到代碼中
file-loader
:將文件輸出到一個文件夾中,使用相對路徑引用輸出文件
source-map-loader
:加載額外的SourceMap文件,方便斷點調試
node-loader
:加載Node.js原生模塊的.node文件
json-loader
:加載json文件
「其餘loader」github
vue-loader
:加載.vue文件
ui-component-loader
:按需加載組件庫
i18n-loader
:加載多語言版本
ignore-loader
:忽略部分文件
module.exports = {
module:{
rules:[
{
test:/\.scss/,
use:[
'style-loader',
{
'css-loader',
options:{
minimize:true
}
},
'sass-loader'
],
}
]
}
}
複製代碼
以上的代碼意思就是對.scss文件的轉換過程,test的配置就是對某一類文件進行轉換,use是使用的loader(轉換器),它是一個數組,遵循從右往左的使用。先sass-loader再css-loader再style-loader。web
咱們默認的loader都是從npm上面下載的,可是假如咱們要使用本身本地寫的loader怎麼辦呢?咱們在webpack裏面有這樣一個配置resolveLoader
,它的意思就是說咱們使用哪裏的loader來加載文件,能夠配置多個地方:面試
module.exports = {
resolveLoader:{
modules:['node_modules','yourPath']
}
}
複製代碼
意思就是說咱們能夠自定義loader的路徑,默認就是從node_modules裏面找,可是假如你的自定義loader放在本地,能夠把你的路徑寫在yourPath裏面(相對路徑)。匹配規則就是從左向右查找。npm
說了這麼多,咱們本身來寫一個簡單的loader吧,雖然是一個沒有意義的loader,可是也讓你們有一個簡單的印象,原來寫一個loader是很簡單的。
npm init -y
,
npm i -D webpack webpack-cli
src/index.js
loaders/myloader.js
webpack.config.js
package.json
{
"name": "myLoader",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
}
}
複製代碼
index.js
console.log('世界上最好的語言是PHP!')
複製代碼
myLoader.js
const loaderUtils = require('loader-utils');
module.exports = function (source) {
const options = loaderUtils.getOptions(this);
const result = source.replace('PHP', options.name);
return result;
}
複製代碼
webpack.config.js
const path = require("path");
module.exports = {
mode: "development",
entry: {
main: "./src/index.js",
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: path.resolve(__dirname, "./loaders/myLoader.js"),
options: {
name: "JavaScript",//這裏就是你要替換的值
},
},
},
],
},
};
複製代碼
好了,到此爲止咱們已經成功地寫了一個loader,接下來咱們就測試一下是否真的work!運行npm run build
以後會輸出一個dist文件夾,裏面有一個main.js文件,盤它。
相對於Loader來講,其實plugin的機制更加靈活,它能夠在webpack的運行過程當中改變輸出結果。簡單來講就是爲輸出添磚加瓦。
extract-text-webpack-plugin
:把JS中的css代碼提到單獨文件中
webpack-parallel-uglify-plugin
:多進程代碼壓縮
html-webpack-plugin
:簡化HTML文件建立
dll-plugin
:提升webpack構建速度
ignore-plugin
:忽略部分文件
咱們先來看一下簡單的插件是怎麼編寫出來的:
class myPlugin {
constructor(options){
}
apply(complier){
complier.plugin('compilation',function(compilation){
})
}
}
//導出
module.exports = myPlugin;
複製代碼
「工做流程」:
俗話說,talk is cheap,show me the code
仍是沿用上面的代碼結構,在根目錄下面建一個myPlugins文件夾,裏面建一個myPlugin.js文件,咱們就自定義一個plugin:
class myPlugin {
constructor(doneCallback, failCallback) {
this.doneCallback = doneCallback;
this.failCallback = failCallback;
}
apply(compiler) {
compiler.hooks.done.tap('myPlugin', (stats) => {
this.doneCallback(stats);
});
compiler.hooks.failed.tap('myPlugin', (err) => {
this.failCallback(err);
});
}
}
module.exports = myPlugin;
複製代碼
而後咱們在webpack.config.js
文件裏面先引入插件
,而後配置插件
便可。
仍是先打包一下,你會發如今打包過程當中,webpack會廣播默認的事件,這裏我就監聽了webpack的done事件
(webpack構建成功,即將退出)和fail事件
(webpack構建失敗,即將退出)。
const myPlugin = require("./plugins/myPlugin");
module.exports = {
plugins: [
new myPlugin(
() => {
//throw new Error('Error!')
console.log("成功監聽到結束事件,能夠執行你想要的函數!");
},
(error) => {
console.log(error);
}
),
],
}
複製代碼
咱們運行以後發現是能夠監聽的,這裏我把兩種狀況都試一下。首先正常構建,而後手動拋出錯誤,結果以下:
今天沒事就折騰一下看似簡單的東西,好比想看一下一些經典loader和plugin的源代碼,自信的我還想看一下webpack的源代碼,發現看不懂,就此打住了。
不過其實plugin和loader的區別也是面試常問的,也會問你知道怎麼寫loader和plugin的問題,雖然本身實現的很簡單甚至有點幼稚,本身感受還好。
相信你們讀了以後應該有本身的理解,之後遇到這個問題也會有本身的想法,你們實踐一下就知道其中的奧祕了。
參考文章:深刻淺出Webpack
文章代碼:https://github.com/wqs2019/myLoader