diff --git a/apps/docs-app/docs/guides/debugging.md b/apps/docs-app/docs/guides/debugging.md index 9f1cf1267..a45cf314b 100644 --- a/apps/docs-app/docs/guides/debugging.md +++ b/apps/docs-app/docs/guides/debugging.md @@ -1,8 +1,10 @@ --- +title: Debugging Techniques +description: Enable Analog debug logging, choose the right scopes, and debug local or GitHub-based Analog builds from another pnpm workspace. sidebar_position: 4 --- -# Debugging +# Debugging Techniques Analog includes structured debug logging powered by [obug](https://www.npmjs.com/package/obug). You can enable debug output through the `debug` option in your Vite config or via the `DEBUG` environment variable. diff --git a/docs/debugging.md b/docs/debugging.md index 439fbbf88..2c1cc2911 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -29,8 +29,8 @@ When debugging package changes in this monorepo, prefer the project-level Nx tar # Focus on Angular plugin HMR/style behavior DEBUG=analog:angular:hmr,analog:angular:styles pnpm nx test vite-plugin-angular -# Focus on platform routing output -DEBUG=analog:platform:routes pnpm nx build platform +# Focus on Compilation API inclusion, emit registration, and transform misses +DEBUG=analog:angular:compilation-api,analog:angular:compiler,analog:angular:emit pnpm nx test vite-plugin-angular # Focus on the style-pipeline integration seam in a served app DEBUG=analog:platform:style-pipeline,analog:angular:style-pipeline pnpm nx serve your-app @@ -47,6 +47,16 @@ first so each `dist` folder contains its generated `package.json`. The source package manifests still contain `catalog:` and `workspace:*` references that are only rewritten during Analog's release-style build pipeline. +Prefer `link:` for active local debugging. + +- `link:` keeps the consumer wired to the live built `dist` directories through + symlinks. +- `file:` can stage a snapshot into the consumer's `.pnpm` store. If you later + rebuild Analog without changing the version or specifier, pnpm may decide the + consumer install is already current and keep serving stale package contents. +- If you must use `file:`, always verify the active installed package contents, + not just the Analog source tree or `dist`. + ### Local checkout example `pnpm-workspace.yaml` @@ -57,11 +67,11 @@ packages: - 'libs/**' overrides: - '@analogjs/platform': file:/path/to/analog/packages/platform/dist - '@analogjs/router': file:/path/to/analog/packages/router/dist - '@analogjs/vite-plugin-angular': file:/path/to/analog/packages/vite-plugin-angular/dist - '@analogjs/vite-plugin-nitro': file:/path/to/analog/packages/vite-plugin-nitro/dist - '@analogjs/vitest-angular': file:/path/to/analog/packages/vitest-angular/dist + '@analogjs/platform': link:/path/to/analog/packages/platform/dist + '@analogjs/router': link:/path/to/analog/packages/router/dist + '@analogjs/vite-plugin-angular': link:/path/to/analog/packages/vite-plugin-angular/dist + '@analogjs/vite-plugin-nitro': link:/path/to/analog/packages/vite-plugin-nitro/dist + '@analogjs/vitest-angular': link:/path/to/analog/packages/vitest-angular/dist ``` Root `package.json` @@ -69,14 +79,14 @@ Root `package.json` ```json { "dependencies": { - "@analogjs/platform": "file:/path/to/analog/packages/platform/dist" + "@analogjs/platform": "link:/path/to/analog/packages/platform/dist" }, "overrides": { - "@analogjs/platform": "file:/path/to/analog/packages/platform/dist", - "@analogjs/router": "file:/path/to/analog/packages/router/dist", - "@analogjs/vite-plugin-angular": "file:/path/to/analog/packages/vite-plugin-angular/dist", - "@analogjs/vite-plugin-nitro": "file:/path/to/analog/packages/vite-plugin-nitro/dist", - "@analogjs/vitest-angular": "file:/path/to/analog/packages/vitest-angular/dist" + "@analogjs/platform": "link:/path/to/analog/packages/platform/dist", + "@analogjs/router": "link:/path/to/analog/packages/router/dist", + "@analogjs/vite-plugin-angular": "link:/path/to/analog/packages/vite-plugin-angular/dist", + "@analogjs/vite-plugin-nitro": "link:/path/to/analog/packages/vite-plugin-nitro/dist", + "@analogjs/vitest-angular": "link:/path/to/analog/packages/vitest-angular/dist" } } ``` @@ -88,13 +98,52 @@ can still resolve transitive packages like `@analogjs/vite-plugin-angular` and ::: :::note -pnpm currently does not allow `file:` entries in `catalog`, so local checkout -wiring needs direct `file:` overrides instead of `catalog:` indirection. +If the consumer workspace uses pnpm `catalog` entries, switch both the catalog +entries and the consumer overrides together. Mixed states are a common source of +confusing resolution behavior. ::: If your app also uses other published Analog packages such as `@analogjs/content` or `@analogjs/storybook-angular`, pin those the same way. +### Consumer validation checklist + +After rebuilding Analog and refreshing the consumer install: + +```bash +# Confirm the active install points at your local dist output +readlink node_modules/@analogjs/vite-plugin-angular + +# Confirm the dev server is actually listening +curl -k -I https://localhost:4200/ + +# Confirm the shell HTML and stylesheet entry are present +lightpanda fetch \ + --insecure-disable-tls-host-verification \ + --wait-until done \ + --wait-ms 12000 \ + --dump html \ + https://localhost:4200/ | sed -n '1,80p' +``` + +What to trust: + +- `curl` is the fastest readiness check. +- `Lightpanda` is useful for reachability, shell HTML, and asset-presence smoke + tests. +- Treat the consumer dev server logs as the source of truth for Angular + compilation failures such as: + - `contains Angular decorators but is not in the TypeScript program` + - missing Angular emit output + - JIT fallback for `@Injectable()` / `@Component()` + +What not to over-trust: + +- `Lightpanda` can surface browser-client or HMR-transport behavior that does + not necessarily mean Analog failed to compile the app correctly. +- A successful Analog rebuild does not prove the consumer is executing the new + package code unless the consumer install is verified. + ### GitHub branch example If you want the same pattern from a GitHub branch instead of a local path, pnpm @@ -136,6 +185,27 @@ those manifests still contain unresolved `catalog:` and `workspace:*` specifiers. ::: +## Useful Angular Debug Scopes + +Start with the smallest scope set that answers the question: + +```bash +DEBUG=analog:angular:compilation-api,analog:angular:compiler pnpm nx serve your-app +DEBUG=analog:angular:emit pnpm nx serve your-app +DEBUG=analog:angular:emit:v pnpm nx serve your-app +``` + +Recommended interpretation: + +- `analog:angular:compilation-api` + - wrapper tsconfig generation, initialization, high-level compilation flow +- `analog:angular:compiler` + - compiler-option mutations and transform-path decisions +- `analog:angular:emit` + - root-name expansion, emit registration, transform misses/hits +- `analog:angular:emit:v` + - per-file root lists, output registration, and normalized emitter lookups + ## Notes - Use the repo root unless you have a specific reason to run inside a package subdirectory. diff --git a/packages/vite-plugin-angular/src/lib/angular-vite-plugin-live-reload.spec.ts b/packages/vite-plugin-angular/src/lib/angular-vite-plugin-live-reload.spec.ts index 324b0606f..280880990 100644 --- a/packages/vite-plugin-angular/src/lib/angular-vite-plugin-live-reload.spec.ts +++ b/packages/vite-plugin-angular/src/lib/angular-vite-plugin-live-reload.spec.ts @@ -479,6 +479,12 @@ describe('angular hmr style preprocessing', () => { mkdirSync(join(tempWorkspaceRoot, 'libs/shared/extra/src'), { recursive: true, }); + mkdirSync(join(tempWorkspaceRoot, 'libs/shared/directory/src'), { + recursive: true, + }); + mkdirSync(join(tempWorkspaceRoot, 'libs/shared/wildcard/src/nested'), { + recursive: true, + }); writeFileSync( join(tempWorkspaceRoot, 'src/app/app.component.ts'), @@ -495,6 +501,17 @@ describe('angular hmr style preprocessing', () => { join(tempWorkspaceRoot, 'libs/shared/extra/src/index.ts'), 'export const extra = true;\n', ); + writeFileSync( + join(tempWorkspaceRoot, 'libs/shared/directory/src/directory.ts'), + 'export const directory = true;\n', + ); + writeFileSync( + join( + tempWorkspaceRoot, + 'libs/shared/wildcard/src/nested/wildcard.ts', + ), + 'export const wildcard = true;\n', + ); writeFileSync( join(tempWorkspaceRoot, 'libs/shared/feature/tsconfig.lib.json'), JSON.stringify( @@ -517,7 +534,9 @@ describe('angular hmr style preprocessing', () => { module: 'esnext', moduleResolution: 'bundler', paths: { + '@shared/directory': ['libs/shared/directory/src'], '@shared/extra': ['libs/shared/extra/src/index.ts'], + '@shared/wildcard/*': ['libs/shared/wildcard/src/**/*'], }, target: 'es2022', }, @@ -562,8 +581,23 @@ describe('angular hmr style preprocessing', () => { normalize( join(tempWorkspaceRoot, 'libs/shared/extra/src/index.ts'), ), + normalize( + join(tempWorkspaceRoot, 'libs/shared/directory/src/directory.ts'), + ), + normalize( + join( + tempWorkspaceRoot, + 'libs/shared/wildcard/src/nested/wildcard.ts', + ), + ), ]), ); + expect(generatedConfig.files).not.toContain( + normalize(join(tempWorkspaceRoot, 'libs/shared/directory/src')), + ); + expect(generatedConfig.files).not.toContain( + normalize(join(tempWorkspaceRoot, 'libs/shared/wildcard/src/nested')), + ); expect(generatedConfig.references).toEqual([ { path: './libs/shared/feature/tsconfig.lib.json' }, ]); diff --git a/packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts b/packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts index 284d2bef4..2ac52c3ec 100644 --- a/packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts +++ b/packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts @@ -2402,6 +2402,15 @@ export function angular(options?: PluginOptions): Plugin[] { : resolve(tsconfigDir, configuredBaseUrl) : tsconfigDir; const discoveredRoots = new Set(); + const addDiscoveredFiles = (pattern: string) => { + for (const match of globSync(pattern, { + dot: true, + absolute: true, + onlyFiles: true, + })) { + discoveredRoots.add(normalizePath(match)); + } + }; for (const targets of Object.values(tsPaths)) { for (const target of targets) { @@ -2410,17 +2419,18 @@ export function angular(options?: PluginOptions): Plugin[] { ); if (target.includes('*')) { - for (const match of globSync(resolvedTarget, { - dot: true, - absolute: true, - })) { - discoveredRoots.add(normalizePath(match)); - } + addDiscoveredFiles(resolvedTarget); continue; } if (existsSync(resolvedTarget)) { - discoveredRoots.add(resolvedTarget); + if (statSync(resolvedTarget).isDirectory()) { + addDiscoveredFiles( + normalizePath(join(resolvedTarget, '**/*.{ts,tsx,js,jsx}')), + ); + } else { + discoveredRoots.add(normalizePath(resolvedTarget)); + } } } }