Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 5, 2025

Fix output.fileName becoming non-enumerable in 1.0.0-beta.46

The issue is that properties decorated with @lazy are not enumerable, making them invisible when spreading objects ({...o}). This breaks compatibility with code that expects to spread output objects.

Changes made:

  • Renamed @lazy decorator to @lazyProp for better clarity
  • Created LazyProperties base class that automatically sets up lazy properties in its constructor
  • Updated OutputChunkImpl, OutputAssetImpl, and RolldownOutputImpl to extend LazyProperties
  • Removed manual setupLazyProperties(this) calls from constructors - now handled by base class
  • Made setupLazyProperties internal since it's only called by the base class
  • Updated all @lazy usages to @lazyProp
  • Added comprehensive documentation explaining the behavior

Architecture:
Classes using lazy properties now follow this pattern:

class MyClass extends LazyProperties {
  @lazyProp
  get expensiveValue() {
    return someExpensiveComputation();
  }
}

This provides a cleaner, more maintainable solution that:

  • Eliminates the need to manually call setupLazyProperties(this) in every constructor
  • Makes the pattern more discoverable and consistent
  • Clearly documents the requirement to extend LazyProperties
  • Preserves all existing functionality (lazy evaluation, caching, enumerability)
Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug]: output.fileName became non-enumerable in 1.0.0-beta.46</issue_title>
<issue_description>### Reproduction link or steps

https://stackblitz.com/edit/diwp1dyb?file=build.js&view=editor

What is expected?

result.output.map((o) => ({...o})).map((o) => o.fileName)
// ['index.js']

What is actually happening?

result.output.map((o) => ({...o})).map((o) => o.fileName)
// [undefined]

System Info

rolldown: 1.0.0-beta.46

Any additional comments?

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@graphite-app
Copy link
Contributor

graphite-app bot commented Nov 5, 2025

How to use the Graphite Merge Queue

Add the label graphite: merge to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

@netlify
Copy link

netlify bot commented Nov 5, 2025

Deploy Preview for rolldown-rs ready!

Name Link
🔨 Latest commit 208e49a
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/690b49071f022a00082d0ccc
😎 Deploy Preview https://deploy-preview-6852--rolldown-rs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI changed the title [WIP] Fix output.fileName non-enumerable bug in version 1.0.0-beta.46 Fix lazy decorator to preserve property enumerability in object spreads Nov 5, 2025
Copilot AI requested a review from shulaoda November 5, 2025 05:34
@hyf0 hyf0 self-assigned this Nov 5, 2025
Copilot AI requested a review from hyf0 November 5, 2025 08:07
@hyf0 hyf0 force-pushed the copilot/fix-file-name-enumerability-bug branch from dba5c24 to b275c23 Compare November 5, 2025 11:41
Copy link
Member

hyf0 commented Nov 5, 2025


How to use the Graphite Merge Queue

Add the label graphite: merge to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@hyf0 hyf0 marked this pull request as ready for review November 5, 2025 11:44
@hyf0 hyf0 changed the title Fix lazy decorator to preserve property enumerability in object spreads fix(node): keys of RolldownOutput should be enummerable Nov 5, 2025
@hyf0 hyf0 changed the title fix(node): keys of RolldownOutput should be enummerable fix(node): keys of RolldownOutput should be enumerable Nov 5, 2025
@hyf0
Copy link
Member

hyf0 commented Nov 5, 2025

@shulaoda Could you review the new changes I made

@graphite-app
Copy link
Contributor

graphite-app bot commented Nov 5, 2025

Merge activity

Fix output.fileName becoming non-enumerable in 1.0.0-beta.46

The issue is that properties decorated with `@lazy` are not enumerable, making them invisible when spreading objects (`{...o}`). This breaks compatibility with code that expects to spread output objects.

**Changes made:**
- Renamed `@lazy` decorator to `@lazyProp` for better clarity
- Created `LazyProperties` base class that automatically sets up lazy properties in its constructor
- Updated `OutputChunkImpl`, `OutputAssetImpl`, and `RolldownOutputImpl` to extend `LazyProperties`
- Removed manual `setupLazyProperties(this)` calls from constructors - now handled by base class
- Made `setupLazyProperties` internal since it's only called by the base class
- Updated all `@lazy` usages to `@lazyProp`
- Added comprehensive documentation explaining the behavior

**Architecture:**
Classes using lazy properties now follow this pattern:
```typescript
class MyClass extends LazyProperties {
  @lazyprop
  get expensiveValue() {
    return someExpensiveComputation();
  }
}
```

This provides a cleaner, more maintainable solution that:
- Eliminates the need to manually call `setupLazyProperties(this)` in every constructor
- Makes the pattern more discoverable and consistent
- Clearly documents the requirement to extend `LazyProperties`
- Preserves all existing functionality (lazy evaluation, caching, enumerability)

<!-- START COPILOT CODING AGENT SUFFIX -->

<details>

<summary>Original prompt</summary>

>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>[Bug]: output.fileName became non-enumerable in 1.0.0-beta.46</issue_title>
> <issue_description>### Reproduction link or steps
>
> https://stackblitz.com/edit/diwp1dyb?file=build.js&view=editor
>
> ### What is expected?
>
> ```js
> result.output.map((o) => ({...o})).map((o) => o.fileName)
> // ['index.js']
> ```
>
> ### What is actually happening?
>
> ```js
> result.output.map((o) => ({...o})).map((o) => o.fileName)
> // [undefined]
> ```
>
> ### System Info
>
> ```Shell
> rolldown: 1.0.0-beta.46
> ```
>
> ### Any additional comments?
>
> _No response_</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>

</details>

- Fixes #6851

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.
@graphite-app graphite-app bot force-pushed the copilot/fix-file-name-enumerability-bug branch from b275c23 to 208e49a Compare November 5, 2025 12:54
@graphite-app graphite-app bot merged commit 208e49a into main Nov 5, 2025
25 checks passed
@graphite-app graphite-app bot deleted the copilot/fix-file-name-enumerability-bug branch November 5, 2025 13:09
shulaoda added a commit that referenced this pull request Nov 10, 2025
## [1.0.0-beta.48] - 2025-11-10

:boom: Breaking Changes

- `this.emitFile` now respects `chunkFileNames` for chunk type
```js
// rolldown.config.js
export default {
  output: {
    chunkFileNames: 'chunks/[name]-[hash].js'
  }
}

// In plugin
this.emitFile({
  type: 'chunk',
  id: './my-module.js'
});

// Before: Output might not follow chunkFileNames pattern
// After: Output follows 'chunks/[name]-[hash].js' pattern
```

- Deprecated top-level options removed
  - `define` → `transform.define`
  - `inject` → `transform.inject`
  - `dropLabels` → `transform.dropLabels`
  - `keepNames` → `output.keepNames`
  - `profilerNames` → `output.generatedCode.profilerNames`

- Stable plugins moved from experimental
```js
// Before
import { replacePlugin, esmExternalRequirePlugin } from 'rolldown/experimental';

// After
import { replacePlugin, esmExternalRequirePlugin } from 'rolldown/plugins';
```

- `RolldownBuild#scan` is removed, now only available from `rolldown/experimental`
```js
// Before: scan was a method on RolldownBuild
const build = await rolldown(config);
await build.scan();

// After: import scan from rolldown/experimental
import { scan } from 'rolldown/experimental';
await scan(config);
```

### 💥 BREAKING CHANGES

- `this.emitFile` does not respect `chunkFileNames` (#6868) by @Copilot
- remove deprecated top-level `dropLabels` option (#6915) by @sapphi-red
- remove deprecated top-level `keepNames` option (#6914) by @sapphi-red
- remove deprecated top-level `profilerNames` option (#6913) by @sapphi-red
- remove deprecated top-level `define` and `inject` options (#6912) by @sapphi-red
- move stable plugins from experimental to `rolldown/plugins` (#6303) by @shulaoda
- node: remove experimental `RolldownBuild#scan`, only expose it from `rolldown/experimental` (#6889) by @hyf0

### 🚀 Features

- add side-effect detection for global constructors with primitive arguments (#6898) by @IWANABETHATGUY
- rust: use `BundleMode` to handle incremental build exhaustively (#6894) by @hyf0
- detect side-effect-free global function calls (#6897) by @IWANABETHATGUY
- expose `parseSync` / `parseAsync` function (#6866) by @sapphi-red
- skip `__toESM` helper when only named imports are used from CJS modules (#6850) by @Copilot
- rolldown_binding: expose `htmlInlineProxyPlugin` (#6856) by @shulaoda
- rolldown_plugin_html_inline_proxy: align `load` hook logic (#6855) by @shulaoda
- rolldown_plugin_html_inline_proxy: align `resolveId` hook logic (#6854) by @shulaoda
- rolldown_plugin_html_inline_proxy: initialize (#6853) by @shulaoda

### 🐛 Bug Fixes

- cli: support nested options in CLI properly (#6911) by @sapphi-red
- debug: ensure injecting `hook_resolve_id_trigger` correctly (#6908) by @hyf0
- use chunk-specific exports for entry module export detection (#6904) by @IWANABETHATGUY
- debug: ensure build get injected and add tests (#6896) by @hyf0
- error: return friendly error for bundler already closed scenario (#6878) by @hyf0
- improve dynamic entry processing with iterative approach (#6869) by @IWANABETHATGUY
- handle tsconfig option resolve error (#6871) by @sapphi-red
- handle error when creating output chunk directories (#6870) by @sapphi-red
- node: `NormalizedOutputOptionsImpl` and `NormalizedInputOptionsImpl` enumerable (#6861) by @hyf0
- node: keys of `RolldownOutput` should be enumerable (#6852) by @Copilot

### 🚜 Refactor

- rust: rename `BundleContext` to `BundleHandle` (#6893) by @hyf0
- rust: rename `build_span` to `bundle_span` (#6892) by @hyf0
- rust: introduce `PluginDriverFactory` to manage creation of `PluginDriver` (#6891) by @hyf0
- crates/rolldown_binding: remove useless `BindingBundlerImpl` (#6888) by @hyf0
- crates/rolldown_binding: rename `Bundler` to `ClassicBundler` and clarify the purpose (#6887) by @hyf0
- rust: rename `BuildFactory/Build` to `BundleFactory/Bundle` (#6886) by @hyf0
- rust: tweak incremental build related methods of `Bundler` (#6884) by @hyf0
- rust: manage build via `BuildFactory` for `Bundler` (#6883) by @hyf0
- node: implement a new `Bundler` that satisfy the usage of `RolldownBuild` (#6877) by @hyf0
- node: remove useless `nonEnumerable` decorator (#6862) by @hyf0

### 📚 Documentation

- add documentation for native replace plugin (#6315) by @shulaoda
- in-depth/directives: expand description of how directives are handled (#6882) by @sapphi-red
- in-depth/bundling-cjs: clarify the condition of `default` export interop (#6875) by @sapphi-red
- add troubleshooting section for `this` in exported functions (#6865) by @sapphi-red
- update prebuilt binaries list based on Node 24 platform support tier (#6864) by @sapphi-red
- remove unsupported [ext] placeholder from entryFileNames and chunkFileNames (#6859) by @Copilot

### ⚡ Performance

- rolldown: improve sourcemap chain processing (#6858) by @Brooooooklyn

### 🧪 Testing

- add test case for issue #6881 with scientific notation (#6906) by @IWANABETHATGUY

### ⚙️ Miscellaneous Tasks

- deps: update npm packages (#6918) by @renovate[bot]
- deps: update dependency rolldown-plugin-dts to v0.17.5 (#6917) by @renovate[bot]
- deps: lock file maintenance (#6907) by @renovate[bot]
- deps: update rust crates (#6905) by @renovate[bot]
- deps: update npm packages (#6903) by @renovate[bot]
- deps: update github-actions (#6902) by @renovate[bot]
- deps: update `oxc_resolver` and `oxc_resolver_napi` (#6901) by @shulaoda
- deps: update dependency rolldown-plugin-dts to v0.17.4 (#6895) by @renovate[bot]
- deps: update dependency tsdown to v0.16.1 (#6885) by @renovate[bot]
- deps: upgrade napi to remove linker args that skip missing symbols (#6867) by @Boshen

Co-authored-by: shulaoda <[email protected]>
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.

[Bug]: output.fileName became non-enumerable in 1.0.0-beta.46

3 participants