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