Skip to content

fix(generate): keep full JSON interface under preserveModules namespa…#10056

Merged
graphite-app[bot] merged 1 commit into
mainfrom
fix-json-namespace-preserve-modules
Jul 1, 2026
Merged

fix(generate): keep full JSON interface under preserveModules namespa…#10056
graphite-app[bot] merged 1 commit into
mainfrom
fix-json-namespace-preserve-modules

Conversation

@IWANABETHATGUY

@IWANABETHATGUY IWANABETHATGUY commented Jul 1, 2026

Copy link
Copy Markdown
Member

What

Builds on the parent PR (#10020). A JSON module imported as a namespace (import * as ns from './x.json') keeps every top-level key materialized — the finalizer only inlines JSON keys when the module namespace object is not included (need_inline_json_prop, see finalizer_context.rs).

This is pre-existing behavior, not a regression. On main a namespace-imported JSON chunk under preserveModules already exports its full interface correctly — import('./dist/data.js') exposes every top-level key. Unlike #10020 (which is a #9934 regression), there is no namespace bug on main. I verified the guard test passes on main.

The reason this PR exists is purely to keep the stack consistent: the parent PR's #10020 narrowing (skip keys absent from json_module_none_self_reference_included_symbol) is too coarse for the namespace case — those keys are absent from that set yet still materialized, so the parent PR alone would drop them:

// parent PR (#10020) alone: only the namespace object survives
export { data_exports };
// with this PR: pre-existing full interface preserved
export { answer, data_exports, data_default as default, nested };

Fix

Mirror the finalizer's full inlining condition rather than the key-set alone: only drop a key when JSON property inlining is actually active — JSON, ESM exports, and the namespace object not included. The stack's net behavior then matches main for the namespace case.

Test

crates/rolldown/tests/rolldown/misc/preserve_modules/json_namespace_preserves_exports: import * as a JSON module under preserveModules and assert (via _test.mjs) that import('./dist/data.js') re-exposes every top-level key plus default. Verified: passes on main, fails on the parent PR alone, passes here.


Stacked on the #10020 fix.

@netlify

netlify Bot commented Jul 1, 2026

Copy link
Copy Markdown

Deploy Preview for rolldown-rs canceled.

Name Link
🔨 Latest commit 335f9f4
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/6a448066e4c83e0008657330

@IWANABETHATGUY IWANABETHATGUY marked this pull request as ready for review July 1, 2026 02:49
@IWANABETHATGUY IWANABETHATGUY requested a review from hyf0 as a code owner July 1, 2026 02:49

IWANABETHATGUY commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

Merge activity

  • Jul 1, 2:49 AM UTC: The merge label 'graphite: merge-when-ready' was detected. This PR will be added to the Graphite merge queue once it meets the requirements.
  • Jul 1, 2:49 AM UTC: IWANABETHATGUY added this pull request to the Graphite merge queue.
  • Jul 1, 2:54 AM UTC: Merged by the Graphite merge queue.

#10056)

### What

Builds on the parent PR (#10020). A JSON module imported as a namespace (`import * as ns from './x.json'`) keeps every top-level key materialized — the finalizer only inlines JSON keys when the module namespace object is **not** included (`need_inline_json_prop`, see `finalizer_context.rs`).

> **This is pre-existing behavior, not a regression.** On `main` a namespace-imported JSON chunk under `preserveModules` already exports its full interface correctly — `import('./dist/data.js')` exposes every top-level key. Unlike #10020 (which *is* a #9934 regression), there is no namespace bug on `main`. I verified the guard test passes on `main`.

The reason this PR exists is purely to keep the stack consistent: the parent PR's #10020 narrowing (skip keys absent from `json_module_none_self_reference_included_symbol`) is too coarse for the namespace case — those keys are absent from that set yet still materialized, so the **parent PR alone** would drop them:

```js
// parent PR (#10020) alone: only the namespace object survives
export { data_exports };
// with this PR: pre-existing full interface preserved
export { answer, data_exports, data_default as default, nested };
```

### Fix

Mirror the finalizer's **full** inlining condition rather than the key-set alone: only drop a key when JSON property inlining is actually active — JSON, ESM exports, and the namespace object **not** included. The stack's net behavior then matches `main` for the namespace case.

### Test

`crates/rolldown/tests/rolldown/misc/preserve_modules/json_namespace_preserves_exports`: `import * as` a JSON module under preserveModules and assert (via `_test.mjs`) that `import('./dist/data.js')` re-exposes every top-level key plus `default`. Verified: passes on `main`, fails on the parent PR alone, passes here.

---

> Stacked on the #10020 fix.
@graphite-app graphite-app Bot force-pushed the fix-json-namespace-preserve-modules branch from 63674a9 to 335f9f4 Compare July 1, 2026 02:50
@graphite-app graphite-app Bot merged commit 335f9f4 into main Jul 1, 2026
34 checks passed
@graphite-app graphite-app Bot deleted the fix-json-namespace-preserve-modules branch July 1, 2026 02:54
@rolldown-guard rolldown-guard Bot mentioned this pull request Jul 1, 2026
shulaoda added a commit that referenced this pull request Jul 1, 2026
## [1.1.4] - 2026-07-01

### 🚀 Features

- disable `experimental.lazyBarrel` by default (#10071) by @shulaoda

### 🐛 Bug Fixes

- dev: disable lazy barrel in dev mode (#10060) by @shulaoda
- generate: keep full JSON interface under preserveModules namespa… (#10056) by @IWANABETHATGUY
- check finalize_other_specifiers in its own Debug attribute (#10032) by @shulaoda
- serialize the KeepAssign unused minify option as "keep_assign" (#10031) by @shulaoda
- keep fragments after the newline fragment in MagicString::last_line (#10023) by @shulaoda
- generate: undeclared JSON named exports under preserveModules (#10020) (#10027) by @IWANABETHATGUY
- deconflict: rename CJS-wrapped locals that shadow chunk-root bindings (#9921) by @IWANABETHATGUY
- rolldown: keep entry facade when a shared chunk holds another entry's module (#9997) by @hyf0
- treeshake: also bail JSON default split when the object escapes (#9996) by @IWANABETHATGUY
- don't classify await in a strict-mode function as top-level await (#9987) by @shulaoda
- avoid spurious leading newline in addon hooks (banner/footer/intro/outro) (#9989) by @shulaoda
- handle JSON default mutation bailouts (#9972) by @TheAlexLichter
- plugin: make lazy hook metadata enumerable (#9991) by @TheAlexLichter
- dev: make init errors in lazy-compiled modules catchable (#9981) by @h-a-n-a
- treeshake: keep computed-key side effects on namespace member access (#9986) by @shulaoda
- binding: validate replace plugin delimiters length instead of panicking (#9984) by @shulaoda
- reconstruct nested rest patterns in into_expression (#9980) by @IWANABETHATGUY
- reconstruct rest patterns as spread in into_expression (#9976) by @shulaoda
- preserve export keyword on multi-declarator exports under keepNames (#9974) by @shulaoda
- deterministically keep the shortest name for deduplicated assets (#9948) by @x1024
- treeshake: apply @__NO_SIDE_EFFECTS__ to cross-chunk namespace calls (#9960) by @IWANABETHATGUY

### 🚜 Refactor

- drop redundant program scope enter/leave in finalizer (#10049) by @shulaoda
- deconflict: extract collect_chunk_scope_captured_names (#10006) by @IWANABETHATGUY
- unify pre-scan multi-declarator split into one decision site (#9982) by @IWANABETHATGUY
- common: return bool from SymbolRef::is_not_reassigned (#9962) by @IWANABETHATGUY

### 📚 Documentation

- rolldown: remove outdated comment for removing parenthesized expression (#10062) by @Dunqing
- use GitHub-flavored alert for Etiquette note in contribution guide (#10012) by @IWANABETHATGUY
- replace: explain the delimiters left and right boundaries (#9985) by @shulaoda
- ast-mutation: remove stale Address Use section after pre-scan refactor (#9983) by @IWANABETHATGUY
- remove fathom (#9968) by @mdong1909
- contribution-guide: code-format main branch references (#9966) by @IWANABETHATGUY
- contribution-guide: fix stale REPL note and tidy wording (#9957) by @hyf0
- contribution-guide: clarify when to discuss before opening a PR (#9955) by @hyf0

### ⚡ Performance

- disable preserve_parens across all parse paths (#10057) by @Dunqing
- common: inline declared_symbols with SmallVec (#9920) by @IWANABETHATGUY
- common: pack TaggedSymbolRef into 8 bytes (#9919) by @IWANABETHATGUY
- sourcemap: skip newline scan on the no-sourcemap join fast path (#9936) by @Boshen

### 🧪 Testing

- dev: error in lazy module should be catchable (#9975) by @sapphi-red
- dev: reject unknown lazy compile modules (#9969) by @sapphi-red

### ⚙️ Miscellaneous Tasks

- deps: update actions/cache action to v6 (#10001) by @renovate[bot]
- trigger vite ecosystem-ci from PR comments (#10058) by @shulaoda
- deps: update napi to v3.10.0 (#10063) by @renovate[bot]
- remove unused From impl for RolldownLabelSpan (#10055) by @shulaoda
- remove dead Diagnostic::with_kind method (#10054) by @shulaoda
- remove unused StatementExt methods (#10053) by @shulaoda
- remove unused ExpressionExt methods (#10052) by @shulaoda
- remove commented-out re_export_all_names field (#10051) by @shulaoda
- deps: update pnpm to v11.9.0 (#10047) by @renovate[bot]
- remove the unused BindingGenerateHmrPatchReturn napi type (#10034) by @shulaoda
- remove the dead inline_entry_chunk_wrapping scaffolding (#10037) by @shulaoda
- deps: bump oxc_resolver to 11.22.0 (#10045) by @Boshen
- remove never-constructed MatchImportKind::_Ignore variant (#10041) by @shulaoda
- remove the unused ScheduledBuild napi struct (#10033) by @shulaoda
- remove dead compute_hmr_update_single method (#10040) by @shulaoda
- drop the redundant visited.insert in manual code splitting (#10038) by @shulaoda
- remove the dead output_assets vector in render_chunk_to_assets (#10036) by @shulaoda
- remove the unused From<String>/Display impls for BindingLogLevel (#10035) by @shulaoda
- deps: upgrade oxc to 0.138.0 and migrate to per-type AST construction (#10018) by @shulaoda
- deps: update rust crates (#9911) by @renovate[bot]
- deps: update test262 submodule for tests (#10016) by @rolldown-guard[bot]
- deps: update github actions (#9999) by @renovate[bot]
- deps: update npm packages (#10000) by @renovate[bot]

### ◀️ Revert

- "fix(plugin): make lazy hook metadata enumerable (#9991)" (#10005) by @shulaoda

### ❤️ New Contributors

* @x1024 made their first contribution in [#9948](#9948)

Co-authored-by: shulaoda <165626830+shulaoda@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants