Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit de1f5f5

Browse files
authored
fix(format/cjs): support cjs-module-lexer for export * from 'external' (#1854)
<!-- Thank you for contributing! --> ### Description <!-- Please insert your description here and provide especially info about the "what" this PR is solving -->
1 parent 4200e64 commit de1f5f5

13 files changed

Lines changed: 122 additions & 81 deletions

File tree

crates/rolldown/src/ecmascript/format/cjs.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use itertools::Itertools;
21
use rolldown_common::{ChunkKind, ExportsKind, Module, WrapKind};
32
use rolldown_error::DiagnosableResult;
43
use rolldown_sourcemap::{ConcatSource, RawSource};
@@ -40,23 +39,23 @@ pub fn render_cjs(
4039
if let ChunkKind::EntryPoint { module: entry_id, .. } = ctx.chunk.kind {
4140
if let Module::Ecma(entry_module) = &ctx.link_output.module_table.modules[entry_id] {
4241
if matches!(entry_module.exports_kind, ExportsKind::Esm) {
43-
entry_module.star_export_module_ids().filter_map(|importee| {
44-
let importee = &ctx.link_output.module_table.modules[importee];
45-
match importee {
46-
Module::External(ext) => Some(&ext.name),
47-
Module::Ecma(_) => {None}
48-
}
49-
}).dedup().for_each(|ext_name| {
50-
let import_stmt =
42+
let meta = &ctx.link_output.metas[entry_id];
43+
meta.require_bindings_for_star_exports.iter().for_each(|(importee_idx, binding_ref)| {
44+
let importee = &ctx.link_output.module_table.modules[*importee_idx];
45+
let binding_ref_name =
46+
ctx.link_output.symbols.canonical_name_for(*binding_ref, &ctx.chunk.canonical_names);
47+
let import_stmt =
5148
"Object.keys($NAME).forEach(function (k) {
52-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
53-
enumerable: true,
54-
get: function () { return $NAME[k]; }
55-
});
49+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
50+
enumerable: true,
51+
get: function () { return $NAME[k]; }
52+
});
5653
});
57-
".replace("$NAME", &format!("require(\"{}\")", &ext_name));
58-
concat_source.add_source(Box::new(RawSource::new(import_stmt)));
59-
});
54+
".replace("$NAME", binding_ref_name);
55+
concat_source.add_source(Box::new(RawSource::new(format!("var {} = require(\"{}\");", binding_ref_name,&importee.stable_id()))));
56+
concat_source.add_source(Box::new(RawSource::new(import_stmt)));
57+
58+
});
6059
}
6160
}
6261
}

crates/rolldown/src/stages/link_stage/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,28 @@ impl<'a> LinkStage<'a> {
224224
{
225225
self.metas[importer.idx].wrap_kind = WrapKind::Cjs;
226226
}
227+
228+
// TODO: should have a better place to put this
229+
if is_entry && matches!(self.options.format, OutputFormat::Cjs) {
230+
importer.star_exports.iter().for_each(|rec_idx| {
231+
let rec = &importer.import_records[*rec_idx];
232+
match &self.module_table.modules[rec.resolved_module] {
233+
Module::Ecma(_) => {}
234+
Module::External(ext) => {
235+
self.metas[importer.idx]
236+
.require_bindings_for_star_exports
237+
.entry(rec.resolved_module)
238+
.or_insert_with(|| {
239+
// Created `SymbolRef` is only join the de-conflict process to avoid conflict with other symbols.
240+
self.symbols.create_symbol(
241+
importer.idx,
242+
legitimize_identifier_name(&ext.name).into_owned().into(),
243+
)
244+
});
245+
}
246+
}
247+
});
248+
};
227249
});
228250
}
229251

crates/rolldown/src/types/linking_metadata.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ pub struct LinkingMetadata {
5555
pub dependencies: Vec<ModuleIdx>,
5656
// `None` the member expression resolve to a ambiguous export.
5757
pub resolved_member_expr_refs: FxHashMap<Span, Option<(SymbolRef, Vec<CompactStr>)>>,
58+
// We need to generate `const ext = require('ext')` for `export * from 'ext'` in cjs output
59+
pub require_bindings_for_star_exports: FxHashMap<ModuleIdx, SymbolRef>,
5860
}
5961

6062
impl LinkingMetadata {

crates/rolldown/src/utils/chunk/deconflict_chunk_symbols.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::borrow::Cow;
22

33
use crate::{stages::link_stage::LinkStageOutput, utils::renamer::Renamer};
4-
use rolldown_common::Chunk;
4+
use rolldown_common::{Chunk, ChunkKind};
55
use rolldown_rstr::ToRstr;
66

77
#[tracing::instrument(level = "trace", skip_all)]
@@ -31,6 +31,16 @@ pub fn deconflict_chunk_symbols(chunk: &mut Chunk, link_output: &LinkStageOutput
3131
chunk.require_binding_names_for_other_chunks.values_mut().for_each(|name_hint| {
3232
*name_hint = renamer.create_conflictless_top_level_name(&format!("require_{name_hint}"));
3333
});
34+
match chunk.kind {
35+
ChunkKind::EntryPoint { module, .. } => {
36+
let meta = &link_output.metas[module];
37+
meta
38+
.require_bindings_for_star_exports
39+
.iter()
40+
.for_each(|(_module, binding_ref)| renamer.add_top_level_symbol(*binding_ref));
41+
}
42+
ChunkKind::Common => {}
43+
}
3444

3545
chunk
3646
.modules

crates/rolldown/tests/esbuild/import_star/re_export_star_external_common_js/artifacts.snap

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ source: crates/rolldown_testing/src/integration_test.rs
77

88
```js
99
"use strict";
10-
Object.keys(require("foo")).forEach(function (k) {
11-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
12-
enumerable: true,
13-
get: function () { return require("foo")[k]; }
14-
});
10+
var foo = require("foo");
11+
Object.keys(foo).forEach(function (k) {
12+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
13+
enumerable: true,
14+
get: function () { return foo[k]; }
15+
});
1516
});
16-
17+
1718
1819
require("foo");
1920

crates/rolldown/tests/rolldown/semantic/export_star_from_external_as_shared_entries_cjs/artifacts.snap

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,29 @@ source: crates/rolldown_testing/src/integration_test.rs
77

88
```js
99
"use strict";
10-
Object.keys(require("node:fs")).forEach(function (k) {
11-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
12-
enumerable: true,
13-
get: function () { return require("node:fs")[k]; }
14-
});
10+
var node_fs = require("node:fs");
11+
Object.keys(node_fs).forEach(function (k) {
12+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
13+
enumerable: true,
14+
get: function () { return node_fs[k]; }
15+
});
1516
});
16-
17+
1718
const require_main = require('./main.cjs');
1819
1920
```
2021
## entry2.cjs
2122

2223
```js
2324
"use strict";
24-
Object.keys(require("node:fs")).forEach(function (k) {
25-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
26-
enumerable: true,
27-
get: function () { return require("node:fs")[k]; }
28-
});
25+
var node_fs = require("node:fs");
26+
Object.keys(node_fs).forEach(function (k) {
27+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
28+
enumerable: true,
29+
get: function () { return node_fs[k]; }
30+
});
2931
});
30-
32+
3133
const require_main = require('./main.cjs');
3234
3335
```

crates/rolldown/tests/rolldown/semantic/export_star_from_external_as_wrapped_entry_cjs/artifacts.snap

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ source: crates/rolldown_testing/src/integration_test.rs
1515

1616
```js
1717
"use strict";
18-
Object.keys(require("node:fs")).forEach(function (k) {
19-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
20-
enumerable: true,
21-
get: function () { return require("node:fs")[k]; }
22-
});
18+
var node_fs = require("node:fs");
19+
Object.keys(node_fs).forEach(function (k) {
20+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
21+
enumerable: true,
22+
get: function () { return node_fs[k]; }
23+
});
2324
});
24-
25+
2526
2627
require("node:fs");
2728

crates/rolldown/tests/rolldown/topics/cjs_module_lexer_compat/.export_star_from_external/artifacts.snap

Lines changed: 0 additions & 36 deletions
This file was deleted.

crates/rolldown/tests/rolldown/topics/cjs_module_lexer_compat/.export_star_from_external/_config.json renamed to crates/rolldown/tests/rolldown/topics/cjs_module_lexer_compat/export_star_from_external/_config.json

File renamed without changes.

crates/rolldown/tests/rolldown/topics/cjs_module_lexer_compat/.export_star_from_external/_test.cjs renamed to crates/rolldown/tests/rolldown/topics/cjs_module_lexer_compat/export_star_from_external/_test.cjs

File renamed without changes.

0 commit comments

Comments
 (0)