webpack的loader和plugin

loader

webpack loader: loader本質(zhì)上是一個(gè)函數(shù),它的作用是將某個(gè)源碼字符串轉(zhuǎn)換成另一個(gè)源碼字符串返回。

loader函數(shù)將在模塊解析的過(guò)程中被調(diào)用,以得到最終的源碼。按照l(shuí)oader配置的書(shū)寫(xiě)順序, 多個(gè)loader從后往前依次調(diào)用, 后面一個(gè)loader的輸出結(jié)果傳入前一個(gè)loader繼續(xù)處理.

2020-01-13-09-35-44.png

代碼示例

var loaderUtils = require('loader-utils');

module.exports = function (sourceCode) {
    var options = loaderUtils.getOptions(this);
    var reg = new RegExp(options.changeVar, "g");
    return sourceCode.replace(reg, "var");
}

在配置文件中的options處書(shū)寫(xiě)的額外參數(shù), 可以在loader函數(shù)內(nèi)的this中讀取到, webpack在this對(duì)象內(nèi)放了很多東西. 使用load-utils包可以幫助我們解析this對(duì)象的內(nèi)容.

plugin

loader的功能定位是轉(zhuǎn)換代碼,而一些其他的操作難以使用loader完成,比如:

  • 當(dāng)webpack生成文件時(shí),順便多生成一個(gè)說(shuō)明描述文件
  • 當(dāng)webpack編譯啟動(dòng)時(shí),控制臺(tái)輸出一句話表示webpack啟動(dòng)了
  • 當(dāng)xxxx時(shí),xxxx
    這種類(lèi)似的功能需要把功能嵌入到webpack的編譯流程中,而這種事情的實(shí)現(xiàn)是依托于plugin的. webpack在編譯的過(guò)程中有許多事件, 我們通過(guò)監(jiān)聽(tīng)這些事件能夠參與到編譯過(guò)程的各個(gè)階段, 并且有機(jī)會(huì)在這些階段來(lái)實(shí)現(xiàn)我們的功能.

plugin的本質(zhì)是一個(gè)帶有apply方法的對(duì)象, 習(xí)慣上我們會(huì)將該對(duì)象寫(xiě)成構(gòu)造函數(shù)的模式.

apply方法有一個(gè)參數(shù)compiler, compiler對(duì)象是在初始化階段創(chuàng)建的, 整個(gè)webpack打包過(guò)程中只有一個(gè)compiler對(duì)象, 后續(xù)完成打包工作的是compiler對(duì)象內(nèi)部創(chuàng)建的compilation(每一次具體的打包過(guò)程都會(huì)有新的compilation對(duì)象). apply方法會(huì)在創(chuàng)建好compiler對(duì)象后調(diào)用, 并向方法傳入compiler.

代碼示例

module.exports = class MyPlugin {
    
    constructor(filename = 'filelist.txt') {
        this.filename = filename;
    }
    
    apply(compiler) {
        // 在這里注冊(cè)事件, 類(lèi)似于window.onload
        compiler.hooks.emit.tap("MyPlugin-emit", function(compilation) {
            // 事件處理函數(shù)
            var fileList = [];
            for (const key in compilation.assets) {
                var content = `[${key}] 大小: ${compilation.assets[key].size()}b`;
                fileList.push(content);
            }
            var str = fileList.join("\n\n");
            compilation.assets[this.filename] = {
                source() {
                    return str;
                },
                size() {
                    return str.length;
                }
            };
        });
    }
}

常用擴(kuò)展

  • css-loader: 將css代碼轉(zhuǎn)換為js代碼, 將css中的其他依賴作為require導(dǎo)入, 以便webpack分析依賴
  • style-loader: 將css-loader轉(zhuǎn)換后的代碼進(jìn)一步處理, 將樣式加到頁(yè)面的style元素中
  • MiniCssExtractPlugin: 將css文件單獨(dú)抽離到輸出目錄(跟js打包方式一樣, 一個(gè)chunk合并成一個(gè)css)
    • 它包含有一個(gè)plugin和一個(gè)loader
    • 在loader配置處以MiniCssExtractPlugin.loader的方式, 替換到原先的style-loader
  • clean-webpack-plugin: 清除輸出目錄
  • html-webpack-plugin: 自動(dòng)生成頁(yè)面
  • copy-webpack-plugin: 復(fù)制靜態(tài)資源(html中直接引用靜態(tài)資源, 希望把靜態(tài)資源復(fù)制到輸出目錄)
  • webpack-dev-server: 開(kāi)發(fā)服務(wù)器(既不是plugin, 也不是loader), 運(yùn)行webpack-dev-server后, 做了以下操作
    1. 內(nèi)部執(zhí)行webpack命令, 傳遞命令參數(shù)
    2. 開(kāi)啟watch
    3. 注冊(cè)hooks, 向webpack中注冊(cè)鉤子函數(shù), 主要功能有: 將資源列表保存, 禁止webpack輸出文件
    4. 用express開(kāi)啟一個(gè)服務(wù)器, 監(jiān)聽(tīng)某端口
  • file-loader: 將導(dǎo)入的文件, 導(dǎo)出為一個(gè)有效url地址, 并將文件輸出到輸出目錄
  • url-loader: 將依賴的文件轉(zhuǎn)換為: 導(dǎo)出一個(gè)base64格式的字符串, 不生成文件到輸出目錄
    1. url-loader可以配置如果文件超過(guò)了設(shè)定的大小, 則不生成base64編碼, 而是交給file-loader處理
    2. url-loader內(nèi)部使用了file-loader, 它的配置項(xiàng)有些自身不用, 是傳遞給file-loader用的

webpack內(nèi)置插件

所有的webpack內(nèi)置插件都作為webpack的靜態(tài)屬性存在

const webpack = require("webpack");
new webpack.插件名(options);
  • DefinePlugin: 定義一些全局的常量
  • BannerPlugin: 為每個(gè)chunk生成的文件頭部添加注釋, 一般用于添加作者, 公司, 版權(quán)信息等
  • ProvidePlugin: 自動(dòng)加載模塊, 而不必導(dǎo)出import或require

解決路徑問(wèn)題

在某些情況下, 例如將圖片用file-loader輸出到dist/img目錄下, js文件輸出到dist/scripts目錄下, 頁(yè)面文件輸出到dist/html目錄下, 此時(shí)js對(duì)圖片的引用會(huì)產(chǎn)生問(wèn)題.

這種問(wèn)題發(fā)生的根本原因是: 模塊中的路徑來(lái)自于某個(gè)loader或plugin, 當(dāng)產(chǎn)生路徑時(shí), loader或plugin只有相對(duì)于dist目錄的路徑, 并不知道該路徑將在哪個(gè)資源中使用, 從而無(wú)法確定最終的正確路徑.

面對(duì)這種情況, 需要依靠webpack的配置publicPath解決.

注意: publicPath通常在output配置項(xiàng)中, 本身沒(méi)有任何作用, 但是某些loader和plugin會(huì)讀取這個(gè)publicPath, 并且它們導(dǎo)出的地址前面, 拼接上這個(gè)配置. 通常output里配置為publicPath: "/" 這樣, 文件的地址就變成了絕對(duì)路徑.

一般, 會(huì)用到publicPath的loader和plugin, 本身也會(huì)支持在自己的配置項(xiàng)中再單獨(dú)配置publicPath項(xiàng).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容