Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9c7ae44
feat(vite-plugin-nitro): investigate nitro/vite plugin migration
benpsnyder Mar 25, 2026
20b14b0
feat(vite-plugin-nitro)!: migrate to nitro/vite first-party plugin
benpsnyder Mar 25, 2026
d06695e
fix(vite-plugin-nitro): fix renderer config and rollup external forwa…
benpsnyder Mar 25, 2026
f6ca965
fix(vite-plugin-nitro): add closeBundle fallback and fix output path …
benpsnyder Mar 25, 2026
f570b31
fix(vite-plugin-nitro): register bundler sanitization in closeBundle …
benpsnyder Mar 25, 2026
00d8739
fix(vite-plugin-nitro): fix closeBundle prerender and SSR entry resol…
benpsnyder Mar 25, 2026
b2dfcf3
fix(vite-plugin-nitro): replace banned Function type with typed cast
benpsnyder Mar 25, 2026
a0a435e
feat(vite-plugin-nitro): implement prerender route resolution for bui…
benpsnyder Mar 25, 2026
964bd8f
fix(vite-plugin-nitro): sanitize bundler config to resolve Nitro v3 a…
benpsnyder Mar 25, 2026
53ff23e
fix(vite-plugin-nitro): restore buildServer/buildSSR for closeBundle …
benpsnyder Mar 25, 2026
85a6f5a
feat(vite-plugin-nitro): use nitro/vite for dev server, delete legacy…
benpsnyder Mar 25, 2026
d55d93b
feat(vite-plugin-nitro): enhance SSR renderer configuration and entry…
benpsnyder Mar 25, 2026
98888f2
fix: work in progress
benpsnyder Mar 25, 2026
77c446c
fix: nitro vite plugin
benpsnyder Mar 25, 2026
c776864
Merge branch 'alpha' into feat/investigate-nitro-vite-plugin
benpsnyder Mar 25, 2026
5b0635a
fix(vite-plugin-nitro): ensure closeBundle only runs in client enviro…
benpsnyder Mar 25, 2026
c8b3499
refactor: remove unused shipping service SSR configuration
benpsnyder Mar 25, 2026
3d0cb7a
refactor(vite-plugin-nitro): enhance plugin architecture and improve …
benpsnyder Mar 25, 2026
9c1c601
Merge remote-tracking branch 'analogjs/alpha' into feat/investigate-n…
benpsnyder Mar 30, 2026
7e8f808
Merge branch 'alpha' into feat/investigate-nitro-vite-plugin
benpsnyder Mar 31, 2026
1c38270
chore: add patch for srvx@0.11.13 to address promise handling in Node…
benpsnyder Mar 31, 2026
d1eaade
Merge remote-tracking branch 'analogjs/alpha' into feat/investigate-n…
benpsnyder Apr 1, 2026
59c49d5
chore: update dependencies to version 3.0.0-alpha.20 in pnpm-lock.yaml
benpsnyder Apr 1, 2026
05e3f8a
Merge branch 'alpha' into feat/investigate-nitro-vite-plugin
benpsnyder Apr 1, 2026
468f116
Merge branch 'alpha' into feat/investigate-nitro-vite-plugin
benpsnyder Apr 5, 2026
1eef3c7
test(vite-plugin-angular): add test for filtering analogjs plugins in…
benpsnyder Apr 5, 2026
b01cc5b
docs: add PR review and description agent skills
brandonroberts Apr 6, 2026
3a2fe95
docs: add test coverage and build artifact checks to review-pr skill
brandonroberts Apr 6, 2026
af717a8
feat(platform): add generic style-pipeline hooks for community plugin…
benpsnyder Apr 6, 2026
94e110f
chore: release 3.0.0-alpha.26 [skip ci]
semantic-release-bot Apr 6, 2026
a15576d
refactor: retire root tsconfig paths and move workspace linking to pa…
benpsnyder Apr 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
name: pr-description
description: Generate a pull request description for the current branch.
---

Generate a pull request description for the current branch.

1. Run `git fetch --all` then `git log --oneline $(git merge-base HEAD origin/beta)..HEAD` to see all commits on this branch.
Expand Down
68 changes: 68 additions & 0 deletions .agents/skills/review-pr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
name: review-pr
description: Review a pull request for functional concerns. Use as a guide for reviewers or submitters preparing a PR.
---

Review the specified pull request for **functional concerns only**. Ignore stylistic nits that don't impact correctness, performance, or maintainability.

The PR number is provided as an argument. If no argument is given, check for an open PR on the current branch.

## 1. Fetch PR context

- Use `gh pr view <number> --json title,body,headRefName,baseRefName,files,additions,deletions` to get metadata
- Use `gh pr diff <number>` to get the full diff
- Read every changed file in the diff — don't skim

## 2. Review focus areas

Evaluate the diff against these categories. Only report findings that have real functional impact:

| Category | What to look for |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **Logic bugs** | Off-by-one errors, incorrect conditions, unreachable code, silent failures |
| **Type safety** | Unsafe casts, type discrimination holes, `any` leaks, incorrect generics |
| **Regex** | ReDoS potential, incorrect escaping, wrong flags, missing anchors |
| **Performance** | Eager evaluation in hot paths, unnecessary allocations per-request, O(n^2) where O(n) is possible |
| **State & concurrency** | Module-scoped mutable state, race conditions, missing cleanup |
| **Code duplication** | Duplicated logic that will drift — only flag if >50 lines or contains branching logic |
| **API contracts** | Breaking changes not flagged, silent behavior changes, incorrect error handling at boundaries |
| **Security** | Injection vectors, credential handling, unsafe deserialization |
| **Test coverage alignment** | Do the tests actually exercise the code paths that changed, or are they testing something adjacent? |
| **Build artifact impact** | Does the change affect what ships in the npm package? New files in `src/` that aren't tree-shakeable, accidental inclusion of test files, etc. |

## 3. Check contribution guidelines

Read `CONTRIBUTING.md` at the repo root and verify the PR complies. Only check mechanical items:

| Guideline | How to verify |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **PR title format** | Must be `type(scope): description`. Type must be one of: build, ci, docs, feat, fix, perf, refactor, style, test. Scope must be a supported package name from CONTRIBUTING.md. |
| **Tests included** | New functionality must have tests. Check the PR body's test plan for unchecked items. |
| **Squash merge** | Preferred unless the PR explains why commit boundaries matter. |
| **Related commits** | All commits should be related. Flag disjoint changes that should be separate PRs. |
| **Linked issues** | The PR should reference related issues. Flag if "Closes #" is empty. |
| **PR template** | Should include affected scope, test plan, and merge strategy recommendation. |

## 4. Output format

Write all findings in **second person**, actionable, ready to post as a review comment.

- Code findings as a flat list grouped by severity
- For each finding:
- Name the category
- Reference the specific file and code
- Explain the functional impact
- Suggest a fix if non-obvious
- Mechanical guideline findings (title format, tests, linked issues, etc.)

Skip categories with no findings. Do not pad the review with praise or filler.

End with a verdict table:

```
| Area | Verdict |
|------|---------|
| ... | ... |
```

Keep verdicts to one phrase: "Clean", "Minor concern", "Should fix before merge", "Blocking".
61 changes: 45 additions & 16 deletions .dagger/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ const DEFAULT_E2E_PROJECTS =

@object()
export class AnalogCi {
private withHeartbeatExec(
ctr: Container,
label: string,
command: string[],
): Container {
return ctr.withExec([
'node',
'tools/scripts/with-heartbeat.mts',
'--label',
label,
'--',
...command,
]);
}

private withNxCloudToken(ctr: Container, nxCloudToken?: Secret): Container {
if (!nxCloudToken) {
return ctr;
Expand All @@ -15,7 +30,7 @@ export class AnalogCi {
}

private withPlaywrightChromium(ctr: Container): Container {
return ctr.withExec([
return this.withHeartbeatExec(ctr, 'Playwright Chromium install', [
'pnpm',
'exec',
'playwright',
Expand All @@ -26,22 +41,27 @@ export class AnalogCi {
}

private withBuildAndVerify(ctr: Container): Container {
return ctr
.withExec([
'pnpm',
'exec',
'nx',
'run-many',
'--target',
'build',
'--all',
])
.withExec(['node', 'tools/scripts/verify-route-freshness.mts'])
.withExec(['pnpm', 'exec', 'nx', 'build-storybook', 'analog-app']);
return this.withHeartbeatExec(
this.withHeartbeatExec(
this.withHeartbeatExec(ctr, 'Nx build run-many', [
'pnpm',
'exec',
'nx',
'run-many',
'--target',
'build',
'--all',
]),
'Route freshness verification',
['node', 'tools/scripts/verify-route-freshness.mts'],
),
'Storybook build',
['pnpm', 'exec', 'nx', 'build-storybook', 'analog-app'],
);
}

private withTestTargets(ctr: Container): Container {
return ctr.withExec([
return this.withHeartbeatExec(ctr, 'Nx test run-many', [
'pnpm',
'exec',
'nx',
Expand All @@ -58,7 +78,7 @@ export class AnalogCi {
ctr: Container,
projects = DEFAULT_E2E_PROJECTS,
): Container {
return ctr.withExec([
return this.withHeartbeatExec(ctr, `Nx e2e run-many (${projects})`, [
'pnpm',
'exec',
'nx',
Expand Down Expand Up @@ -150,7 +170,16 @@ export class AnalogCi {
.withDirectory('/app', source)
.withWorkdir('/app')
.withMountedCache('/app/.nx/cache', nxCache)
.withExec(['pnpm', 'install', '--frozen-lockfile']);
.withExec([
'node',
'tools/scripts/with-heartbeat.mts',
'--label',
'pnpm install',
'--',
'pnpm',
'install',
'--frozen-lockfile',
]);
}

/** Check formatting via the workspace prettier:check script. */
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
NX_VERBOSE_LOGGING: ${{ vars.NX_VERBOSE_LOGGING }}
NX_ISOLATE_PLUGINS: 'false'
ANALOG_CI_HEARTBEAT_MS: '30000'

concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
Expand Down Expand Up @@ -127,11 +128,11 @@ jobs:
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- name: Install
run: pnpm install --frozen-lockfile --prefer-offline
run: node tools/scripts/with-heartbeat.mts --label "pnpm install" -- pnpm install --frozen-lockfile --prefer-offline
- name: Build
run: pnpm build
run: node tools/scripts/with-heartbeat.mts --label "pnpm build" -- pnpm build
- name: Verify route freshness
run: node tools/scripts/verify-route-freshness.mts
run: node tools/scripts/with-heartbeat.mts --label "verify route freshness" -- node tools/scripts/verify-route-freshness.mts

build-native-windows:
name: Native / Windows
Expand All @@ -158,11 +159,11 @@ jobs:
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- name: Install
run: pnpm install --frozen-lockfile --prefer-offline
run: node tools/scripts/with-heartbeat.mts --label "pnpm install" -- pnpm install --frozen-lockfile --prefer-offline
- name: Build
run: pnpm build
run: node tools/scripts/with-heartbeat.mts --label "pnpm build" -- pnpm build
- name: Verify route freshness
run: node tools/scripts/verify-route-freshness.mts
run: node tools/scripts/with-heartbeat.mts --label "verify route freshness" -- node tools/scripts/verify-route-freshness.mts
- name: Verify
run: more dist\apps\blog-app\analog\public\index.html

Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,5 @@ vitest.config.*.timestamp*
gradle.properties
.cursor
.claude
gradle.properties
gradle.properties
*.tsbuildinfo
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# [3.0.0-alpha.26](https://github.com/analogjs/analog/compare/v3.0.0-alpha.25...v3.0.0-alpha.26) (2026-04-06)

### Features

- **platform:** add generic style-pipeline hooks for community plugins ([#2245](https://github.com/analogjs/analog/issues/2245)) ([df8971a](https://github.com/analogjs/analog/commit/df8971a50be6f00715a01d3ee66ceea07e3c71f0))

# [3.0.0-alpha.25](https://github.com/analogjs/analog/compare/v3.0.0-alpha.24...v3.0.0-alpha.25) (2026-04-05)

### Bug Fixes
Expand Down
7 changes: 7 additions & 0 deletions apps/analog-app-e2e/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
"cwd": "apps/analog-app-e2e",
"command": "playwright test"
}
},
"typecheck": {
"executor": "nx:run-commands",
"options": {
"cwd": "apps/analog-app-e2e",
"command": "pnpm exec tsgo -p tsconfig.json --noEmit"
}
}
}
}
9 changes: 9 additions & 0 deletions apps/analog-app/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import type { StorybookConfig } from '@analogjs/storybook-angular';
import { mergeConfig } from 'vite';

const config: StorybookConfig = {
stories: ['../src/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],
Expand All @@ -12,6 +13,14 @@ const config: StorybookConfig = {
name: getAbsolutePath('@analogjs/storybook-angular'),
options: {},
},
async viteFinal(config) {
return mergeConfig(config, {
build: {
// Lightning CSS currently chokes on the generated Storybook preview CSS.
cssMinify: 'esbuild',
},
});
},
};

export default config;
Expand Down
5 changes: 4 additions & 1 deletion apps/analog-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
"version": "0.0.0",
"dependencies": {
"@analogjs/content": "workspace:*",
"@analogjs/my-package": "workspace:*",
"@analogjs/router": "workspace:*",
"@analogjs/top-bar": "workspace:*",
"es-toolkit": "catalog:"
},
"devDependencies": {
"@analogjs/platform": "workspace:*",
"@analogjs/storybook-angular": "workspace:*",
"@analogjs/vite-plugin-angular": "workspace:*"
"@analogjs/vite-plugin-angular": "workspace:*",
"@analogjs/vitest-angular": "workspace:*"
}
}
18 changes: 16 additions & 2 deletions apps/analog-app/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
"targets": {
"build": {
"executor": "@nx/vite:build",
"dependsOn": ["platform:build", "router:build"],
"dependsOn": [
"platform:build",
"router:build",
"my-package:build",
"top-bar:build"
],
"outputs": [
"{options.outputPath}",
"{workspaceRoot}/dist/apps/analog-app/.nitro",
Expand Down Expand Up @@ -54,7 +59,9 @@
"options": {
"cwd": "dist/apps/analog-app/analog",
"command": "node --unhandled-rejections=throw ./server/index.mjs",
"env": { "PORT": "43000" }
"env": {
"PORT": "43000"
}
},
"dependsOn": ["build"]
},
Expand Down Expand Up @@ -98,6 +105,13 @@
"loadPaths": []
}
}
},
"typecheck": {
"executor": "nx:run-commands",
"options": {
"cwd": "apps/analog-app",
"command": "pnpm exec tsgo -p tsconfig.app.json --noEmit"
}
}
}
}
2 changes: 1 addition & 1 deletion apps/analog-app/src/app/pages/package.page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { MyPackage } from 'my-package';
import { MyPackage } from '@analogjs/my-package';

@Component({
imports: [MyPackage],
Expand Down
30 changes: 28 additions & 2 deletions apps/analog-app/src/main.server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
import 'zone.js/node';
import '@angular/compiler';
import '@angular/platform-server/init';
import { render } from '@analogjs/router/server';
import { enableProdMode } from '@angular/core';
import {
bootstrapApplication,
type BootstrapContext,
} from '@angular/platform-browser';
import { renderApplication } from '@angular/platform-server';
import { provideServerContext } from '@analogjs/router/server';
import type { ServerContext } from '@analogjs/router/tokens';

import { config } from './app/app.config.server';
import { AppComponent } from './app/app.component';

export default render(AppComponent, config);
if (import.meta.env.PROD) {
enableProdMode();
}

export function bootstrap(context?: BootstrapContext) {
return bootstrapApplication(AppComponent, config, context);
}

export default async function render(
url: string,
document: string,
serverContext: ServerContext,
) {
return renderApplication(bootstrap, {
document,
url,
platformProviders: [provideServerContext(serverContext)],
});
}
Loading
Loading