@taujs/create-taujs 0.3.1 → 0.4.0

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.
Files changed (2) hide show
  1. package/dist/index.js +209 -24
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -45,11 +45,15 @@ var PACKAGE_MANAGERS = {
45
45
  pnpm: "pnpm install",
46
46
  yarn: "yarn install"
47
47
  };
48
- var FRAMEWORKS = ["react", "vue"];
48
+ var FRAMEWORKS = ["react", "vue", "solid"];
49
+ var PACKAGE_MANAGER_NAMES = Object.keys(PACKAGE_MANAGERS);
49
50
  function parseArgs() {
50
51
  const rawArgs = process.argv.slice(2);
51
52
  let projectName;
52
53
  let framework;
54
+ let packageManager;
55
+ let sawInstall = false;
56
+ let sawNoInstall = false;
53
57
  for (let i = 0; i < rawArgs.length; i++) {
54
58
  const arg = rawArgs[i];
55
59
  if (arg === "--framework") {
@@ -60,12 +64,37 @@ function parseArgs() {
60
64
  framework = arg.slice("--framework=".length);
61
65
  continue;
62
66
  }
67
+ if (arg === "--package-manager") {
68
+ packageManager = rawArgs[++i];
69
+ continue;
70
+ }
71
+ if (arg.startsWith("--package-manager=")) {
72
+ packageManager = arg.slice("--package-manager=".length);
73
+ continue;
74
+ }
75
+ if (arg === "--install") {
76
+ sawInstall = true;
77
+ continue;
78
+ }
79
+ if (arg === "--no-install") {
80
+ sawNoInstall = true;
81
+ continue;
82
+ }
63
83
  if (!arg.startsWith("-") && !projectName) {
64
84
  projectName = arg;
65
85
  continue;
66
86
  }
67
87
  }
68
- return { projectName, framework };
88
+ return {
89
+ projectName,
90
+ framework,
91
+ packageManager,
92
+ install: sawInstall && !sawNoInstall ? true : sawNoInstall && !sawInstall ? false : void 0,
93
+ installConflict: sawInstall && sawNoInstall
94
+ };
95
+ }
96
+ function validatePackageManager(value) {
97
+ return PACKAGE_MANAGER_NAMES.includes(value) ? true : `Package manager must be one of: ${PACKAGE_MANAGER_NAMES.join(", ")}`;
69
98
  }
70
99
  function validateProjectName(value) {
71
100
  if (!value) return "Project name is required";
@@ -79,7 +108,19 @@ function validateFramework(value) {
79
108
  }
80
109
  async function main() {
81
110
  console.log(pc.cyan("\nWelcome to \u03C4js (taujs)\n"));
82
- const { projectName: argName, framework: argFramework } = parseArgs();
111
+ const { projectName: argName, framework: argFramework, packageManager: argPackageManager, install: argInstall, installConflict } = parseArgs();
112
+ if (installConflict) {
113
+ console.log(pc.red("\n\u2716 --install and --no-install are mutually exclusive"));
114
+ process.exit(1);
115
+ }
116
+ if (argPackageManager) {
117
+ const res = validatePackageManager(argPackageManager);
118
+ if (res !== true) {
119
+ console.log(pc.red(`
120
+ \u2716 Invalid package manager "${argPackageManager}": ${res}`));
121
+ process.exit(1);
122
+ }
123
+ }
83
124
  if (argName) {
84
125
  const res = validateProjectName(argName);
85
126
  if (res !== true) {
@@ -110,12 +151,13 @@ async function main() {
110
151
  message: "Framework:",
111
152
  choices: [
112
153
  { title: "React", value: "react" },
113
- { title: "Vue", value: "vue" }
154
+ { title: "Vue", value: "vue" },
155
+ { title: "Solid", value: "solid" }
114
156
  ],
115
157
  initial: 0
116
158
  },
117
159
  {
118
- type: "select",
160
+ type: argPackageManager ? null : "select",
119
161
  name: "packageManager",
120
162
  message: "Package manager:",
121
163
  choices: [
@@ -126,7 +168,7 @@ async function main() {
126
168
  initial: 0
127
169
  },
128
170
  {
129
- type: "confirm",
171
+ type: argInstall === void 0 ? "confirm" : null,
130
172
  name: "installDeps",
131
173
  message: "Install dependencies now?",
132
174
  initial: true
@@ -158,8 +200,8 @@ async function main() {
158
200
  }
159
201
  const config = {
160
202
  projectName,
161
- packageManager: answers.packageManager,
162
- installDeps: answers.installDeps,
203
+ packageManager: argPackageManager ?? answers.packageManager,
204
+ installDeps: argInstall ?? answers.installDeps,
163
205
  framework
164
206
  };
165
207
  await createProject(config);
@@ -236,9 +278,19 @@ function planFiles(config) {
236
278
  { path: "src/server/services/registry.ts", content: generateServiceRegistry() },
237
279
  { path: "src/server/services/example.service.ts", content: generateExampleService() },
238
280
  { path: "src/server/types.d.ts", content: generateServiceTypesAugmentation() },
239
- { path: "src/client/public/favicon.svg", content: generateFavicon() }
281
+ { path: "src/client/public/favicon.svg", content: generateFavicon() },
282
+ // Solid's managed compiler owns a DISJOINT tsconfig project: it must claim the client TSX and
283
+ // nothing else. Pointing it at the root tsconfig would make it claim `src/server/**` too, which
284
+ // is not Solid TSX and is compiled by the server toolchain.
285
+ ...framework === "solid" ? [{ path: "tsconfig.solid.json", json: generateSolidCompilerTsConfig() }] : []
240
286
  ];
241
- const client = framework === "vue" ? [
287
+ const client = framework === "solid" ? [
288
+ { path: "src/client/App.tsx", content: generateAppComponentSolid() },
289
+ { path: "src/client/renderId.ts", content: generateSolidRenderId() },
290
+ { path: "src/client/entry-client.tsx", content: generateEntryClientSolid() },
291
+ { path: "src/client/entry-server.tsx", content: generateEntryServerSolid() },
292
+ { path: "src/client/vite-env.d.ts", content: generateViteEnv() }
293
+ ] : framework === "vue" ? [
242
294
  { path: "src/client/App.vue", content: generateAppVue() },
243
295
  { path: "src/client/HomePage.vue", content: generateHomePageVue() },
244
296
  { path: "src/client/StreamingPage.vue", content: generateStreamingPageVue() },
@@ -273,10 +325,10 @@ function generatePackageJson(projectName, framework) {
273
325
  type: "module",
274
326
  scripts: {
275
327
  dev: "cross-env NODE_ENV=development tsx watch --ignore vite.config.ts --trace-warnings --tsconfig ./src/server/tsconfig.json ./src/server/index.ts --loglevel verbose",
276
- "build:client": "tsx build.ts",
277
- "build:entry-server": "cross-env BUILD_MODE=ssr tsx build.ts",
328
+ "build:client": "cross-env NODE_ENV=production tsx build.ts",
329
+ "build:entry-server": "cross-env NODE_ENV=production BUILD_MODE=ssr tsx build.ts",
278
330
  "build:server": "esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/vue",
279
- build: "tsx build.ts && cross-env BUILD_MODE=ssr tsx build.ts && esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/vue",
331
+ build: "cross-env NODE_ENV=production tsx build.ts && cross-env NODE_ENV=production BUILD_MODE=ssr tsx build.ts && esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/vue",
280
332
  start: "cross-env NODE_ENV=production node dist/server/index.js",
281
333
  lint: "vue-tsc --noEmit"
282
334
  },
@@ -292,6 +344,9 @@ function generatePackageJson(projectName, framework) {
292
344
  "@types/node": "^22.10.5",
293
345
  "@vitejs/plugin-vue": "^6.0.0",
294
346
  "cross-env": "^7.0.3",
347
+ // `build:server` invokes the esbuild BINARY directly, so it must be a declared dependency
348
+ // of the generated project - it is not inherited from vite's own copy.
349
+ esbuild: "^0.25.0",
295
350
  tsx: "^4.19.3",
296
351
  typescript: "^5.7.3",
297
352
  vite: "^7.1.11",
@@ -299,6 +354,43 @@ function generatePackageJson(projectName, framework) {
299
354
  }
300
355
  };
301
356
  }
357
+ if (framework === "solid") {
358
+ return {
359
+ name: projectName,
360
+ version: "0.1.0",
361
+ private: true,
362
+ type: "module",
363
+ scripts: {
364
+ dev: "cross-env NODE_ENV=development tsx watch --ignore vite.config.ts --trace-warnings --tsconfig ./src/server/tsconfig.json ./src/server/index.ts --loglevel verbose",
365
+ "build:client": "cross-env NODE_ENV=production tsx build.ts",
366
+ "build:entry-server": "cross-env NODE_ENV=production BUILD_MODE=ssr tsx build.ts",
367
+ "build:server": "esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/solid",
368
+ build: "cross-env NODE_ENV=production tsx build.ts && cross-env NODE_ENV=production BUILD_MODE=ssr tsx build.ts && esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/solid",
369
+ start: "cross-env NODE_ENV=production node dist/server/index.js",
370
+ lint: "tsc --noEmit"
371
+ },
372
+ dependencies: {
373
+ "@taujs/server": "latest",
374
+ "@taujs/solid": "latest",
375
+ fastify: "^5.2.0",
376
+ "solid-js": "^1.9.0"
377
+ },
378
+ devDependencies: {
379
+ "@taujs/mcp": "latest",
380
+ "@types/node": "^22.10.5",
381
+ "cross-env": "^7.0.3",
382
+ // `build:server` invokes the esbuild BINARY directly, so it must be a declared dependency
383
+ // of the generated project - it is not inherited from vite's own copy.
384
+ esbuild: "^0.25.0",
385
+ tsx: "^4.19.3",
386
+ typescript: "^5.7.3",
387
+ vite: "^7.1.11",
388
+ // The managed compiler instantiates this internally with `ssr: true` forced; the app never
389
+ // adds it to `plugins` itself.
390
+ "vite-plugin-solid": "^2.11.0"
391
+ }
392
+ };
393
+ }
302
394
  return {
303
395
  name: projectName,
304
396
  version: "0.1.0",
@@ -306,10 +398,10 @@ function generatePackageJson(projectName, framework) {
306
398
  type: "module",
307
399
  scripts: {
308
400
  dev: "cross-env NODE_ENV=development tsx watch --ignore vite.config.ts --trace-warnings --tsconfig ./src/server/tsconfig.json ./src/server/index.ts --loglevel verbose",
309
- "build:client": "tsx build.ts",
310
- "build:entry-server": "cross-env BUILD_MODE=ssr tsx build.ts",
401
+ "build:client": "cross-env NODE_ENV=production tsx build.ts",
402
+ "build:entry-server": "cross-env NODE_ENV=production BUILD_MODE=ssr tsx build.ts",
311
403
  "build:server": "esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/react",
312
- build: "tsx build.ts && cross-env BUILD_MODE=ssr tsx build.ts && esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/react",
404
+ build: "cross-env NODE_ENV=production tsx build.ts && cross-env NODE_ENV=production BUILD_MODE=ssr tsx build.ts && esbuild src/server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.js --external:fastify --external:@taujs/server --external:@taujs/react",
313
405
  start: "cross-env NODE_ENV=production node dist/server/index.js",
314
406
  lint: "tsc --noEmit"
315
407
  },
@@ -327,6 +419,9 @@ function generatePackageJson(projectName, framework) {
327
419
  "@types/react-dom": "^19.0.2",
328
420
  "@vitejs/plugin-react": "^4.6.0",
329
421
  "cross-env": "^7.0.3",
422
+ // `build:server` invokes the esbuild BINARY directly, so it must be a declared dependency
423
+ // of the generated project - it is not inherited from vite's own copy.
424
+ esbuild: "^0.25.0",
330
425
  tsx: "^4.19.3",
331
426
  typescript: "^5.7.3",
332
427
  vite: "^7.1.11"
@@ -351,8 +446,10 @@ function generateTsConfig(framework) {
351
446
  target: "ES2022",
352
447
  module: "ESNext",
353
448
  lib: ["ES2022", "DOM", "DOM.Iterable"],
354
- // Vue SFCs are typed by vue-tsc; React needs the automatic JSX runtime.
449
+ // Vue SFCs are typed by vue-tsc; React needs the automatic JSX runtime; Solid PRESERVES JSX
450
+ // for its own Babel transform and types it through `solid-js`.
355
451
  ...framework === "react" ? { jsx: "react-jsx" } : {},
452
+ ...framework === "solid" ? { jsx: "preserve", jsxImportSource: "solid-js" } : {},
356
453
  moduleResolution: "bundler",
357
454
  resolveJsonModule: true,
358
455
  allowImportingTsExtensions: true,
@@ -378,11 +475,15 @@ function generateServerTsConfig() {
378
475
  };
379
476
  }
380
477
  function generateTaujsConfig(framework) {
381
- const pluginImport = framework === "vue" ? `
382
- import { pluginVue } from '@taujs/vue/plugin';` : "";
383
- const pluginsLine = framework === "vue" ? `
384
- plugins: [pluginVue()],` : "";
385
- return `import { defineConfig } from '@taujs/server/config';${pluginImport}
478
+ const rendererImport = framework === "vue" ? `
479
+ import { vueRenderer } from '@taujs/vue/renderer';` : framework === "solid" ? `
480
+ import { solidRenderer } from '@taujs/solid/renderer';` : `
481
+ import { reactRenderer } from '@taujs/react/renderer';`;
482
+ const rendererLine = framework === "vue" ? `
483
+ renderer: vueRenderer(),` : framework === "solid" ? `
484
+ renderer: solidRenderer({ project: './tsconfig.solid.json' }),` : `
485
+ renderer: reactRenderer({ project: './tsconfig.json' }),`;
486
+ return `import { defineConfig } from '@taujs/server/config';${rendererImport}
386
487
 
387
488
  export default defineConfig({
388
489
  server: {
@@ -390,10 +491,16 @@ export default defineConfig({
390
491
  host: 'localhost',
391
492
  hmrPort: 5174,
392
493
  },
494
+ // Declared Vite surface - applied to dev and build. See https://taujs.dev/reference/taujs-config/#vite-configuration
495
+ // vite: {
496
+ // define: { __APP_VERSION__: JSON.stringify('0.0.0') },
497
+ // plugins: [],
498
+ // },
499
+ // alias: { '@components': './src/client/shared/components' },
393
500
  apps: [
394
501
  {
395
502
  appId: 'main',
396
- entryPoint: '',${pluginsLine}
503
+ entryPoint: '',${rendererLine}
397
504
  routes: [
398
505
  {
399
506
  path: '/',
@@ -1065,6 +1172,82 @@ export const { renderSSR, renderStream } = createRenderer({
1065
1172
  });
1066
1173
  `;
1067
1174
  }
1175
+ function generateSolidCompilerTsConfig() {
1176
+ return {
1177
+ compilerOptions: {
1178
+ jsx: "preserve",
1179
+ jsxImportSource: "solid-js"
1180
+ },
1181
+ include: ["src/client/**/*.tsx"]
1182
+ };
1183
+ }
1184
+ function generateSolidRenderId() {
1185
+ return `/**
1186
+ * The renderId is a SHARED constant: the server renders Solid's markers and serialised data under
1187
+ * this namespace, and the client must hydrate under the SAME one. It is imported by BOTH entries
1188
+ * on purpose - a literal duplicated in two files is a hydration bug waiting to happen.
1189
+ */
1190
+ export const RENDER_ID = 'app';
1191
+ `;
1192
+ }
1193
+ function generateAppComponentSolid() {
1194
+ return `import { Show } from 'solid-js';
1195
+ import { useSSRStore } from '@taujs/solid';
1196
+
1197
+ type RouteData = { message?: string };
1198
+
1199
+ export function App() {
1200
+ // Route data arrives through the store, which the renderer provides. On the server it is already
1201
+ // committed before the render begins; on the client it is seeded from window.__INITIAL_DATA__.
1202
+ const store = useSSRStore<RouteData>();
1203
+
1204
+ return (
1205
+ <main>
1206
+ <h1>\u03C4js + Solid</h1>
1207
+ <Show when={store.data().message} fallback={<p>No route data.</p>}>
1208
+ <p>{store.data().message}</p>
1209
+ </Show>
1210
+ </main>
1211
+ );
1212
+ }
1213
+ `;
1214
+ }
1215
+ function generateEntryClientSolid() {
1216
+ return `import { hydrateApp } from '@taujs/solid';
1217
+
1218
+ import { App } from './App';
1219
+ import { RENDER_ID } from './renderId';
1220
+
1221
+ hydrateApp({
1222
+ app: () => <App />,
1223
+ renderId: RENDER_ID,
1224
+ rootElementId: 'root',
1225
+ onHydrationError: (error) => {
1226
+ console.error('Hydration failed:', error);
1227
+ },
1228
+ });
1229
+ `;
1230
+ }
1231
+ function generateEntryServerSolid() {
1232
+ return `import { createRenderer } from '@taujs/solid';
1233
+
1234
+ import { App } from './App';
1235
+ import { RENDER_ID } from './renderId';
1236
+
1237
+ export const { renderSSR, renderStream } = createRenderer({
1238
+ appComponent: () => <App />,
1239
+ renderId: RENDER_ID,
1240
+ headContent: ({ data, meta }) => \`
1241
+ <title>\${meta?.title || "\u03C4js - Composing systems, not just apps"}</title>
1242
+ <meta name="description" content="\${
1243
+ meta?.description ||
1244
+ data?.message ||
1245
+ "\u03C4js - Composing systems, not just apps"
1246
+ }">
1247
+ \`,
1248
+ });
1249
+ `;
1250
+ }
1068
1251
  function generateServerIndex() {
1069
1252
  return `import { createServer } from '@taujs/server';
1070
1253
  import config from '../../taujs.config.ts';
@@ -1098,7 +1281,9 @@ export type ServiceRegistry = typeof serviceRegistry;
1098
1281
  `;
1099
1282
  }
1100
1283
  function generateServiceTypesAugmentation() {
1101
- return `declare module '@taujs/server/config' {
1284
+ return `import '@taujs/server/config';
1285
+
1286
+ declare module '@taujs/server/config' {
1102
1287
  interface ServiceContext {
1103
1288
  tenantId?: string;
1104
1289
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taujs/create-taujs",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Scaffold a new τjs application",
5
5
  "author": "Aoede <taujs@aoede.uk.net> (https://www.aoede.uk.net)",
6
6
  "homepage": "https://taujs.dev/",