Skip to content

Commit

Permalink
fix: tidy up error messaging for unexpected use of Node.js APIs
Browse files Browse the repository at this point in the history
Fixes #6822
  • Loading branch information
petebacondarwin committed Sep 25, 2024
1 parent 5e2e62c commit 87cd2c0
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 35 deletions.
7 changes: 7 additions & 0 deletions .changeset/early-tigers-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

fix: tidy up error messaging for unexpected use of Node.js APIs

Fixes #6822
116 changes: 96 additions & 20 deletions packages/wrangler/src/__tests__/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9256,27 +9256,103 @@ export default{
`);
});

it("should recommend node compatibility mode when using node builtins and node-compat isn't enabled", async () => {
it("should recommend node compatibility flag mode when using node builtins and no node compat is enabled", async () => {
writeWranglerToml();
fs.writeFileSync(
"index.js",
`
import path from 'path';
console.log(path.join("some/path/to", "a/file.txt"));
export default {}
`
);
let err: esbuild.BuildFailure | undefined;
try {
await runWrangler("deploy index.js --dry-run"); // expecting this to throw, as node compatibility isn't enabled
} catch (e) {
err = e as esbuild.BuildFailure;
}
expect(
esbuild.formatMessagesSync(err?.errors ?? [], { kind: "error" }).join()
).toMatch(
/The package "path" wasn't found on the file system but is built into node\.\s+Add "node_compat = true" to your wrangler\.toml file and make sure to prefix the module name with "node:" to enable Node.js compatibility\./
);
fs.writeFileSync("index.js", "import path from 'path';");

await expect(
runWrangler("deploy index.js --dry-run").catch((e) =>
esbuild
.formatMessagesSync(e?.errors ?? [], { kind: "error" })
.join()
.trim()
)
).resolves.toMatchInlineSnapshot(`
"✘ [ERROR] Could not resolve \\"path\\"
index.js:1:17:
1 │ import path from 'path';
╵ ~~~~~~
The package \\"path\\" wasn't found on the file system but is built into node.
- Add the \\"nodejs_compat\\" compatibility flag to your project."
`);
});

it("should recommend node compatibility flag mode when using node builtins and node compat is set only to nodejs_als", async () => {
writeWranglerToml({
compatibility_flags: ["nodejs_als"],
});
fs.writeFileSync("index.js", "import path from 'path';");

await expect(
runWrangler("deploy index.js --dry-run").catch((e) =>
esbuild
.formatMessagesSync(e?.errors ?? [], { kind: "error" })
.join()
.trim()
)
).resolves.toMatchInlineSnapshot(`
"✘ [ERROR] Could not resolve \\"path\\"
index.js:1:17:
1 │ import path from 'path';
╵ ~~~~~~
The package \\"path\\" wasn't found on the file system but is built into node.
- Add the \\"nodejs_compat\\" compatibility flag to your project."
`);
});

it("should recommend node compatibility flag mode when using node builtins and `node_compat` is true", async () => {
writeWranglerToml({
node_compat: true,
});
fs.writeFileSync("index.js", "import fs from 'diagnostics_channel';");

await expect(
runWrangler("deploy index.js --dry-run").catch((e) =>
esbuild
.formatMessagesSync(e?.errors ?? [], { kind: "error" })
.join()
.trim()
)
).resolves.toMatchInlineSnapshot(`
"✘ [ERROR] Could not resolve \\"diagnostics_channel\\"
index.js:1:15:
1 │ import fs from 'diagnostics_channel';
╵ ~~~~~~~~~~~~~~~~~~~~~
The package \\"diagnostics_channel\\" wasn't found on the file system but is built into node.
- Try removing the legacy \\"node_compat\\" setting and add the \\"nodejs_compat\\" compatibility flag in your project"
`);
});

it("should recommend updating the compatibility date mode when using node builtins and the `nodejs_compat` flag", async () => {
writeWranglerToml({
compatibility_date: "2024/09/01", // older than Sept 23rd, 2024
compatibility_flags: ["nodejs_compat"],
});
fs.writeFileSync("index.js", "import fs from 'path';");

await expect(
runWrangler("deploy index.js --dry-run").catch((e) =>
esbuild
.formatMessagesSync(e?.errors ?? [], { kind: "error" })
.join()
.trim()
)
).resolves.toMatchInlineSnapshot(`
"✘ [ERROR] Could not resolve \\"path\\"
index.js:1:15:
1 │ import fs from 'path';
╵ ~~~~~~
The package \\"path\\" wasn't found on the file system but is built into node.
- Make sure to prefix the module name with \\"node:\\" or update your compatibility_date to 2024/09/23 or later."
`);
});

it("should polyfill node builtins when enabled", async () => {
Expand Down
20 changes: 12 additions & 8 deletions packages/wrangler/src/deployment-bundle/build-failures.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { builtinModules } from "node:module";
import type { NodeJSCompatMode } from "./node-compat";
import type * as esbuild from "esbuild";

/**
Expand All @@ -19,23 +20,26 @@ const nodeBuiltinResolveErrorText = new RegExp(
*/
export function rewriteNodeCompatBuildFailure(
errors: esbuild.Message[],
forPages = false
compatMode: NodeJSCompatMode = null
) {
for (const error of errors) {
const match = nodeBuiltinResolveErrorText.exec(error.text);
if (match !== null) {
const issue = `The package "${match[1]}" wasn't found on the file system but is built into node.`;
let text = `The package "${match[1]}" wasn't found on the file system but is built into node.\n`;

const instructionForUser = `${
forPages
? 'Add the "nodejs_compat" compatibility flag to your Pages project'
: 'Add "node_compat = true" to your wrangler.toml file'
} and make sure to prefix the module name with "node:" to enable Node.js compatibility.`;
if (compatMode === null || compatMode === "als") {
text += `- Add the "nodejs_compat" compatibility flag to your project.\n`;
} else if (compatMode === "legacy") {
text += `- Try removing the legacy "node_compat" setting and add the "nodejs_compat" compatibility flag in your project\n`;
}
if (compatMode === "v1" && !match[1].startsWith("node:")) {
text += `- Make sure to prefix the module name with "node:" or update your compatibility_date to 2024/09/23 or later.\n`;
}

error.notes = [
{
location: null,
text: `${issue}\n${instructionForUser}`,
text,
},
];
}
Expand Down
6 changes: 2 additions & 4 deletions packages/wrangler/src/deployment-bundle/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ export type BundleOptions = {
sourcemap?: esbuild.CommonOptions["sourcemap"];
plugins?: esbuild.Plugin[];
isOutfile?: boolean;
forPages?: boolean;
local: boolean;
projectRoot: string | undefined;
defineNavigatorUserAgent: boolean;
Expand Down Expand Up @@ -172,7 +171,6 @@ export async function bundleWorker(
sourcemap,
plugins,
isOutfile,
forPages,
local,
projectRoot,
defineNavigatorUserAgent,
Expand Down Expand Up @@ -485,8 +483,8 @@ export async function bundleWorker(
};
}
} catch (e) {
if (nodejsCompatMode !== "legacy" && isBuildFailure(e)) {
rewriteNodeCompatBuildFailure(e.errors, forPages);
if (isBuildFailure(e)) {
rewriteNodeCompatBuildFailure(e.errors, nodejsCompatMode);
}
throw e;
}
Expand Down
1 change: 0 additions & 1 deletion packages/wrangler/src/pages/functions/buildPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export function buildPluginFromFunctions({
// TODO: mock AE datasets in Pages functions for dev
mockAnalyticsEngineDatasets: [],
targetConsumer: local ? "dev" : "deploy",
forPages: true,
local,
projectRoot: getPagesProjectRoot(),
defineNavigatorUserAgent,
Expand Down
2 changes: 0 additions & 2 deletions packages/wrangler/src/pages/functions/buildWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ export function buildWorkerFromFunctions({
serveLegacyAssetsFromWorker: false,
checkFetch: local,
targetConsumer: local ? "dev" : "deploy",
forPages: true,
local,
projectRoot: getPagesProjectRoot(),
defineNavigatorUserAgent,
Expand Down Expand Up @@ -189,7 +188,6 @@ export function buildRawWorker({
serveLegacyAssetsFromWorker: false,
checkFetch: local,
targetConsumer: local ? "dev" : "deploy",
forPages: true,
local,
projectRoot: getPagesProjectRoot(),
defineNavigatorUserAgent,
Expand Down

0 comments on commit 87cd2c0

Please sign in to comment.