怎樣寫一個webpack loader


在上一篇《webpack從入門到上線》介紹了wepack的配置和相關的概念,這一篇介紹怎樣寫一個webpack loader. 通過寫一個js的html模板為例子。

上篇文章已提及,loader加載器就是對各種非正常資源的解析,轉化成瀏覽器可以識別的js/css文件等,甚至可以說loader就是一個小型的編譯器。例如sass loader:將sass格式編譯成css,在安裝sass的過程中你會發現,其實sass用的是C++,sass本身是面向對象的。但是本文不會介紹怎樣寫一個編譯器(我也不知道),只是簡單介紹下怎樣寫一個loader,拋磚引玉。

有什么樣的場景需要寫一個loader呢?

有一個就是在js里面寫html的模板,會有點不太方便,一個是語法不是高亮的,第二個是需要雙引號把每一行包起來,或者用數組push之類的,所以如果能夠require一個html文件,然后轉化成相應的js字符串,那就比較方便了。(如果你用react開發的,用jsx是比較自然的事情)。我在網上找了下,沒有找到能夠比較符合上面兩點需求的loader,所以就自己嘗試寫一個吧。

js模板通常有三種場景:

  1. 純html,一個文件就是一個模板,直接轉成字符串即可;
  2. 需要有變量,一個文件有幾個模板,每個模板對應一個變量
  3. 再復雜一點,模板是require了其它的工廠模塊生成的字符串

現在開始來寫loader

loader的基本框架

首先在工程的node_modules下面新建一個文件夾html-template-loader,在里面創建一個index.js做為這個loader的js文件。這樣就可以在webpack.config.js里面添加一個loader了:

以.tpl.html作為后綴名,也就是說在邏輯代碼里面引入一個.tpl.html結尾的文件,就歸這個loader處理

重點就在於,這個loader怎么寫呢?

loader也需要寫成一個模塊,一個基本的loader的寫法:

是的,你沒看錯,一個loader就是這么簡單。關鍵在於理解loader的機制——其實loader最后會創建一個模塊,當我們require一個需要讓loader的解析的文件之后,通過上面第7行的return——return里面的內容就是自動創建的模塊的內容,跟平時自已寫的模塊的區別就在於這個要自己拼成一個js語法合法的字符串。

如上面生成的exports為:

那么webpack自動創建這樣一個模塊:

在我這個工程,這個模塊的id為109,然后require的返回結果就是這個tpl的object。

另外一方面,初始化的時候可以拿到source,這個source就是webpack以utf-8讀的整個文件的內容,以字符串的形式作為一個參數傳進來。

所以現在目標就很明確了,我們需要處理這個source的字符串,然后再返回一個可以eval的字符串。需要定義loader的輸入和輸出的格式,這是作為loader開發者的權利,同時中間的處理過程對用戶屏蔽。

loader的具體實現

把source這整一個文件,拆成一行一行處理:

難點就在於第8行的process函數怎么寫,怎樣拼成一個合法的tpl字符串。

如果是上面提到的第一種場景,則很簡單,直接加就好了;

如果是第二種場景需要用變量區分的,那么需要自定義一個語法,由於我們用的是html,因為有高亮的功能。所以可考慮用html的注釋的標簽:

我們的語法就是<!–%變量名%–>,像上面定義了兩個變量email和alert,接下來在process函數里面就可以進行識別、拼一個object的字符串。

 

如果是第三種場景需要引入第三方模塊的,則需要在最后一行return的時候加上require這個函數的代碼,即:

同樣地,需要定義一個語法,require的代碼用script的方式:

以一個generate的屬性標志,這塊是需要依賴的代碼,也就是說要把它拼在前面。

正常的調用就用一個script,不帶屬性:

最后把它轉成一個object.

 

經過合適的處理之后,最后生成的模塊是這樣的:

具體處理代碼略,詳見github

 

loader的高階話題

1.  loader支持鏈式,上一個loader的處理結果可以給下一個loader,像sass的loader是這樣寫的:

或者是寫在配置文件里面:

sass處理完之后給css的loader,css的loader處理完后給style的loader,loader間的數據傳遞通過loader的定義的callback函數,例如上面的loader可以在return之前再加一行:

這樣就可以傳給下一個loader,最后一個loader一定要有return的內容;

2. loader可以緩存,可以加快速度

3. 其它:loader支持異步,loader的加載可以用異步的方式,loader可以傳參數等等,詳見官方文檔:HOW TO WRITE A LOADER,官方文檔比較繞,不是從0開始,也沒有給一個完整的demo,具體可以再另外查查。

 

寫loader關鍵在於怎么編譯這個文件,上面是用的把它拆成一行一行的方式,然后做了個簡單的處理,一般編譯是要用到語法樹。

 

 我的個人博客:http://yincheng.site/webpack-loader

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM