Summary
compileEnvFiles in dist/cli/build/open-next/compile-env-files.js uses fs.appendFileSync to write .open-next/cloudflare/next-env.mjs. The function is not idempotent — if it is ever invoked twice against the same outputDir, the file ends up with duplicate export const production = {…}, export const development = {…}, export const test = {…} lines.
Wrangler then rejects the bundle at deploy time:
X [ERROR] Multiple exports with the same name "production"
.open-next/cloudflare/next-env.mjs:4:13:
4 │ export const production = {…}
~~~~~~~~~~
The symbol "production" was originally declared here:
.open-next/cloudflare/next-env.mjs:1:13:
1 │ export const production = {…}
~~~~~~~~~~
Source
dist/cli/build/open-next/compile-env-files.js (v1.15.1, line 10):
["production", "development", "test"].forEach((mode) =>
fs.appendFileSync(
path.join(envDir, `next-env.mjs`),
`export const ${mode} = ${JSON.stringify(extractProjectEnvVars(mode, buildOpts))};\n`
)
);
Reproduction
On Windows 11 / Node 22 / @opennextjs/cloudflare@1.15.1, the duplicated-file state reproduced in this project across several npm run cf:build runs — the file consistently ended up with 6 lines (each export written twice) rather than 3. I could not isolate a deterministic call path that invokes compileEnvFiles twice in a single build, but the symptom appears reliably and is consistent with a second invocation against a non-empty file (since appendFileSync always appends and never truncates).
Suggested fix
Make the writer idempotent. Either:
- Truncate first (smallest diff):
const targetPath = path.join(envDir, "next-env.mjs");
fs.writeFileSync(targetPath, "");
["production", "development", "test"].forEach((mode) =>
fs.appendFileSync(targetPath, `export const ${mode} = …\n`)
);
- Single write: build the whole content in memory and
writeFileSync once.
Either makes the function safe to call multiple times without producing duplicate exports.
Workaround
I'm currently pinning a truncate-then-append patch via patch-package:
- ["production", "development", "test"].forEach((mode) => fs.appendFileSync(path.join(envDir, `next-env.mjs`), …));
+ const targetPath = path.join(envDir, "next-env.mjs");
+ fs.writeFileSync(targetPath, "");
+ ["production", "development", "test"].forEach((mode) => fs.appendFileSync(targetPath, …));
Happy to open a PR if helpful.
Summary
compileEnvFilesindist/cli/build/open-next/compile-env-files.jsusesfs.appendFileSyncto write.open-next/cloudflare/next-env.mjs. The function is not idempotent — if it is ever invoked twice against the sameoutputDir, the file ends up with duplicateexport const production = {…},export const development = {…},export const test = {…}lines.Wrangler then rejects the bundle at deploy time:
Source
dist/cli/build/open-next/compile-env-files.js(v1.15.1, line 10):Reproduction
On Windows 11 / Node 22 /
@opennextjs/cloudflare@1.15.1, the duplicated-file state reproduced in this project across severalnpm run cf:buildruns — the file consistently ended up with 6 lines (each export written twice) rather than 3. I could not isolate a deterministic call path that invokescompileEnvFilestwice in a single build, but the symptom appears reliably and is consistent with a second invocation against a non-empty file (sinceappendFileSyncalways appends and never truncates).Suggested fix
Make the writer idempotent. Either:
writeFileSynconce.Either makes the function safe to call multiple times without producing duplicate exports.
Workaround
I'm currently pinning a
truncate-then-appendpatch viapatch-package:Happy to open a PR if helpful.