Skip to content

Commit

Permalink
feat: optimize flight transform plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
yimingjfe committed Jan 10, 2025
1 parent aa8dce1 commit 6fbac7e
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 85 deletions.
Binary file not shown.
97 changes: 15 additions & 82 deletions packages/cli/flight-server-transform-plugin/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
use std::path::PathBuf;
use path_slash::PathBufExt;
use serde::{Serialize, Deserialize};
use serde_json::json;
use swc_core::{
common::{comments::{Comment, CommentKind, Comments}, DUMMY_SP},
ecma::{
common::{comments::{Comment, CommentKind, Comments}, DUMMY_SP}, ecma::{
ast::{ArrowExpr, BindingIdent, BlockStmt, BlockStmtOrExpr, CallExpr, Callee, ClassDecl, Decl, DefaultDecl, ExportDecl, ExportDefaultDecl, ExportDefaultExpr, ExportSpecifier, Expr, ExprOrSpread, ExprStmt, FnDecl, Function, Ident, IdentName, ImportDecl, ImportNamedSpecifier, ImportPhase, ImportSpecifier, Lit, MemberExpr, MemberProp, Module, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, NewExpr, Param, Pat, Program, ReturnStmt, Stmt, Str, ThrowStmt, Tpl, TplElement, VarDecl, VarDeclKind, VarDeclarator},
parser::{Syntax, TsSyntax},
transforms::testing::{test, test_fixture},
visit::{visit_mut_pass, VisitMut, VisitMutWith}
}, plugin::metadata::TransformPluginMetadataContextKind, testing::fixture
}, plugin::metadata::TransformPluginMetadataContextKind, quote, testing::fixture
};
use swc_core::plugin::{plugin_transform, proxies::TransformPluginProgramMetadata};

Expand Down Expand Up @@ -112,89 +110,24 @@ where
imported: None,
is_type_only: false,
})],
src: Box::new(Str::from(self.runtime_path.clone())),
src: Box::new(Str::from(self.runtime_path.as_str())),
type_only: false,
with: None,
phase: ImportPhase::Evaluation,
}))
}

fn create_proxy_function(&self) -> ModuleItem {
let error_msg = format!(
"Attempted to call {{}}() from the server of {} but {{}} is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.",
self.filename
);

let parts: Vec<&str> = error_msg.split("{}").collect();

ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
ident: Ident::new("createClientReferenceProxy".into(), DUMMY_SP, Default::default()),
function: Box::new(Function {
params: vec![Param {
span: DUMMY_SP,
decorators: vec![],
pat: Pat::Ident(BindingIdent {
id: Ident::new("exportName".into(), DUMMY_SP, Default::default()),
type_ann: None,
}),
}],
ctxt: Default::default(),
body: Some(BlockStmt {
span: DUMMY_SP,
stmts: vec![Stmt::Return(ReturnStmt {
span: DUMMY_SP,
arg: Some(Box::new(Expr::Arrow(ArrowExpr {
span: DUMMY_SP,
params: vec![],
body: Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt {
span: DUMMY_SP,
stmts: vec![Stmt::Throw(ThrowStmt {
span: DUMMY_SP,
arg: Box::new(Expr::New(NewExpr {
span: DUMMY_SP,
callee: Box::new(Expr::Ident(Ident::new("Error".into(), DUMMY_SP, Default::default()))),
args: Some(vec![ExprOrSpread {
spread: None,
expr: Box::new(Expr::Tpl(Tpl {
span: DUMMY_SP,
exprs: vec![
Box::new(Expr::Ident(Ident::new("exportName".into(), DUMMY_SP, Default::default()))),
Box::new(Expr::Ident(Ident::new("exportName".into(), DUMMY_SP, Default::default()))),
],
quasis: parts.iter().enumerate().map(|(i, &text)| {
TplElement {
span: DUMMY_SP,
tail: i == parts.len() - 1,
cooked: Some(text.into()),
raw: text.into(),
}
}).collect(),
})),
}]),
ctxt: Default::default(),
type_args: None,
})),
})],
ctxt: Default::default(),
})),
ctxt: Default::default(),
is_async: false,
is_generator: false,
return_type: None,
type_params: None,
}))),
})],
ctxt: Default::default(),
}),
span: DUMMY_SP,
is_async: false,
is_generator: false,
return_type: None,
type_params: None,
decorators: vec![],
}),
declare: false,
})))
quote!(
"function createClientReferenceProxy($export_name) {
const filename = $file_path;
return () => {
throw new Error(`Attempted to call ${$export_name}() from the server of ${filename} but ${$export_name} is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.`);
}
}" as ModuleItem,
file_path: Expr = Str::from(self.filename.as_str()).into(),
export_name = Ident::new("exportName".into(), DUMMY_SP, Default::default())
)
}

fn create_client_reference(&self, export_name: &str) -> Expr {
Expand Down Expand Up @@ -238,7 +171,7 @@ where
imported: None,
is_type_only: false,
})],
src: Box::new(Str::from(self.runtime_path.clone())),
src: Box::new(Str::from(self.runtime_path.as_str())),
type_only: false,
with: None,
phase: ImportPhase::Evaluation,
Expand Down Expand Up @@ -761,7 +694,7 @@ pub fn process_transform(program: Program, metadata: TransformPluginProgramMetad
let config = serde_json::from_str::<TransformConfig>(
&metadata.get_transform_plugin_config().unwrap_or_default()
).unwrap_or_default();
let comments = metadata.comments.clone();
let comments = metadata.comments;

program.apply(&mut visit_mut_pass(TransformVisitor::new(filename, comments, config.app_dir, config.runtime_path)))
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ exports[`rscServerLoader > support use client directive 1`] = `
{\\"directive\\":\\"client\\",\\"exportNames\\":[{\\"exportName\\":\\"ClassA\\",\\"id\\":\\"fixtures/client-component.jsx#ClassA\\"},{\\"exportName\\":\\"ComponentA\\",\\"id\\":\\"fixtures/client-component.jsx#ComponentA\\"},{\\"exportName\\":\\"MemoizedComponentA\\",\\"id\\":\\"fixtures/client-component.jsx#MemoizedComponentA\\"},{\\"exportName\\":\\"ComponentB\\",\\"id\\":\\"fixtures/client-component.jsx#ComponentB\\"},{\\"exportName\\":\\"foo\\",\\"id\\":\\"fixtures/client-component.jsx#foo\\"},{\\"exportName\\":\\"ComponentC\\",\\"id\\":\\"fixtures/client-component.jsx#ComponentC\\"},{\\"exportName\\":\\"ComponentD\\",\\"id\\":\\"fixtures/client-component.jsx#ComponentD\\"},{\\"exportName\\":\\"bar\\",\\"id\\":\\"fixtures/client-component.jsx#bar\\"},{\\"exportName\\":\\"ComponentE\\",\\"id\\":\\"fixtures/client-component.jsx#ComponentE\\"},{\\"exportName\\":\\"ComponentF\\",\\"id\\":\\"fixtures/client-component.jsx#ComponentF\\"},{\\"exportName\\":\\"default\\",\\"id\\":\\"fixtures/client-component.jsx#default\\"}]}*/ \\"use client\\";
import { registerClientReference } from \\"@modern-js/runtime/rsc/server\\";
function createClientReferenceProxy(exportName) {
const filename = \\"fixtures/client-component.jsx\\";
return ()=>{
throw new Error(\`Attempted to call \${exportName}() from the server of fixtures/client-component.jsx but \${exportName} is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\`);
throw new Error(\`Attempted to call \${exportName}() from the server of \${filename} but \${exportName} is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\`);
};
}
export const ClassA = registerClientReference(createClientReferenceProxy(\\"ClassA\\"), \\"fixtures/client-component.jsx#ClassA\\", \\"ClassA\\");
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/rsc-csr-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'server-only';
import { Suspense } from 'react';
import styles from './App.module.less';
import Suspended from './Suspended';
import { Counter } from './components/Counter';
import { getCountState } from './components/ServerState';
import Suspended from './components/Suspended';

const App = () => {
const countStateFromServer = getCountState();
Expand Down

0 comments on commit 6fbac7e

Please sign in to comment.