Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 136 additions & 49 deletions crates/oxc_transformer/src/plugins/module_runner_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ impl<'a> ModuleRunnerTransform<'a> {
}

const SSR_MODULE_EXPORTS_KEY: Atom<'static> = Atom::new_const("__vite_ssr_exports__");
const SSR_EXPORT_DEFAULT_KEY: Atom<'static> = Atom::new_const("__vite_ssr_export_default__");
const SSR_IMPORT_KEY: Atom<'static> = Atom::new_const("__vite_ssr_import__");
const SSR_DYNAMIC_IMPORT_KEY: Atom<'static> = Atom::new_const("__vite_ssr_dynamic_import__");
const SSR_EXPORT_ALL_KEY: Atom<'static> = Atom::new_const("__vite_ssr_exportAll__");
Expand Down Expand Up @@ -166,7 +167,12 @@ impl<'a> ModuleRunnerTransform<'a> {
);
}
Statement::ExportDefaultDeclaration(export) => {
Self::transform_export_default_declaration(&mut new_stmts, export, ctx);
Self::transform_export_default_declaration(
&mut new_stmts,
&mut hoist_exports,
export,
ctx,
);
}
_ => {
new_stmts.push(stmt);
Expand Down Expand Up @@ -536,11 +542,13 @@ impl<'a> ModuleRunnerTransform<'a> {
/// export default function () {}
/// export default {}
/// // to
/// __vite_ssr_exports__.default = function () {}
/// __vite_ssr_exports__.default = {}
/// Object.defineProperty(__vite_ssr_exports__, 'default', { enumerable: true, configurable: true, get(){ return __vite_ssr_export_default__ } });
/// const __vite_ssr_export_default__ = function () {}
/// const __vite_ssr_export_default__ = {}
/// ```
fn transform_export_default_declaration(
new_stmts: &mut ArenaVec<'a, Statement<'a>>,
hoist_exports: &mut Vec<Statement<'a>>,
export: ArenaBox<'a, ExportDefaultDeclaration<'a>>,
ctx: &mut TraverseCtx<'a>,
) {
Expand All @@ -549,28 +557,26 @@ impl<'a> ModuleRunnerTransform<'a> {
ExportDefaultDeclarationKind::FunctionDeclaration(mut func) => {
if let Some(id) = &func.id {
let ident = BoundIdentifier::from_binding_ident(id).create_read_expression(ctx);
new_stmts.extend([
Statement::FunctionDeclaration(func),
Self::create_export(span, ident, DEFAULT, ctx),
]);
new_stmts.push(Statement::FunctionDeclaration(func));
hoist_exports.push(Self::create_export(span, ident, DEFAULT, ctx));
} else {
func.r#type = FunctionType::FunctionExpression;
let right = Expression::FunctionExpression(func);
new_stmts.push(Self::create_export_default_assignment(span, right, ctx));
hoist_exports.push(Self::create_export_default(span, ctx));
}
return;
}
ExportDefaultDeclarationKind::ClassDeclaration(mut class) => {
if let Some(id) = &class.id {
let ident = BoundIdentifier::from_binding_ident(id).create_read_expression(ctx);
new_stmts.extend([
Statement::ClassDeclaration(class),
Self::create_export(span, ident, DEFAULT, ctx),
]);
new_stmts.push(Statement::ClassDeclaration(class));
hoist_exports.push(Self::create_export(span, ident, DEFAULT, ctx));
} else {
class.r#type = ClassType::ClassExpression;
let right = Expression::ClassExpression(class);
new_stmts.push(Self::create_export_default_assignment(span, right, ctx));
hoist_exports.push(Self::create_export_default(span, ctx));
}
return;
}
Expand All @@ -582,6 +588,7 @@ impl<'a> ModuleRunnerTransform<'a> {
};

new_stmts.push(Self::create_export_default_assignment(span, expr, ctx));
hoist_exports.push(Self::create_export_default(span, ctx));
}

/// Transform import specifiers, and return an imported names object.
Expand Down Expand Up @@ -780,20 +787,30 @@ impl<'a> ModuleRunnerTransform<'a> {
ctx.ast.statement_expression(span, Self::create_define_property(arguments, ctx))
}

// __vite_ssr_exports__.default = right;
fn create_export_default(span: Span, ctx: &mut TraverseCtx<'a>) -> Statement<'a> {
Self::create_export(
span,
ctx.create_unbound_ident_expr(SPAN, SSR_EXPORT_DEFAULT_KEY, ReferenceFlags::Read),
DEFAULT,
ctx,
)
}

// const __vite_ssr_export_default__ = right;
fn create_export_default_assignment(
span: Span,
right: Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Statement<'a> {
let object =
ctx.create_unbound_ident_expr(SPAN, SSR_MODULE_EXPORTS_KEY, ReferenceFlags::Read);
let property = ctx.ast.identifier_name(SPAN, DEFAULT);
let member = ctx.ast.member_expression_static(SPAN, object, property, false);
let target = AssignmentTarget::from(member);
let operator = AssignmentOperator::Assign;
let assignment = ctx.ast.expression_assignment(SPAN, operator, target, right);
ctx.ast.statement_expression(span, assignment)
let binding = ctx.generate_binding_in_current_scope(
SSR_EXPORT_DEFAULT_KEY,
SymbolFlags::BlockScopedVariable,
);
let pattern = binding.create_binding_pattern(ctx);
let kind = VariableDeclarationKind::Const;
let declarator = ctx.ast.variable_declarator(SPAN, kind, pattern, Some(right), false);
let declaration = ctx.ast.declaration_variable(span, kind, ctx.ast.vec1(declarator), false);
Statement::from(declaration)
}
}

Expand Down Expand Up @@ -1187,7 +1204,19 @@ const __vite_ssr_import_0__ = await __vite_ssr_import__('vue', { importedNames:

#[test]
fn export_default() {
test_same("export default {}", "__vite_ssr_exports__.default = {};");
test_same(
"export default {}",
"
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return __vite_ssr_export_default__;
}
});
const __vite_ssr_export_default__ = {};
",
);
}

#[test]
Expand Down Expand Up @@ -1436,22 +1465,22 @@ class A extends __vite_ssr_import_0__.Foo {}",
export class B extends Foo {}
",
"
Object.defineProperty(__vite_ssr_exports__, 'B', {
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return B;
return A;
}
});
const __vite_ssr_import_0__ = await __vite_ssr_import__('./dependency', { importedNames: ['Foo'] });
class A extends __vite_ssr_import_0__.Foo {}
Object.defineProperty(__vite_ssr_exports__, 'default', {
Object.defineProperty(__vite_ssr_exports__, 'B', {
enumerable: true,
configurable: true,
get() {
return A;
return B;
}
});
const __vite_ssr_import_0__ = await __vite_ssr_import__('./dependency', { importedNames: ['Foo'] });
class A extends __vite_ssr_import_0__.Foo {}
class B extends __vite_ssr_import_0__.Foo {}
",
);
Expand All @@ -1461,44 +1490,73 @@ class A extends __vite_ssr_import_0__.Foo {}",
#[test]
fn should_handle_default_export_variants() {
// default anonymous functions
test_same("export default function() {}", "__vite_ssr_exports__.default = function() {};");
test_same(
"export default function() {}",
"
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return __vite_ssr_export_default__;
}
});
const __vite_ssr_export_default__ = function() {};
",
);

// default anonymous class
test_same("export default class {}", "__vite_ssr_exports__.default = class {};");
test_same(
"export default class {}",
"
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return __vite_ssr_export_default__;
}
});
const __vite_ssr_export_default__ = class {};
",
);

// default named functions
test_same(
"export default function foo() {}\nfoo.prototype = Object.prototype;",
"function foo() {}
"
export default function foo() {}
foo.prototype = Object.prototype;
",
"
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return foo;
}
enumerable: true,
configurable: true,
get() {
return foo;
}
});
foo.prototype = Object.prototype;",
function foo() {}
foo.prototype = Object.prototype;
",
);

// default named classes
test_same(
"export default class A {}\nexport class B extends A {}",
"
Object.defineProperty(__vite_ssr_exports__, 'B', {
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return B;
return A;
}
});
class A {}
Object.defineProperty(__vite_ssr_exports__, 'default', {
Object.defineProperty(__vite_ssr_exports__, 'B', {
enumerable: true,
configurable: true,
get() {
return A;
return B;
}
});
class A {}
class B extends A {}
",
);
Expand Down Expand Up @@ -1830,15 +1888,37 @@ function fn2() {}
// return Math.random()
// }
test_same(
"export default (function getRandom() {
return Math.random();
});",
"__vite_ssr_exports__.default = function getRandom() {
"
export default (function getRandom() {
return Math.random();
};",
});
",
"
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return __vite_ssr_export_default__;
}
});
const __vite_ssr_export_default__ = function getRandom() {
return Math.random();
};
",
);

test_same("export default (class A {});", "__vite_ssr_exports__.default = class A {};");
test_same(
"export default (class A {});",
"
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return __vite_ssr_export_default__;
}
});
const __vite_ssr_export_default__ = class A {};",
);
}

// https://github.com/vitejs/vite/issues/8002
Expand Down Expand Up @@ -2085,6 +2165,13 @@ console.log(__vite_ssr_import_1__.foo + 2);",
console.log(bar)
",
"
Object.defineProperty(__vite_ssr_exports__, 'default', {
enumerable: true,
configurable: true,
get() {
return __vite_ssr_export_default__;
}
});
Object.defineProperty(__vite_ssr_exports__, 'bar', {
enumerable: true,
configurable: true,
Expand All @@ -2094,7 +2181,7 @@ Object.defineProperty(__vite_ssr_exports__, 'bar', {
});
const __vite_ssr_import_0__ = await __vite_ssr_import__('./foo', { importedNames: ['foo'] });
const __vite_ssr_import_1__ = await __vite_ssr_import__('./bar');
__vite_ssr_exports__.default = (0, __vite_ssr_import_0__.foo)();
const __vite_ssr_export_default__ = (0, __vite_ssr_import_0__.foo)();
console.log(bar);
",
);
Expand Down
Loading