Skip to content

Commit

Permalink
refactor: unify the renderer (rolldown#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
hyf0 committed Nov 3, 2023
1 parent 997c0bd commit 9418bbe
Show file tree
Hide file tree
Showing 13 changed files with 771 additions and 696 deletions.
1 change: 1 addition & 0 deletions crates/rolldown/src/bundler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod chunk_graph;
mod graph;
mod module;
pub mod options;
mod renderer;
mod runtime;
pub mod utils;
mod visitors;
Expand Down
17 changes: 6 additions & 11 deletions crates/rolldown/src/bundler/module/normal_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use oxc::{
};
use rolldown_common::{
ExportsKind, ImportRecord, ImportRecordId, LocalOrReExport, ModuleId, ModuleType, NamedImport,
ResolvedExport, ResourceId, StmtInfo, StmtInfos, SymbolRef, WrapKind,
ResolvedExport, ResourceId, StmtInfo, StmtInfos, SymbolRef,
};
use rolldown_oxc::OxcProgram;
use rustc_hash::{FxHashMap, FxHashSet};
Expand All @@ -18,10 +18,7 @@ use crate::bundler::{
linker_info::{LinkingInfo, LinkingInfoVec},
symbols::Symbols,
},
visitors::{
cjs_renderer::CjsRenderer, esm_renderer::EsmRenderer, wrapped_esm_renderer::WrappedEsmRenderer,
RendererBase,
},
renderer::{AstRenderContext, AstRenderer, RenderKind},
};

use super::{Module, ModuleRenderContext, ModuleVec};
Expand Down Expand Up @@ -60,7 +57,7 @@ impl NormalModule {
// FIXME: should not clone here
let mut source = MagicString::new(source.to_string());
let self_linking_info = &ctx.graph.linking_infos[self.id];
let base = RendererBase::new(
let base = AstRenderContext::new(
ctx.graph,
ctx.canonical_names,
&mut source,
Expand All @@ -69,11 +66,9 @@ impl NormalModule {
self_linking_info,
);

match &self_linking_info.wrap_kind {
WrapKind::None => EsmRenderer::new(base).apply(),
WrapKind::CJS => CjsRenderer::new(base).apply(),
WrapKind::ESM => WrappedEsmRenderer::new(base).apply(),
}
let render_kind = RenderKind::from_wrap_kind(&self_linking_info.wrap_kind);
let mut renderer = AstRenderer::new(base, render_kind);
renderer.render();

source.prepend(format!("// {}\n", self.resource_id.prettify()));

Expand Down
204 changes: 204 additions & 0 deletions crates/rolldown/src/bundler/renderer/impl_visit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
use oxc::{
ast::{ast::ExportDefaultDeclarationKind, Visit},
span::GetSpan,
};
use rolldown_common::ExportsKind;

use crate::bundler::{module::Module, renderer::RenderControl};

use super::AstRenderer;

impl<'ast, 'r> Visit<'ast> for AstRenderer<'r> {
fn visit_binding_identifier(&mut self, ident: &'ast oxc::ast::ast::BindingIdentifier) {
self.render_binding_identifier(ident);
}

fn visit_call_expression(&mut self, expr: &'ast oxc::ast::ast::CallExpression<'ast>) {
match &expr.callee {
oxc::ast::ast::Expression::Identifier(callee_ident) if callee_ident.name == "require" => {
let Module::Normal(importee) = self.get_importee_by_span(expr.span) else {
return;
};
let importee_linking_info = &self.ctx.graph.linking_infos[importee.id];
let wrap_ref_name = self.canonical_name_for(importee_linking_info.wrap_symbol.unwrap());
if importee.exports_kind == ExportsKind::CommonJs {
self.ctx.source.update(expr.span.start, expr.span.end, format!("{wrap_ref_name}()"));
} else {
let ns_name = self.canonical_name_for(importee.namespace_symbol);
let to_commonjs_ref_name = self.canonical_name_for_runtime(&"__toCommonJS".into());
if self.ctx.call_result_un_used {
self.ctx.source.update(expr.span.start, expr.span.end, format!("{wrap_ref_name}()"));
} else {
self.ctx.source.update(
expr.span.start,
expr.span.end,
format!("({wrap_ref_name}(), {to_commonjs_ref_name}({ns_name}))"),
);
}
}
self.ctx.call_result_un_used = false;
return;
}
_ => {}
}

// visit children
for arg in &expr.arguments {
self.visit_argument(arg);
}

if let oxc::ast::ast::Expression::Identifier(s) = &expr.callee {
self.render_identifier_reference(s, true);
} else {
self.visit_expression(&expr.callee);
}

if let Some(parameters) = &expr.type_parameters {
self.visit_ts_type_parameter_instantiation(parameters);
}
}

fn visit_identifier_reference(&mut self, ident: &'ast oxc::ast::ast::IdentifierReference) {
self.render_identifier_reference(ident, false);
}

fn visit_import_declaration(&mut self, decl: &'ast oxc::ast::ast::ImportDeclaration<'ast>) {
self.remove_node(decl.span);
let module_id = self.ctx.module.get_import_module_by_span(decl.span);
let importee = &self.ctx.graph.modules[module_id];
let importee_linking_info = &self.ctx.graph.linking_infos[module_id];
let Module::Normal(importee) = importee else { return };

if importee.exports_kind == ExportsKind::CommonJs {
self.hoisted_module_declaration(
decl.span.start,
self.ctx.generate_import_commonjs_module(
importee,
&self.ctx.graph.linking_infos[importee.id],
true,
),
);
} else if let Some(wrap_ref) = importee_linking_info.wrap_symbol {
let wrap_ref_name = self.canonical_name_for(wrap_ref);
// init wrapped esm module
self.hoisted_module_declaration(decl.span.start, format!("{wrap_ref_name}();\n"));
}
}

fn visit_export_all_declaration(
&mut self,
decl: &'ast oxc::ast::ast::ExportAllDeclaration<'ast>,
) {
if let Module::Normal(importee) = self.get_importee_by_span(decl.span) {
if importee.exports_kind == ExportsKind::CommonJs {
// __reExport(a_exports, __toESM(require_c()));
let namespace_name = &self.ctx.canonical_names[&self.ctx.module.namespace_symbol];
let re_export_runtime_symbol_name = self.canonical_name_for_runtime(&"__reExport".into());
self.hoisted_module_declaration(
decl.span.start,
format!(
"{re_export_runtime_symbol_name}({namespace_name}, {});",
self.ctx.generate_import_commonjs_module(
importee,
&self.ctx.graph.linking_infos[importee.id],
false
)
),
);
}
}
self.remove_node(decl.span);
}

fn visit_import_expression(&mut self, expr: &oxc::ast::ast::ImportExpression<'ast>) {
if let oxc::ast::ast::Expression::StringLiteral(str) = &expr.source {
if let Some(chunk_id) =
self.ctx.chunk_graph.module_to_chunk[self.ctx.module.get_import_module_by_span(expr.span)]
{
let chunk = &self.ctx.chunk_graph.chunks[chunk_id];
self.overwrite(
str.span.start,
str.span.end,
// TODO: the path should be relative to the current importer chunk
format!("'./{}'", chunk.file_name.as_ref().unwrap()),
);
} else {
// external module doesn't belong to any chunk, just keep this as it is
}
}
}

fn visit_statement(&mut self, stmt: &'ast oxc::ast::ast::Statement<'ast>) {
// Mark the start position for place hoisted module declarations.
if self.ctx.first_stmt_start.is_none() {
let hoisted_decl = if let oxc::ast::ast::Statement::ModuleDeclaration(decl) = stmt {
match &decl.0 {
oxc::ast::ast::ModuleDeclaration::ImportDeclaration(_)
| oxc::ast::ast::ModuleDeclaration::ExportAllDeclaration(_) => true,
oxc::ast::ast::ModuleDeclaration::ExportNamedDeclaration(decl) => decl.source.is_some(),
_ => false,
}
} else {
false
};
if !hoisted_decl {
self.ctx.first_stmt_start = Some(stmt.span().start);
}
}

if self.try_render_require_statement(stmt).is_skip() {
return;
}

// visit children
self.visit_statement_match(stmt);
}

fn visit_export_named_declaration(
&mut self,
decl: &'ast oxc::ast::ast::ExportNamedDeclaration<'ast>,
) {
let control = match &mut self.kind {
super::RenderKind::WrappedEsm(_) => {
self.render_export_named_declaration_for_wrapped_esm(decl)
}
super::RenderKind::Cjs => RenderControl::Continue,
super::RenderKind::Esm => self.render_export_named_declaration_for_esm(decl),
};

if control.is_skip() {
return;
}
// visit children
if let Some(decl) = &decl.declaration {
self.visit_declaration(decl);
}
}

fn visit_export_default_declaration(
&mut self,
decl: &'ast oxc::ast::ast::ExportDefaultDeclaration<'ast>,
) {
let control = match &mut self.kind {
super::RenderKind::WrappedEsm(_) => {
self.render_export_default_declaration_for_wrapped_esm(decl)
}
super::RenderKind::Cjs | super::RenderKind::Esm => self.strip_export_keyword(decl),
};

if control.is_skip() {
return;
}

// visit children

match &decl.declaration {
ExportDefaultDeclarationKind::Expression(expr) => self.visit_expression(expr),
ExportDefaultDeclarationKind::FunctionDeclaration(func) => {
self.visit_function(func);
}
ExportDefaultDeclarationKind::ClassDeclaration(class) => self.visit_class(class),
_ => {}
}
}
}
Loading

0 comments on commit 9418bbe

Please sign in to comment.