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