You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@wdio/bundler#build can produce a self-inconsistent dist/ in the turbo remote cache, which is then replayed on every cache hit and breaks any package that builds through the bundler. This surfaced on #505 as repeated Build [<OS>] failures:
❌ Build failed: Rollup build failed: Cannot destructure property
'injectDependencyPlugin' of '(intermediate value)' as it is undefined.
node "…/packages/bundler/dist/cli.js" build
Mechanism
The bundler's compiled dist/cli.js loads its plugins via a content-hash-named dynamic chunk: await import('./plugins-<hash>.js').then(n => n.p).
packages/bundler/dist/ is gitignored — it is 100% built in CI / restored from the turbo remote cache.
When the cached cli.js and its plugins-<hash>.js chunk don't agree (the chunk doesn't export what cli.js expects), n.p is undefined → the destructure throws.
It stayed dormant for weeks: every service build was a turbo cache hit, so node bundler/dist/cli.js was never actually executed. The first service src/** cache-miss in a while (a launcher edit on feat(browser-mode): wire devServer auto-start into the four launchers (#417) #505) invoked the bundler CLI and hit the poisoned artifact. Green on one OS / red on another, and green locally (fresh, consistent dist/), are all consistent with a bad cached artifact rather than bad source.
Contributing factors
build had no clean step — rollup's hashed chunks accumulate in dist/ across incremental builds, so a cached dist/** can contain a stale/foreign chunk alongside a newer cli.js.
The bundler's turbo build.inputs don't capture the toolchain.inputs is ['src/**', 'tsconfig*.json', 'wdio-bundler.config.ts', 'rollup.config.ts', 'package.json'] — it does not include pnpm-lock.yaml. A rollup (or other build-dep) bump via a lockfile-only change keeps the same cache key while changing the actual build output → a future re-poison is possible.
build(bundler): clean dist before rollup (shx rm -rf dist && rollup …) — busts the poisoned cache key (changes package.json) and forces a fresh, self-consistent rebuild that gets re-cached; prevents stale-chunk accumulation. (commit 01aa761a8)
@wdio/bundler declared as a devDependency on all bundler-consuming packages so turbo's ^build orders @wdio/bundler#build before consumers (commit 00c11d931).
This unblocks CI but doesn't permanently close factor #2.
Proposed durable fix (pick one/some)
Add pnpm-lock.yaml to the bundler's build.inputs (and any other package that runs a bundled toolchain) so a toolchain bump invalidates the cache key.
Give the plugins chunk a stable, non-hashed name (rollup output.chunkFileNames) or inline it, so cli.js ↔ chunk can't drift by filename.
Consider whether @wdio/bundler#build should be remote-cached at all, given it is the toolchain other builds depend on.
Notes
Adding the @wdio/bundler devDep also introduced harmless pnpm install-time WARNs (Failed to create bin … wdio-bundler … dist/cli.js) because the bin target doesn't exist until the bundler is built. Cosmetic; the build invokes the CLI by absolute path, not the linked bin.
Summary
@wdio/bundler#buildcan produce a self-inconsistentdist/in the turbo remote cache, which is then replayed on every cache hit and breaks any package that builds through the bundler. This surfaced on #505 as repeatedBuild [<OS>]failures:Mechanism
dist/cli.jsloads its plugins via a content-hash-named dynamic chunk:await import('./plugins-<hash>.js').then(n => n.p).packages/bundler/dist/is gitignored — it is 100% built in CI / restored from the turbo remote cache.cli.jsand itsplugins-<hash>.jschunk don't agree (the chunk doesn't export whatcli.jsexpects),n.pisundefined→ the destructure throws.node bundler/dist/cli.jswas never actually executed. The first servicesrc/**cache-miss in a while (a launcher edit on feat(browser-mode): wire devServer auto-start into the four launchers (#417) #505) invoked the bundler CLI and hit the poisoned artifact. Green on one OS / red on another, and green locally (fresh, consistentdist/), are all consistent with a bad cached artifact rather than bad source.Contributing factors
buildhad no clean step — rollup's hashed chunks accumulate indist/across incremental builds, so a cacheddist/**can contain a stale/foreign chunk alongside a newercli.js.build.inputsdon't capture the toolchain.inputsis['src/**', 'tsconfig*.json', 'wdio-bundler.config.ts', 'rollup.config.ts', 'package.json']— it does not includepnpm-lock.yaml. A rollup (or other build-dep) bump via a lockfile-only change keeps the same cache key while changing the actual build output → a future re-poison is possible.Stopgap already shipped (on #505)
build(bundler): clean dist before rollup(shx rm -rf dist && rollup …) — busts the poisoned cache key (changespackage.json) and forces a fresh, self-consistent rebuild that gets re-cached; prevents stale-chunk accumulation. (commit01aa761a8)@wdio/bundlerdeclared as adevDependencyon all bundler-consuming packages so turbo's^buildorders@wdio/bundler#buildbefore consumers (commit00c11d931).This unblocks CI but doesn't permanently close factor #2.
Proposed durable fix (pick one/some)
pnpm-lock.yamlto the bundler'sbuild.inputs(and any other package that runs a bundled toolchain) so a toolchain bump invalidates the cache key.output.chunkFileNames) or inline it, socli.js↔ chunk can't drift by filename.@wdio/bundler#buildshould be remote-cached at all, given it is the toolchain other builds depend on.Notes
@wdio/bundlerdevDep also introduced harmlesspnpminstall-time WARNs (Failed to create bin … wdio-bundler … dist/cli.js) because the bin target doesn't exist until the bundler is built. Cosmetic; the build invokes the CLI by absolute path, not the linked bin.🤖 Generated with Claude Code