摘要:完整專題上一篇已經(jīng)介紹了編寫(xiě)插件所需要了解的基礎(chǔ)知識(shí),這篇我們就開(kāi)始編寫(xiě)插件了。如字面意思,他們分別代表了節(jié)點(diǎn)數(shù)據(jù)父節(jié)點(diǎn)群數(shù)據(jù)。看到這里你已經(jīng)可以動(dòng)手開(kāi)始嘗試寫(xiě)一個(gè)插件了。使用上述文件目錄結(jié)構(gòu)為在中編寫(xiě)程序。
完整專題:http://www.codefrom.com/p/Babel.js
上一篇已經(jīng)介紹了編寫(xiě)babel.js插件所需要了解的基礎(chǔ)知識(shí),這篇我們就開(kāi)始編寫(xiě)babel.js插件了。
第一篇傳送門(mén): Babel.js插件開(kāi)發(fā)之一 - Babel與AST
開(kāi)始新建一個(gè)新的ES6項(xiàng)目,創(chuàng)建目錄結(jié)構(gòu)如下的項(xiàng)目:
YourProject/ |- src/ | |- index.es6 |- js/ | |- app.js
進(jìn)入到 YourProject 并安裝babel開(kāi)發(fā)模塊 babel-core
$ cd path/to/YourProject/ $ npm install babel-core
之后目錄結(jié)構(gòu)如下:
YourProject/ |- src/ |- js/ |- node_modules/ | |- babel-core/ | |- ... |- app.js
新建插件目錄
cd node_modules/ mkdir babel-plugin-test
并且新建目錄下的nodejs模塊文件,之后目錄結(jié)構(gòu)如下:
fileYourProject/ |- src/ |- js/ |- node_modules/ | |- babel-core/ | |- babel-plugin-test/ | |- index.js | |- package.json |- app.js
接下來(lái)我們就可以在 index.js 中編寫(xiě)插件了。
轉(zhuǎn)換由于AST中節(jié)點(diǎn)類型眾多,我在這里就講如何通過(guò)如上文檔中的個(gè)別常用的類型進(jìn)行轉(zhuǎn)換,其他的都是類似的。
PS: 最近Babel.js更新了5.6+的API,支持用ES6編寫(xiě),也換了新的轉(zhuǎn)換器接口= = 可素他們自己官方的栗子都跑不起來(lái)= =,放棄,之后弄明白再換上新借口的版本,現(xiàn)在依然按照可用的例子進(jìn)行講解。
首先 創(chuàng)建一個(gè)入口: 在新創(chuàng)建的 index.js 中添加:
javascript"use strict"; module.exports = function(babel) { var t = babel.types; // AST模塊 var imports = {}; // 如果你有自己的模塊組織方式,用這里把模塊名和路徑記錄下來(lái)。 var moduleRoot = ""; // 你其他的自定義變量 // module_name寫(xiě)你的插件名稱,但并不在調(diào)用時(shí)使用 return new babel.Transformer("module_name", { // 這里寫(xiě)你的轉(zhuǎn)換邏輯 [邏輯區(qū)域] }); };
在AST中,我們可以把整個(gè)程序看成一個(gè) Program 例如
var a = 42; var b = 5; var c = a + b;
其AST樹(shù)長(zhǎng)這樣:(圖 1)
program 是它的根節(jié)點(diǎn)。
于是我們可以在上面的邏輯區(qū)域添加以下代碼:
Program: function(node) { },
除了 Program 常用的還有:
Class (對(duì)類的處理方法)
NewExpression (對(duì)new新建對(duì)象表達(dá)式的處理)
CallExpression (對(duì)調(diào)用函數(shù)表達(dá)式的處理)
MethodDefinition (對(duì)類成員方法的處理)
... (等等)
它們都有三個(gè)傳入?yún)?shù): node 、 parent 、scope :
注: 你可以通過(guò)調(diào)試查看他們的具體構(gòu)造。
如字面意思,他們分別代表了: 節(jié)點(diǎn)數(shù)據(jù)、 父節(jié)點(diǎn)、群數(shù)據(jù)。其中,節(jié)點(diǎn)數(shù)據(jù) node 是操作一條語(yǔ)句主要的參數(shù)~。
節(jié)點(diǎn)數(shù)據(jù)就是該節(jié)點(diǎn)的屬性以及內(nèi)容,其具體的數(shù)據(jù)格式可以看我在第一篇相關(guān)概念中最后提到的兩篇文檔:
ES5: https://github.com/estree/estree/blob/master/spec.md - 文檔 1
ES6: https://github.com/estree/estree/blob/master/es6.md - 文檔 2
例如,上面圖1中的那顆樹(shù)的 Program 的節(jié)點(diǎn)數(shù)據(jù),文檔 1中相關(guān)描述如下:
Program
interface Program <: Node { type: "Program"; body: [ Statement ]; }
我們可以看到其 node 參數(shù)是一個(gè) Node 類型的數(shù)據(jù),包含了兩個(gè)屬性:公共屬性 type 代表節(jié)點(diǎn)類別,body 代表其內(nèi)容,這里是一個(gè)子節(jié)點(diǎn)的列表,列表中有三個(gè)VariableDeclaration 代表程序中的三條語(yǔ)句,其類型也是 Node 。
假設(shè)我們定義了一種模塊化的方法(類似AMD的requirejs),我們將整個(gè)程序包裹在一個(gè) test.defineModule(function(){/* block */}) 方法中。
那我們可以這樣構(gòu)建Program:
"use strict"; module.exports = function(babel) { var t = babel.types; // AST模塊 return new babel.Transformer("module_name", { // 這里寫(xiě)你的轉(zhuǎn)換邏輯 [邏輯區(qū)域] Program: function(node) { var moduleFunction = t.functionExpression( // [1] t.identifier(""), // [2] [], // [3] t.blockStatement(node.body) // [4] ); var moduleDefine = t.callExpression( // [5] t.identifier("test.defineModule"), // [6] [moduleFunction] // [7] ); var moduleExpression = t.expressionStatement(moduleDefine); // [8] node.body = [moduleExpression]; // [9] return node; // [10] } }); };
這里你只定義了Program的轉(zhuǎn)換機(jī)制,因此其他的轉(zhuǎn)換還是會(huì)按照默認(rèn)的方式進(jìn)行轉(zhuǎn)換。
按照這種機(jī)制,上面的AST樹(shù)的示例程序就被轉(zhuǎn)換成下面這樣了:
"use strict"; test.defineModule(function () { var a = 42; var b = 5; var c = a + b; });
下面我們來(lái)逐行分析一下(以邏輯的順序):
[5] 新建一個(gè)函數(shù)調(diào)用 moduleDefine
[6] 這個(gè)被調(diào)用函數(shù)的名字叫做 "test.defineModule" 即: test.defineModule()
[8] 整個(gè)函數(shù)調(diào)用是一個(gè)完整的表達(dá)式 moduleExpression ,即: test.defineModule();
接下來(lái)我們需要向這個(gè)函數(shù)調(diào)用中填入?yún)?shù)列表
[7] 這個(gè)參數(shù)列表中有一個(gè)參數(shù) moduleFunction
1 moduleFunction 是一個(gè)函數(shù)
[2] 這個(gè)函數(shù)的名稱是 "",即: 這是一個(gè)匿名函數(shù)
[3] 這個(gè)函數(shù)的參數(shù)列表為空
[4] 這個(gè)函數(shù)的內(nèi)容塊的內(nèi)容是原本Program節(jié)點(diǎn)的內(nèi)容
[9] 把原有的Program節(jié)點(diǎn)的內(nèi)容替換成新的
[10] 返回這個(gè)改動(dòng),當(dāng)然你是直接在原本的對(duì)象實(shí)例上改動(dòng)的,不返回也可以
同樣你也可以重新定義 ImportDeclaration 和 ExportDeclaration,其結(jié)構(gòu)略微與普通節(jié)點(diǎn)有所不同,例如:
ImportDeclaration: function(node) { node.specifiers.forEach(function(specifier){ if(specifier.type == "ImportDefaultSpecifier"){ imports[specifier.local.name] = node.source.value; } }); this.dangerouslyRemove(); }, ExportDeclaration: function(){ this.dangerouslyRemove(); }
其作用為:將export 和import的相關(guān)轉(zhuǎn)換都刪掉,并且將import的值和路徑都記錄下來(lái),可以在其他的轉(zhuǎn)換中用到,又或者直接在ImportDeclaration 中直接對(duì)import的變量進(jìn)行操作,例如:
對(duì)
import $ from "jquery"
我們希望轉(zhuǎn)化成
var $ = test.requireModule("jquery");
并將其放入模塊內(nèi):
ImportDeclaration: function(node) { var self = this; node.specifiers.forEach(function(specifier){ if(specifier.type == "ImportDefaultSpecifier"){ //imports[specifier.local.name] = node.source.value; var requireCall = t.callExpression( t.identifier("test.requireModule"), [t.literal(node.source.value)] ); var assignEx = t.assignmentExpression( "=", t.identifier(specifier.local.name), requireCall ); self.insertAfter(t.expressionStatement(assignEx)); } }); this.dangerouslyRemove(); },
將其假如之前的test.defineModule的轉(zhuǎn)換中,則我們發(fā)現(xiàn)
import $ from "jquery" var a = 42; var b = 5; var c = a + b;
被轉(zhuǎn)換為了:
"use strict"; test.defineModule(function () { $ = test.requireModule("jquery"); var a = 42; var b = 5; var c = a + b; });
ImportDeclaration 在上述文檔2中的描述為:
interface ImportDeclaration <: Node { type: "ImportDeclaration"; specifiers: [ ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier ]; source: Literal; }
其 specifiers 列表中的 specifiers 可能有三種類型,在文檔中都有很詳細(xì)的描述,這里就不多說(shuō)了。
按照這樣的理解,所有的方法都可以通過(guò)查看上面的文檔 1和文檔 2的說(shuō)明進(jìn)行改動(dòng)。
看到這里你已經(jīng)可以動(dòng)手開(kāi)始嘗試寫(xiě)一個(gè)babel.js插件了。
使用上述文件目錄結(jié)構(gòu)為:
YourProject/ |- src/ |- js/ |- node_modules/ | |- babel-core/ | |- babel-plugin-test/ | |- index.js | |- package.json |- app.js
在 src 中編寫(xiě)es6程序 test.es6 。
YourProject/ |- src/ | |- test.es6 |- js/ |- node_modules/ | |- babel-core/ | |- babel-plugin-test/ | |- index.js | |- package.json |- app.js
到Y(jié)ourProject目錄下。執(zhí)行
$ babel src/ -d js/ --plugins babel-plugin-test
則在 js 文件夾中就是你轉(zhuǎn)化好的js文件啦~。
還有第三篇是有關(guān)英文文檔的翻譯。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/85823.html
摘要:有沒(méi)有辦法實(shí)現(xiàn)就局部刷新呢當(dāng)然是有第十步執(zhí)行為了實(shí)現(xiàn)局部熱加載,我們需要添加插件。 前言 用了3個(gè)多月的vue自認(rèn)為已經(jīng)是一名合格的vue框架api搬運(yùn)工,對(duì)于vue的api使用到達(dá)了一定瓶頸,無(wú)奈水平有限,每每深入底層觀賞源碼時(shí)候都迷失了自己。 遂決定再找個(gè)框架學(xué)習(xí)學(xué)習(xí)看看能否突破思維局限,加上本人早已對(duì)React、RN技術(shù)垂涎已久,于是決定找找教程來(lái)學(xué)習(xí)。無(wú)奈第一步就卡在了環(huán)境搭...
摘要:和類似的預(yù)處理器還有等。的用處非常多,包括給自動(dòng)加前綴使用下一代語(yǔ)法等,目前越來(lái)越多的人開(kāi)始用它,它很可能會(huì)成為預(yù)處理器的最終贏家。 webpack實(shí)戰(zhàn) 查看所有文檔頁(yè)面:全棧開(kāi)發(fā),獲取更多信息。快馬加鞭,加班加點(diǎn),終于把這個(gè)文檔整理出來(lái)了,順便深入地學(xué)習(xí)一番,鞏固知識(shí),就是太累人,影響睡眠時(shí)間和質(zhì)量。極客就是想要把事情做到極致,開(kāi)始了就必須到達(dá)終點(diǎn)。 原文鏈接:webpack實(shí)戰(zhàn),原...
摘要:然而在當(dāng)前以為主要編譯工具的實(shí)際工程應(yīng)用中依然存在問(wèn)題。涉及到的技術(shù)主要為模塊機(jī)制插件編寫(xiě)與插件編寫(xiě)。使用可以參考或,歡迎。上一篇應(yīng)用到前端工程上模塊的編寫(xiě) 在上一篇文章WebAssembly應(yīng)用到前端工程(上)—— webassembly模塊的編寫(xiě)中,完成了@ne_fe/gis模塊的編寫(xiě)與發(fā)布。然而webassembly在當(dāng)前以webpack4為主要編譯工具的實(shí)際工程應(yīng)用中依然存在問(wèn)...
摘要:在做項(xiàng)目中一直使用的是腳手架搭建的環(huán)境,一直沒(méi)有仔細(xì)的去了解這一工具,這周末抽出一天時(shí)間通過(guò)官網(wǎng)還有各種博客文章算是了解了一些內(nèi)容,起碼可以在項(xiàng)目中自己完成的配置了。不過(guò)好像目前瀏覽器端對(duì)這種諸如之類的方法支持的還不錯(cuò)了。 在做項(xiàng)目中一直使用的是腳手架搭建的環(huán)境,一直沒(méi)有仔細(xì)的去了解 babel 這一工具,這周末抽出一天時(shí)間通過(guò)官網(wǎng)還有各種博客文章算是了解了一些內(nèi)容,起碼可以在項(xiàng)目中自...
摘要:使用時(shí)也要注意范圍和層級(jí)。服務(wù)端配置服務(wù)端使用,最簡(jiǎn)單的方式是通過(guò)。云引擎是推出的服務(wù)器端運(yùn)行環(huán)境,支持和環(huán)境,功能強(qiáng)大而且目前免費(fèi),結(jié)合,使原本復(fù)雜的開(kāi)發(fā)工作變得簡(jiǎn)單高效。目前也支持和海外節(jié)點(diǎn),輕松滿足你的業(yè)務(wù)需求。 構(gòu)建一個(gè)應(yīng)用程序總是會(huì)面對(duì)異步調(diào)用,不論是在 Web 前端界面,還是 Node.js 服務(wù)端都是如此,JavaScript 里面處理異步調(diào)用一直是非常惡心的一件事情。以...
閱讀 1415·2023-04-26 01:58
閱讀 2294·2021-11-04 16:04
閱讀 1783·2021-08-31 09:42
閱讀 1774·2021-07-25 21:37
閱讀 1074·2019-08-30 15:54
閱讀 2079·2019-08-30 15:53
閱讀 3057·2019-08-29 13:28
閱讀 2696·2019-08-29 10:56