Repository navigation
Description
Reproduction link or steps
package.json:
{
"type": "module",
"dependencies": {
"rolldown": "1.3.0",
"rolldown12": "npm:rolldown@1.2.16"
}
}src/main.js:
export function load(lang) {
return import(`./locales/${lang}.js`)
}src/locales/en.js and src/locales/de.js: export default 'en' and export default 'de'
repro.js:
import { rolldown as rolldown13 } from 'rolldown'
import { rolldown as rolldown12 } from 'rolldown12'
import { dynamicImportVarsPlugin } from 'rolldown/experimental' // from rolldown 1.3.0
for (const [version, rolldown] of [['1.3.0', rolldown13], ['1.2.16', rolldown12]]) {
const bundle = await rolldown({ input: 'src/main.js', plugins: [dynamicImportVarsPlugin()] })
const { output } = await bundle.generate({ format: 'esm' })
const transformed = !output[0].code.includes('import(`')
console.log(`bundled with rolldown ${version}: dynamic import transformed: ${transformed}`)
}Run npm install && node repro.js:
bundled with rolldown 1.3.0: dynamic import transformed: true
bundled with rolldown 1.2.16: dynamic import transformed: false
What is expected?
Rolldown applies the built-in plugin, or fails the build with an error that the plugin was created by another rolldown package.
What is actually happening?
Rolldown ignores the plugin without an error or warning, and the bundle contains the untransformed import(`./locales/${lang}.js`). The check plugin instanceof BuiltinPlugin (in bindingify-input-options.ts, normalize-plugin-option.ts and plugin-driver.ts) fails for the BuiltinPlugin class of the other package, so the object ends up as a JS plugin without hooks.
System Info
System:
OS: Windows 11 10.0.26300
CPU: (28) x64 13th Gen Intel(R) Core(TM) i7-13850HX
Memory: 8.23 GB / 31.66 GB
Binaries:
Node: 24.21.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.22 - C:\Program Files\nodejs\yarn.CMD
npm: 9.8.1 - C:\Program Files\nodejs\npm.CMD
pnpm: 10.33.4 - C:\Program Files\nodejs\pnpm.CMD
npmPackages:
rolldown: 1.3.0 => 1.3.0
Any additional comments?
We publish a plugin package that wraps dynamicImportVarsPlugin and importGlobPlugin from rolldown/experimental, with rolldown as peer dependency. After a dependency update, our project resolved rolldown 1.3.0, while tsdown 0.23.5 depends on rolldown ~1.2.16. tsdown bundled with 1.2.16 and skipped both plugins, and the build succeeded with broken dynamic imports. Every package that returns built-in plugins can run into this when the rolldown of the project differs from the rolldown of tsdown or Vite.
Proposal: the BuiltinPlugin constructor sets a brand such as Symbol.for('rolldown.BuiltinPlugin'), and the plugin normalization throws an error for branded objects that fail the instanceof check, with the plugin name and a hint to install a single rolldown version. Passing such plugins on to the native binding is an alternative, but the options of a built-in plugin can change between versions. I can open a PR for the error if this approach is fine.
As a workaround, our plugin now compares this.meta.rolldownVersion with VERSION from its own rolldown in buildStart and fails the build on a mismatch.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Activity