├── .editorconfig
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
└── tasks.json
├── README.md
├── angular.json
├── app.config.ts
├── index.client.html
├── package-lock.json
├── package.json
├── public
├── .gitkeep
└── favicon.ico
├── src
├── app
│ ├── app-root.analog
│ ├── app.config.server.ts
│ ├── app.config.ts
│ └── pages
│ │ ├── get-posts.ts
│ │ └── index.page.analog
├── main.server.ts
├── main.ts
├── styles.css
└── vite-env.d.ts
├── tsconfig.app.json
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | /bazel-out
8 |
9 | # Node
10 | /node_modules
11 | npm-debug.log
12 | yarn-error.log
13 |
14 | # IDEs and editors
15 | .idea/
16 | .project
17 | .classpath
18 | .c9/
19 | *.launch
20 | .settings/
21 | *.sublime-workspace
22 |
23 | # Visual Studio Code
24 | .vscode/*
25 | !.vscode/settings.json
26 | !.vscode/tasks.json
27 | !.vscode/launch.json
28 | !.vscode/extensions.json
29 | .history/*
30 |
31 | # Miscellaneous
32 | /.angular/cache
33 | /.nx/cache
34 | /.nx/workspace-data
35 | .sass-cache/
36 | /connect.lock
37 | /coverage
38 | /libpeerconnection.log
39 | testem.log
40 | /typings
41 |
42 | # System files
43 | .DS_Store
44 | Thumbs.db
45 |
46 | .output
47 | .vinxi
48 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template", "analogjs.vscode-analog"]
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "name": "ng serve",
7 | "type": "chrome",
8 | "request": "launch",
9 | "preLaunchTask": "npm: start",
10 | "url": "http://localhost:5173/"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3 | "version": "2.0.0",
4 | "tasks": [
5 | {
6 | "type": "npm",
7 | "script": "start",
8 | "isBackground": true,
9 | "problemMatcher": {
10 | "owner": "typescript",
11 | "pattern": "$tsc",
12 | "background": {
13 | "activeOnStart": true,
14 | "beginsPattern": {
15 | "regexp": "(.*?)"
16 | },
17 | "endsPattern": {
18 | "regexp": "bundle generation complete"
19 | }
20 | }
21 | }
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Start: Analog SFCs, Vinxi, and Server Functions
2 |
3 | - [Analog](https://analogjs.org)
4 | - [Angular](https://angular.dev)
5 | - [Vinxi](https://vinxi.vercel.app)
6 |
7 | ## Setup
8 |
9 | Run `npm install` to install the application dependencies.
10 |
11 | ## Development
12 |
13 | Run `npm run dev` for a dev server. Navigate to `http://localhost:3000/`.
14 |
15 | ## Build
16 |
17 | Run `npm run build` to build the client/server project. The build artifacts are located in the `.output` directory.
18 |
19 | ## Community
20 |
21 | - Visit and Star the [GitHub Repo](https://github.com/analogjs/analog)
22 | - Join the [Discord](https://chat.analogjs.org)
23 | - Follow us on [Twitter](https://twitter.com/analogjs)
24 | - Become a [Sponsor](https://github.com/sponsors/brandonroberts)
25 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "my-app": {
7 | "projectType": "application",
8 | "root": ".",
9 | "sourceRoot": "src",
10 | "prefix": "app",
11 | "architect": {
12 | "build": {
13 | "builder": "@analogjs/platform:vite",
14 | "options": {
15 | "configFile": "vite.config.ts",
16 | "main": "src/main.ts",
17 | "outputPath": "dist/client",
18 | "tsConfig": "tsconfig.app.json"
19 | },
20 | "defaultConfiguration": "production",
21 | "configurations": {
22 | "development": {
23 | "mode": "development"
24 | },
25 | "production": {
26 | "sourcemap": false,
27 | "mode": "production"
28 | }
29 | }
30 | },
31 | "serve": {
32 | "builder": "@analogjs/platform:vite-dev-server",
33 | "defaultConfiguration": "development",
34 | "options": {
35 | "buildTarget": "my-app:build",
36 | "port": 5173
37 | },
38 | "configurations": {
39 | "development": {
40 | "buildTarget": "my-app:build:development",
41 | "hmr": true
42 | },
43 | "production": {
44 | "buildTarget": "my-app:build:production"
45 | }
46 | }
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app.config.ts:
--------------------------------------------------------------------------------
1 | import angular from '@analogjs/vite-plugin-angular';
2 | import { createApp } from "vinxi";
3 | import { serverFunctions } from '@vinxi/server-functions/plugin';
4 |
5 | export default createApp({
6 | routers: [
7 | {
8 | name: "public",
9 | type: "static",
10 | dir: "./public",
11 | },
12 | {
13 | name: "ssr",
14 | type: "http",
15 | handler: "./src/main.server.ts",
16 | plugins: () => [
17 | {
18 | config() {
19 | return {
20 | ssr: {
21 | noExternal: [
22 | '@angular/**',
23 | '@analogjs/**',
24 | 'zone.js/**'
25 | ]
26 | }
27 | }
28 | },
29 | },
30 | angular({
31 | experimental: {
32 | supportAnalogFormat: true
33 | }
34 | }),
35 | ],
36 | },
37 | {
38 | name: "client",
39 | type: "client",
40 | handler: "./src/main.ts",
41 | base: "/_base",
42 | plugins: () => [
43 | angular({
44 | transformFilter(code) {
45 | return !code.includes('createServerReference');
46 | },
47 | experimental: {
48 | supportAnalogFormat: true
49 | }
50 | }),
51 | serverFunctions.client()
52 | ],
53 | },
54 | serverFunctions.router()
55 | ],
56 | });
--------------------------------------------------------------------------------
/index.client.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Angular Start
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "analog-angular-vinxi",
3 | "version": "0.0.0",
4 | "type": "module",
5 | "engines": {
6 | "node": ">=18.19.1"
7 | },
8 | "scripts": {
9 | "ng": "ng",
10 | "dev": "vinxi dev",
11 | "start": "npm run dev",
12 | "build": "vinxi build",
13 | "watch": "ng build --watch --configuration development",
14 | "test": "ng test"
15 | },
16 | "private": true,
17 | "dependencies": {
18 | "@analogjs/content": "^1.7.3-beta.1",
19 | "@analogjs/router": "^1.7.3-beta.1",
20 | "@angular/animations": "^18.0.0",
21 | "@angular/build": "^18.0.0",
22 | "@angular/common": "^18.0.0",
23 | "@angular/compiler": "^18.0.0",
24 | "@angular/core": "^18.0.0",
25 | "@angular/forms": "^18.0.0",
26 | "@angular/platform-browser": "^18.0.0",
27 | "@angular/platform-browser-dynamic": "^18.0.0",
28 | "@angular/platform-server": "^18.0.0",
29 | "@angular/router": "^18.0.0",
30 | "front-matter": "^4.0.2",
31 | "marked": "^5.0.2",
32 | "marked-gfm-heading-id": "^3.1.0",
33 | "marked-highlight": "^2.0.1",
34 | "marked-mangle": "^1.1.7",
35 | "prismjs": "^1.29.0",
36 | "rxjs": "~7.8.0",
37 | "tslib": "^2.3.0",
38 | "zone.js": "~0.14.3"
39 | },
40 | "devDependencies": {
41 | "@analogjs/platform": "^1.7.3-beta.1",
42 | "@analogjs/vite-plugin-angular": "^1.7.3-beta.1",
43 | "@analogjs/vitest-angular": "^1.7.3-beta.1",
44 | "@angular/cli": "^18.0.0",
45 | "@angular/compiler-cli": "^18.0.0",
46 | "@vinxi/server-functions": "^0.4.2",
47 | "typescript": "~5.4.2",
48 | "vinxi": "^0.4.2",
49 | "vite": "^5.0.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/public/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brandonroberts/analog-angular-start/04f633016b5f50c2e17a86c5bd2382d98cddc909/public/.gitkeep
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brandonroberts/analog-angular-start/04f633016b5f50c2e17a86c5bd2382d98cddc909/public/favicon.ico
--------------------------------------------------------------------------------
/src/app/app-root.analog:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/app/app.config.server.ts:
--------------------------------------------------------------------------------
1 | import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
2 | import { provideServerRendering } from '@angular/platform-server';
3 |
4 | import { appConfig } from './app.config';
5 |
6 | const serverConfig: ApplicationConfig = {
7 | providers: [provideServerRendering()],
8 | };
9 |
10 | export const config = mergeApplicationConfig(appConfig, serverConfig);
11 |
--------------------------------------------------------------------------------
/src/app/app.config.ts:
--------------------------------------------------------------------------------
1 | import {
2 | provideHttpClient,
3 | withFetch,
4 | } from '@angular/common/http';
5 | import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
6 | import { provideClientHydration } from '@angular/platform-browser';
7 | import { provideRouter } from '@angular/router';
8 |
9 | export const appConfig: ApplicationConfig = {
10 | providers: [
11 | provideZoneChangeDetection({ eventCoalescing: true }),
12 | provideRouter([
13 | { path: '', pathMatch: 'full', loadComponent: () => import('./pages/index.page.analog') },
14 | { path: '**', loadComponent: () => import('./pages/index.page.analog') }
15 | ]),
16 | provideHttpClient(
17 | withFetch(),
18 | ),
19 | provideClientHydration()
20 | ],
21 | };
22 |
--------------------------------------------------------------------------------
/src/app/pages/get-posts.ts:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | export async function getPosts() {
4 | const res = await fetch('https://jsonplaceholder.typicode.com/posts');
5 |
6 | if (!res.ok) {
7 | return { error: true };
8 | }
9 |
10 | const data = await res.json();
11 |
12 | console.log('server!');
13 |
14 | return data;
15 | }
--------------------------------------------------------------------------------
/src/app/pages/index.page.analog:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 | Angular Start: Analog SFCs, Vinxi, and Server Functions
20 |
21 |
22 | Docs |
23 | GitHub |
24 | Sponsor
25 |
26 |
27 |
28 |
29 |
30 | @for(post of posts(); track post.id) {
31 | - {{ post.title }}
32 | }
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/main.server.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js/node';
2 | import '@angular/platform-server/init';
3 | import { enableProdMode } from '@angular/core';
4 | import { bootstrapApplication } from '@angular/platform-browser';
5 | import { renderApplication } from '@angular/platform-server';
6 | import { provideServerContext } from '@analogjs/router/server';
7 | import { ServerRequest } from '@analogjs/router/tokens';
8 | import { defineEventHandler } from 'vinxi/http';
9 | import { getManifest } from 'vinxi/manifest';
10 |
11 | import template from '../index.client.html?raw';
12 |
13 | import { config } from './app/app.config.server';
14 | import App from './app/app-root.analog';
15 |
16 | if (import.meta.env.PROD) {
17 | enableProdMode();
18 | }
19 |
20 | export function bootstrap() {
21 | return bootstrapApplication(App, config);
22 | }
23 |
24 | export default defineEventHandler(async(event) => {
25 | const clientManifest = getManifest('client');
26 | const client = import.meta.env.DEV ? '/_base/src/main.ts': clientManifest.inputs[clientManifest.handler].output.path;
27 | const html = await renderApplication(bootstrap, {
28 | document: template.replace('__MAIN__', client),
29 | url: event.node.req.originalUrl,
30 | platformProviders: [provideServerContext({ req: event.node.req as ServerRequest, res: event.node.res })],
31 | });
32 |
33 | return html;
34 | });
35 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js';
2 | import { bootstrapApplication } from '@angular/platform-browser';
3 |
4 | import App from './app/app-root.analog';
5 | import { appConfig } from './app/app.config';
6 |
7 | bootstrapApplication(App, appConfig);
8 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.analog' {
4 | const cmp: any;
5 | export default cmp;
6 | }
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": ["src/main.ts", "src/main.server.ts"],
9 | "include": [
10 | "src/**/*.d.ts",
11 | "src/app/pages/**/*.page.ts",
12 | "src/server/middleware/**/*.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "noImplicitOverride": true,
10 | "noPropertyAccessFromIndexSignature": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "sourceMap": true,
14 | "declaration": false,
15 | "downlevelIteration": true,
16 | "experimentalDecorators": true,
17 | "moduleResolution": "Bundler",
18 | "importHelpers": true,
19 | "target": "ES2022",
20 | "module": "ES2022",
21 | "lib": ["ES2022", "dom"],
22 | "useDefineForClassFields": false,
23 | "skipLibCheck": true
24 | },
25 | "angularCompilerOptions": {
26 | "enableI18nLegacyMessageIdFormat": false,
27 | "strictInjectionParameters": true,
28 | "strictInputAccessModifiers": true,
29 | "strictTemplates": true
30 | }
31 | }
32 |
--------------------------------------------------------------------------------