Skip to content

Commit dd29ae9

Browse files
niemyjskiclaude
andcommitted
Add resolve-package-imports build step and update Next.js example
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c6f087d commit dd29ae9

File tree

10 files changed

+136
-14
lines changed

10 files changed

+136
-14
lines changed

example/nextjs/app/api/demo/route.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { after } from "next/server";
22

3-
import { Exceptionless, KnownEventDataKeys, startup } from "../../../lib/exceptionless-server.js";
3+
import { startup } from "../../../lib/exceptionless-server.js";
44
import { buildRequestContextFromRequest } from "../../../lib/next-request.js";
55

66
export async function POST(request) {
@@ -12,7 +12,7 @@ export async function POST(request) {
1212
throw new Error("Route handler crash from the Exceptionless Next.js demo");
1313
}
1414

15-
await startup();
15+
const { Exceptionless, KnownEventDataKeys } = await startup();
1616

1717
const builder = Exceptionless.createLog("nextjs.route", "Route handler log from the demo page", "info").addTags("route-handler");
1818

@@ -21,6 +21,7 @@ export async function POST(request) {
2121
await builder.submit();
2222

2323
after(async () => {
24+
const { Exceptionless } = await startup();
2425
await Exceptionless.processQueue();
2526
});
2627

example/nextjs/instrumentation.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ export async function onRequestError(error, request, context) {
1414
return;
1515
}
1616

17-
const { Exceptionless, KnownEventDataKeys, startup, toError } = await import("./lib/exceptionless-server.js");
17+
const { startup } = await import("./lib/exceptionless-server.js");
1818
const digest = typeof error === "object" && error !== null && "digest" in error ? error.digest : undefined;
1919

20-
await startup();
20+
const { Exceptionless, KnownEventDataKeys, toError } = await startup();
2121

2222
const builder = Exceptionless.createUnhandledException(toError(error), `nextjs.${context.routeType}`).addTags("on-request-error");
2323

example/nextjs/lib/exceptionless-browser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Exceptionless, KnownEventDataKeys } from "../../../packages/browser/dist/index.bundle.js";
1+
import { Exceptionless, KnownEventDataKeys } from "@exceptionless/browser";
22

33
export { Exceptionless };
44

example/nextjs/lib/exceptionless-server.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { Exceptionless, KnownEventDataKeys, toError } from "../../../packages/node/dist/index.bundle.js";
1+
import { ExceptionlessClient, KnownEventDataKeys, toError } from "@exceptionless/core";
22

3-
export { Exceptionless, KnownEventDataKeys, toError };
3+
export { KnownEventDataKeys, toError };
4+
5+
export const Exceptionless = new ExceptionlessClient();
46

57
let startupPromise;
68

7-
export function startup() {
8-
startupPromise ??= Exceptionless.startup((config) => {
9+
export async function startup() {
10+
startupPromise ??= (async () => {
11+
await Exceptionless.startup((config) => {
912
if (process.env.EXCEPTIONLESS_API_KEY ?? process.env.NEXT_PUBLIC_EXCEPTIONLESS_API_KEY) {
1013
config.apiKey = process.env.EXCEPTIONLESS_API_KEY ?? process.env.NEXT_PUBLIC_EXCEPTIONLESS_API_KEY;
1114
}
@@ -50,7 +53,9 @@ export function startup() {
5053
return Promise.resolve();
5154
}
5255
});
53-
});
56+
57+
return { Exceptionless, KnownEventDataKeys, toError };
58+
})();
5459

5560
return startupPromise;
5661
}

packages/browser/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
}
4040
},
4141
"scripts": {
42-
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
42+
"build": "tsc -p tsconfig.json && node ../../scripts/resolve-package-imports.mjs && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
4343
"watch": "tsc -p ../core/tsconfig.json -w --preserveWatchOutput & tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --watch --outfile=dist/index.bundle.js",
4444
"test": "cd ../.. && vitest run --project browser",
4545
"test:watch": "cd ../.. && vitest --project browser"

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
}
4040
},
4141
"scripts": {
42-
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
42+
"build": "tsc -p tsconfig.json && node ../../scripts/resolve-package-imports.mjs && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
4343
"watch": "tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --watch --outfile=dist/index.bundle.js",
4444
"test": "cd ../.. && vitest run --project core",
4545
"test:watch": "cd ../.. && vitest --project core"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import path from "path";
2+
import { describe, expect, test } from "vitest";
3+
4+
import { rewritePackageImportSpecifiers } from "../../../scripts/resolve-package-imports.mjs";
5+
6+
describe("rewritePackageImportSpecifiers", () => {
7+
test("should rewrite top-level package imports to relative paths", () => {
8+
const filePath = path.resolve("packages/core/dist/index.js");
9+
const distDir = path.resolve("packages/core/dist");
10+
11+
const result = rewritePackageImportSpecifiers('export { Configuration } from "#/configuration/Configuration.js";\n', filePath, distDir);
12+
13+
expect(result).toBe('export { Configuration } from "./configuration/Configuration.js";\n');
14+
});
15+
16+
test("should rewrite nested package imports to relative paths", () => {
17+
const filePath = path.resolve("packages/core/dist/submission/DefaultSubmissionClient.js");
18+
const distDir = path.resolve("packages/core/dist");
19+
20+
const result = rewritePackageImportSpecifiers('import { SettingsManager } from "#/configuration/SettingsManager.js";\n', filePath, distDir);
21+
22+
expect(result).toBe('import { SettingsManager } from "../configuration/SettingsManager.js";\n');
23+
});
24+
25+
test("should rewrite dynamic imports to relative paths", () => {
26+
const filePath = path.resolve("packages/core/dist/index.js");
27+
const distDir = path.resolve("packages/core/dist");
28+
29+
const result = rewritePackageImportSpecifiers('const module = await import("#/plugins/default/HeartbeatPlugin.js");\n', filePath, distDir);
30+
31+
expect(result).toBe('const module = await import("./plugins/default/HeartbeatPlugin.js");\n');
32+
});
33+
});

packages/node/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"node": ">=18"
4343
},
4444
"scripts": {
45-
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --platform=node --format=esm --conditions=source --outfile=dist/index.bundle.js",
45+
"build": "tsc -p tsconfig.json && node ../../scripts/resolve-package-imports.mjs && esbuild src/index.ts --bundle --sourcemap --platform=node --format=esm --conditions=source --outfile=dist/index.bundle.js",
4646
"watch": "tsc -p ../core/tsconfig.json -w --preserveWatchOutput & tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --platform=node --sourcemap --format=esm --conditions=source --watch --outfile=dist/index.bundle.js",
4747
"test": "cd ../.. && vitest run --project node",
4848
"test:watch": "cd ../.. && vitest --project node"

packages/react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
}
4040
},
4141
"scripts": {
42-
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
42+
"build": "tsc -p tsconfig.json && node ../../scripts/resolve-package-imports.mjs && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
4343
"watch": "tsc -p ../core/tsconfig.json -w --preserveWatchOutput & tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --watch --outfile=dist/index.bundle.js"
4444
},
4545
"sideEffects": false,
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import path from "node:path";
2+
import { readdir, readFile, stat, writeFile } from "node:fs/promises";
3+
import { fileURLToPath } from "node:url";
4+
5+
const PACKAGE_IMPORT_PREFIX = "#/";
6+
const FILE_PATTERN = /\.(?:js|d\.ts)$/;
7+
8+
export function rewritePackageImportSpecifiers(source, filePath, distDir) {
9+
const rewrite = (match, prefix, specifier, suffix) => `${prefix}${toRelativeSpecifier(filePath, distDir, specifier)}${suffix}`;
10+
11+
return source
12+
.replace(/(from\s+["'])#\/([^"']+)(["'])/g, rewrite)
13+
.replace(/(import\(\s*["'])#\/([^"']+)(["']\s*\))/g, rewrite);
14+
}
15+
16+
export async function rewritePackageDistImports(packageDir) {
17+
const distDir = path.join(packageDir, "dist");
18+
const files = await collectFiles(distDir);
19+
20+
await Promise.all(
21+
files.map(async (filePath) => {
22+
if (!FILE_PATTERN.test(filePath)) {
23+
return;
24+
}
25+
26+
const source = await readFile(filePath, "utf8");
27+
const rewritten = rewritePackageImportSpecifiers(source, filePath, distDir);
28+
29+
if (rewritten !== source) {
30+
await writeFile(filePath, rewritten, "utf8");
31+
}
32+
})
33+
);
34+
}
35+
36+
async function collectFiles(directory) {
37+
const entries = await readdir(directory, { withFileTypes: true });
38+
const files = [];
39+
40+
for (const entry of entries) {
41+
const entryPath = path.join(directory, entry.name);
42+
43+
if (entry.isDirectory()) {
44+
files.push(...(await collectFiles(entryPath)));
45+
continue;
46+
}
47+
48+
if (entry.isFile()) {
49+
files.push(entryPath);
50+
}
51+
}
52+
53+
return files;
54+
}
55+
56+
function toRelativeSpecifier(filePath, distDir, specifier) {
57+
const targetPath = path.join(distDir, specifier);
58+
let relativePath = path.relative(path.dirname(filePath), targetPath).replaceAll(path.sep, "/");
59+
60+
if (!relativePath.startsWith(".")) {
61+
relativePath = `./${relativePath}`;
62+
}
63+
64+
return relativePath;
65+
}
66+
67+
async function main() {
68+
const requestedDirectory = process.argv[2] ? path.resolve(process.cwd(), process.argv[2]) : process.cwd();
69+
const distDirectory = path.join(requestedDirectory, "dist");
70+
const distStats = await stat(distDirectory).catch(() => null);
71+
72+
if (!distStats?.isDirectory()) {
73+
throw new Error(`Expected a dist directory in ${requestedDirectory}`);
74+
}
75+
76+
await rewritePackageDistImports(requestedDirectory);
77+
}
78+
79+
const currentFilePath = fileURLToPath(import.meta.url);
80+
81+
if (process.argv[1] && path.resolve(process.argv[1]) === currentFilePath) {
82+
await main();
83+
}

0 commit comments

Comments
 (0)