摘要:這個由提供的工具。在轉(zhuǎn)換步驟是異步時,你可以這樣告訴本次轉(zhuǎn)換是異步的,會在中回調(diào)結(jié)果通過返回異步執(zhí)行后的結(jié)果參考編寫一個
本文示例源代碼請戳github博客,建議大家動手敲敲代碼。
本文不會介紹loader的一些使用方法,不熟悉的同學(xué)請自行查看Webpack loader1、背景
首先我們來看一下為什么需要loader,以及他能干什么?
webpack 只能理解 JavaScript 和 JSON 文件。loader 讓 webpack 能夠去處理其他類型的文件,并將它們轉(zhuǎn)換為有效模塊,以供應(yīng)用程序使用,以及被添加到依賴圖中。
本質(zhì)上來說,loader 就是一個 node 模塊,這很符合 webpack 中「萬物皆模塊」的思路。既然是 node 模塊,那就一定會導(dǎo)出點什么。在 webpack 的定義中,loader 導(dǎo)出一個函數(shù),loader 會在轉(zhuǎn)換源模塊resource的時候調(diào)用該函數(shù)。在這個函數(shù)內(nèi)部,我們可以通過傳入 this 上下文給 Loader API 來使用它們。最終裝換成可以直接引用的模塊。
2、xml-Loader 實現(xiàn)前面我們已經(jīng)知道,由于 Webpack 是運行在 Node.js 之上的,一個 Loader 其實就是一個 Node.js 模塊,這個模塊需要導(dǎo)出一個函數(shù)。 這個導(dǎo)出的函數(shù)的工作就是獲得處理前的原內(nèi)容,對原內(nèi)容執(zhí)行處理后,返回處理后的內(nèi)容。
一個簡單的loader源碼如下
module.exports = function(source) { // source 為 compiler 傳遞給 Loader 的一個文件的原內(nèi)容 // 該函數(shù)需要返回處理后的內(nèi)容,這里簡單起見,直接把原內(nèi)容返回了,相當(dāng)于該 Loader 沒有做任何轉(zhuǎn)換 return source; };
由于 Loader 運行在 Node.js 中,你可以調(diào)用任何 Node.js 自帶的 API,或者安裝第三方模塊進(jìn)行調(diào)用:
const xml2js = require("xml2js"); const parser = new xml2js.Parser(); module.exports = function(source) { this.cacheable && this.cacheable(); const self = this; parser.parseString(source, function (err, result) { self.callback(err, !err && "module.exports = " + JSON.stringify(result)); }); };
這里我們事簡單實現(xiàn)一個xml-loader;
注意:如果是處理順序排在最后一個的 loader,那么它的返回值將最終交給 webpack 的 require,換句話說,它一定是一段可執(zhí)行的 JS 腳本 (用字符串來存儲),更準(zhǔn)確來說,是一個 node 模塊的 JS 腳本,所以我們需要用module.exports =導(dǎo)出。
整個過程相當(dāng)于這個 loader 把源文件
// 這里是 source 模塊
轉(zhuǎn)化為
// example.js module.exports = "這里是 source 模塊";
然后交給 require 調(diào)用方:
// applySomeModule.js var source = require("example.js"); console.log(source); // 這里是 source 模塊
寫完后我們要怎么在本地驗證呢?下面我們來寫個簡單的demo進(jìn)行驗證。
2.1、驗證首先我們創(chuàng)建一個根目錄xml-loader,此目錄下 npm init -y生成默認(rèn)的package.json文件 ,在文件中配置打包命令
"scripts": { "dev": "webpack-dev-server" },
之后npm i -D webpack webpack-cli,安裝完webpack,在根目錄 創(chuàng)建配置文件webpack.config.js
const path = require("path"); module.exports = { entry: "./src/index.js", output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js", }, module: { rules: [ { test: /.xml$/, use: ["xml-loader"], } ] }, resolveLoader: { modules: [path.join(__dirname, "/src/loader")] }, devServer: { contentBase: "./dist", overlay: { warnings: true, errors: true }, open: true } }
在根目錄創(chuàng)建一個src目錄,里面創(chuàng)建index.js,
import data from "./foo.xml"; function component() { var element = document.createElement("div"); element.innerHTML = data.note.body; element.classList.add("header"); console.log(data); return element; } document.body.appendChild(component());
同時還有一個foo.xml文件
Mary John Reminder dd Call Cindy on Tuesday dd
最后把上面的xml-loader放到src/loader文件夾下。
完整的demo源碼請看
最終我們的運行效果如下圖
至此一個簡單的webpack loader就實現(xiàn)完成了。當(dāng)然最終使用你可以發(fā)布到npm上。
3、一些議論知識補(bǔ)充 3.1、獲得 Loader 的 options當(dāng)我們配置loader時我們經(jīng)常會看到有這樣的配置
ules: [{ test: /.html$/, use: [ { loader: "html-loader", options: { minimize: true } }], }]
那么我們在loader中怎么獲取這寫配置信息呢?答案是loader-utils。這個由webpack提供的工具。下面我們來看下使用方法
const loaderUtils = require("loader-utils"); module.exports = function(source) { // 獲取到用戶給當(dāng)前 Loader 傳入的 options const options = loaderUtils.getOptions(this); return source; };
沒錯就是這么簡單。
3.2、加載本地 Loader1、path.resolve
可以簡單通過在 rule 對象設(shè)置 path.resolve 指向這個本地文件
{ test: /.js$/ use: [ { loader: path.resolve("path/to/loader.js"), options: {/* ... */} } ] }
2、ResolveLoader
這個就是上面我用到的方法。ResolveLoader 用于配置 Webpack 如何尋找 Loader。 默認(rèn)情況下只會去 node_modules 目錄下尋找,為了讓 Webpack 加載放在本地項目中的 Loader 需要修改 resolveLoader.modules。
假如本地的 Loader 在項目目錄中的 ./loaders/loader-name 中,則需要如下配置:
module.exports = { resolveLoader:{ // 去哪些目錄下尋找 Loader,有先后順序之分 modules: ["node_modules","./loaders/"], } }
加上以上配置后, Webpack 會先去 node_modules 項目下尋找 Loader,如果找不到,會再去 ./loaders/ 目錄下尋找。
3、npm link
npm link 專門用于開發(fā)和調(diào)試本地 npm 模塊,能做到在不發(fā)布模塊的情況下,把本地的一個正在開發(fā)的模塊的源碼鏈接到項目的 node_modules 目錄下,讓項目可以直接使用本地的 npm 模塊。 由于是通過軟鏈接的方式實現(xiàn)的,編輯了本地的 Npm 模塊代碼,在項目中也能使用到編輯后的代碼。
完成 npm link 的步驟如下:
確保正在開發(fā)的本地 npm 模塊(也就是正在開發(fā)的 Loader)的 package.json 已經(jīng)正確配置好;
在本地 npm 模塊根目錄下執(zhí)行 npm link,把本地模塊注冊到全局;
在項目根目錄下執(zhí)行 npm link loader-name,把第2步注冊到全局的本地 Npm 模塊鏈接到項目的 node_moduels 下,其中的 loader-name 是指在第1步中的package.json 文件中配置的模塊名稱。
鏈接好 Loader 到項目后你就可以像使用一個真正的 Npm 模塊一樣使用本地的 Loader 了。(npm link不是很熟,復(fù)制被人的)
3.3、緩存加速在有些情況下,有些轉(zhuǎn)換操作需要大量計算非常耗時,如果每次構(gòu)建都重新執(zhí)行重復(fù)的轉(zhuǎn)換操作,構(gòu)建將會變得非常緩慢。 為此,Webpack 會默認(rèn)緩存所有 Loader 的處理結(jié)果,也就是說在需要被處理的文件或者其依賴的文件沒有發(fā)生變化時, 是不會重新調(diào)用對應(yīng)的 Loader 去執(zhí)行轉(zhuǎn)換操作的。
如果你想讓 Webpack 不緩存該 Loader 的處理結(jié)果,可以這樣:
module.exports = function(source) { // 關(guān)閉該 Loader 的緩存功能 this.cacheable(false); return source; };3.4、處理二進(jìn)制數(shù)據(jù)
在默認(rèn)的情況下,Webpack 傳給 Loader 的原內(nèi)容都是 UTF-8 格式編碼的字符串。 但有些場景下 Loader 不是處理文本文件,而是處理二進(jìn)制文件,例如 file-loader,就需要 Webpack 給 Loader 傳入二進(jìn)制格式的數(shù)據(jù)。 為此,你需要這樣編寫 Loader:
module.exports = function(source) { // 在 exports.raw === true 時,Webpack 傳給 Loader 的 source 是 Buffer 類型的 source instanceof Buffer === true; // Loader 返回的類型也可以是 Buffer 類型的 // 在 exports.raw !== true 時,Loader 也可以返回 Buffer 類型的結(jié)果 return source; }; // 通過 exports.raw 屬性告訴 Webpack 該 Loader 是否需要二進(jìn)制數(shù)據(jù) module.exports.raw = true;
以上代碼中最關(guān)鍵的代碼是最后一行 module.exports.raw = true;,沒有該行 Loader 只能拿到字符串。
3.5、同步與異步Loader 有同步和異步之分,上面介紹的 Loader 都是同步的 Loader,因為它們的轉(zhuǎn)換流程都是同步的,轉(zhuǎn)換完成后再返回結(jié)果。 但在有些場景下轉(zhuǎn)換的步驟只能是異步完成的,例如你需要通過網(wǎng)絡(luò)請求才能得出結(jié)果,如果采用同步的方式網(wǎng)絡(luò)請求就會阻塞整個構(gòu)建,導(dǎo)致構(gòu)建非常緩慢。
在轉(zhuǎn)換步驟是異步時,你可以這樣:
module.exports = function(source) { // 告訴 Webpack 本次轉(zhuǎn)換是異步的,Loader 會在 callback 中回調(diào)結(jié)果 var callback = this.async(); someAsyncOperation(source, function(err, result, sourceMaps, ast) { // 通過 callback 返回異步執(zhí)行后的結(jié)果 callback(err, result, sourceMaps, ast); }); };
參考
編寫一個webpack loader
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/103821.html
摘要:這里是里面的內(nèi)容安裝如果速度太慢,建議使用淘寶的,和的區(qū)別建議去了解一下。安裝以及相關(guān)插件使用加載器繼續(xù)修改里面的內(nèi)容,給對象加一個屬性。 很多人剛學(xué)習(xí)react的時候,往往因為繁瑣的配置而頭疼,這里我將手把手教大家怎么用webpack配置react和redux的環(huán)境,這篇教程包括前端react和后臺node整個網(wǎng)站的環(huán)境配置,對node沒興趣的可以只看這篇。這里是下篇鏈接:手把手教你...
摘要:這里是里面的內(nèi)容安裝如果速度太慢,建議使用淘寶的,和的區(qū)別建議去了解一下。安裝以及相關(guān)插件使用加載器繼續(xù)修改里面的內(nèi)容,給對象加一個屬性。 很多人剛學(xué)習(xí)react的時候,往往因為繁瑣的配置而頭疼,這里我將手把手教大家怎么用webpack配置react和redux的環(huán)境,這篇教程包括前端react和后臺node整個網(wǎng)站的環(huán)境配置,對node沒興趣的可以只看這篇。這里是下篇鏈接:手把手教你...
摘要:有沒有辦法實現(xiàn)就局部刷新呢當(dāng)然是有第十步執(zhí)行為了實現(xiàn)局部熱加載,我們需要添加插件。 前言 用了3個多月的vue自認(rèn)為已經(jīng)是一名合格的vue框架api搬運工,對于vue的api使用到達(dá)了一定瓶頸,無奈水平有限,每每深入底層觀賞源碼時候都迷失了自己。 遂決定再找個框架學(xué)習(xí)學(xué)習(xí)看看能否突破思維局限,加上本人早已對React、RN技術(shù)垂涎已久,于是決定找找教程來學(xué)習(xí)。無奈第一步就卡在了環(huán)境搭...
摘要:夾在中間的被鏈?zhǔn)秸{(diào)用,他們拿到上個的返回值,為下一個提供輸入。最終把返回值和傳給。前面我們說過,也是一個模塊,它導(dǎo)出一個函數(shù),該函數(shù)的參數(shù)是的源模塊,處理后把返回值交給下一個。 文:小 boy(滬江網(wǎng)校Web前端工程師)本文原創(chuàng),轉(zhuǎn)載請注明作者及出處 showImg(https://segmentfault.com/img/remote/1460000012990131?w=1083...
閱讀 803·2021-11-24 09:38
閱讀 1005·2021-11-11 11:01
閱讀 3249·2021-10-19 13:22
閱讀 1536·2021-09-22 15:23
閱讀 2840·2021-09-08 09:35
閱讀 2777·2019-08-29 11:31
閱讀 2130·2019-08-26 11:47
閱讀 1575·2019-08-26 11:44