@nestjs-ssr/react 0.1.9 → 0.1.11

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.
package/src/cli/init.ts DELETED
@@ -1,313 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
4
- import { join, resolve, dirname } from 'path';
5
- import { fileURLToPath } from 'url';
6
- import { execSync } from 'child_process';
7
- import { consola } from 'consola';
8
- import { defineCommand, runMain } from 'citty';
9
-
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = dirname(__filename);
12
-
13
- const main = defineCommand({
14
- meta: {
15
- name: 'nestjs-ssr',
16
- description: 'Initialize @nestjs-ssr/react in your NestJS project',
17
- version: '0.1.6',
18
- },
19
- args: {
20
- force: {
21
- type: 'boolean',
22
- description: 'Overwrite existing files',
23
- alias: 'f',
24
- },
25
- views: {
26
- type: 'string',
27
- description: 'Views directory path',
28
- default: 'src/views',
29
- },
30
- 'skip-install': {
31
- type: 'boolean',
32
- description: 'Skip automatic dependency installation',
33
- default: false,
34
- },
35
- },
36
- async run({ args }) {
37
- const cwd = process.cwd();
38
- const viewsDir = args.views;
39
-
40
- consola.box('@nestjs-ssr/react initialization');
41
- consola.start('Setting up your NestJS SSR React project...\n');
42
-
43
- // Find template files - check both src/ (dev) and dist/ (production) locations
44
- const templateLocations = [
45
- resolve(__dirname, '../../src/templates'), // Development (ts-node/tsx)
46
- resolve(__dirname, '../templates'), // Built package (dist/cli -> dist/templates)
47
- ];
48
- const templateDir = templateLocations.find(loc => existsSync(join(loc, 'entry-client.tsx')));
49
-
50
- if (!templateDir) {
51
- consola.error('Failed to locate template files');
52
- consola.info('Searched:', templateLocations);
53
- process.exit(1);
54
- }
55
-
56
- // Find global.d.ts - check both src/ (dev) and package root (production)
57
- const globalTypesLocations = [
58
- resolve(__dirname, '../../src/global.d.ts'), // Development
59
- resolve(__dirname, '../global.d.ts'), // Built (dist/cli -> dist/../src/global.d.ts)
60
- ];
61
- const globalTypesSrc = globalTypesLocations.find(loc => existsSync(loc));
62
-
63
- if (!globalTypesSrc) {
64
- consola.error('Failed to locate global.d.ts');
65
- consola.info('Searched:', globalTypesLocations);
66
- process.exit(1);
67
- }
68
-
69
- // Check that tsconfig.json exists - we don't create it
70
- const tsconfigPath = join(cwd, 'tsconfig.json');
71
- if (!existsSync(tsconfigPath)) {
72
- consola.error('No tsconfig.json found in project root');
73
- consola.info('Please create a tsconfig.json file first');
74
- process.exit(1);
75
- }
76
-
77
- // 1. Copy entry-client.tsx to views directory
78
- consola.start('Creating entry-client.tsx...');
79
- const entryClientSrc = join(templateDir, 'entry-client.tsx');
80
- const entryClientDest = join(cwd, viewsDir, 'entry-client.tsx');
81
-
82
- // Create views directory if it doesn't exist
83
- mkdirSync(join(cwd, viewsDir), { recursive: true });
84
-
85
- if (existsSync(entryClientDest) && !args.force) {
86
- consola.warn(`${viewsDir}/entry-client.tsx already exists (use --force to overwrite)`);
87
- } else {
88
- copyFileSync(entryClientSrc, entryClientDest);
89
- consola.success(`Created ${viewsDir}/entry-client.tsx`);
90
- }
91
-
92
- // 2. Copy entry-server.tsx to views directory
93
- consola.start('Creating entry-server.tsx...');
94
- const entryServerSrc = join(templateDir, 'entry-server.tsx');
95
- const entryServerDest = join(cwd, viewsDir, 'entry-server.tsx');
96
-
97
- if (existsSync(entryServerDest) && !args.force) {
98
- consola.warn(`${viewsDir}/entry-server.tsx already exists (use --force to overwrite)`);
99
- } else {
100
- copyFileSync(entryServerSrc, entryServerDest);
101
- consola.success(`Created ${viewsDir}/entry-server.tsx`);
102
- }
103
-
104
- // 2. Copy global.d.ts
105
- consola.start('Creating global.d.ts...');
106
- const globalTypesDest = join(cwd, 'src/global.d.ts');
107
-
108
- if (existsSync(globalTypesDest) && !args.force) {
109
- consola.warn('src/global.d.ts already exists (use --force to overwrite)');
110
- } else {
111
- copyFileSync(globalTypesSrc, globalTypesDest);
112
- consola.success('Created src/global.d.ts');
113
- }
114
-
115
- // 4. Update/create vite.config.js
116
- consola.start('Configuring vite.config.js...');
117
- const viteConfigPath = join(cwd, 'vite.config.js');
118
- const viteConfigTs = join(cwd, 'vite.config.ts');
119
- const useTypeScript = existsSync(viteConfigTs);
120
- const configPath = useTypeScript ? viteConfigTs : viteConfigPath;
121
-
122
- if (existsSync(configPath)) {
123
- consola.warn(`${useTypeScript ? 'vite.config.ts' : 'vite.config.js'} already exists`);
124
- consola.info('Please manually add to your Vite config:');
125
- consola.log(' import { resolve } from \'path\';');
126
- consola.log(' build: {');
127
- consola.log(' rollupOptions: {');
128
- consola.log(` input: { client: resolve(__dirname, '${viewsDir}/entry-client.tsx') }`);
129
- consola.log(' }');
130
- consola.log(' }');
131
- } else {
132
- const viteConfig = `import { defineConfig } from 'vite';
133
- import react from '@vitejs/plugin-react';
134
- import { resolve } from 'path';
135
-
136
- export default defineConfig({
137
- plugins: [react()],
138
- resolve: {
139
- alias: {
140
- '@': resolve(__dirname, 'src'),
141
- },
142
- },
143
- server: {
144
- port: 5173,
145
- strictPort: true,
146
- hmr: { port: 5173 },
147
- },
148
- build: {
149
- outDir: 'dist/client',
150
- manifest: true,
151
- rollupOptions: {
152
- input: {
153
- client: resolve(__dirname, '${viewsDir}/entry-client.tsx'),
154
- },
155
- },
156
- },
157
- });
158
- `;
159
- writeFileSync(viteConfigPath, viteConfig);
160
- consola.success('Created vite.config.js');
161
- }
162
-
163
- // 5. Update tsconfig.json
164
- consola.start('Configuring tsconfig.json...');
165
- try {
166
- const tsconfig = JSON.parse(readFileSync(tsconfigPath, 'utf-8'));
167
-
168
- let updated = false;
169
-
170
- if (!tsconfig.compilerOptions) {
171
- tsconfig.compilerOptions = {};
172
- }
173
-
174
- // Ensure jsx is set
175
- if (tsconfig.compilerOptions.jsx !== 'react-jsx') {
176
- tsconfig.compilerOptions.jsx = 'react-jsx';
177
- updated = true;
178
- }
179
-
180
- // Ensure paths includes @ alias
181
- if (!tsconfig.compilerOptions.paths) {
182
- tsconfig.compilerOptions.paths = {};
183
- }
184
- if (!tsconfig.compilerOptions.paths['@/*']) {
185
- tsconfig.compilerOptions.paths['@/*'] = ['./src/*'];
186
- updated = true;
187
- }
188
-
189
- // Ensure types includes vite/client
190
- if (!tsconfig.compilerOptions.types) {
191
- tsconfig.compilerOptions.types = [];
192
- }
193
- if (!tsconfig.compilerOptions.types.includes('vite/client')) {
194
- tsconfig.compilerOptions.types.push('vite/client');
195
- updated = true;
196
- }
197
-
198
- if (updated) {
199
- writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
200
- consola.success('Updated tsconfig.json');
201
- } else {
202
- consola.info('tsconfig.json already configured');
203
- }
204
- } catch (error) {
205
- consola.error('Failed to update tsconfig.json:', error);
206
- }
207
-
208
- // 6. Setup build scripts
209
- consola.start('Configuring build scripts...');
210
- const packageJsonPath = join(cwd, 'package.json');
211
-
212
- if (!existsSync(packageJsonPath)) {
213
- consola.warn('No package.json found, skipping build script setup');
214
- } else {
215
- try {
216
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
217
-
218
- if (!packageJson.scripts) {
219
- packageJson.scripts = {};
220
- }
221
-
222
- const existingBuild = packageJson.scripts.build;
223
- const defaultNestBuild = 'nest build';
224
- const ssrBuildPrefix = 'vite build && ';
225
-
226
- let shouldUpdate = false;
227
- let newBuildScript = '';
228
-
229
- if (!existingBuild) {
230
- // No build script exists, create one
231
- newBuildScript = `${ssrBuildPrefix}${defaultNestBuild}`;
232
- shouldUpdate = true;
233
- } else if (existingBuild.includes('vite build')) {
234
- // Already has vite build
235
- consola.info('Build script already includes vite build');
236
- } else if (existingBuild === defaultNestBuild) {
237
- // Default nest build, prepend vite build
238
- newBuildScript = `${ssrBuildPrefix}${existingBuild}`;
239
- shouldUpdate = true;
240
- } else {
241
- // Custom build script, ask user
242
- consola.warn(`Found custom build script: "${existingBuild}"`);
243
- consola.info('SSR requires running "vite build" before your build command');
244
- consola.info(`Recommended: ${ssrBuildPrefix}${existingBuild}`);
245
- consola.info('Please manually update your build script in package.json');
246
- }
247
-
248
- if (shouldUpdate) {
249
- packageJson.scripts.build = newBuildScript;
250
- writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
251
- consola.success(`Updated build script to: "${newBuildScript}"`);
252
- }
253
-
254
- // 7. Check and install dependencies
255
- if (!args['skip-install']) {
256
- consola.start('Checking dependencies...');
257
- const requiredDeps = {
258
- 'react': '^19.0.0',
259
- 'react-dom': '^19.0.0',
260
- 'vite': '^7.0.0',
261
- '@vitejs/plugin-react': '^4.0.0'
262
- };
263
-
264
- const missingDeps: string[] = [];
265
- const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
266
-
267
- for (const [dep, version] of Object.entries(requiredDeps)) {
268
- if (!allDeps[dep]) {
269
- missingDeps.push(`${dep}@${version}`);
270
- }
271
- }
272
-
273
- if (missingDeps.length > 0) {
274
- consola.info(`Missing dependencies: ${missingDeps.join(', ')}`);
275
-
276
- // Detect package manager
277
- let packageManager = 'npm';
278
- if (existsSync(join(cwd, 'pnpm-lock.yaml'))) packageManager = 'pnpm';
279
- else if (existsSync(join(cwd, 'yarn.lock'))) packageManager = 'yarn';
280
-
281
- const installCmd = packageManager === 'npm'
282
- ? `npm install ${missingDeps.join(' ')}`
283
- : `${packageManager} add ${missingDeps.join(' ')}`;
284
-
285
- try {
286
- consola.start(`Installing dependencies with ${packageManager}...`);
287
- execSync(installCmd, {
288
- cwd,
289
- stdio: 'inherit'
290
- });
291
- consola.success('Dependencies installed!');
292
- } catch (error) {
293
- consola.error('Failed to install dependencies:', error);
294
- consola.info(`Please manually run: ${installCmd}`);
295
- }
296
- } else {
297
- consola.success('All required dependencies are already installed');
298
- }
299
- }
300
- } catch (error) {
301
- consola.error('Failed to update package.json:', error);
302
- }
303
- }
304
-
305
- consola.success('\nInitialization complete!');
306
- consola.box('Next steps');
307
- consola.info(`1. Create your first view component in ${viewsDir}/`);
308
- consola.info('2. Render it from a NestJS controller using render.render()');
309
- consola.info('3. Run your dev server with: pnpm start:dev');
310
- },
311
- });
312
-
313
- runMain(main);