babelプラグイン入門
4518 ワード
バベルについて
BabelはJavaScriptコンパイラです.
Babelは、ECMAScript 2015+バージョンのコードを後方互換性のあるJavaScript構文に変換するためのツールチェーンであり、現在および古いバージョンのブラウザまたは他の環境で動作することができる.
babelの翻訳過程も三つの段階に分けられます.この三つのステップは具体的に:
解析パース
コード解析を抽象的な構文ツリー(すなわちAST)に生成します.
Trans formを変換
ASTに対して一連の操作を変換して、babelはASTを受け取って、babel-traverseを通じて(通って)それを遍歴して、この過程の中で添加、更新と除去などの操作を行います.
ジェネレーション
変換したASTをJSコードに変換し、使用したモジュールはbabel-generatorです.
私達が編纂したbabelプラグインは主に第二段階の転換過程の仕事に集中しています.コードの転化と開拓に専念しています.解析と生成の下側の相関操作には対応するモジュールサポートがあります.ここでは主に何をすればいいのかを理解しています.
準備工作
正式に始まる前に、二つの概念を紹介する必要があります.
Visitors訪問者
訪問者はAST遍歴のための言語横断のパターンです.簡単に言えば、それらはオブジェクトであり、ツリー構造において特定のノードを取得する方法を定義している.抽象的な話ですから、例を見てみましょう.
パス
より具体的なAPIはBabelプラグインマニュアルを見ることができます.
プラグインの書式
プラグインの完全なフォーマットは以下の通りです.
ここには注目すべき問題があります.すべてのBabelプラグインは同じプロセスを共有します.
つまり、彼らのノードに対する処理は相互に影響しうる.
例えば、すべての方法にtry-catchを追加する必要があります.FuntionDeclaration訪問を定義して、すべての関数にアクセスする必要があります.
しかし、他のプラグインでは、例えばBabel-presetはいくつかの補助関数を生成します.これらの補助関数は私たちの訪問者にもアクセスされます.しかし、私たちはソースの処理が必要です.
これらの元のコードにないノードへのアクセスを避けるために、筆者は今も最善の方法を見つけていません.次のような試みがあります.は、sourceMapを使用して、ノードがsourceMapの中で見つけられない場合、生成されたコードと判断する.しかし、sourceMapはwebpackを使って取得する必要があります.(もっといい方法があるかもしれませんが、まだ見つけられていません.ご指摘ください.)このようにプラグインの配置が複雑で、汎用性が足りません. は、 は、ノードが巡回を開始する前に、手動で追加のエルゴードを追加し、処理が完了したら他のプラグインによって処理される.筆者が今使っている方法です.今のところは比較的正確ですが、余分な遍歴が必要です. 開始
まずVisitorを定義して方法声明にアクセスします.
筆者は、比較的完全なプラグインを作成しました.
不完全なところは補充してください.
ソーストランスポート
BabelはJavaScriptコンパイラです.
Babelは、ECMAScript 2015+バージョンのコードを後方互換性のあるJavaScript構文に変換するためのツールチェーンであり、現在および古いバージョンのブラウザまたは他の環境で動作することができる.
// Babel : ES2015
[1, 2, 3].map((n) => n + 1);
// Babel : ES5
[1, 2, 3].map(function(n) {
return n + 1;
});
バベルは何をしましたかbabelの翻訳過程も三つの段階に分けられます.この三つのステップは具体的に:
解析パース
コード解析を抽象的な構文ツリー(すなわちAST)に生成します.
Trans formを変換
ASTに対して一連の操作を変換して、babelはASTを受け取って、babel-traverseを通じて(通って)それを遍歴して、この過程の中で添加、更新と除去などの操作を行います.
ジェネレーション
変換したASTをJSコードに変換し、使用したモジュールはbabel-generatorです.
私達が編纂したbabelプラグインは主に第二段階の転換過程の仕事に集中しています.コードの転化と開拓に専念しています.解析と生成の下側の相関操作には対応するモジュールサポートがあります.ここでは主に何をすればいいのかを理解しています.
準備工作
正式に始まる前に、二つの概念を紹介する必要があります.
Visitors訪問者
訪問者はAST遍歴のための言語横断のパターンです.簡単に言えば、それらはオブジェクトであり、ツリー構造において特定のノードを取得する方法を定義している.抽象的な話ですから、例を見てみましょう.
const MyVisitor = {
Identifier(path) {
console.log("Im Identifier");
},
FunctionDeclaration(path){
console.log("Im FunctionDeclaration");
}
};
これは簡単な訪問者であり、AST遍歴中に使用されると、Identifier
にツリー内で出会うたびにIdentifier()
方法を呼び出し、FunctionDeclaration
に出会うとFunctionDeclaration()
方法を呼び出す.パス
Visitors
は、各ノードを巡回するときに、ノードの情報とノードと所在の位置を含み、特定のノードを修正するために、path
パラメータを導入する.path
と呼ばれるのは、現在のノードオブジェクトではなく、2つのノード間で接続されているオブジェクトを表しているからです.より具体的なAPIはBabelプラグインマニュアルを見ることができます.
プラグインの書式
プラグインの完全なフォーマットは以下の通りです.
export default function({ types: t }) {
return {
pre(state) { //
},
visitor: { //
VariableDeclaration(path) {
// ... ...
}
},
post(state) { //
},
};
}
注意ここには注目すべき問題があります.すべてのBabelプラグインは同じプロセスを共有します.
つまり、彼らのノードに対する処理は相互に影響しうる.
例えば、すべての方法にtry-catchを追加する必要があります.FuntionDeclaration訪問を定義して、すべての関数にアクセスする必要があります.
しかし、他のプラグインでは、例えばBabel-presetはいくつかの補助関数を生成します.これらの補助関数は私たちの訪問者にもアクセスされます.しかし、私たちはソースの処理が必要です.
これらの元のコードにないノードへのアクセスを避けるために、筆者は今も最善の方法を見つけていません.次のような試みがあります.
path.node.loc
を介して助けられる.この方法は正確ではなく、一部の生成ノードにもlocation属性が含まれている.まずVisitorを定義して方法声明にアクセスします.
const funcVisitor = {
FunctionDeclaration(path) {
const functionBody = path.node.body; // body
if (functionBody.type === 'BlockStatement') { // block
const body = functionBody.body; // block body
path.get('body').replaceWith(wrapFunction({
BODY: body,
HANDLER:t.identifier('console.log')
}))
}
}
}
babel-templateを介してASTノードを素早く生成します.const wrapFunction = template(`{
try {
BODY
} catch(err) {
HANDLER(err)
}
}`);
次に組み立てますconst t = require('@babel/types');
const wrapFunction = template(`{
try {
BODY
} catch(err) {
HANDLER(err)
}
}`);
const funcVisitor = {
FunctionDeclaration(path) {
const functionBody = path.node.body; // body
if (functionBody.type === 'BlockStatement') { // block
const body = functionBody.body; // block body
path.get('body').replaceWith(wrapFunction({
BODY: body,
HANDLER:t.identifier('console.log')
}))
}
}
}
module.exports = function () {
return {
pre(file){ //
file.path.traverse(funcVisitor); //
}
};
};
使用webpack.config.js
const myPlugin = require('xxx')
module: {
rules: [
{
test: /\.js$/,
exclude:/node_modules/,// node_module
loader:'babel-loader',
options:{
plugins:[myPlugin]
},
},
]
},
テストして、コードを入力します.function Foo(){
console.log('Im foo')
}
出力function Foo(){
try{
console.log('Im foo')
}catch (err) {
console.error(err)
}
}
簡単な方法声明のためにtry-catchを追加するbabelプラグインが開発されました.ただ、試験中の簡単な状況に対処できるだけです.筆者は、比較的完全なプラグインを作成しました.
Promise
に.catch
を追加することもできます.また、方法に対して、キャプチャ文を注入することもできます.設定も比較的柔軟で、ディレクトリとファイルフィルタをサポートします.不完全なところは補充してください.
ソーストランスポート