requirejs的外掛介紹與製作
本文由作者鄭海波授權網易雲社群釋出。
前言
我這裡就不介紹requirejs了, 簡而言之: requirejs是支援AMD規範的模組載入器, 事實上它也是AMD的最直接推動者。
現在可供挑選的開源模組解決方案很多,比如component、cjs+browserify、umd等等,但是無疑類似requirejs這類載入系統是現在最成熟和可靠的解決方案,所以regularjs第一步就是提供對requirejs的外掛支援。
requirejs的外掛體系
requirejs的原始碼內部預留了hook,使得你可以建立外掛來增強這個模組系統,並且這個外掛可以做到影響到你的OPTIMIZER階段,一些資源可以被處理為標準的AMD模組。
外掛普遍被用來
預編譯
載入非js文字
lint 或 test 後置或前置的操作 等等
example 比如它本身是不支援載入文字資訊的,但是你可以通過text!外掛來載入。
require(['text!foo.html', 'jquery'], function(foo, $){ $('#anchor').html(foo); })
需要注意的是由於文字無法用script標籤進行載入,所以text內部是通過XHR來載入的,即它會受到同源策略的影響。
優化OPTIMIZER
由於requirejs同時提供工具(npm:requirejs)可以靜態打包優化AMD,剛才的那個text!foo.html
define('text!foo.html',[],function () { return '<h2>早上好\n</h2>'; });
requirejs的外掛其實是一個實現的特定介面的標準AMD模組,它在定義時與其它業務模組並無區別。
例如官方text外掛的原始檔
define(['module'], function (module) { 'use strict'; var text = { load: function(){} .... } return text })
其中load等介面是外掛必須實現的,
對於各個介面描述我就不細究了,大家可以參考官網
順便列舉一些有用的requirejs外掛
text外掛(最常用外掛) 如果你的文字內容無需在打包優化階段做處理,幾乎都可以使用這個外掛來完成載入
json外掛 比樓上多做了一步JSON.parse.
amd-loader(好東西): 注意不要requirejs本身弄混了,因為requirejs本身不是基於xhr的,這個外掛主要是提供完善的xhr支援來載入文字內容。一句化即它是[外掛的loader外掛],作者事後才發現有這麼一個外掛...繞了不少彎路。具體例子可以檢視es6
handlebars 用來載入handlebar的外掛
其實由於amd等模組系統佔據了開發中的模組入口這一環,其實在開發中可以有無限的可能性,這也是常規大公司都會自造一個輪子來最優配置的緣由之一,事實上requirejs目前的外掛系統已經有足夠的靈活性來定製自己的策略。
實現requirejs-regular的過程
背景
首先我們先理清我們的需求, 與常規的的模板預編譯類似,我們的外掛主要為了實現兩個功能。
在開發階段,我們希望能載入js檔案一樣,載入我們的模板檔案,這帶來的幾個好處
這使得我們不必將模板零散的填充到頁面的script 或 textarea標籤中
依賴系統唯一化, 模板依賴整合進了模組依賴中
在優化階段(即requirejs提供的OPTIMIZER的上線打包功能),我們的模板字串可以被預處理為序列化的AST物件,這樣就不會發生瀏覽器端的解析,效率更高。
實現
一個外掛模組會同時跑在瀏覽器端(開發環境)和node端(為線上或測試環境的打包優化工具),所以你的外掛模組必須可以同時跑在瀏覽器端和node端,這個幾乎是整個開發環境最麻煩的一部分
regular.js的單檔案雖然是umd模組可以支援amd環境,但是由於依賴的dom。所以首先要將parser部分(不依賴dom)打成一個AMD模組,由於regularjs本身就是基於commonjs的模組構建,將其中一部分打成AMD模組是分分鐘的事情,這裡我們使用webpack來打包成regular-parser.js,簡單起見我們隨regularjs模組一同釋出到bower上
我們還要解決模板的載入問題,外掛內部的載入問題也要手動解決,即你至少要實現loader介面和get介面。這裡我們完全可以偷個懶,直接使用!text外掛。
即外掛會依賴這兩個模組
define(['text', 'regular-parser'], function(text, parser){ //blalalalala... return{ load: load, write: write } })
然後我們只需要實現兩個介面:
load
var buildMap = {};function load(name, req, onLoad, config){ text.load(name, req, function(data,r){ onLoad( (buildMap[name] = parser.parse(data, false)) ); }, config); }
這裡直接使用了text外掛的純文字載入,需要注意的是這個onLoad介面,傳入引數相當於模組的內容,我們這裡預parse了這段文字內容。即你通過rgl!template.html
最終會獲得解析後的AST資料。
其實對於regularjs來講在瀏覽器端有無進行模組系統層面的預解析並無意義,關鍵是在打包優化階段。這裡的buildMap主要是為了儲存這段內容用於打包使用。
write 實現write介面主要是為了在打包優化階段改寫相關模組
var tpl = function(str, data){ return str.replace(/\{\{(\w+)\}\}/g, function(all, name){ return data[name] || "" }) }var template ='define("{{pn}}!{{mn}}",function(){ return {{ast}} });\n';function write(pn, mn, writeModule){ if(buildMap[mn]){ writeModule( tpl(template,{ pn: pn, mn: mn, ast: parser.parse(buildMap[mn]) }) ) } }
此時這個外掛必須依賴於兩個模組,即必須同時保證text
和regular-parser
模組同時存在,類似的方案可以檢視hogan,它必須保證環境中有hogan
和text
才可以執行. 熟悉requirejs打包過程的同學也知道,除了loader端的配置,我們在build的打包檔案也需要一併將這些依賴模組剔除,因為上線時是不需要這些外掛的。所以這將大大增加配置成本,其實解決方案也很簡單,就是使用[webpack]再將其打包成一個standlone的AMD模組即可,具體可以參考這裡的gulpfile。
大功告成
使用就非常簡單了,和你使用requirejs-text差不多,
1.首先下載rgl.js,最簡單的就是bower安裝
bower install regularjs-regular --save
save引數是安裝後並寫入到bower.json中,這個和npm一致
2.配置
require.config({ paths : { "rgl": '../../bower_components/regularjs-regular/rgl', // 同時載入我們的regularjs來使用這些模板 "regularjs": '../../bower_components/regularjs/dist/regular' } });
3.使用
require(['rgl!./foo.html', 'regularjs'], function( tpl, Regular){ var Foo = Regular.extend({ template: tpl }) new Foo({}).$inject("#app") });
4.打包
模板檔案<h2>{{message}}</h2>
經過外掛處理後會打包成
define("rgl!foo.html",function(){return [{"type":"element","tag":"h2","attrs":[],"children":[{"type":"expression","body":"_c_._sg_('message', _d_['message'])","constant":false,"setbody":"_c_._ss_('message',_p_,_d_, '=')"}]}] });
即上線後就不會有parse了,比如PO主目前正在開發的專案在初期就有幾十個模板檔案,build成單檔案後的執行時開銷還是應該儘量避免.
tip:build.js記得通過stubModules配置專案刪除掉這個外掛模組,具體看demo的build.js。
對於NEJ的使用者
NEJ的新模組系統支援上述類似的regular模板載入了
網易杭州的同事,事實上你已經可以在NEJ的新模組系統中(完全相容老版本)通過regular!path/to/template.html
的方式來載入你的regular模板了,打包之後模板將會被預解析,同時新版NEJ也支援text!
載入純文字內容, 詳詢@飛鍋。新版本的載入系統,支援類似AMD的注入寫法,並且相容老版本的模組寫法,親測好用哈。
免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等套餐
更多網易技術、產品、運營經驗分享請訪問網易雲社群。
相關文章:
【推薦】 微服務監控探索
【推薦】 中秋福利|10本技術圖書(程式語言、資料分析等)免費送
【推薦】 網易雲安全兩篇論文入選計算機視覺頂級會議ICCV