@alloy-js/core 0.23.0-dev.12 → 0.23.0-dev.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/dev/src/debug/cli.js +3 -2
  2. package/dist/dev/src/debug/cli.js.map +1 -1
  3. package/dist/dev/src/debug/source-map.browser.js +24 -0
  4. package/dist/dev/src/debug/source-map.browser.js.map +1 -0
  5. package/dist/dev/src/debug/trace.js +7 -6
  6. package/dist/dev/src/debug/trace.js.map +1 -1
  7. package/dist/dev/src/host/node-host.browser.js +21 -0
  8. package/dist/dev/src/host/node-host.browser.js.map +1 -0
  9. package/dist/dev/src/host/node-host.js +20 -0
  10. package/dist/dev/src/host/node-host.js.map +1 -0
  11. package/dist/dev/src/render-stack.js +4 -3
  12. package/dist/dev/src/render-stack.js.map +1 -1
  13. package/dist/dev/src/write-output.js +6 -5
  14. package/dist/dev/src/write-output.js.map +1 -1
  15. package/dist/dev/test/browser-build.test.js +67 -68
  16. package/dist/dev/test/browser-build.test.js.map +1 -1
  17. package/dist/src/debug/cli.d.ts.map +1 -1
  18. package/dist/src/debug/cli.js +3 -2
  19. package/dist/src/debug/cli.js.map +1 -1
  20. package/dist/src/debug/source-map.browser.d.ts +16 -0
  21. package/dist/src/debug/source-map.browser.d.ts.map +1 -0
  22. package/dist/src/debug/source-map.browser.js +24 -0
  23. package/dist/src/debug/source-map.browser.js.map +1 -0
  24. package/dist/src/debug/trace.d.ts.map +1 -1
  25. package/dist/src/debug/trace.js +7 -6
  26. package/dist/src/debug/trace.js.map +1 -1
  27. package/dist/src/host/node-host.browser.d.ts +11 -0
  28. package/dist/src/host/node-host.browser.d.ts.map +1 -0
  29. package/dist/src/host/node-host.browser.js +21 -0
  30. package/dist/src/host/node-host.browser.js.map +1 -0
  31. package/dist/src/host/node-host.d.ts +11 -0
  32. package/dist/src/host/node-host.d.ts.map +1 -0
  33. package/dist/src/host/node-host.js +20 -0
  34. package/dist/src/host/node-host.js.map +1 -0
  35. package/dist/src/render-stack.d.ts.map +1 -1
  36. package/dist/src/render-stack.js +4 -3
  37. package/dist/src/render-stack.js.map +1 -1
  38. package/dist/src/write-output.d.ts.map +1 -1
  39. package/dist/src/write-output.js +6 -5
  40. package/dist/src/write-output.js.map +1 -1
  41. package/dist/test/browser-build.test.js +67 -68
  42. package/dist/test/browser-build.test.js.map +1 -1
  43. package/dist/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +5 -1
  45. package/src/debug/cli.ts +3 -2
  46. package/src/debug/source-map.browser.ts +30 -0
  47. package/src/debug/trace.ts +7 -6
  48. package/src/host/node-host.browser.ts +23 -0
  49. package/src/host/node-host.ts +22 -0
  50. package/src/render-stack.ts +4 -3
  51. package/src/write-output.ts +6 -5
  52. package/test/browser-build.test.ts +71 -78
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alloy-js/core",
3
- "version": "0.23.0-dev.12",
3
+ "version": "0.23.0-dev.13",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,8 +43,12 @@
43
43
  "browser": {
44
44
  "./dist/src/host/alloy-host.js": "./dist/src/host/alloy-host.browser.js",
45
45
  "./src/host/alloy-host.ts": "./src/host/alloy-host.browser.ts",
46
+ "./dist/src/host/node-host.js": "./dist/src/host/node-host.browser.js",
47
+ "./src/host/node-host.ts": "./src/host/node-host.browser.ts",
46
48
  "./dist/src/inspect.js": "./dist/src/inspect.browser.js",
47
49
  "./src/inspect.ts": "./src/inspect.browser.ts",
50
+ "./dist/src/debug/source-map.js": "./dist/src/debug/source-map.browser.js",
51
+ "./src/debug/source-map.ts": "./src/debug/source-map.browser.ts",
48
52
  "./dist/src/devtools/devtools-server.js": "./dist/src/devtools/devtools-server.browser.js",
49
53
  "./src/devtools/devtools-server.ts": "./src/devtools/devtools-server.browser.ts"
50
54
  },
package/src/debug/cli.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import Table from "cli-table3";
2
2
  import pc from "picocolors";
3
3
  import { contextsByKey } from "../context.js";
4
+ import { stdoutWrite } from "../host/node-host.js";
4
5
  import { getContext, untrack } from "../reactivity.js";
5
6
  import { isReactiveTarget } from "./effects.js";
6
7
 
@@ -143,7 +144,7 @@ export function debugStack() {
143
144
  currentContext.componentOwner &&
144
145
  currentContext.componentOwner.component.name !== "Provider"
145
146
  ) {
146
- process.stdout.write(
147
+ stdoutWrite(
147
148
  style.component.name(currentContext.componentOwner.component.name) +
148
149
  "\n",
149
150
  );
@@ -164,7 +165,7 @@ export function debugStack() {
164
165
  : pc.gray("(none)"),
165
166
  ]);
166
167
 
167
- process.stdout.write(table.toString() + "\n\n");
168
+ stdoutWrite(table.toString() + "\n\n");
168
169
  foundContexts = [];
169
170
  }
170
171
 
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Browser stub for source-map resolution.
3
+ *
4
+ * Source maps are not resolved in the browser — all functions pass through
5
+ * their inputs unchanged.
6
+ */
7
+
8
+ import type { SourceLocation } from "../devtools/devtools-protocol.js";
9
+
10
+ export function loadSourceMapSupport() {
11
+ // no-op in browser
12
+ }
13
+
14
+ export function getRealPath(fileName: string): string {
15
+ return fileName;
16
+ }
17
+
18
+ export function resolveSourceMap(
19
+ fileName: string,
20
+ line: number,
21
+ col: number,
22
+ ): { fileName: string; line: number; col: number } {
23
+ return { fileName, line, col };
24
+ }
25
+
26
+ export function resolveComponentSource(
27
+ source: SourceLocation | undefined,
28
+ ): SourceLocation | undefined {
29
+ return source;
30
+ }
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import type { ServerToClientMessage } from "../devtools/devtools-protocol.js";
5
5
  import { isDevtoolsEnabled } from "../devtools/devtools-server.js";
6
+ import { env, sourceMapsEnabled } from "../host/node-host.js";
6
7
  import { untrack } from "../reactivity.js";
7
8
  import { initTrace, isTraceEnabled } from "./trace-writer.js";
8
9
 
@@ -21,12 +22,12 @@ export function isDebugEnabled(): boolean {
21
22
  // Environment configuration
22
23
  // ─────────────────────────────────────────────────────────────────────────────
23
24
 
24
- const traceEnv = process.env.ALLOY_TRACE ?? "";
25
+ const traceEnv = env("ALLOY_TRACE") ?? "";
25
26
  const tracePhases = new Set<string>(
26
27
  traceEnv === "" ? [] : traceEnv.split(",").map((t) => t.trim()),
27
28
  );
28
29
 
29
- const debuggerIdsEnv = process.env.ALLOY_BREAK_ON_DID ?? "";
30
+ const debuggerIdsEnv = env("ALLOY_BREAK_ON_DID") ?? "";
30
31
  const debuggerIds = new Set<number>();
31
32
  debuggerIdsEnv.split(",").forEach((id) => {
32
33
  const num = parseInt(id, 10);
@@ -37,9 +38,9 @@ debuggerIdsEnv.split(",").forEach((id) => {
37
38
 
38
39
  /** Parse the ALLOY_BREAK_ON_DID environment variable into a set of IDs. */
39
40
  export function parseBreakOnIds(): Set<number> {
40
- const env = process.env.ALLOY_BREAK_ON_DID ?? "";
41
+ const raw = env("ALLOY_BREAK_ON_DID") ?? "";
41
42
  const ids = new Set<number>();
42
- env.split(",").forEach((id) => {
43
+ raw.split(",").forEach((id) => {
43
44
  const num = parseInt(id, 10);
44
45
  if (!isNaN(num)) {
45
46
  ids.add(num);
@@ -65,7 +66,7 @@ if (tracePhases.size > 0) {
65
66
  }
66
67
 
67
68
  // Initialize SQLite trace writer if ALLOY_DEBUG_TRACE is set
68
- const traceDbEnv = process.env.ALLOY_DEBUG_TRACE;
69
+ const traceDbEnv = env("ALLOY_DEBUG_TRACE");
69
70
  if (traceDbEnv) {
70
71
  const traceDbPath =
71
72
  traceDbEnv === "1" || traceDbEnv === "true" ? "alloy-trace.db" : traceDbEnv;
@@ -82,7 +83,7 @@ if (traceDbEnv) {
82
83
  if (import.meta.url.includes("/dist/dev/")) {
83
84
  // eslint-disable-next-line no-console
84
85
  console.log("Alloy debug build loaded.");
85
- if (process.sourceMapsEnabled) {
86
+ if (sourceMapsEnabled()) {
86
87
  // eslint-disable-next-line no-console
87
88
  console.log(" Source maps enabled.");
88
89
  } else {
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Browser stub for Node.js host APIs.
3
+ *
4
+ * Replaces `node-host.ts` in browser builds so that no Node.js globals
5
+ * (`process`, etc.) are referenced.
6
+ */
7
+
8
+ export function env(_key: string): string | undefined {
9
+ return undefined;
10
+ }
11
+
12
+ export function cwd(): string {
13
+ return "";
14
+ }
15
+
16
+ export function stdoutWrite(text: string): void {
17
+ // eslint-disable-next-line no-console
18
+ console.log(text);
19
+ }
20
+
21
+ export function sourceMapsEnabled(): boolean {
22
+ return false;
23
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Node.js host APIs.
3
+ *
4
+ * Provides access to Node.js-specific process APIs. In browser builds this
5
+ * module is replaced by `node-host.browser.ts` which returns safe defaults.
6
+ */
7
+
8
+ export function env(key: string): string | undefined {
9
+ return process.env[key];
10
+ }
11
+
12
+ export function cwd(): string {
13
+ return process.cwd();
14
+ }
15
+
16
+ export function stdoutWrite(text: string): void {
17
+ process.stdout.write(text);
18
+ }
19
+
20
+ export function sourceMapsEnabled(): boolean {
21
+ return !!(process as any).sourceMapsEnabled;
22
+ }
@@ -2,6 +2,7 @@ import pc from "picocolors";
2
2
  import { contextsByKey } from "./context.js";
3
3
  import { SourceDirectoryContext } from "./context/source-directory.js";
4
4
  import { SourceFileContext } from "./context/source-file.js";
5
+ import { cwd } from "./host/node-host.js";
5
6
  import { Context, getContext } from "./reactivity.js";
6
7
  import { Component, Props, SourceLocation } from "./runtime/component.js";
7
8
 
@@ -125,12 +126,12 @@ function formatValue(value: unknown): string {
125
126
  }
126
127
 
127
128
  function formatSourceLocation(source: SourceLocation): string {
128
- const cwd = process.cwd();
129
+ const currentCwd = cwd();
129
130
  let filePath = source.fileName;
130
131
 
131
132
  // Convert to relative path if under cwd
132
- if (filePath.startsWith(cwd)) {
133
- filePath = filePath.slice(cwd.length + 1); // +1 to remove leading slash
133
+ if (currentCwd && filePath.startsWith(currentCwd)) {
134
+ filePath = filePath.slice(currentCwd.length + 1); // +1 to remove leading slash
134
135
  }
135
136
 
136
137
  return `${filePath}:${source.lineNumber}:${source.columnNumber}`;
@@ -1,5 +1,6 @@
1
1
  import { dirname, relative, resolve } from "pathe";
2
2
  import { AlloyHost } from "./host/alloy-host.js";
3
+ import { cwd } from "./host/node-host.js";
3
4
  import { OutputDirectory } from "./render.js";
4
5
  import { traverseOutput } from "./utils.js";
5
6
  /**
@@ -17,7 +18,7 @@ export async function writeOutput(
17
18
  return;
18
19
  }
19
20
  // eslint-disable-next-line no-console
20
- console.log("create", relative(process.cwd(), path));
21
+ console.log("create", relative(cwd(), path));
21
22
  await AlloyHost.mkdir(path);
22
23
  },
23
24
  async visitFile(file) {
@@ -25,10 +26,10 @@ export async function writeOutput(
25
26
  const path = resolve(basePath, file.path);
26
27
  if (await AlloyHost.exists(path)) {
27
28
  // eslint-disable-next-line no-console
28
- console.log("overwrite", relative(process.cwd(), path));
29
+ console.log("overwrite", relative(cwd(), path));
29
30
  } else {
30
31
  // eslint-disable-next-line no-console
31
- console.log("create", relative(process.cwd(), path));
32
+ console.log("create", relative(cwd(), path));
32
33
  }
33
34
 
34
35
  await AlloyHost.write(path, file.contents);
@@ -38,10 +39,10 @@ export async function writeOutput(
38
39
  const target = resolve(basePath, file.path);
39
40
  if (await AlloyHost.exists(target)) {
40
41
  // eslint-disable-next-line no-console
41
- console.log("copy over", relative(process.cwd(), target));
42
+ console.log("copy over", relative(cwd(), target));
42
43
  } else {
43
44
  // eslint-disable-next-line no-console
44
- console.log("copy", relative(process.cwd(), target));
45
+ console.log("copy", relative(cwd(), target));
45
46
  }
46
47
  await AlloyHost.mkdir(dirname(target));
47
48
  await AlloyHost.write(target, AlloyHost.read(source).stream());
@@ -1,91 +1,84 @@
1
- import { execSync } from "child_process";
2
1
  import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
3
2
  import { join } from "path";
3
+ import { build, type Rolldown } from "vite";
4
4
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
5
5
 
6
- const testDir = join(__dirname, ".temp", "vite-test-project");
6
+ const tempDir = join(__dirname, ".temp", "browser-build-test");
7
+ const entryFile = join(tempDir, "entry.js");
7
8
 
8
- describe("Browser Build Test", () => {
9
- beforeAll(() => {
10
- // Cleanup previous runs
11
- if (existsSync(testDir)) {
12
- rmSync(testDir, { recursive: true, force: true });
13
- }
9
+ /**
10
+ * Bundles `@alloy-js/core` for the browser using Vite and returns
11
+ * the concatenated output code.
12
+ *
13
+ * Uses the `browser` export condition from the package exports map,
14
+ * which resolves to the compiled browser entry. This requires the
15
+ * package to be built first (the CI pipeline and `pnpm build` handle
16
+ * this automatically).
17
+ */
18
+ async function bundleForBrowser(): Promise<string> {
19
+ const result = await build({
20
+ configFile: false,
21
+ logLevel: "silent",
22
+ resolve: {
23
+ conditions: ["browser", "import"],
24
+ },
25
+ // Disable automatic process.env replacement so we can detect leaks
26
+ define: {},
27
+ build: {
28
+ write: false,
29
+ minify: false,
30
+ rollupOptions: {
31
+ input: entryFile,
32
+ output: { format: "es" },
33
+ // Disable tree-shaking so we catch process.* references in ANY
34
+ // code path, even if it would be removed in a production build.
35
+ treeshake: false,
36
+ external: (id) => {
37
+ // Bundle @alloy-js packages — these are what we're validating
38
+ if (id.startsWith("@alloy-js/")) return false;
39
+ // Bundle relative/absolute imports (intra-package)
40
+ if (id.startsWith(".") || id.startsWith("/")) return false;
41
+ // Externalize third-party deps (vue, pathe, picocolors, …)
42
+ return true;
43
+ },
44
+ },
45
+ },
46
+ });
14
47
 
15
- // Create a temporary Vite project
16
- mkdirSync(testDir, { recursive: true });
48
+ const output = (
49
+ Array.isArray(result) ?
50
+ result[0]
51
+ : result) as Rolldown.RolldownOutput;
52
+ const chunks = output.output.filter(
53
+ (o): o is Rolldown.OutputChunk => o.type === "chunk",
54
+ );
55
+ return chunks.map((c) => c.code).join("\n");
56
+ }
17
57
 
18
- execSync("npm init -y", { cwd: testDir });
19
- execSync("npm install vite", { cwd: testDir });
20
- execSync("npm install ../../..", { cwd: testDir });
58
+ describe("browser build", () => {
59
+ beforeAll(() => {
60
+ if (existsSync(tempDir)) {
61
+ rmSync(tempDir, { recursive: true, force: true });
62
+ }
63
+ mkdirSync(tempDir, { recursive: true });
64
+ writeFileSync(entryFile, 'export * from "@alloy-js/core";\n');
65
+ });
21
66
 
22
- // Create a minimal Vite app
23
- writeFileSync(
24
- join(testDir, "index.js"),
25
- `
26
- import { writeOutput } from "@alloy-js/core";
27
- console.log("Alloy-js core imported successfully!", writeOutput);
28
- `,
29
- );
67
+ afterAll(() => {
68
+ if (existsSync(tempDir)) {
69
+ rmSync(tempDir, { recursive: true, force: true });
70
+ }
71
+ });
30
72
 
31
- writeFileSync(
32
- join(testDir, "vite.config.js"),
33
- `
34
- import { defineConfig } from "vite";
35
-
36
- export default defineConfig({
37
- build: {
38
- outDir: "dist",
39
- target: "esnext",
40
- }
41
- });
42
- `,
43
- );
73
+ it("should bundle for browser without Node.js polyfills", async () => {
74
+ const code = await bundleForBrowser();
44
75
 
45
- // Create an index.html file
46
- writeFileSync(
47
- join(testDir, "index.html"),
48
- `
49
- <!DOCTYPE html>
50
- <html lang="en">
51
- <head>
52
- <meta charset="UTF-8">
53
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
54
- <title>Vite Test</title>
55
- </head>
56
- <body>
57
- <script type="module" src="/index.js"></script>
58
- </body>
59
- </html>
60
- `,
61
- );
76
+ // The browser bundle must not reference the Node.js `process` global.
77
+ // If this fails, a file is using process.env / process.cwd / etc.
78
+ // without going through host/node-host.ts (or another browser-overridden module).
79
+ expect(code).not.toMatch(/\bprocess\./);
62
80
 
63
- writeFileSync(
64
- join(testDir, "package.json"),
65
- JSON.stringify(
66
- {
67
- type: "module",
68
- scripts: {
69
- build: "vite build",
70
- },
71
- },
72
- null,
73
- 2,
74
- ),
75
- );
81
+ // Should not contain static require("node:…") calls
82
+ expect(code).not.toMatch(/require\(\s*["']node:/);
76
83
  }, 30_000);
77
-
78
- it("Vite should build successfully", () => {
79
- // Run Vite build process and wait for completion
80
- expect(() => {
81
- execSync("npm run build", { cwd: testDir, stdio: "inherit" });
82
- }).not.toThrow();
83
- }, 10000);
84
-
85
- afterAll(() => {
86
- // Ensure testDir exists before attempting to remove it
87
- if (existsSync(testDir)) {
88
- rmSync(testDir, { recursive: true, force: true });
89
- }
90
- });
91
84
  });