-
Notifications
You must be signed in to change notification settings - Fork 737
Description
Reproduction link or steps
When there is an import of kind import * as dep from "./dep.js" which is later used as dep.clashingIdentifier() then Rolldown adds that clashingIdentifier into scope as is + renames already existing local clashingIdentifier into clashingIdentifier$1. The problem is that it does not check whether there already was another local clashingIdentifier$1. That results into two declarations of the same identifier which is an error.
This is not a synthetic theoretical issue, I discovered it in real world project.
Context: I use Gleam + Lustre for web development and Vite for bundling my projects. After upgrading to Vite 8.0 I discovered that produced JS code started failing with errors like Uncaught SyntaxError: Identifier 'v' has already been declared.
When Gleam is used with JavaScript as a target, Gleam compiler generates *.mjs files which I then import in HTML and/or other JS/TS modules (and vice versa) and bundle the whole project using Vite 8.0. There are a couple of things that come together to cause the issue.
Firstly, let's say there is a Gleam module that imports another Gleam module import lustre/vdom/path which is then path.child(some_path). Gleam compiler transpiles such import to import * as $path from "../../lustre/vdom/path.mjs" and the function call to $path.child(some_path).
Secondly, Gleam has shadowing and if in some scope there is a declaration like let child = "shadowed" which is at some later point followed by let child = "value" — that is a totally valid (and still immutable) Gleam code. However Gleam compiler would produce following JS for those: let child = "shadowed"; for the first assignment and let child$1 = "value"; for the second assignment. You can see this in Gleam Playground without having to install Gleam: just click "Compiled JavaScript" tab on the right side.
And as you might've guessed, if I happen to have both of those things in the same module — the import of a Gleam package with the child function, and a shadowed local variable with the same name — that leads to the exact situation that was shown in the Rolldown REPL and Rolldown generates invalid JavaScript.
What is expected?
When deconflicting(?) I expect Rolldown to check if identifier name like identifier$1 is already taken before it chooses to use it.
What is actually happening?
When rewriting imports of valid JavaScript code Rolldown creates name conflicts that result in errors like Uncaught SyntaxError: Identifier '...' has already been declared. For example, valid JS like:
import * as dep from "./dep.js";
function test(head, tail) {
let clashingIdentifier = head; // <- this was OK
let middle = dep.clashingIdentifier();
let clashingIdentifier$1 = tail; // <- this was OK
return clashingIdentifier + middle + clashingIdentifier$1;
}
test("head", "tail");gets transformed into
import { clashingIdentifier } from "./dep.js";
//#region index.js
function test(head, tail) {
let clashingIdentifier$1 = head; // <- this is a conflict now
let middle = clashingIdentifier();
let clashingIdentifier$1 = tail; // <- this is a conflict now
return clashingIdentifier$1 + middle + clashingIdentifier$1;
}
test("head", "tail");
//#endregionSystem Info
System:
OS: macOS 15.5
CPU: (8) x64 Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
Memory: 1.32 GB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 25.8.0 - /Users/idea-list/.local/share/mise/installs/node/25.8.0/bin/node
npm: 11.11.0 - /Users/idea-list/.local/share/mise/installs/node/25.8.0/bin/npm
pnpm: 10.28.0 - /etc/profiles/per-user/idea-list/bin/pnpm
bun: 1.3.3 - /etc/profiles/per-user/idea-list/bin/bun
Browsers:
Brave Browser: 145.1.87.188
Safari: 18.5
npmPackages:
rolldown: ^1.0.0-rc.9 => 1.0.0-rc.9Any additional comments?
No response
Metadata
Metadata
Assignees
Type
Fields
Give feedbackPriority
Effort