create-analog 3.0.0-beta.4 → 3.0.0-beta.40

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.
@@ -0,0 +1,18 @@
1
+ import { Module, OnModuleInit } from '@nestjs/common';
2
+ import { HttpAdapterHost } from '@nestjs/core';
3
+ import { createAnalogHandler } from '@analogjs/router/server';
4
+
5
+ import { HelloController } from './hello.controller';
6
+ import { HelloService } from './hello.service';
7
+
8
+ @Module({
9
+ controllers: [HelloController],
10
+ providers: [HelloService],
11
+ })
12
+ export class AppModule implements OnModuleInit {
13
+ constructor(private readonly adapterHost: HttpAdapterHost) {}
14
+
15
+ onModuleInit(): void {
16
+ this.adapterHost.httpAdapter.use(createAnalogHandler());
17
+ }
18
+ }
@@ -0,0 +1,13 @@
1
+ import { Controller, Get } from '@nestjs/common';
2
+
3
+ import { HelloService } from './hello.service';
4
+
5
+ @Controller('api/v1/hello')
6
+ export class HelloController {
7
+ constructor(private readonly hello: HelloService) {}
8
+
9
+ @Get()
10
+ get() {
11
+ return this.hello.greet();
12
+ }
13
+ }
@@ -0,0 +1,8 @@
1
+ import { Injectable } from '@nestjs/common';
2
+
3
+ @Injectable()
4
+ export class HelloService {
5
+ greet() {
6
+ return { message: 'Hello World' };
7
+ }
8
+ }
@@ -0,0 +1,30 @@
1
+ import 'reflect-metadata';
2
+ import { NestFactory } from '@nestjs/core';
3
+ import type { NestExpressApplication } from '@nestjs/platform-express';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { toFetchHandler } from 'srvx/node';
6
+
7
+ import { AppModule } from './app.module';
8
+
9
+ // Keeps the request body for Analog after Nest's body parsers have run.
10
+ const app = await NestFactory.create<NestExpressApplication>(AppModule, {
11
+ rawBody: true,
12
+ });
13
+
14
+ // Vite serves client files in development.
15
+ if (!import.meta.env.DEV) {
16
+ const clientDir = fileURLToPath(new URL('../client', import.meta.url));
17
+ app.useStaticAssets(clientDir, { index: false });
18
+ }
19
+
20
+ await app.init();
21
+ const server = app.getHttpAdapter().getInstance();
22
+
23
+ if (!import.meta.env.DEV) {
24
+ await app.listen(process.env['PORT'] ?? 3000);
25
+ }
26
+
27
+ export default {
28
+ fetch: toFetchHandler((req, res) => server(req, res)),
29
+ close: () => app.close(),
30
+ };
package/index.js CHANGED
@@ -13,6 +13,7 @@ import prompts from 'prompts';
13
13
  * @typedef {'latest' | 'blog' | 'minimal'} StarterTemplate
14
14
  * @typedef {StarterTemplate | `angular-v${number}`} Template
15
15
  * @typedef {'prismjs' | 'shiki'} HighlighterId
16
+ * @typedef {'nitro' | 'nestjs'} ServerId
16
17
  * @typedef {(value: string) => string} Colorizer
17
18
  *
18
19
  * @typedef {object} Variant
@@ -42,6 +43,7 @@ import prompts from 'prompts';
42
43
  * @property {Template} [variant]
43
44
  * @property {boolean} [tailwind]
44
45
  * @property {HighlighterId} [syntaxHighlighter]
46
+ * @property {ServerId} [server]
45
47
  *
46
48
  * @typedef {object} UserAgentPackage
47
49
  * @property {string} name
@@ -51,6 +53,7 @@ import prompts from 'prompts';
51
53
  * _: string[];
52
54
  * template?: string;
53
55
  * t?: string;
56
+ * server?: string;
54
57
  * skipTailwind?: boolean | string;
55
58
  * skipGit?: boolean | string;
56
59
  * } & Record<string, unknown>} CliArgv
@@ -60,8 +63,12 @@ const CLI_DIR = path.dirname(fileURLToPath(import.meta.url));
60
63
  const DEFAULT_TARGET_DIR = 'analog-project';
61
64
  const DEFAULT_BLOG_HIGHLIGHTER = 'prismjs';
62
65
 
66
+ // Skips the server prompt while set. Remove it to let users choose.
67
+ /** @type {ServerId | undefined} */
68
+ const DEFAULT_SERVER = 'nitro';
69
+
63
70
  /** @type {readonly Template[]} */
64
- const H3_TEMPLATES = ['latest', 'blog', 'minimal'];
71
+ const H3_TEMPLATES = ['latest', 'blog', 'minimal', 'angular-v20'];
65
72
  const VERSIONED_TEMPLATE = /^angular-v\d+$/;
66
73
 
67
74
  // Avoids autoconversion to number of the project name by defining that the args
@@ -114,6 +121,21 @@ const HIGHLIGHTERS = {
114
121
  },
115
122
  };
116
123
 
124
+ /** @type {Readonly<Record<ServerId, string>>} */
125
+ const SERVERS = {
126
+ nitro: 'Nitro (prerendering, static sites, deployment presets)',
127
+ nestjs: 'NestJS',
128
+ };
129
+
130
+ const NESTJS_DEPENDENCIES = {
131
+ '@nestjs/common': '^12.3.2',
132
+ '@nestjs/core': '^12.3.2',
133
+ '@nestjs/platform-express': '^12.3.2',
134
+ h3: '^1.13.0',
135
+ 'reflect-metadata': '^0.2.2',
136
+ srvx: '^1.0.8',
137
+ };
138
+
117
139
  /** @type {Readonly<Record<string, string>>} */
118
140
  const renameFiles = {
119
141
  _gitignore: '.gitignore',
@@ -130,6 +152,7 @@ async function init() {
130
152
  let targetDir = formatTargetDir(argv._[0]);
131
153
  let template = resolveTemplate(argv.template ?? argv.t);
132
154
  let skipTailwind = fromBoolArg(argv.skipTailwind);
155
+ let server = resolveServer(argv.server) ?? DEFAULT_SERVER;
133
156
  const skipGit = fromBoolArg(argv.skipGit ?? argv['skip-git']) ?? false;
134
157
 
135
158
  // Internal flag (no prompt): when set, strip the `overrides` block that
@@ -209,6 +232,18 @@ async function init() {
209
232
  ),
210
233
  initial: 1,
211
234
  },
235
+ {
236
+ type: (_, values) =>
237
+ server || (values.variant ?? template) !== 'latest'
238
+ ? null
239
+ : 'select',
240
+ name: 'server',
241
+ message: reset('Which server would you like to use?'),
242
+ choices: Object.entries(SERVERS).map(([value, title]) => ({
243
+ title,
244
+ value,
245
+ })),
246
+ },
212
247
  {
213
248
  type: skipTailwind === undefined ? 'confirm' : null,
214
249
  name: 'tailwind',
@@ -235,6 +270,13 @@ async function init() {
235
270
  throw new Error('A project template must be selected.');
236
271
  }
237
272
 
273
+ server = result.server ?? server ?? 'nitro';
274
+ if (server === 'nestjs' && template !== 'latest') {
275
+ throw new Error(
276
+ 'The NestJS server is only available for the Full-stack Application (latest) template.',
277
+ );
278
+ }
279
+
238
280
  const highlighter =
239
281
  syntaxHighlighter ??
240
282
  (template === 'blog' ? DEFAULT_BLOG_HIGHLIGHTER : undefined);
@@ -281,7 +323,12 @@ async function init() {
281
323
  write('postcss.config.mjs', TAILWIND_POSTCSS_CONFIG);
282
324
  }
283
325
 
326
+ if (server === 'nestjs') {
327
+ addNestServer(root, filesDir);
328
+ }
329
+
284
330
  replacePlaceholders(root, 'vite.config.ts', {
331
+ ...getServerPlaceholders(template, server),
285
332
  __TAILWIND_IMPORT__: !skipTailwind
286
333
  ? "import tailwindcss from '@tailwindcss/vite';\n"
287
334
  : '',
@@ -305,6 +352,10 @@ async function init() {
305
352
  ensureSyntaxHighlighter(root, pkg, highlighter);
306
353
  }
307
354
 
355
+ if (server === 'nestjs') {
356
+ addNestDependencies(pkg);
357
+ }
358
+
308
359
  if (!skipTailwind) {
309
360
  addTailwindDependencies(pkg);
310
361
  }
@@ -497,13 +548,65 @@ function addTailwindDependencies(pkg) {
497
548
  pkg.devDependencies['@tailwindcss/vite'] = '^4.2.2';
498
549
  }
499
550
 
551
+ /**
552
+ * @param {string} root
553
+ * @param {string} filesDir
554
+ * @returns {void}
555
+ */
556
+ function addNestServer(root, filesDir) {
557
+ fs.rmSync(path.join(root, 'src/server/routes'), {
558
+ recursive: true,
559
+ force: true,
560
+ });
561
+ copyDir(path.join(filesDir, 'nestjs'), root);
562
+
563
+ const tsconfigPath = path.join(root, 'tsconfig.json');
564
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
565
+ tsconfig.compilerOptions.experimentalDecorators = true;
566
+ tsconfig.compilerOptions.emitDecoratorMetadata = true;
567
+ fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + '\n');
568
+ }
569
+
570
+ /**
571
+ * @param {Template} template
572
+ * @param {ServerId} server
573
+ * @returns {Record<string, string>}
574
+ */
575
+ function getServerPlaceholders(template, server) {
576
+ if (template !== 'latest') {
577
+ return {};
578
+ }
579
+
580
+ return server === 'nestjs'
581
+ ? {
582
+ __NITRO_IMPORT__: '',
583
+ __ANALOG_OPTIONS__: "{ server: { entry: 'src/server/main.ts' } }",
584
+ __NITRO_PLUGIN__: '',
585
+ }
586
+ : {
587
+ __NITRO_IMPORT__: "import nitro from '@analogjs/vite-plugin-nitro';\n",
588
+ __ANALOG_OPTIONS__: '',
589
+ __NITRO_PLUGIN__: ' nitro(),\n',
590
+ };
591
+ }
592
+
593
+ /**
594
+ * @param {PackageJson} pkg
595
+ * @returns {void}
596
+ */
597
+ function addNestDependencies(pkg) {
598
+ Object.assign(pkg.dependencies, NESTJS_DEPENDENCIES);
599
+ delete pkg.devDependencies['@analogjs/vite-plugin-nitro'];
600
+ pkg.scripts.preview = 'node dist/server/main.js';
601
+ }
602
+
500
603
  /**
501
604
  * @param {PackageJson} pkg
502
605
  * @param {Template} template
503
606
  * @returns {void}
504
607
  */
505
608
  function addYarnDevDependencies(pkg, template) {
506
- if (H3_TEMPLATES.includes(template)) {
609
+ if (H3_TEMPLATES.includes(template) && !pkg.dependencies?.h3) {
507
610
  pkg.devDependencies ??= {};
508
611
  pkg.devDependencies.h3 = '^1.13.0';
509
612
  }
@@ -612,6 +715,20 @@ function fromBoolArg(arg) {
612
715
  return arg === '' || arg === 'true';
613
716
  }
614
717
 
718
+ /**
719
+ * @param {string | undefined} value
720
+ * @returns {ServerId | undefined}
721
+ */
722
+ function resolveServer(value) {
723
+ if (value === undefined || Object.hasOwn(SERVERS, value)) {
724
+ return /** @type {ServerId | undefined} */ (value);
725
+ }
726
+
727
+ throw new Error(
728
+ `Unknown server "${value}". Use one of: ${Object.keys(SERVERS).join(', ')}.`,
729
+ );
730
+ }
731
+
615
732
  /**
616
733
  * @param {string | undefined} value
617
734
  * @returns {Template | undefined}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-analog",
3
- "version": "3.0.0-beta.4",
3
+ "version": "3.0.0-beta.40",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Brandon Roberts",
@@ -39,9 +39,9 @@
39
39
  "prompts": "^2.4.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@analogjs/platform": "3.0.0-beta.4",
43
- "@analogjs/vite-plugin-angular": "3.0.0-beta.4",
44
- "@analogjs/vite-plugin-nitro": "3.0.0-beta.4",
42
+ "@analogjs/platform": "3.0.0-beta.40",
43
+ "@analogjs/vite-plugin-angular": "3.0.0-beta.40",
44
+ "@analogjs/vite-plugin-nitro": "3.0.0-beta.40",
45
45
  "h3": "^1.15.11"
46
46
  },
47
47
  "publishConfig": {
@@ -16,8 +16,8 @@
16
16
  },
17
17
  "private": true,
18
18
  "dependencies": {
19
- "@analogjs/content": "^3.0.0-beta.4",
20
- "@analogjs/router": "^3.0.0-beta.4",
19
+ "@analogjs/content": "^3.0.0-beta.40",
20
+ "@analogjs/router": "^3.0.0-beta.40",
21
21
  "@angular/animations": "^20.0.0",
22
22
  "@angular/common": "^20.0.0",
23
23
  "@angular/compiler": "^20.0.0",
@@ -37,15 +37,16 @@
37
37
  "zone.js": "~0.15.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@analogjs/platform": "^3.0.0-beta.4",
41
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.4",
42
- "@analogjs/vitest-angular": "^3.0.0-beta.4",
40
+ "@analogjs/platform": "^3.0.0-beta.40",
41
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.40",
42
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.40",
43
+ "@analogjs/vitest-angular": "^3.0.0-beta.40",
43
44
  "@angular-devkit/build-angular": "^20.0.0",
44
45
  "@angular/build": "^20.0.0",
45
46
  "@angular/cli": "^20.0.0",
46
47
  "@angular/compiler-cli": "^20.0.0",
47
48
  "jsdom": "^22.0.0",
48
- "typescript": "6.0.2",
49
+ "typescript": "~5.9.0",
49
50
  "vite": "^7.0.0",
50
51
  "vite-tsconfig-paths": "^6.1.1",
51
52
  "vitest": "^5.0.0"
@@ -1,3 +1,3 @@
1
- import { defineHandler } from 'nitro/h3';
1
+ import { defineEventHandler } from 'h3';
2
2
 
3
- export default defineHandler(() => ({ message: 'Hello World' }));
3
+ export default defineEventHandler(() => ({ message: 'Hello World' }));
@@ -2,6 +2,8 @@
2
2
 
3
3
  import { defineConfig } from 'vite';
4
4
  __TAILWIND_IMPORT__import analog from '@analogjs/platform';
5
+ import angular from '@analogjs/vite-plugin-angular';
6
+ import nitro from '@analogjs/vite-plugin-nitro';
5
7
 
6
8
  // https://vitejs.dev/config/
7
9
  export default defineConfig(({ mode }) => ({
@@ -12,8 +14,10 @@ export default defineConfig(({ mode }) => ({
12
14
  mainFields: ['module'],
13
15
  },
14
16
  plugins: [
15
- __TAILWIND_PLUGIN__ analog(),
16
- ],
17
+ analog(),
18
+ angular(),
19
+ nitro(),
20
+ __TAILWIND_PLUGIN__ ],
17
21
  test: {
18
22
  globals: true,
19
23
  environment: 'jsdom',
@@ -16,8 +16,8 @@
16
16
  },
17
17
  "private": true,
18
18
  "dependencies": {
19
- "@analogjs/content": "^3.0.0-beta.4",
20
- "@analogjs/router": "^3.0.0-beta.4",
19
+ "@analogjs/content": "^3.0.0-beta.40",
20
+ "@analogjs/router": "^3.0.0-beta.40",
21
21
  "@angular/animations": "^21.0.0",
22
22
  "@angular/common": "^21.0.0",
23
23
  "@angular/compiler": "^21.0.0",
@@ -36,9 +36,9 @@
36
36
  "tslib": "^2.3.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@analogjs/platform": "^3.0.0-beta.4",
40
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.4",
41
- "@analogjs/vitest-angular": "^3.0.0-beta.4",
39
+ "@analogjs/platform": "^3.0.0-beta.40",
40
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.40",
41
+ "@analogjs/vitest-angular": "^3.0.0-beta.40",
42
42
  "@angular/build": "^21.0.0",
43
43
  "@angular/cli": "^21.0.0",
44
44
  "@angular/compiler-cli": "^21.0.0",
@@ -16,8 +16,8 @@
16
16
  },
17
17
  "private": true,
18
18
  "dependencies": {
19
- "@analogjs/content": "^3.0.0-beta.4",
20
- "@analogjs/router": "^3.0.0-beta.4",
19
+ "@analogjs/content": "^3.0.0-beta.40",
20
+ "@analogjs/router": "^3.0.0-beta.40",
21
21
  "@angular/animations": "^22.0.0",
22
22
  "@angular/common": "^22.0.0",
23
23
  "@angular/compiler": "^22.0.0",
@@ -35,10 +35,10 @@
35
35
  "tslib": "^2.3.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@analogjs/platform": "^3.0.0-beta.4",
39
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.4",
40
- "@analogjs/vite-plugin-nitro": "^3.0.0-beta.4",
41
- "@analogjs/vitest-angular": "^3.0.0-beta.4",
38
+ "@analogjs/platform": "^3.0.0-beta.40",
39
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.40",
40
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.40",
41
+ "@analogjs/vitest-angular": "^3.0.0-beta.40",
42
42
  "@angular/build": "^22.0.0",
43
43
  "@angular/cli": "^22.0.0",
44
44
  "@angular/compiler-cli": "^22.0.0",
@@ -12,7 +12,7 @@ Run `npm start` for a dev server. Navigate to `http://localhost:5173/`. The appl
12
12
 
13
13
  ## Build
14
14
 
15
- Run `npm run build` to build the client/server project. The client build artifacts are located in the `dist/analog/public` directory. The server for the API build artifacts are located in the `dist/analog/server` directory.
15
+ Run `npm run build` to build the client and server, and `npm run preview` to start the production server.
16
16
 
17
17
  ## Test
18
18
 
@@ -16,8 +16,8 @@
16
16
  },
17
17
  "private": true,
18
18
  "dependencies": {
19
- "@analogjs/content": "^3.0.0-beta.4",
20
- "@analogjs/router": "^3.0.0-beta.4",
19
+ "@analogjs/content": "^3.0.0-beta.40",
20
+ "@analogjs/router": "^3.0.0-beta.40",
21
21
  "@angular/animations": "^22.0.0",
22
22
  "@angular/common": "^22.0.0",
23
23
  "@angular/compiler": "^22.0.0",
@@ -36,10 +36,10 @@
36
36
  "tslib": "^2.3.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@analogjs/platform": "^3.0.0-beta.4",
40
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.4",
41
- "@analogjs/vite-plugin-nitro": "^3.0.0-beta.4",
42
- "@analogjs/vitest-angular": "^3.0.0-beta.4",
39
+ "@analogjs/platform": "^3.0.0-beta.40",
40
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.40",
41
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.40",
42
+ "@analogjs/vitest-angular": "^3.0.0-beta.40",
43
43
  "@angular/build": "^22.0.0",
44
44
  "@angular/cli": "^22.0.0",
45
45
  "@angular/compiler-cli": "^22.0.0",
@@ -3,8 +3,7 @@
3
3
  import { defineConfig } from 'vite';
4
4
  __TAILWIND_IMPORT__import analog from '@analogjs/platform';
5
5
  import angular from '@analogjs/vite-plugin-angular';
6
- import nitro from '@analogjs/vite-plugin-nitro';
7
-
6
+ __NITRO_IMPORT__
8
7
  // https://vitejs.dev/config/
9
8
  export default defineConfig(({ mode }) => ({
10
9
  build: {
@@ -14,10 +13,9 @@ export default defineConfig(({ mode }) => ({
14
13
  mainFields: ['module'],
15
14
  },
16
15
  plugins: [
17
- analog(),
16
+ analog(__ANALOG_OPTIONS__),
18
17
  angular(),
19
- nitro(),
20
- __TAILWIND_PLUGIN__ ],
18
+ __NITRO_PLUGIN____TAILWIND_PLUGIN__ ],
21
19
  test: {
22
20
  globals: true,
23
21
  environment: 'jsdom',
@@ -16,8 +16,8 @@
16
16
  },
17
17
  "private": true,
18
18
  "dependencies": {
19
- "@analogjs/content": "^3.0.0-beta.4",
20
- "@analogjs/router": "^3.0.0-beta.4",
19
+ "@analogjs/content": "^3.0.0-beta.40",
20
+ "@analogjs/router": "^3.0.0-beta.40",
21
21
  "@angular/animations": "^22.0.0",
22
22
  "@angular/common": "^22.0.0",
23
23
  "@angular/compiler": "^22.0.0",
@@ -36,10 +36,10 @@
36
36
  "tslib": "^2.3.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@analogjs/platform": "^3.0.0-beta.4",
40
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.4",
41
- "@analogjs/vite-plugin-nitro": "^3.0.0-beta.4",
42
- "@analogjs/vitest-angular": "^3.0.0-beta.4",
39
+ "@analogjs/platform": "^3.0.0-beta.40",
40
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.40",
41
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.40",
42
+ "@analogjs/vitest-angular": "^3.0.0-beta.40",
43
43
  "@angular/build": "^22.0.0",
44
44
  "@angular/cli": "^22.0.0",
45
45
  "@angular/compiler-cli": "^22.0.0",