-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Allen Zhang (张涛)
committed
Oct 21, 2024
1 parent
077ad43
commit 48bb173
Showing
3 changed files
with
66 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
/target | ||
Cargo.lock | ||
swc_plugin_canyon.wasm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,75 @@ | ||
#![allow(clippy::not_unsafe_ptr_arg_deref)] | ||
|
||
use swc_common::{Spanned, SyntaxContext}; | ||
use swc_core::plugin::proxies::TransformPluginProgramMetadata; | ||
use swc_ecma_ast::{Program, Script, Expr, ExprStmt, Stmt, Lit, Str, BinExpr, op, Ident}; | ||
use swc_ecma_visit::{as_folder, Fold, FoldWith, VisitMut, VisitMutWith}; | ||
use swc_plugin_macro::plugin_transform; | ||
use swc_core::{ | ||
ecma::{ | ||
transforms::testing::test, | ||
} | ||
use swc_core::ecma::{ | ||
ast::{ | ||
Program, Module, Expr, Stmt, ModuleItem, Ident, Lit, KeyValueProp, Prop, PropName, | ||
ObjectLit, ExprStmt, AssignExpr, AssignOp, MemberExpr, MemberProp, | ||
}, | ||
transforms::testing::test_inline, | ||
visit::{as_folder, FoldWith, VisitMut}, | ||
}; | ||
use swc_core::ecma::ast::{AssignTarget, IdentName}; | ||
use swc_core::ecma::visit::VisitMutWith; | ||
use swc_core::plugin::{plugin_transform, proxies::TransformPluginProgramMetadata}; | ||
|
||
#[plugin_transform] | ||
fn plugin(program: Program, metadata: TransformPluginProgramMetadata) -> Program { | ||
// 确认插件被调用 | ||
println!("SWC 插件被调用"); | ||
pub struct TransformVisitor { | ||
injected: bool, // 用于确保只注入一次 | ||
} | ||
|
||
// 打印文件路径 | ||
if let Some(context) = metadata.get_context(&swc_core::plugin::metadata::TransformPluginMetadataContextKind::Filename) { | ||
println!("当前文件的路径: {}", context); | ||
} else { | ||
println!("无法获取文件路径"); | ||
impl TransformVisitor { | ||
pub fn new() -> Self { | ||
Self { injected: false } | ||
} | ||
|
||
// 直接在每个文件末尾插入指定的代码 | ||
program.fold_with(&mut AddSimpleCode) | ||
} | ||
|
||
impl VisitMut for TransformVisitor { | ||
fn visit_mut_module(&mut self, module: &mut Module) { | ||
// 先调用父类的 visit_mut_module 方法 | ||
module.visit_mut_children_with(self); | ||
|
||
// 在最后一行注入 window.canyon = {name: "zt"}; | ||
if !self.injected { | ||
// 创建 window.canyon 的 MemberExpr | ||
let window_canyon = Expr::Member(MemberExpr { | ||
obj: Box::new(Expr::Ident(Ident::new("window".into(), Default::default(), Default::default()))), | ||
prop: MemberProp::Ident(IdentName::from(Ident::new("__canyon__".into(), Default::default(), Default::default()))), | ||
span: Default::default(), | ||
}); | ||
|
||
|
||
struct AddSimpleCode; | ||
// 默认为"",如果没有设置环境变量,则会报错 | ||
let dsn = std::env::var("dsn").unwrap_or_default(); | ||
|
||
impl Fold for AddSimpleCode { | ||
fn fold_script(&mut self, mut script: Script) -> Script { | ||
// 插入的代码是 console.log('hi'); | ||
let new_code = Expr::Call(swc_ecma_ast::CallExpr { | ||
callee: swc_ecma_ast::Callee::Expr(Box::new(Expr::Member(swc_ecma_ast::MemberExpr { | ||
obj: Box::new(Expr::Ident(Ident::new("console".into(), Default::default(), SyntaxContext::empty()))), | ||
// prop: Box::new(Expr::Ident(Ident::new("log".into(), Default::default(), SyntaxContext::empty()))), | ||
let object_lit = Expr::Object(ObjectLit { | ||
props: vec![Prop::KeyValue(KeyValueProp { | ||
key: PropName::Ident(IdentName::from(Ident::new("dsn".into(), Default::default(), Default::default()))), | ||
value: Box::new(Expr::Lit(Lit::Str(dsn.into()))), | ||
}).into()], | ||
span: Default::default(), | ||
prop: Default::default(), | ||
}))), | ||
args: vec![swc_ecma_ast::ExprOrSpread { | ||
spread: None, | ||
expr: Box::new(Expr::Lit(Lit::Str(Str { | ||
value: "hi".into(), | ||
span: Default::default(), | ||
raw: None, | ||
}))), | ||
}], | ||
span: Default::default(), | ||
type_args: None, | ||
ctxt: Default::default(), | ||
}); | ||
}); | ||
|
||
// 构建表达式语句并插入 | ||
let new_item = Stmt::Expr(ExprStmt { | ||
expr: Box::new(new_code), | ||
span: Default::default(), | ||
}); | ||
// 读取当前环境变量,把环境变量的dsn赋值给window.__canyon__.dsn | ||
// 创建 window.canyon = {name: "zt"} 的赋值表达式 | ||
let assign_expr = AssignExpr { | ||
left: AssignTarget::try_from(Box::new(window_canyon)).unwrap(), // 直接使用 Box<Expr> | ||
op: AssignOp::Assign, | ||
right: Box::new(object_lit), | ||
span: Default::default(), | ||
}; | ||
|
||
// 在脚本的末尾追加语句 | ||
script.body.push(new_item); | ||
// 创建表达式语句 | ||
let assign_stmt = Stmt::Expr(ExprStmt { | ||
expr: Box::new(Expr::Assign(assign_expr)), | ||
span: Default::default(), | ||
}); | ||
|
||
script | ||
// 将新的语句添加到模块体中 | ||
module.body.push(ModuleItem::Stmt(assign_stmt)); | ||
self.injected = true; // 标记为已注入 | ||
} | ||
} | ||
} | ||
|
||
/// SWC 插件的主函数 | ||
#[plugin_transform] | ||
pub fn process_transform(program: Program, _metadata: TransformPluginProgramMetadata) -> Program { | ||
program.fold_with(&mut as_folder(TransformVisitor::new())) | ||
} |