diff --git a/.changeset/unlucky-actors-swim.md b/.changeset/unlucky-actors-swim.md new file mode 100644 index 000000000000..92da1215f1b8 --- /dev/null +++ b/.changeset/unlucky-actors-swim.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +fix: prevent \_\_cf_cjs name collision in the hybrid Nodejs compat plugin diff --git a/fixtures/pages-functions-unenv-alias/functions/[[path]].ts b/fixtures/pages-functions-unenv-alias/functions/[[path]].ts new file mode 100644 index 000000000000..b39ea9a77bca --- /dev/null +++ b/fixtures/pages-functions-unenv-alias/functions/[[path]].ts @@ -0,0 +1,10 @@ +const fetch = require("cross-fetch"); + +export const onRequest = () => { + const supportsDefaultExports = typeof fetch === "function"; + const supportsNamedExports = typeof fetch.Headers === "function"; + + return new Response( + supportsDefaultExports && supportsNamedExports ? "OK!" : "KO!" + ); +}; diff --git a/fixtures/pages-functions-unenv-alias/package.json b/fixtures/pages-functions-unenv-alias/package.json new file mode 100644 index 000000000000..ea4d0bcb669e --- /dev/null +++ b/fixtures/pages-functions-unenv-alias/package.json @@ -0,0 +1,25 @@ +{ + "name": "pages-functions-unenv-alias", + "private": true, + "sideEffects": false, + "scripts": { + "check:type": "tsc", + "dev:functions-app": "wrangler pages dev --port 8792", + "test:ci": "vitest run", + "test:watch": "vitest", + "type:tests": "tsc -p ./tests/tsconfig.json" + }, + "devDependencies": { + "@cloudflare/workers-tsconfig": "workspace:^", + "typescript": "catalog:default", + "undici": "catalog:default", + "vitest": "catalog:default", + "wrangler": "workspace:*" + }, + "engines": { + "node": ">=16.13" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/fixtures/pages-functions-unenv-alias/tests/index.test.ts b/fixtures/pages-functions-unenv-alias/tests/index.test.ts new file mode 100644 index 000000000000..7059f2842b23 --- /dev/null +++ b/fixtures/pages-functions-unenv-alias/tests/index.test.ts @@ -0,0 +1,21 @@ +import { resolve } from "node:path"; +import { fetch } from "undici"; +import { describe, it } from "vitest"; +import { runWranglerPagesDev } from "../../shared/src/run-wrangler-long-lived"; + +describe("Pages functions with unenv aliased packages", () => { + it("should run dev server when requiring an unenv aliased package", async ({ + expect, + onTestFinished, + }) => { + const { ip, port, stop } = await runWranglerPagesDev( + resolve(__dirname, ".."), + "./functions", + ["--port=0", "--inspector-port=0"] + ); + onTestFinished(stop); + const response = await fetch(`http://${ip}:${port}/`); + const body = await response.text(); + expect(body).toEqual(`OK!`); + }); +}); diff --git a/fixtures/pages-functions-unenv-alias/tests/tsconfig.json b/fixtures/pages-functions-unenv-alias/tests/tsconfig.json new file mode 100644 index 000000000000..d2ce7f144694 --- /dev/null +++ b/fixtures/pages-functions-unenv-alias/tests/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@cloudflare/workers-tsconfig/tsconfig.json", + "compilerOptions": { + "types": ["node"] + }, + "include": ["**/*.ts", "../../../node-types.d.ts"] +} diff --git a/fixtures/pages-functions-unenv-alias/tsconfig.json b/fixtures/pages-functions-unenv-alias/tsconfig.json new file mode 100644 index 000000000000..7d1b8444dea9 --- /dev/null +++ b/fixtures/pages-functions-unenv-alias/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "esModuleInterop": true, + "module": "CommonJS", + "lib": ["ES2020"], + "types": ["node", "@cloudflare/workers-types"], + "moduleResolution": "node", + "noEmit": true, + "skipLibCheck": true, + "checkJs": true + }, + "include": [ + "apps/workerjs-directory/_worker.js/index.js", + "apps/workerjs-file/_worker.js", + "functions/[[path]].ts", + "tests", + "../../node-types.d.ts" + ] +} diff --git a/fixtures/pages-functions-unenv-alias/vitest.config.mts b/fixtures/pages-functions-unenv-alias/vitest.config.mts new file mode 100644 index 000000000000..846cddc41995 --- /dev/null +++ b/fixtures/pages-functions-unenv-alias/vitest.config.mts @@ -0,0 +1,9 @@ +import { defineProject, mergeConfig } from "vitest/config"; +import configShared from "../../vitest.shared"; + +export default mergeConfig( + configShared, + defineProject({ + test: {}, + }) +); diff --git a/fixtures/pages-functions-unenv-alias/wrangler.toml b/fixtures/pages-functions-unenv-alias/wrangler.toml new file mode 100644 index 000000000000..a4053f7c1a53 --- /dev/null +++ b/fixtures/pages-functions-unenv-alias/wrangler.toml @@ -0,0 +1,3 @@ +name = "pages-functions-unenv-alias" +compatibility_date = "2024-12-30" +compatibility_flags = ["nodejs_compat"] diff --git a/packages/wrangler/src/deployment-bundle/esbuild-plugins/hybrid-nodejs-compat.ts b/packages/wrangler/src/deployment-bundle/esbuild-plugins/hybrid-nodejs-compat.ts index b3a04bbecf7c..d7b35c75657d 100644 --- a/packages/wrangler/src/deployment-bundle/esbuild-plugins/hybrid-nodejs-compat.ts +++ b/packages/wrangler/src/deployment-bundle/esbuild-plugins/hybrid-nodejs-compat.ts @@ -143,29 +143,18 @@ function handleUnenvAliasedPackages( }; }); - build.initialOptions.banner = { js: "", ...build.initialOptions.banner }; - build.initialOptions.banner.js += dedent` - function __cf_cjs(esm) { - const cjs = 'default' in esm ? esm.default : {}; - for (const [k, v] of Object.entries(esm)) { - if (k !== 'default') { - Object.defineProperty(cjs, k, { - enumerable: true, - value: v, - }); - } - } - return cjs; - } - `; - build.onLoad( { filter: /.*/, namespace: REQUIRED_UNENV_ALIAS_NAMESPACE }, ({ path }) => { return { contents: dedent` import * as esm from '${path}'; - module.exports = __cf_cjs(esm); + module.exports = Object.entries(esm) + .filter(([k,]) => k !== 'default') + .reduce((cjs, [k, value]) => + Object.defineProperty(cjs, k, { value, enumerable: true }), + "default" in esm ? esm.default : {} + ); `, loader: "js", }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f3106f85c233..b6d7f319ecca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -476,6 +476,24 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/pages-functions-unenv-alias: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:^ + version: link:../../packages/workers-tsconfig + typescript: + specifier: catalog:default + version: 5.7.3 + undici: + specifier: catalog:default + version: 5.28.4 + vitest: + specifier: catalog:default + version: 2.1.9(@types/node@18.19.74)(@vitest/ui@2.1.9)(msw@2.4.3(typescript@5.7.3))(supports-color@9.2.2) + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + fixtures/pages-functions-wasm-app: devDependencies: '@cloudflare/workers-tsconfig': @@ -14671,7 +14689,7 @@ snapshots: '@rollup/pluginutils@5.1.0(rollup@4.30.1)': dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: @@ -14679,7 +14697,7 @@ snapshots: '@rollup/pluginutils@5.1.4(rollup@4.30.1)': dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: