create-analog 3.0.0-beta.22 → 3.0.0-beta.24

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,34 @@
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
+
6
+ import { AppModule } from './app.module';
7
+
8
+ async function createNestApp() {
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
+ return app.init();
21
+ }
22
+
23
+ export async function createApp() {
24
+ const app = await createNestApp();
25
+ return {
26
+ handle: app.getHttpAdapter().getInstance(),
27
+ close: () => app.close(),
28
+ };
29
+ }
30
+
31
+ if (!import.meta.env.DEV) {
32
+ const app = await createNestApp();
33
+ await app.listen(process.env['PORT'] ?? 3000);
34
+ }
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,6 +63,10 @@ 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
71
  const H3_TEMPLATES = ['latest', 'blog', 'minimal', 'angular-v20'];
65
72
  const VERSIONED_TEMPLATE = /^angular-v\d+$/;
@@ -114,6 +121,20 @@ 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
+ };
137
+
117
138
  /** @type {Readonly<Record<string, string>>} */
118
139
  const renameFiles = {
119
140
  _gitignore: '.gitignore',
@@ -130,6 +151,7 @@ async function init() {
130
151
  let targetDir = formatTargetDir(argv._[0]);
131
152
  let template = resolveTemplate(argv.template ?? argv.t);
132
153
  let skipTailwind = fromBoolArg(argv.skipTailwind);
154
+ let server = resolveServer(argv.server) ?? DEFAULT_SERVER;
133
155
  const skipGit = fromBoolArg(argv.skipGit ?? argv['skip-git']) ?? false;
134
156
 
135
157
  // Internal flag (no prompt): when set, strip the `overrides` block that
@@ -209,6 +231,18 @@ async function init() {
209
231
  ),
210
232
  initial: 1,
211
233
  },
234
+ {
235
+ type: (_, values) =>
236
+ server || (values.variant ?? template) !== 'latest'
237
+ ? null
238
+ : 'select',
239
+ name: 'server',
240
+ message: reset('Which server would you like to use?'),
241
+ choices: Object.entries(SERVERS).map(([value, title]) => ({
242
+ title,
243
+ value,
244
+ })),
245
+ },
212
246
  {
213
247
  type: skipTailwind === undefined ? 'confirm' : null,
214
248
  name: 'tailwind',
@@ -235,6 +269,13 @@ async function init() {
235
269
  throw new Error('A project template must be selected.');
236
270
  }
237
271
 
272
+ server = result.server ?? server ?? 'nitro';
273
+ if (server === 'nestjs' && template !== 'latest') {
274
+ throw new Error(
275
+ 'The NestJS server is only available for the Full-stack Application (latest) template.',
276
+ );
277
+ }
278
+
238
279
  const highlighter =
239
280
  syntaxHighlighter ??
240
281
  (template === 'blog' ? DEFAULT_BLOG_HIGHLIGHTER : undefined);
@@ -281,7 +322,12 @@ async function init() {
281
322
  write('postcss.config.mjs', TAILWIND_POSTCSS_CONFIG);
282
323
  }
283
324
 
325
+ if (server === 'nestjs') {
326
+ addNestServer(root, filesDir);
327
+ }
328
+
284
329
  replacePlaceholders(root, 'vite.config.ts', {
330
+ ...getServerPlaceholders(template, server),
285
331
  __TAILWIND_IMPORT__: !skipTailwind
286
332
  ? "import tailwindcss from '@tailwindcss/vite';\n"
287
333
  : '',
@@ -305,6 +351,10 @@ async function init() {
305
351
  ensureSyntaxHighlighter(root, pkg, highlighter);
306
352
  }
307
353
 
354
+ if (server === 'nestjs') {
355
+ addNestDependencies(pkg);
356
+ }
357
+
308
358
  if (!skipTailwind) {
309
359
  addTailwindDependencies(pkg);
310
360
  }
@@ -497,13 +547,65 @@ function addTailwindDependencies(pkg) {
497
547
  pkg.devDependencies['@tailwindcss/vite'] = '^4.2.2';
498
548
  }
499
549
 
550
+ /**
551
+ * @param {string} root
552
+ * @param {string} filesDir
553
+ * @returns {void}
554
+ */
555
+ function addNestServer(root, filesDir) {
556
+ fs.rmSync(path.join(root, 'src/server/routes'), {
557
+ recursive: true,
558
+ force: true,
559
+ });
560
+ copyDir(path.join(filesDir, 'nestjs'), root);
561
+
562
+ const tsconfigPath = path.join(root, 'tsconfig.json');
563
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
564
+ tsconfig.compilerOptions.experimentalDecorators = true;
565
+ tsconfig.compilerOptions.emitDecoratorMetadata = true;
566
+ fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + '\n');
567
+ }
568
+
569
+ /**
570
+ * @param {Template} template
571
+ * @param {ServerId} server
572
+ * @returns {Record<string, string>}
573
+ */
574
+ function getServerPlaceholders(template, server) {
575
+ if (template !== 'latest') {
576
+ return {};
577
+ }
578
+
579
+ return server === 'nestjs'
580
+ ? {
581
+ __NITRO_IMPORT__: '',
582
+ __ANALOG_OPTIONS__: "{ server: { entry: 'src/server/main.ts' } }",
583
+ __NITRO_PLUGIN__: '',
584
+ }
585
+ : {
586
+ __NITRO_IMPORT__: "import nitro from '@analogjs/vite-plugin-nitro';\n",
587
+ __ANALOG_OPTIONS__: '',
588
+ __NITRO_PLUGIN__: ' nitro(),\n',
589
+ };
590
+ }
591
+
592
+ /**
593
+ * @param {PackageJson} pkg
594
+ * @returns {void}
595
+ */
596
+ function addNestDependencies(pkg) {
597
+ Object.assign(pkg.dependencies, NESTJS_DEPENDENCIES);
598
+ delete pkg.devDependencies['@analogjs/vite-plugin-nitro'];
599
+ pkg.scripts.preview = 'node dist/server/main.js';
600
+ }
601
+
500
602
  /**
501
603
  * @param {PackageJson} pkg
502
604
  * @param {Template} template
503
605
  * @returns {void}
504
606
  */
505
607
  function addYarnDevDependencies(pkg, template) {
506
- if (H3_TEMPLATES.includes(template)) {
608
+ if (H3_TEMPLATES.includes(template) && !pkg.dependencies?.h3) {
507
609
  pkg.devDependencies ??= {};
508
610
  pkg.devDependencies.h3 = '^1.13.0';
509
611
  }
@@ -612,6 +714,20 @@ function fromBoolArg(arg) {
612
714
  return arg === '' || arg === 'true';
613
715
  }
614
716
 
717
+ /**
718
+ * @param {string | undefined} value
719
+ * @returns {ServerId | undefined}
720
+ */
721
+ function resolveServer(value) {
722
+ if (value === undefined || Object.hasOwn(SERVERS, value)) {
723
+ return /** @type {ServerId | undefined} */ (value);
724
+ }
725
+
726
+ throw new Error(
727
+ `Unknown server "${value}". Use one of: ${Object.keys(SERVERS).join(', ')}.`,
728
+ );
729
+ }
730
+
615
731
  /**
616
732
  * @param {string | undefined} value
617
733
  * @returns {Template | undefined}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-analog",
3
- "version": "3.0.0-beta.22",
3
+ "version": "3.0.0-beta.24",
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.22",
43
- "@analogjs/vite-plugin-angular": "3.0.0-beta.22",
44
- "@analogjs/vite-plugin-nitro": "3.0.0-beta.22",
42
+ "@analogjs/platform": "3.0.0-beta.24",
43
+ "@analogjs/vite-plugin-angular": "3.0.0-beta.24",
44
+ "@analogjs/vite-plugin-nitro": "3.0.0-beta.24",
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.22",
20
- "@analogjs/router": "^3.0.0-beta.22",
19
+ "@analogjs/content": "^3.0.0-beta.24",
20
+ "@analogjs/router": "^3.0.0-beta.24",
21
21
  "@angular/animations": "^20.0.0",
22
22
  "@angular/common": "^20.0.0",
23
23
  "@angular/compiler": "^20.0.0",
@@ -37,10 +37,10 @@
37
37
  "zone.js": "~0.15.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@analogjs/platform": "^3.0.0-beta.22",
41
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.22",
42
- "@analogjs/vite-plugin-nitro": "^3.0.0-beta.22",
43
- "@analogjs/vitest-angular": "^3.0.0-beta.22",
40
+ "@analogjs/platform": "^3.0.0-beta.24",
41
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.24",
42
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.24",
43
+ "@analogjs/vitest-angular": "^3.0.0-beta.24",
44
44
  "@angular-devkit/build-angular": "^20.0.0",
45
45
  "@angular/build": "^20.0.0",
46
46
  "@angular/cli": "^20.0.0",
@@ -16,8 +16,8 @@
16
16
  },
17
17
  "private": true,
18
18
  "dependencies": {
19
- "@analogjs/content": "^3.0.0-beta.22",
20
- "@analogjs/router": "^3.0.0-beta.22",
19
+ "@analogjs/content": "^3.0.0-beta.24",
20
+ "@analogjs/router": "^3.0.0-beta.24",
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.22",
40
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.22",
41
- "@analogjs/vitest-angular": "^3.0.0-beta.22",
39
+ "@analogjs/platform": "^3.0.0-beta.24",
40
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.24",
41
+ "@analogjs/vitest-angular": "^3.0.0-beta.24",
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.22",
20
- "@analogjs/router": "^3.0.0-beta.22",
19
+ "@analogjs/content": "^3.0.0-beta.24",
20
+ "@analogjs/router": "^3.0.0-beta.24",
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.22",
39
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.22",
40
- "@analogjs/vite-plugin-nitro": "^3.0.0-beta.22",
41
- "@analogjs/vitest-angular": "^3.0.0-beta.22",
38
+ "@analogjs/platform": "^3.0.0-beta.24",
39
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.24",
40
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.24",
41
+ "@analogjs/vitest-angular": "^3.0.0-beta.24",
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.22",
20
- "@analogjs/router": "^3.0.0-beta.22",
19
+ "@analogjs/content": "^3.0.0-beta.24",
20
+ "@analogjs/router": "^3.0.0-beta.24",
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.22",
40
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.22",
41
- "@analogjs/vite-plugin-nitro": "^3.0.0-beta.22",
42
- "@analogjs/vitest-angular": "^3.0.0-beta.22",
39
+ "@analogjs/platform": "^3.0.0-beta.24",
40
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.24",
41
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.24",
42
+ "@analogjs/vitest-angular": "^3.0.0-beta.24",
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.22",
20
- "@analogjs/router": "^3.0.0-beta.22",
19
+ "@analogjs/content": "^3.0.0-beta.24",
20
+ "@analogjs/router": "^3.0.0-beta.24",
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.22",
40
- "@analogjs/vite-plugin-angular": "^3.0.0-beta.22",
41
- "@analogjs/vite-plugin-nitro": "^3.0.0-beta.22",
42
- "@analogjs/vitest-angular": "^3.0.0-beta.22",
39
+ "@analogjs/platform": "^3.0.0-beta.24",
40
+ "@analogjs/vite-plugin-angular": "^3.0.0-beta.24",
41
+ "@analogjs/vite-plugin-nitro": "^3.0.0-beta.24",
42
+ "@analogjs/vitest-angular": "^3.0.0-beta.24",
43
43
  "@angular/build": "^22.0.0",
44
44
  "@angular/cli": "^22.0.0",
45
45
  "@angular/compiler-cli": "^22.0.0",