直接上例子,簡單易懂!
創建一個demo(make_loader)
- 新建一個文件,名字爲make_loader
- 在make_loader目錄下初始化項目:npm init -y
- 安裝webpack、webpack-li:npm i webpack webpack-cli -D
- 在make_loader目錄下新建src目錄,寫業務代碼
- 在make_loader目錄下新建一個loaders文件夾,用來書寫loader代碼
- 在make_loader目錄下新建webpack.config.js配置文件
目錄結構如下:
|--make_loader
|--node_modules
|--src
|--index.js
|--loaders
|--replaceLoader.js
|--package-lock.json
|--package.json
|--webpack.config.js
src/index.js中的業務代碼:
console.log('hello xiaochengzi');
在loaders/replaceLoader.js文件裏書寫我們的loader代碼:
module.exports = function(source) { // 這裏不能用箭頭函數
return source.replace('xiaochengzi', this.query.name);
}
- loader對外暴露的函數,切記不能使用箭頭函數。因爲在這個函數裏,我們會用到this指向,webpack在調用loader的時候,會把this做一些變更。變更之後才能用this裏的一些方法,如果寫成箭頭函數,這裏的this指向就會有問題,所以這裏的function一定是聲明式的function
- 參數source爲我們引入文件的源代碼
- 在這裏拿到代碼之後,就可以把代碼做一個變更,然後再返回出去
- 可以通過this.query取到傳遞的options內的一些參數
在webpack.config.js中做loader的使用配置:
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.js/,
use: [
{
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
options: {
name: 'world' // 傳遞給loader的參數
}
}
] // 使用自己寫的loader模塊
}]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
- 在module中配置loader使用規則
- 在options中傳遞loader參數
執行打包:npm run build
打包後的文件爲:hellow world
由此可見,我們在業務代碼中打印的 ‘hello xiaochengzi’ 通過我們編寫的loader替換成了 ‘hello world’。
到此,一個最最簡單的loader就編寫好了~
————————— ?———————————
loader中常用的API
使用loader-utils分析參數:
// loader-utils模塊需要單獨使用npm下載安裝
const loaderUtils = require('loader-utils');
module.exports = function(source) {
// 使用loader-utils中的getOptions接收loader參數
const options = loaderUtils.getOptions(this);
return source.replace('xiaochengzi', options.name);
}
callback的使用:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
const result = source.replace('xiaochengzi', options.name);
this.callback(null, result);
}
對於callback回調函數,官方解釋是這樣的:
如果loader裏要寫一些異步的代碼的時候,需要先聲明:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
const callback = this.async(); // 聲明一下異步操作
setTimeout(() => {
const result = source.replace('xiaochengzi', options.name);
callback(null, result); // 在回調裏返回結果
}, 1000)
}
- 使用 this.async() 進行異步聲明操作。
更多loader-API請參考官方文檔:loader-API
編寫打包多個loader時webpack.config.js配置:
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.js/,
use: [
{
loader: path.resolve(__dirname, './loaders/replaceLoader.js')
},
{
loader: path.resolve(__dirname, './loaders/replaceLoaderAsync.js'),
options: {
name: 'world'
}
}
] // 使用自己寫的loader模塊
}]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
- 由於loader從下向上執行,所以先執行replaceLoaderAsync.js,再執行replaceLoader.js。
在loaders文件夾下新增replaceLoaderAsync.js文件:(第一個loader)
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
const callback = this.async(); // 聲明一下異步操作
setTimeout(() => {
const result = source.replace('xiaochengzi', options.name);
callback(null, result);
}, 1000)
}
- 使用異步代碼把我們打印的信息從 ‘hello xiaochengzi’ 替換爲 ‘world’.
./loaders/replaceLoader.js: (第二個loader)
module.exports = function(source) {
return source.replace('world', 'ranran')
}
再次執行打包:npm run build
- 根據配置好的loader,我們打印的信息將通過replaceLoaderAsync.js從 ‘hello xiaochengzi’ 替換爲 ‘hello world’ ,最終再通過replaceLoader.js替換爲 ‘hello ranran’。
知識補充
當配置多個自己編寫的loader時,每次都需要使用path.resolve來指定路徑讀取loader,如:
其實,我們可以通過其他配置,去除這部分冗餘代碼:(如)
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
resolveLoader: {
modules: ['node_modules', './loaders']
}, // 當你去使用loader的時候,它會幫你去做一些事情
module: {
rules: [{
test: /\.js/,
use: [
{
loader: 'replaceLoader'
},
{
loader: 'replaceLoaderAsync',
options: {
name: 'world'
}
}
] // 使用自己寫的loader模塊
}]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
- webpack中的 resolveLoader 當你去使用loader的時候,它會幫你去做一些事情
- modules: [‘node_modules’, ‘./loaders’] 指當你使用loader的時候,webpack首先會去node_modules文件夾下找對應的loader模塊,如果找不到就會去loaders文件夾下去找。
執行打包:npm run build
最終打印爲 ‘hello ranran’ ,成功執行。
總結:loader在我們項目開發中的用處還是比較大的,比如:代碼的異常捕獲、中英文網站的切換等。