style-loader為什么要使用pitch方法原理解析
loader
loader是一個函數(shù),loader模塊要默認導出該函數(shù),同時這個函數(shù)上可以有pitch方法,webpack會執(zhí)行這個pitch方法,pitch方法會影響webpack后續(xù)行為。
loader的作用是將源文件轉(zhuǎn)化為可以執(zhí)行的js模塊,webpack會檢查loader返回的這個模塊是否是正確的,符合js模塊化規(guī)范,如果有錯誤會終止打包。例如我定義了一個test.js
模塊,其默認導出一個函數(shù):
test.js
module.exports = function (a, b) { return a+b; }
然后定義一個test-loader
,讓其只會匹配test.js
:
module.exports = function (content) { return `var a = {name: 'wjl'}; module.exports = a;` }
test-loader
返回了一段新的代碼,默認導出一個對象,在index.js
中我們導入test.js
模塊,嘗試輸出對象上的name
屬性,然后通過webpack
打包:
const a = require('./test.js') console.log(a.name)
打包結(jié)果為main.js
,運行main.js
可以正確得到輸出。這說明webpack
執(zhí)行了var a = {name: 'wjl'}; module.exports = a;
,test.js
模塊最終導出的內(nèi)容為a
。
當把test-loader
的導出語句刪除,改為以下內(nèi)容時,能夠正確通過webpack
檢查,但是index.js
中不能訪問導出對象了:
test-loader.js
module.exports = function (content) { // return `var a = {name: 'wjl'}; console.log(123); module.exports = a;` return `var a = {name: 'wjl'}; console.log(123);` }
index.js
const a = require('./test.js') console.log(a, a.name)
運行導出文件main.js
得到
這是由于這個模塊沒有導出內(nèi)容(對象上沒有屬性),test.js
的模塊代碼會在運行時執(zhí)行(輸出123,cjs的模塊需要執(zhí)行完模塊內(nèi)容才能得到導出對象)。
(如果loader
導出的內(nèi)容中含有import
或require
等語句,webpack
會再次進行相關(guān)內(nèi)容的導入,這方面的知識目前暫時不分析)
loader總結(jié):loader
的作用是將準備導入的模塊里面的內(nèi)容轉(zhuǎn)換成可以正常執(zhí)行的js
模塊代碼,轉(zhuǎn)換后的內(nèi)容會在運行時執(zhí)行,以得到模塊的導出內(nèi)容或執(zhí)行其他副作用代碼。
pitch
為什么需要使用pitch?我們以css-loader
和style-loader
作為分析。
在只使用css-loader
的情況下,假設(shè)我們有兩個文件:index.css
和index.js
,index.css
定義了一些樣式,index.js
導入了index.css
:
index.css
:
body { font-size: 16px; color: red; }
index.js
:
const style = require('./index.css') console.log(style);
運行結(jié)果為:
css-loader
將目標樣式文件轉(zhuǎn)換成一個js對象并導出了該對象,默認屬性上有index.css
文件的信息。
需要注意的是,這個對象是執(zhí)行完css-loader
轉(zhuǎn)換的模塊內(nèi)容后得到的!我們先定義一個普通的my-style-loader
根據(jù)調(diào)用順序拿到css-loader
的返回值:
my-style-loader
:
module.exports = function (source) { console.log('*******************'); console.log(source); console.log('*******************'); return source; }
css-loader
將index.css
模塊轉(zhuǎn)換為以下內(nèi)容:
// Imports import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from "./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/runtime/noSourceMaps.js"; import ___CSS_LOADER_API_IMPORT___ from "./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/runtime/api.js"; var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___); // Module ___CSS_LOADER_EXPORT___.push([module.id, "body {\r\n font-size: 16px;\r\n color: red;\r\n}", ""]); // Exports export default ___CSS_LOADER_EXPORT___; ?
也就是說,index.css
里面的內(nèi)容,還是要執(zhí)行完index.css
模塊才能得到
使用style-loader
的目的是往document
中插入style
標簽,如果style-loader
是一個普通loader
的話,它需要執(zhí)行css-loader
返回的模塊才能得到css
樣式,當然可以解析css-loader
返回的模塊內(nèi)容,然后得到樣式,然后返回創(chuàng)建style
標簽的相關(guān)語句,但是這樣工作量太大了。而返回的模塊中有import
相關(guān)的語句時,webpack
還會加載那些import的內(nèi)容,但是例如./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/runtime/api.js
是會被webpack
最終打包生成的模塊,在nodejs環(huán)境中是無法得到的。
打包產(chǎn)物:
一個模塊加載(import '!!xxxx-loader!./index.css')被webpack
打包之后會添加到module map
里面,鍵就是請求路徑。
style-loader
的思路就是,得到css-loader
的模塊內(nèi)容,然后再將模塊內(nèi)容插入到style
標簽中,再將style
標簽插入文檔中。
為了得到css-loader
處理后的內(nèi)容(需要能被執(zhí)行),style-loader
構(gòu)造了一個新的require
語句,即:
require(`${loaderUtils.stringifyRequest(this, '!!' + remainingRequest)}`) // !!./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/cjs.js!./index.css
webpack
發(fā)現(xiàn)返回的內(nèi)容中有模塊導入,然后使用路徑中的loader
去加載這個模塊,并將其保存在內(nèi)存中(多個文件引用同一個模塊,目標模塊只會被處理一次)。
總結(jié)
loader
和picher
本質(zhì)上都是改變目標文件的內(nèi)容,讓它變成符合js語法的代碼,如果返回的內(nèi)容有不存在的導入,則會再次執(zhí)行導入。
webpack
每個loader
處理的結(jié)果都會生成單獨的模塊,但是在loader
函數(shù)中,它無法之前使用了哪些loader,也無法知道已生成模塊的名字,因此style-loader
無法在loader
函數(shù)中導入已經(jīng)生成的模塊。
而pitch
階段可以獲取到之后的loader
順序,實現(xiàn)起來也更加方便。
以上就是style-loader為什么要使用pitch方法原理解析的詳細內(nèi)容,更多關(guān)于style-loader使用pitch方法的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
才發(fā)現(xiàn)的超鏈接js導致網(wǎng)頁中GIF動畫停止的解決方法
才發(fā)現(xiàn)的超鏈接js導致網(wǎng)頁中GIF動畫停止的解決方法...2007-11-11JS導入本地json文件數(shù)據(jù)的三類方法舉例講解
作為一名剛?cè)胄械拈_發(fā)者,你可能會遇到需要在JavaScript中引用JSON文件的情況,下面這篇文章主要給大家介紹了關(guān)于JS導入本地json文件數(shù)據(jù)的三類方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-09-09用云開發(fā)Cloudbase實現(xiàn)小程序多圖片內(nèi)容安全監(jiān)測的代碼詳解
這篇文章主要介紹了用云開發(fā)Cloudbase實現(xiàn)小程序多圖片內(nèi)容安全監(jiān)測,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06輕松實現(xiàn)javascript數(shù)據(jù)雙向綁定
這篇文章教大家輕松實現(xiàn)javascript數(shù)據(jù)雙向綁定,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2015-11-11使用post方法實現(xiàn)json往返傳輸數(shù)據(jù)的方法
今天小編就為大家分享一篇關(guān)于使用post方法實現(xiàn)json往返傳輸數(shù)據(jù)的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03iview通過Dropdown(下拉菜單)實現(xiàn)的右鍵菜單
這篇文章主要介紹了iview通過Dropdown(下拉菜單)實現(xiàn)的右鍵菜單 ,需要的朋友可以參考下2018-10-10JavaScript獲取當前網(wǎng)頁標題(title)的方法
這篇文章主要介紹了JavaScript獲取當前網(wǎng)頁標題(title)的方法,涉及javascript中document.title方法的使用,需要的朋友可以參考下2015-04-04關(guān)于JavaScript中高階函數(shù)的魅力詳解
高階函數(shù):英文叫Higher-order function。JavaScript的函數(shù)其實都指向某個變量。下面這篇文章主要給大家介紹了關(guān)于JavaScript中高階函數(shù)的魅力,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2018-09-09