Skip to content

[Bug]: Produced JS contains conflicting identifiers #8739

@idea-list

Description

@idea-list

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.

REPL with minimal repro

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");
//#endregion

System 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.9

Any additional comments?

No response

Metadata

Metadata

Assignees

Type

Priority

None yet

Effort

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions