今天為大家?guī)?lái)一篇前端技術(shù)文章,其實(shí)也是想給那些不僅希望解決問(wèn)題,也想知道問(wèn)題出現(xiàn)的原因的”鉆牛角尖“程序猿刨析一下,抹掉你腦袋的種種“疑問(wèn)”!

遇到這個(gè)問(wèn)題的概率可能很小,當(dāng)然了能夠出現(xiàn)這個(gè)疑問(wèn),證明你已經(jīng)開(kāi)始對(duì)你的技術(shù)進(jìn)行提升,并希望通過(guò)更便捷的方式來(lái)提升效率。

是怎么遇到這個(gè)問(wèn)題的呢?

前提:

1、基于vue-cli腳手架創(chuàng)建的Vue工程

2、只有一個(gè).vue文件包含/deep/透?jìng)髡Z(yǔ)法

整體來(lái)講一下,是因?yàn)閚ode-sass這個(gè)css編譯器目前官方已經(jīng)宣布停止更新了,并建議切換到dart-sass編譯器,所以整個(gè)前端工程需要升級(jí)一下這個(gè)編譯器,切換到dart-sass上面。

整體來(lái)說(shuō),升級(jí)切換到dart-sass并不難,因?yàn)槲覀冎恍枰獔?zhí)行一下下面的命令:

npm uninstall node-sass;

npm install sass -D;

然后很開(kāi)心的就執(zhí)行了:npm run serve;

結(jié)果編譯失敗,并沒(méi)有成功運(yùn)行:

一般解決辦法:

很明顯,在.vue文件當(dāng)中,我們?cè)谶M(jìn)行樣式透?jìng)鞯臅r(shí)候,采用了/deep/語(yǔ)法,而dart-sass并不支持,但是dart-sass是支持::v-deep語(yǔ)法的。

那么我們第一時(shí)間能夠想到的就是全部手動(dòng)打開(kāi)文件將所有/deep/替換成::v-deep,來(lái)進(jìn)行解決。

不過(guò)這種辦法可以說(shuō)非常緩慢,要知道我們的項(xiàng)目可能已經(jīng)累積到成千上百個(gè)文件,每一個(gè)打開(kāi)都需要進(jìn)行替換,是非常耗費(fèi)時(shí)間和精力的。

當(dāng)然了有些同學(xué)或許會(huì)采用工具進(jìn)行文件目錄下對(duì)文件整體替換,這也是一種解決辦法。

但是他們最終都會(huì)導(dǎo)致之前的所有代碼都需要更改變動(dòng),那么有沒(méi)有什么辦法在不改動(dòng)原有代碼的情況下,實(shí)現(xiàn)語(yǔ)法的替換呢?甚至說(shuō),我們依然可以采用原有的/deep/語(yǔ)法來(lái)寫(xiě),但是最終編譯的時(shí)候自動(dòng)轉(zhuǎn)換為::v-deep?

Webpack自定義Loader預(yù)處理器解決辦法

.vue文件之所以能夠被webpack處理,是因?yàn)樗衯ue-loader預(yù)處理器,可以將.vue文件進(jìn)行編譯,轉(zhuǎn)換成js,而且每一個(gè)預(yù)處理是可以進(jìn)行級(jí)聯(lián)調(diào)用的,前一個(gè)loader輸出的內(nèi)容可以作為下一個(gè)loader的內(nèi)容傳入進(jìn)去。

所以我們可以采用自定義loader的方法,來(lái)實(shí)現(xiàn)上面的進(jìn)行自動(dòng)替換,于是我就寫(xiě)了一個(gè)非常簡(jiǎn)單的預(yù)處理器Loader,通過(guò)正則表達(dá)式來(lái)匹配文件內(nèi)容,如果包含/deep/我們就對(duì)內(nèi)容進(jìn)行替換,然后返回替換后的內(nèi)容。

第一步:新建一個(gè)preSassLoader.js處理器

constloaderUtils=require('loader-utils');
module.exports=function(content,map,meta){
if(/\/deep\//g.test(content)){
console.log('找到含有/deep/的文件');
content=content.replace(/\/deep\//,'::v-deep');
}
returncontent;
};

第二步:在vue.config.js文件中,我們?cè)黾訉?duì).vue文件的自定義loader處理器

chainWebpack:}

第三步:?jiǎn)?dòng)工程項(xiàng)目

執(zhí)行:npm run serve;

結(jié)果是編譯成功,一般來(lái)說(shuō),到這兒其實(shí)就算是解決了上面自動(dòng)替換的需求,但是我們有沒(méi)有發(fā)現(xiàn)圖中標(biāo)出的4個(gè)紅框中的內(nèi)容,這個(gè)自定義preSassLoader其實(shí)對(duì)于同一個(gè).vue文件來(lái)說(shuō)執(zhí)行了4次,(本項(xiàng)目為測(cè)試項(xiàng)目,只有一個(gè).vue文件當(dāng)中有/deep/語(yǔ)法)

對(duì)于講究效率的我來(lái)說(shuō),這是難以接受的,一個(gè)文件只需要替換一次就夠了,不用執(zhí)行這么多遍,所以我就開(kāi)始分析為什么走了4遍?

我開(kāi)始在網(wǎng)上搜索,這個(gè)內(nèi)容可以說(shuō)少之又少,不過(guò)也有人提出了這樣的疑問(wèn),不過(guò)并沒(méi)有人來(lái)為他解答,不知道那個(gè)提問(wèn)的人現(xiàn)在心中的疑問(wèn)消除了沒(méi)?

不過(guò)我仔細(xì)一想也基本就能理解了,很少有人會(huì)這樣自定義一個(gè)loader來(lái)進(jìn)行處理吧,大部分人都采用第一種解決辦法就完事了。

既然網(wǎng)上找不到,那就只能自己進(jìn)行分析了,開(kāi)啟Debug

通過(guò)vscode配置npm 調(diào)試模式:

通過(guò)觀察分析,我們發(fā)現(xiàn)在我們自定義loader處理器里面有個(gè)resourceQuery字段是不一樣的

那么我們?cè)黾右粋€(gè)輸出,將resourceQuery進(jìn)行打印

從上圖紅框中,我們就不難發(fā)現(xiàn),4次的resourceQuery已經(jīng)解釋了,其實(shí)一個(gè).vue單文件當(dāng)中,有3大塊,template模板,script,和style,構(gòu)成了一個(gè)頁(yè)面所需的元素,而vue-loader就是對(duì)這個(gè).vue單文件進(jìn)行編譯轉(zhuǎn)換,而多出來(lái)的那個(gè)處理應(yīng)該是cache-loader,也就是說(shuō)對(duì)于一個(gè).vue文件來(lái)說(shuō),會(huì)生成四種請(qǐng)求鏈接:

1、test.vue

2、test.vue?vue&type=template&id=fac91d24&scoped=true&

3、test.vue?vue&type=script&lang=js&

4、test.vue?vue&type=style&index=0&id=fac91d24&scoped=true&lang=scss&

所以我們可以通過(guò)resourceQuery來(lái)進(jìn)行過(guò)濾處理,此處我們用/type=style/來(lái)進(jìn)行過(guò)濾

加上過(guò)濾條件后,這個(gè)真的就執(zhí)行一次了。

你以為到這兒就完事了?還差得遠(yuǎn)呢!?。?/p>

雖然我們的處理邏輯執(zhí)行了一遍,但是你有沒(méi)有發(fā)現(xiàn),其實(shí)進(jìn)入到這個(gè)preSassLoader的.vue請(qǐng)求是一個(gè)也沒(méi)有減少,我們其實(shí)只需要一個(gè).vue文件只進(jìn)入一次就可以了,而不是這一個(gè)文件的4次不同請(qǐng)求都被這個(gè)預(yù)處理器接收到。

這是因?yàn)槲覀冊(cè)谂渲米远xpreSassLoader的時(shí)候,捕獲的是.vue文件而沒(méi)有匹配resourceQuery后面的請(qǐng)求串,導(dǎo)致只要是.vue?xxx的請(qǐng)求這個(gè)預(yù)處理器都能接收到。

所以我們自己新建一個(gè)rule規(guī)則來(lái)進(jìn)行精確匹配:

在vue.config.js中注釋掉之前的匹配:

chainWebpack:config=>{
//注釋掉
//config.module
//.rule('vue')
//.use('preSassLoader')
//.loader('./src/loaders/preSassLoader');
config.module
.rule('preDeep')
.test(/\.vue$/)
.use('preSassLoader')
.loader('./src/loaders/preSassLoader');
}

就暫時(shí)到這兒吧,希望可以解答遇到這個(gè)問(wèn)題時(shí)候的你的疑問(wèn)!