Skip to content

Commit

Permalink
feat: create cross-chunk links for runtime module and facade symbols (#…
Browse files Browse the repository at this point in the history
…114)

* feat: create cross-chunk links for runtime module and facade symbols

* comments

* Update failed tests
  • Loading branch information
hyf0 authored Oct 28, 2023
1 parent ef8ed1a commit 0c1e164
Show file tree
Hide file tree
Showing 48 changed files with 196 additions and 26 deletions.
21 changes: 19 additions & 2 deletions crates/rolldown/src/bundler/bundle/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ impl<'a> Bundle<'a> {

for stmt_info in module.stmt_infos.iter().chain(linking_info.facade_stmt_infos.iter()) {
for declared in &stmt_info.declared_symbols {
// TODO: pass debug_assert!(self.graph.symbols.get(*declared).chunk_id.is_none());
// FIXME: I don't think this is correct, even though the assigned chunk_id is the same as the current chunk_id.
// A declared symbol should only be processed once.
debug_assert!(
self.graph.symbols.get(*declared).chunk_id.unwrap_or(chunk_id) == chunk_id
);

self.graph.symbols.get_mut(*declared).chunk_id = Some(chunk_id);
}

Expand Down Expand Up @@ -98,11 +105,13 @@ impl<'a> Bundle<'a> {
}
}
}

for (chunk_id, chunk) in chunk_graph.chunks.iter_mut_enumerated() {
let chunk_meta_imports = &chunk_meta_imports_vec[chunk_id];
for import_ref in chunk_meta_imports.iter().copied() {
let importee_chunk_id = self.graph.symbols.get(import_ref).chunk_id.unwrap();
let import_symbol = self.graph.symbols.get(import_ref);
let importee_chunk_id = import_symbol.chunk_id.unwrap_or_else(|| {
panic!("symbol {import_ref:?} {import_symbol:?} is not assigned to any chunk")
});
if chunk_id != importee_chunk_id {
chunk
.imports_from_other_chunks
Expand Down Expand Up @@ -168,6 +177,14 @@ impl<'a> Bundle<'a> {
FxHashMap::with_capacity_and_hasher(self.graph.entries.len(), BuildHasherDefault::default());
let mut chunks = ChunksVec::with_capacity(self.graph.entries.len());

// FIXME: should only do this while `ROLLDOWN_TEST=1`
let _runtime_chunk_id = chunks.push(Chunk::new(
Some("_rolldown_runtime".to_string()),
None,
BitSet::new(0),
vec![self.graph.runtime.id],
));

// Create chunk for each static and dynamic entry
for (entry_index, (name, module_id)) in self.graph.entries.iter().enumerate() {
let count: u32 = u32::try_from(entry_index).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion crates/rolldown/src/bundler/chunk/render_chunk_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Chunk {
.collect::<Vec<_>>();
import_items.sort();
s.append(format!(
"import {{ {} }} from \"./{}\";",
"import {{ {} }} from \"./{}\";\n",
import_items.join(", "),
chunk.file_name.as_ref().unwrap()
));
Expand Down
22 changes: 19 additions & 3 deletions crates/rolldown/src/bundler/graph/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ impl<'graph> Linker<'graph> {
linking_infos: &mut LinkingInfoVec,
) {
let linking_info = &mut linking_infos[target];
if let Module::Normal(module) = &self.graph.modules[target] {
module.initialize_namespace(linking_info);
}
if linking_info.wrap_symbol.is_some() {
return;
}
Expand All @@ -170,6 +173,7 @@ impl<'graph> Linker<'graph> {
match &self.graph.modules[target] {
Module::Normal(module) => {
module.create_wrap_symbol(linking_info, symbols);

let name = if module.exports_kind == ExportsKind::CommonJs {
"__commonJS".into()
} else {
Expand All @@ -187,13 +191,25 @@ impl<'graph> Linker<'graph> {

#[allow(clippy::needless_collect)]
fn mark_extra_symbols(&mut self, symbols: &mut Symbols, linking_infos: &mut LinkingInfoVec) {
for id in &self.graph.sorted_modules {
let importer = &self.graph.modules[*id];
// Determine if the namespace symbol need to be generated
for importer_id in &self.graph.sorted_modules {
let importer = &self.graph.modules[*importer_id];

if let Module::Normal(importer) = importer {
let has_reexport_all_from_cjs = importer.get_star_exports_modules().any(|importee| matches!(&self.graph.modules[importee], Module::Normal(m) if m.exports_kind == ExportsKind::CommonJs));
if has_reexport_all_from_cjs {
self.graph.modules[*importer_id]
.mark_symbol_for_namespace_referenced(&mut linking_infos[*importer_id]);
}
}

importer
.import_records()
.iter()
.filter_map(|rec| {
(rec.is_import_namespace && rec.resolved_module.is_valid()).then_some(rec.resolved_module)
((rec.is_import_namespace || matches!(rec.kind, ImportKind::Require))
&& rec.resolved_module.is_valid())
.then_some(rec.resolved_module)
})
.for_each(|importee| {
self.graph.modules[importee]
Expand Down
13 changes: 13 additions & 0 deletions crates/rolldown/src/bundler/graph/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ impl Symbols {
Self { inner, references_table: reference_table }
}

pub fn create_facade_symbol(&mut self, owner: ModuleId) -> SymbolRef {
let symbol_id = self.inner[owner].push(Symbol {
// name is meaningless for facade symbols
name: Atom::new_inline("#FACADE#"),
link: None,
chunk_id: None,
namespace_alias: None,
});
let symbol_ref = SymbolRef { owner, symbol: symbol_id };
self.references_table[owner].push(Some(symbol_id));
symbol_ref
}

pub fn create_symbol(&mut self, owner: ModuleId, name: Atom) -> SymbolRef {
let symbol_id =
self.inner[owner].push(Symbol { name, link: None, chunk_id: None, namespace_alias: None });
Expand Down
21 changes: 16 additions & 5 deletions crates/rolldown/src/bundler/module/normal_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,14 +333,25 @@ impl NormalModule {

pub fn generate_symbol_import_and_use(
&self,
symbol_ref_from_importee: SymbolRef,
other_module_symbol_ref: SymbolRef,
self_linking_info: &mut LinkingInfo,
symbols: &mut Symbols,
) {
debug_assert!(symbol_ref_from_importee.owner != self.id);
let name = symbols.get_original_name(symbol_ref_from_importee).clone();
let local_symbol_ref = self.generate_local_symbol(name, self_linking_info, symbols);
symbols.union(local_symbol_ref, symbol_ref_from_importee);
debug_assert!(other_module_symbol_ref.owner != self.id);
// Create a facade symbol belongs to the self module.
let facade_ref = symbols.create_facade_symbol(self.id);
// The facade symbol is used to reference the symbol from the other module.
symbols.union(facade_ref, other_module_symbol_ref);

self_linking_info.facade_stmt_infos.push(StmtInfo {
// Since the facade symbol is created, it should be declared. This will be used to
// 1. de-conflict the symbol in the de-conflict pass
declared_symbols: vec![facade_ref],
// Since the facade symbol is used, it should be referenced. This will be used to
// create correct cross-chunk links
referenced_symbols: vec![facade_ref],
..Default::default()
});
}

pub fn generate_local_symbol(
Expand Down
11 changes: 3 additions & 8 deletions crates/rolldown/src/bundler/visitors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@ impl<'ast> RendererContext<'ast> {
) -> Self {
let wrap_symbol_name =
linking_info.wrap_symbol.and_then(|s| get_symbol_final_name(s, &graph.symbols, final_names));
let namespace_symbol_name = get_symbol_final_name(
(module.id, module.namespace_symbol.symbol).into(),
&graph.symbols,
final_names,
);
let namespace_symbol_name =
get_symbol_final_name(module.namespace_symbol, &graph.symbols, final_names);
let default_symbol_name = module
.default_export_symbol
.and_then(|s| get_symbol_final_name((module.id, s).into(), &graph.symbols, final_names));
Expand Down Expand Up @@ -266,9 +263,7 @@ impl<'ast> RendererContext<'ast> {
if importee.exports_kind == ExportsKind::CommonJs {
self.source.update(expr.span.start, expr.span.end, format!("{wrap_symbol_name}()"));
} else {
let namespace_name = self
.get_symbol_final_name((importee.id, importee.namespace_symbol.symbol).into())
.unwrap();
let namespace_name = self.get_symbol_final_name(importee.namespace_symbol).unwrap();
let to_commonjs_runtime_symbol_name =
self.get_runtime_symbol_final_name(&"__toCommonJS".into());
self.source.update(
Expand Down
2 changes: 2 additions & 0 deletions crates/rolldown/tests/common/case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ impl Case {
assets.sort_by_key(|c| c.file_name.clone());
assets
.iter()
// FIXME: should render the runtime module while tree shaking being supported
.filter(|asset| !asset.file_name.contains("rolldown_runtime"))
.flat_map(|asset| {
[
Cow::Owned(format!("# {}\n", asset.file_name)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/common_js_from_es6
# entry_js.js

```js
import { __esm, __toCommonJS } from "./_rolldown_runtime.js";
// bar.js
function bar$1() {
return 'bar'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/empty_export_clause_bundle_as_
# entry_js.js

```js
import { __esm, __toCommonJS } from "./_rolldown_runtime.js";
// types.mjs
var types_ns = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/es6_from_common_js
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// bar.js
var require_bar = __commonJS({
'bar.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/export_forms_common_js
# entry_js.js

```js
import { __esm, __toCommonJS } from "./_rolldown_runtime.js";
// h.js
async function foo$1() {}
var h_ns = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/import_missing_common_js
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/nested_common_js
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/nested_es6_from_common_js
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/new_expression_common_js
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/re_export_common_js_as_es6
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/require_child_dir_common_js
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// dir/index.js
var require_dir_index = __commonJS({
'dir/index.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/require_parent_dir_common_js
# dir_entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// index.js
var require_require_parent_dir_common_js_index = __commonJS({
'index.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/require_with_call_inside_try
# entry_js.js

```js
import { __commonJS } from "./_rolldown_runtime.js";
// entry.js
var require_entry = __commonJS({
'entry.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/simple_common_js
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/default/use_strict_directive_bundle_is
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// cjs.js
var require_cjs = __commonJS({
'cjs.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/import_star/import_namespace_undefined
# 2.js

```js
import { __commonJS } from "./_rolldown_runtime.js";
// foo/no-side-effects.cjs
var require_no_side_effects = __commonJS({
'foo/no-side-effects.cjs'(exports, module) {
Expand All @@ -22,12 +24,14 @@ var no_side_effects_ns = {
};
console.log('js')
export { no_side_effects_ns$1 as no_side_effects_ns, no_side_effects_ns$2 as no_side_effects_ns$1, no_side_effects_ns as no_side_effects_ns$2 };
export { no_side_effects_ns$1 as no_side_effects_ns, no_side_effects_ns$2 as no_side_effects_ns$1, no_side_effects_ns as no_side_effects_ns$2, require_no_side_effects };
```
# entry-default_js.js

```js
import { no_side_effects_ns as no_side_effects_ns$2, no_side_effects_ns$1 as no_side_effects_ns, no_side_effects_ns$2 as no_side_effects_ns$1 } from "./2.js";
import { __toESM } from "./_rolldown_runtime.js";
import { no_side_effects_ns as no_side_effects_ns$2, no_side_effects_ns$1 as no_side_effects_ns, no_side_effects_ns$2 as no_side_effects_ns$1, require_no_side_effects } from "./2.js";
// entry-default.js
var no_side_effects_ns$2 = __toESM(require_no_side_effects());
Expand All @@ -42,7 +46,9 @@ console.log(
# entry-nope_js.js

```js
import { no_side_effects_ns as no_side_effects_ns$2, no_side_effects_ns$1 as no_side_effects_ns, no_side_effects_ns$2 as no_side_effects_ns$1 } from "./2.js";
import { __toESM } from "./_rolldown_runtime.js";
import { no_side_effects_ns as no_side_effects_ns$2, no_side_effects_ns$1 as no_side_effects_ns, no_side_effects_ns$2 as no_side_effects_ns$1, require_no_side_effects } from "./2.js";
// entry-nope.js
var no_side_effects_ns$2 = __toESM(require_no_side_effects());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/import_star/import_star_and_common_js
# entry_js.js

```js
import { __esm, __toCommonJS } from "./_rolldown_runtime.js";
// foo.js
var foo;
var foo_ns = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/import_star/import_star_common_js_capt
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/import_star/import_star_common_js_no_c
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/import_star/import_star_common_js_unus
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ input_file: crates/rolldown/tests/esbuild/import_star/namespace_import_missing_c
# entry_js.js

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.js";
// foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
Expand Down
Loading

0 comments on commit 0c1e164

Please sign in to comment.