@tanstack/cli 0.71.1 → 0.72.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.
- package/dist/cli.js +21 -5
- package/dist/command-line.js +53 -3
- package/dist/dev-watch.js +3 -1
- package/dist/options.js +50 -11
- package/dist/types/cli.d.ts +124 -1
- package/dist/types/types.d.ts +1 -0
- package/dist/types/ui-prompts.d.ts +2 -1
- package/dist/ui-prompts.js +26 -3
- package/package.json +2 -2
- package/skills/create-app-scaffold/SKILL.md +16 -2
- package/skills/create-app-scaffold/references/bundlers.md +27 -0
- package/skills/create-app-scaffold/references/create-flag-compatibility-matrix.md +13 -5
- package/skills/create-app-scaffold/references/framework-adapters.md +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Command, InvalidArgumentError, Option } from 'commander';
|
|
|
4
4
|
import { cancel, confirm, intro, isCancel, log } from '@clack/prompts';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import semver from 'semver';
|
|
7
|
-
import { SUPPORTED_PACKAGE_MANAGERS, addToApp, compileAddOn, compileStarter, createApp, devAddOn, getAllAddOns, getFrameworkByName, getFrameworks, initAddOn, initStarter, isDemoFilePath, } from '@tanstack/create';
|
|
7
|
+
import { SUPPORTED_PACKAGE_MANAGERS, addToApp, compileAddOn, compileStarter, createApp, devAddOn, getAllAddOns, getBundlers, getFrameworkByName, getFrameworks, initAddOn, initStarter, isDemoFilePath, resolveBundler, } from '@tanstack/create';
|
|
8
8
|
import { LIBRARY_GROUPS, fetchDocContent, fetchLibraries, fetchPartners, searchTanStackDocs, } from './discovery.js';
|
|
9
9
|
import { getTelemetryStatus, setTelemetryEnabled, } from './telemetry-config.js';
|
|
10
10
|
import { createTelemetryClient } from './telemetry.js';
|
|
@@ -97,7 +97,7 @@ function getCreateCommandVariant(options) {
|
|
|
97
97
|
}
|
|
98
98
|
return 'scaffold';
|
|
99
99
|
}
|
|
100
|
-
function getCreateTelemetryProperties(projectName, options) {
|
|
100
|
+
export function getCreateTelemetryProperties(projectName, options) {
|
|
101
101
|
const addOnIds = Array.isArray(options.addOns)
|
|
102
102
|
? sanitizeIdList(options.addOns)
|
|
103
103
|
: undefined;
|
|
@@ -110,6 +110,7 @@ function getCreateTelemetryProperties(projectName, options) {
|
|
|
110
110
|
: undefined,
|
|
111
111
|
command_variant: getCreateCommandVariant(options),
|
|
112
112
|
deployment: options.deployment ? sanitizeId(options.deployment) : undefined,
|
|
113
|
+
bundler: options.buildTool ? sanitizeId(options.buildTool) : undefined,
|
|
113
114
|
examples: options.examples,
|
|
114
115
|
blank: !!options.blank,
|
|
115
116
|
framework: options.framework ? sanitizeId(options.framework) : undefined,
|
|
@@ -127,7 +128,7 @@ function getCreateTelemetryProperties(projectName, options) {
|
|
|
127
128
|
yes: !!options.yes,
|
|
128
129
|
};
|
|
129
130
|
}
|
|
130
|
-
function getResolvedCreateTelemetryProperties(finalOptions, cliOptions) {
|
|
131
|
+
export function getResolvedCreateTelemetryProperties(finalOptions, cliOptions) {
|
|
131
132
|
const includeExamples = finalOptions.includeExamples !== false;
|
|
132
133
|
const addOnIds = sanitizeIdList(finalOptions.chosenAddOns.map((addOn) => addOn.id));
|
|
133
134
|
const deployment = finalOptions.chosenAddOns.find((addOn) => addOn.type === 'deployment');
|
|
@@ -137,6 +138,7 @@ function getResolvedCreateTelemetryProperties(finalOptions, cliOptions) {
|
|
|
137
138
|
add_on_count: addOnIds.length,
|
|
138
139
|
add_on_ids: addOnIds,
|
|
139
140
|
deployment: deployment ? sanitizeId(deployment.id) : undefined,
|
|
141
|
+
bundler: sanitizeId(finalOptions.bundler ?? 'vite'),
|
|
140
142
|
examples: includeExamples,
|
|
141
143
|
blank: finalOptions.projectPreset === 'blank',
|
|
142
144
|
framework: sanitizeId(finalOptions.framework.id),
|
|
@@ -185,6 +187,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
185
187
|
lines.push(` Project: ${finalOptions.projectName}`);
|
|
186
188
|
lines.push(` Location: ${finalOptions.targetDir}`);
|
|
187
189
|
lines.push(` Framework: ${finalOptions.framework.name}`);
|
|
190
|
+
lines.push(` Build tool: ${resolveBundler(finalOptions.framework, finalOptions.bundler).name}`);
|
|
188
191
|
lines.push(` Mode: ${finalOptions.mode}`);
|
|
189
192
|
if (finalOptions.projectPreset === 'blank') {
|
|
190
193
|
lines.push(` Preset: blank`);
|
|
@@ -401,6 +404,12 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
401
404
|
}
|
|
402
405
|
}
|
|
403
406
|
}
|
|
407
|
+
const bundlers = new Set();
|
|
408
|
+
for (const framework of getFrameworks()) {
|
|
409
|
+
for (const bundler of getBundlers(framework)) {
|
|
410
|
+
bundlers.add(bundler.id);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
404
413
|
// Mode is always file-router (TanStack Start)
|
|
405
414
|
const defaultMode = 'file-router';
|
|
406
415
|
const categoryAliases = {
|
|
@@ -475,7 +484,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
475
484
|
}, async (telemetry) => {
|
|
476
485
|
validateCreateCommandOptions(options);
|
|
477
486
|
if (options.listAddOns) {
|
|
478
|
-
const addOns = await getAllAddOns(getFrameworkByName(options.framework || defaultFramework || 'React'), defaultMode);
|
|
487
|
+
const addOns = await getAllAddOns(getFrameworkByName(options.framework || defaultFramework || 'React'), defaultMode, options.buildTool);
|
|
479
488
|
const visibleAddOns = addOns.filter((a) => !forcedAddOns.includes(a.id));
|
|
480
489
|
telemetry.mergeProperties({
|
|
481
490
|
result_count: visibleAddOns.length,
|
|
@@ -511,7 +520,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
511
520
|
return;
|
|
512
521
|
}
|
|
513
522
|
if (options.addonDetails) {
|
|
514
|
-
const addOns = await getAllAddOns(getFrameworkByName(options.framework || defaultFramework || 'React'), defaultMode);
|
|
523
|
+
const addOns = await getAllAddOns(getFrameworkByName(options.framework || defaultFramework || 'React'), defaultMode, options.buildTool);
|
|
515
524
|
const addOn = addOns.find((a) => a.id === options.addonDetails) ??
|
|
516
525
|
addOns.find((a) => a.id.toLowerCase() === options.addonDetails.toLowerCase());
|
|
517
526
|
if (!addOn) {
|
|
@@ -702,6 +711,13 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
|
|
|
702
711
|
});
|
|
703
712
|
}
|
|
704
713
|
cmd
|
|
714
|
+
.option(`--build-tool <${Array.from(bundlers).join('|')}>`, 'select the project build tool', (value) => {
|
|
715
|
+
const buildTool = Array.from(bundlers).find((item) => item.toLowerCase() === value.toLowerCase());
|
|
716
|
+
if (!buildTool) {
|
|
717
|
+
throw new InvalidArgumentError(`Invalid build tool: ${value}. The following are allowed: ${Array.from(bundlers).join(', ')}`);
|
|
718
|
+
}
|
|
719
|
+
return buildTool;
|
|
720
|
+
})
|
|
705
721
|
.option('--starter [url-or-id]', 'DEPRECATED: use --template. Initializes from a template URL or built-in id', false)
|
|
706
722
|
.option('--template-id <id>', 'initialize using a built-in template id')
|
|
707
723
|
.option('--template [url-or-id]', 'initialize this project from a template URL or built-in template id')
|
package/dist/command-line.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import { DEFAULT_PACKAGE_MANAGER, finalizeAddOns, getFrameworkById, getPackageManager, getRawRegistry, loadStarter, populateAddOnOptionsDefaults, } from '@tanstack/create';
|
|
3
|
+
import { DEFAULT_PACKAGE_MANAGER, finalizeAddOns, getFrameworkById, getPackageManager, getRawRegistry, loadStarter, populateAddOnOptionsDefaults, resolveBundler, } from '@tanstack/create';
|
|
4
4
|
import { resolveProjectLocation, validateProjectName, } from './utils.js';
|
|
5
5
|
const SUPPORTED_LEGACY_TEMPLATES = new Set([
|
|
6
6
|
'file-router',
|
|
@@ -217,6 +217,30 @@ export async function listTemplateChoices(preferredFramework) {
|
|
|
217
217
|
export function validateLegacyCreateFlags(cliOptions) {
|
|
218
218
|
const warnings = [];
|
|
219
219
|
const legacyTemplate = getLegacyTemplateValue(cliOptions.template);
|
|
220
|
+
const isSupportedLegacyTemplate = legacyTemplate !== undefined &&
|
|
221
|
+
SUPPORTED_LEGACY_TEMPLATES.has(legacyTemplate);
|
|
222
|
+
if (cliOptions.buildTool?.toLowerCase() === 'rsbuild') {
|
|
223
|
+
if (cliOptions.starter ||
|
|
224
|
+
(cliOptions.template && !isSupportedLegacyTemplate) ||
|
|
225
|
+
cliOptions.templateId) {
|
|
226
|
+
return {
|
|
227
|
+
warnings,
|
|
228
|
+
error: 'Rsbuild does not currently support --starter, --template, or --template-id.',
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (cliOptions.deployment) {
|
|
232
|
+
return {
|
|
233
|
+
warnings,
|
|
234
|
+
error: 'Rsbuild does not currently support --deployment.',
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (cliOptions.addOns) {
|
|
238
|
+
return {
|
|
239
|
+
warnings,
|
|
240
|
+
error: 'Rsbuild currently supports toolchains only. Use --toolchain eslint or --toolchain biome.',
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
220
244
|
if (cliOptions.blank &&
|
|
221
245
|
(cliOptions.starter || cliOptions.template || cliOptions.templateId)) {
|
|
222
246
|
return {
|
|
@@ -304,6 +328,8 @@ export async function normalizeOptions(cliOptions, forcedAddOns, opts) {
|
|
|
304
328
|
let routerOnly = !!cliOptions.routerOnly;
|
|
305
329
|
const blank = cliOptions.blank === true;
|
|
306
330
|
const legacyTemplate = getLegacyTemplateValue(cliOptions.template);
|
|
331
|
+
const isSupportedLegacyTemplate = legacyTemplate !== undefined &&
|
|
332
|
+
SUPPORTED_LEGACY_TEMPLATES.has(legacyTemplate);
|
|
307
333
|
if (!cliOptions.starter) {
|
|
308
334
|
if (cliOptions.template && !legacyTemplate) {
|
|
309
335
|
cliOptions.starter = cliOptions.template;
|
|
@@ -320,6 +346,24 @@ export async function normalizeOptions(cliOptions, forcedAddOns, opts) {
|
|
|
320
346
|
cliOptions.starter = cliOptions.templateId;
|
|
321
347
|
}
|
|
322
348
|
const preferredFramework = (cliOptions.framework || 'react').toLowerCase();
|
|
349
|
+
const initialFramework = getFrameworkById(preferredFramework);
|
|
350
|
+
let framework = initialFramework;
|
|
351
|
+
const bundler = initialFramework
|
|
352
|
+
? resolveBundler(initialFramework, cliOptions.buildTool).id
|
|
353
|
+
: (cliOptions.buildTool ?? 'vite');
|
|
354
|
+
if (bundler === 'rsbuild') {
|
|
355
|
+
if (cliOptions.starter ||
|
|
356
|
+
(cliOptions.template && !isSupportedLegacyTemplate) ||
|
|
357
|
+
cliOptions.templateId) {
|
|
358
|
+
throw new Error('Rsbuild does not currently support templates.');
|
|
359
|
+
}
|
|
360
|
+
if (cliOptions.deployment || opts?.forcedDeployment) {
|
|
361
|
+
throw new Error('Rsbuild does not currently support deployments.');
|
|
362
|
+
}
|
|
363
|
+
if (forcedAddOns?.length || cliOptions.addOns) {
|
|
364
|
+
throw new Error('Rsbuild currently supports toolchains only. Use --toolchain eslint or --toolchain biome.');
|
|
365
|
+
}
|
|
366
|
+
}
|
|
323
367
|
const starter = !routerOnly && !blank && cliOptions.starter
|
|
324
368
|
? await loadStarter(await resolveStarterSpecifier(cliOptions.starter, preferredFramework))
|
|
325
369
|
: undefined;
|
|
@@ -329,7 +373,11 @@ export async function normalizeOptions(cliOptions, forcedAddOns, opts) {
|
|
|
329
373
|
cliOptions.framework = starter.framework;
|
|
330
374
|
mode = starter.mode;
|
|
331
375
|
}
|
|
332
|
-
const
|
|
376
|
+
const resolvedFramework = getFrameworkById(cliOptions.framework || 'react');
|
|
377
|
+
if (resolvedFramework) {
|
|
378
|
+
resolveBundler(resolvedFramework, bundler);
|
|
379
|
+
}
|
|
380
|
+
framework = resolvedFramework;
|
|
333
381
|
async function selectAddOns() {
|
|
334
382
|
// Edge case for Windows Powershell
|
|
335
383
|
if (Array.isArray(cliOptions.addOns) && cliOptions.addOns.length === 1) {
|
|
@@ -364,7 +412,7 @@ export async function normalizeOptions(cliOptions, forcedAddOns, opts) {
|
|
|
364
412
|
if (!routerOnly && !cliOptions.deployment && opts?.forcedDeployment) {
|
|
365
413
|
selectedAddOns.add(opts.forcedDeployment);
|
|
366
414
|
}
|
|
367
|
-
return await finalizeAddOns(framework, mode, Array.from(selectedAddOns));
|
|
415
|
+
return await finalizeAddOns(framework, mode, Array.from(selectedAddOns), bundler);
|
|
368
416
|
}
|
|
369
417
|
return [];
|
|
370
418
|
}
|
|
@@ -390,6 +438,7 @@ export async function normalizeOptions(cliOptions, forcedAddOns, opts) {
|
|
|
390
438
|
targetDir,
|
|
391
439
|
framework,
|
|
392
440
|
mode,
|
|
441
|
+
bundler,
|
|
393
442
|
typescript,
|
|
394
443
|
tailwind,
|
|
395
444
|
packageManager: cliOptions.packageManager ||
|
|
@@ -405,6 +454,7 @@ export async function normalizeOptions(cliOptions, forcedAddOns, opts) {
|
|
|
405
454
|
},
|
|
406
455
|
starter: starter,
|
|
407
456
|
projectPreset: blank ? 'blank' : 'default',
|
|
457
|
+
routerOnly,
|
|
408
458
|
};
|
|
409
459
|
normalized.includeExamples =
|
|
410
460
|
includeExamples;
|
package/dist/dev-watch.js
CHANGED
|
@@ -176,7 +176,7 @@ export class DevWatchManager {
|
|
|
176
176
|
if (!registeredFramework) {
|
|
177
177
|
throw new Error(`Failed to register framework: ${this.options.framework.id}`);
|
|
178
178
|
}
|
|
179
|
-
const updatedChosenAddons = await finalizeAddOns(registeredFramework, this.options.cliOptions.mode, chosenAddonIds);
|
|
179
|
+
const updatedChosenAddons = await finalizeAddOns(registeredFramework, this.options.cliOptions.mode, chosenAddonIds, this.options.cliOptions.bundler);
|
|
180
180
|
// Check if package metadata was modified
|
|
181
181
|
const packageMetadataChanged = Array.from(changes).some((filePath) => {
|
|
182
182
|
const normalized = filePath.replace(/\\/g, '/');
|
|
@@ -327,6 +327,8 @@ export class DevWatchManager {
|
|
|
327
327
|
addOns,
|
|
328
328
|
basePackageJSON,
|
|
329
329
|
optionalPackages,
|
|
330
|
+
bundlers: this.options.framework.bundlers,
|
|
331
|
+
defaultBundler: this.options.framework.defaultBundler,
|
|
330
332
|
supportedModes: this.options.framework.supportedModes,
|
|
331
333
|
};
|
|
332
334
|
}
|
package/dist/options.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { intro } from '@clack/prompts';
|
|
2
|
-
import { finalizeAddOns, getFrameworkById, getFrameworks, getPackageManager, loadStarter, populateAddOnOptionsDefaults, readConfigFile, } from '@tanstack/create';
|
|
3
|
-
import { getProjectName, promptForAddOnOptions, promptForEnvVars, selectAddOns, selectDeployment, selectExamples, selectFramework, selectGit, selectInstall, selectPackageManager, selectTemplate, selectToolchain, } from './ui-prompts.js';
|
|
4
|
-
import { listTemplateChoices, resolveStarterSpecifier, } from './command-line.js';
|
|
2
|
+
import { finalizeAddOns, getAllAddOns, getFrameworkById, getFrameworks, getPackageManager, loadStarter, populateAddOnOptionsDefaults, readConfigFile, resolveBundler, } from '@tanstack/create';
|
|
3
|
+
import { getProjectName, promptForAddOnOptions, promptForEnvVars, selectAddOns, selectBundler, selectDeployment, selectExamples, selectFramework, selectGit, selectInstall, selectPackageManager, selectTemplate, selectToolchain, } from './ui-prompts.js';
|
|
4
|
+
import { listTemplateChoices, resolveStarterSpecifier, validateLegacyCreateFlags, } from './command-line.js';
|
|
5
5
|
import { resolveProjectLocation, validateProjectName, } from './utils.js';
|
|
6
6
|
export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], forcedDeployment, showDeploymentOptions = true, defaultFrameworkId, }) {
|
|
7
7
|
const options = {};
|
|
@@ -18,6 +18,25 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
18
18
|
options.framework = await selectFramework(availableFrameworks, defaultFrameworkId);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
options.bundler = await selectBundler(options.framework, cliOptions.buildTool);
|
|
22
|
+
if (options.bundler === 'rsbuild') {
|
|
23
|
+
const validation = validateLegacyCreateFlags({
|
|
24
|
+
...cliOptions,
|
|
25
|
+
buildTool: options.bundler,
|
|
26
|
+
addOns: Array.isArray(cliOptions.addOns) && cliOptions.addOns.length > 0
|
|
27
|
+
? cliOptions.addOns
|
|
28
|
+
: undefined,
|
|
29
|
+
});
|
|
30
|
+
if (validation.error) {
|
|
31
|
+
throw new Error(validation.error);
|
|
32
|
+
}
|
|
33
|
+
if (forcedAddOns.length > 0) {
|
|
34
|
+
throw new Error('Rsbuild does not currently support forced add-ons.');
|
|
35
|
+
}
|
|
36
|
+
if (forcedDeployment) {
|
|
37
|
+
throw new Error('Rsbuild does not currently support deployments.');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
21
40
|
const projectLocation = resolveProjectLocation({
|
|
22
41
|
projectName: cliOptions.projectName ?? (await getProjectName()),
|
|
23
42
|
targetDir: cliOptions.targetDir,
|
|
@@ -48,7 +67,7 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
48
67
|
cliOptions.starter = cliOptions.templateId;
|
|
49
68
|
}
|
|
50
69
|
}
|
|
51
|
-
if (!routerOnly && !blank && !cliOptions.starter) {
|
|
70
|
+
if (options.bundler !== 'rsbuild' && !routerOnly && !blank && !cliOptions.starter) {
|
|
52
71
|
const starterChoices = await listTemplateChoices(options.framework.id);
|
|
53
72
|
const selectedTemplateId = await selectTemplate(starterChoices.map((choice) => ({
|
|
54
73
|
id: choice.id,
|
|
@@ -59,7 +78,7 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
59
78
|
cliOptions.starter = selectedTemplateId;
|
|
60
79
|
}
|
|
61
80
|
}
|
|
62
|
-
const starter = !routerOnly && !blank && cliOptions.starter
|
|
81
|
+
const starter = options.bundler !== 'rsbuild' && !routerOnly && !blank && cliOptions.starter
|
|
63
82
|
? await loadStarter(await resolveStarterSpecifier(cliOptions.starter, options.framework.id))
|
|
64
83
|
: undefined;
|
|
65
84
|
if (starter) {
|
|
@@ -78,12 +97,12 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
78
97
|
detectedPackageManager || (await selectPackageManager());
|
|
79
98
|
}
|
|
80
99
|
// Toolchain selection
|
|
81
|
-
const toolchain = blank && cliOptions.toolchain === undefined
|
|
100
|
+
const toolchain = blank && options.bundler !== 'rsbuild' && cliOptions.toolchain === undefined
|
|
82
101
|
? undefined
|
|
83
102
|
: await selectToolchain(options.framework, cliOptions.toolchain);
|
|
84
103
|
// Deployment selection
|
|
85
104
|
let deployment;
|
|
86
|
-
if (routerOnly) {
|
|
105
|
+
if (routerOnly || options.bundler === 'rsbuild') {
|
|
87
106
|
deployment = undefined;
|
|
88
107
|
}
|
|
89
108
|
else if (cliOptions.deployment) {
|
|
@@ -112,7 +131,7 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
112
131
|
if (deployment) {
|
|
113
132
|
addOns.add(deployment);
|
|
114
133
|
}
|
|
115
|
-
if (!routerOnly) {
|
|
134
|
+
if (!routerOnly && options.bundler !== 'rsbuild') {
|
|
116
135
|
for (const addOn of starter?.dependsOn || []) {
|
|
117
136
|
addOns.add(addOn);
|
|
118
137
|
}
|
|
@@ -120,7 +139,7 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
120
139
|
addOns.add(addOn);
|
|
121
140
|
}
|
|
122
141
|
}
|
|
123
|
-
if (!routerOnly && Array.isArray(cliOptions.addOns)) {
|
|
142
|
+
if (!routerOnly && options.bundler !== 'rsbuild' && Array.isArray(cliOptions.addOns)) {
|
|
124
143
|
for (const addOn of cliOptions.addOns) {
|
|
125
144
|
if (addOn.toLowerCase() === 'start') {
|
|
126
145
|
continue;
|
|
@@ -128,7 +147,7 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
128
147
|
addOns.add(addOn);
|
|
129
148
|
}
|
|
130
149
|
}
|
|
131
|
-
else if (!routerOnly && !blank) {
|
|
150
|
+
else if (!routerOnly && options.bundler !== 'rsbuild' && !blank) {
|
|
132
151
|
for (const addOn of await selectAddOns(options.framework, options.mode, 'add-on', 'What add-ons would you like for your project?', forcedAddOns)) {
|
|
133
152
|
addOns.add(addOn);
|
|
134
153
|
}
|
|
@@ -138,13 +157,14 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
|
|
|
138
157
|
}
|
|
139
158
|
}
|
|
140
159
|
}
|
|
141
|
-
const chosenAddOns = Array.from(await finalizeAddOns(options.framework, options.mode, Array.from(addOns)));
|
|
160
|
+
const chosenAddOns = Array.from(await finalizeAddOns(options.framework, options.mode, Array.from(addOns), options.bundler));
|
|
142
161
|
options.chosenAddOns = includeExamples
|
|
143
162
|
? chosenAddOns
|
|
144
163
|
: chosenAddOns.filter((addOn) => addOn.type !== 'example');
|
|
145
164
|
options.tailwind =
|
|
146
165
|
!blank || options.chosenAddOns.some((addOn) => addOn.tailwind === true);
|
|
147
166
|
options.projectPreset = blank ? 'blank' : 'default';
|
|
167
|
+
options.routerOnly = routerOnly;
|
|
148
168
|
// Prompt for add-on options in interactive mode
|
|
149
169
|
if (Array.isArray(cliOptions.addOns)) {
|
|
150
170
|
// Non-interactive mode: use defaults
|
|
@@ -184,6 +204,25 @@ export async function promptForAddOns() {
|
|
|
184
204
|
}
|
|
185
205
|
intro(`Adding new add-ons to '${config.projectName}'`);
|
|
186
206
|
const addOns = new Set();
|
|
207
|
+
const bundler = resolveBundler(framework, config.bundler).id;
|
|
208
|
+
if (bundler === 'rsbuild') {
|
|
209
|
+
const toolchains = getAllAddOns(framework, config.mode, bundler).filter((addOn) => addOn.type === 'toolchain');
|
|
210
|
+
const configuredAddOnIds = new Set(config.chosenAddOns.map((addOn) => addOn.toLowerCase()));
|
|
211
|
+
const configuredExclusiveGroups = new Set(toolchains
|
|
212
|
+
.filter((addOn) => configuredAddOnIds.has(addOn.id.toLowerCase()))
|
|
213
|
+
.flatMap((addOn) => addOn.exclusive ?? []));
|
|
214
|
+
const unavailableToolchains = toolchains
|
|
215
|
+
.filter((addOn) => configuredAddOnIds.has(addOn.id.toLowerCase()) ||
|
|
216
|
+
addOn.exclusive?.some((exclusive) => configuredExclusiveGroups.has(exclusive)))
|
|
217
|
+
.map((addOn) => addOn.id);
|
|
218
|
+
if (unavailableToolchains.length === toolchains.length) {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
for (const addOn of await selectAddOns(framework, config.mode, 'toolchain', 'Which toolchain would you like to add?', unavailableToolchains, false, bundler)) {
|
|
222
|
+
addOns.add(addOn);
|
|
223
|
+
}
|
|
224
|
+
return Array.from(addOns);
|
|
225
|
+
}
|
|
187
226
|
for (const addOn of await selectAddOns(framework, config.mode, 'add-on', 'What add-ons would you like for your project?', config.chosenAddOns)) {
|
|
188
227
|
addOns.add(addOn);
|
|
189
228
|
}
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,4 +1,127 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CliOptions } from './types.js';
|
|
2
|
+
import type { FrameworkDefinition, Options } from '@tanstack/create';
|
|
3
|
+
export declare function getCreateTelemetryProperties(projectName: string, options: CliOptions): {
|
|
4
|
+
add_on_count: number | undefined;
|
|
5
|
+
add_on_ids: string[] | undefined;
|
|
6
|
+
addon_details_id: string | undefined;
|
|
7
|
+
command_variant: string;
|
|
8
|
+
deployment: string | undefined;
|
|
9
|
+
bundler: string | undefined;
|
|
10
|
+
examples: boolean | undefined;
|
|
11
|
+
blank: boolean;
|
|
12
|
+
framework: string | undefined;
|
|
13
|
+
git: boolean | undefined;
|
|
14
|
+
install: boolean;
|
|
15
|
+
intent: boolean;
|
|
16
|
+
interactive: boolean;
|
|
17
|
+
json: boolean;
|
|
18
|
+
non_interactive: boolean;
|
|
19
|
+
package_manager: "npm" | "yarn" | "pnpm" | "bun" | "deno" | undefined;
|
|
20
|
+
project_name_provided: boolean;
|
|
21
|
+
router_only: boolean;
|
|
22
|
+
target_dir_flag: boolean;
|
|
23
|
+
toolchain: string | undefined;
|
|
24
|
+
yes: boolean;
|
|
25
|
+
starter_kind?: undefined;
|
|
26
|
+
starter_id?: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
add_on_count: number | undefined;
|
|
29
|
+
add_on_ids: string[] | undefined;
|
|
30
|
+
addon_details_id: string | undefined;
|
|
31
|
+
command_variant: string;
|
|
32
|
+
deployment: string | undefined;
|
|
33
|
+
bundler: string | undefined;
|
|
34
|
+
examples: boolean | undefined;
|
|
35
|
+
blank: boolean;
|
|
36
|
+
framework: string | undefined;
|
|
37
|
+
git: boolean | undefined;
|
|
38
|
+
install: boolean;
|
|
39
|
+
intent: boolean;
|
|
40
|
+
interactive: boolean;
|
|
41
|
+
json: boolean;
|
|
42
|
+
non_interactive: boolean;
|
|
43
|
+
package_manager: "npm" | "yarn" | "pnpm" | "bun" | "deno" | undefined;
|
|
44
|
+
project_name_provided: boolean;
|
|
45
|
+
router_only: boolean;
|
|
46
|
+
target_dir_flag: boolean;
|
|
47
|
+
toolchain: string | undefined;
|
|
48
|
+
yes: boolean;
|
|
49
|
+
starter_kind: string;
|
|
50
|
+
starter_id?: undefined;
|
|
51
|
+
} | {
|
|
52
|
+
add_on_count: number | undefined;
|
|
53
|
+
add_on_ids: string[] | undefined;
|
|
54
|
+
addon_details_id: string | undefined;
|
|
55
|
+
command_variant: string;
|
|
56
|
+
deployment: string | undefined;
|
|
57
|
+
bundler: string | undefined;
|
|
58
|
+
examples: boolean | undefined;
|
|
59
|
+
blank: boolean;
|
|
60
|
+
framework: string | undefined;
|
|
61
|
+
git: boolean | undefined;
|
|
62
|
+
install: boolean;
|
|
63
|
+
intent: boolean;
|
|
64
|
+
interactive: boolean;
|
|
65
|
+
json: boolean;
|
|
66
|
+
non_interactive: boolean;
|
|
67
|
+
package_manager: "npm" | "yarn" | "pnpm" | "bun" | "deno" | undefined;
|
|
68
|
+
project_name_provided: boolean;
|
|
69
|
+
router_only: boolean;
|
|
70
|
+
target_dir_flag: boolean;
|
|
71
|
+
toolchain: string | undefined;
|
|
72
|
+
yes: boolean;
|
|
73
|
+
starter_id: string | undefined;
|
|
74
|
+
starter_kind: string;
|
|
75
|
+
};
|
|
76
|
+
export declare function getResolvedCreateTelemetryProperties(finalOptions: Options, cliOptions: CliOptions): {
|
|
77
|
+
add_on_count: number;
|
|
78
|
+
add_on_ids: string[];
|
|
79
|
+
deployment: string | undefined;
|
|
80
|
+
bundler: string | undefined;
|
|
81
|
+
examples: boolean;
|
|
82
|
+
blank: boolean;
|
|
83
|
+
framework: string | undefined;
|
|
84
|
+
git: boolean;
|
|
85
|
+
install: boolean;
|
|
86
|
+
intent: boolean;
|
|
87
|
+
package_manager: "npm" | "yarn" | "pnpm" | "bun" | "deno";
|
|
88
|
+
router_only: boolean;
|
|
89
|
+
toolchain: string | undefined;
|
|
90
|
+
starter_kind?: undefined;
|
|
91
|
+
starter_id?: undefined;
|
|
92
|
+
} | {
|
|
93
|
+
add_on_count: number;
|
|
94
|
+
add_on_ids: string[];
|
|
95
|
+
deployment: string | undefined;
|
|
96
|
+
bundler: string | undefined;
|
|
97
|
+
examples: boolean;
|
|
98
|
+
blank: boolean;
|
|
99
|
+
framework: string | undefined;
|
|
100
|
+
git: boolean;
|
|
101
|
+
install: boolean;
|
|
102
|
+
intent: boolean;
|
|
103
|
+
package_manager: "npm" | "yarn" | "pnpm" | "bun" | "deno";
|
|
104
|
+
router_only: boolean;
|
|
105
|
+
toolchain: string | undefined;
|
|
106
|
+
starter_kind: string;
|
|
107
|
+
starter_id?: undefined;
|
|
108
|
+
} | {
|
|
109
|
+
add_on_count: number;
|
|
110
|
+
add_on_ids: string[];
|
|
111
|
+
deployment: string | undefined;
|
|
112
|
+
bundler: string | undefined;
|
|
113
|
+
examples: boolean;
|
|
114
|
+
blank: boolean;
|
|
115
|
+
framework: string | undefined;
|
|
116
|
+
git: boolean;
|
|
117
|
+
install: boolean;
|
|
118
|
+
intent: boolean;
|
|
119
|
+
package_manager: "npm" | "yarn" | "pnpm" | "bun" | "deno";
|
|
120
|
+
router_only: boolean;
|
|
121
|
+
toolchain: string | undefined;
|
|
122
|
+
starter_id: string | undefined;
|
|
123
|
+
starter_kind: string;
|
|
124
|
+
};
|
|
2
125
|
export declare function cli({ name, appName, forcedAddOns, forcedDeployment, defaultFramework, frameworkDefinitionInitializers, showDeploymentOptions, legacyAutoCreate, defaultRouterOnly, }: {
|
|
3
126
|
name: string;
|
|
4
127
|
appName: string;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AddOn, PackageManager } from '@tanstack/create';
|
|
2
2
|
import type { Framework } from '@tanstack/create/dist/types/types.js';
|
|
3
|
+
export declare function selectBundler(framework: Framework, bundlerId?: string): Promise<string>;
|
|
3
4
|
export declare function selectFramework(frameworks: Array<Framework>, defaultFrameworkId?: string): Promise<Framework>;
|
|
4
5
|
export declare function selectInstall(): Promise<boolean>;
|
|
5
6
|
export declare function getProjectName(): Promise<string>;
|
|
@@ -9,7 +10,7 @@ export declare function selectTemplate(templates: Array<{
|
|
|
9
10
|
name: string;
|
|
10
11
|
description?: string;
|
|
11
12
|
}>): Promise<string | undefined>;
|
|
12
|
-
export declare function selectAddOns(framework: Framework, mode: string, type: string, message: string, forcedAddOns?: Array<string>, allowMultiple?: boolean): Promise<Array<string>>;
|
|
13
|
+
export declare function selectAddOns(framework: Framework, mode: string, type: string, message: string, forcedAddOns?: Array<string>, allowMultiple?: boolean, bundlerId?: string): Promise<Array<string>>;
|
|
13
14
|
export declare function selectGit(): Promise<boolean>;
|
|
14
15
|
export declare function selectExamples(): Promise<boolean>;
|
|
15
16
|
export declare function selectToolchain(framework: Framework, toolchain?: string | false): Promise<string | undefined>;
|
package/dist/ui-prompts.js
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
import { cancel, confirm, isCancel, multiselect, note, password, select, text, } from '@clack/prompts';
|
|
2
|
-
import { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getAllAddOns, } from '@tanstack/create';
|
|
2
|
+
import { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getAllAddOns, getBundlers, getDefaultBundler, resolveBundler, } from '@tanstack/create';
|
|
3
3
|
import { isCurrentDirectoryProjectNameInput, validateProjectName, } from './utils.js';
|
|
4
4
|
import { orderAddOnsForPartnerPlacement } from './partner-placement.js';
|
|
5
|
+
export async function selectBundler(framework, bundlerId) {
|
|
6
|
+
if (bundlerId) {
|
|
7
|
+
return resolveBundler(framework, bundlerId).id;
|
|
8
|
+
}
|
|
9
|
+
const bundlers = getBundlers(framework);
|
|
10
|
+
if (bundlers.length === 1) {
|
|
11
|
+
return bundlers[0].id;
|
|
12
|
+
}
|
|
13
|
+
const selected = await select({
|
|
14
|
+
message: 'Select build tool:',
|
|
15
|
+
options: bundlers.map((bundler) => ({
|
|
16
|
+
value: bundler.id,
|
|
17
|
+
label: bundler.name,
|
|
18
|
+
hint: bundler.description,
|
|
19
|
+
})),
|
|
20
|
+
initialValue: getDefaultBundler(framework).id,
|
|
21
|
+
});
|
|
22
|
+
if (isCancel(selected)) {
|
|
23
|
+
cancel('Operation cancelled.');
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
return resolveBundler(framework, selected).id;
|
|
27
|
+
}
|
|
5
28
|
export async function selectFramework(frameworks, defaultFrameworkId) {
|
|
6
29
|
const initialValue = (defaultFrameworkId &&
|
|
7
30
|
frameworks.find((f) => f.id.toLowerCase() === defaultFrameworkId.toLowerCase())?.id) ||
|
|
@@ -95,8 +118,8 @@ export async function selectTemplate(templates) {
|
|
|
95
118
|
}
|
|
96
119
|
return selected;
|
|
97
120
|
}
|
|
98
|
-
export async function selectAddOns(framework, mode, type, message, forcedAddOns = [], allowMultiple = true) {
|
|
99
|
-
const allAddOns = await getAllAddOns(framework, mode);
|
|
121
|
+
export async function selectAddOns(framework, mode, type, message, forcedAddOns = [], allowMultiple = true, bundlerId) {
|
|
122
|
+
const allAddOns = await getAllAddOns(framework, mode, bundlerId);
|
|
100
123
|
const addOns = allAddOns.filter((addOn) => addOn.type === type);
|
|
101
124
|
if (addOns.length === 0) {
|
|
102
125
|
return [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0",
|
|
4
4
|
"description": "TanStack CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"tempy": "^3.1.0",
|
|
45
45
|
"validate-npm-package-name": "^7.0.0",
|
|
46
46
|
"zod": "^3.24.2",
|
|
47
|
-
"@tanstack/create": "0.
|
|
47
|
+
"@tanstack/create": "0.71.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@playwright/test": "^1.58.2",
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-app-scaffold
|
|
3
3
|
description: >
|
|
4
|
-
Scaffold a TanStack app with tanstack create using --framework, --template,
|
|
4
|
+
Scaffold a TanStack app with tanstack create using --framework, --build-tool, --template,
|
|
5
5
|
--toolchain, --deployment, --add-ons, --blank, and --router-only. Covers flag
|
|
6
6
|
compatibility, non-interactive defaults, and intent-preserving command
|
|
7
7
|
construction.
|
|
8
8
|
metadata:
|
|
9
9
|
type: core
|
|
10
10
|
library: tanstack-cli
|
|
11
|
-
library_version: "0.
|
|
11
|
+
library_version: "0.71.0"
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# Create App Scaffold
|
|
@@ -28,6 +28,19 @@ npx @tanstack/cli create acme-web \
|
|
|
28
28
|
|
|
29
29
|
## Core Patterns
|
|
30
30
|
|
|
31
|
+
### Choose Vite or Rsbuild explicitly
|
|
32
|
+
|
|
33
|
+
Vite is the default. Use Rsbuild for React or Solid when the requested project
|
|
34
|
+
fits its initial compatibility surface.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @tanstack/cli create acme-web \
|
|
38
|
+
--framework react \
|
|
39
|
+
--build-tool rsbuild \
|
|
40
|
+
--toolchain biome \
|
|
41
|
+
-y
|
|
42
|
+
```
|
|
43
|
+
|
|
31
44
|
### Build a deterministic non-interactive scaffold
|
|
32
45
|
|
|
33
46
|
```bash
|
|
@@ -162,5 +175,6 @@ See also: query-docs-library-metadata/SKILL.md § Common Mistakes
|
|
|
162
175
|
|
|
163
176
|
- [Create flag compatibility matrix](references/create-flag-compatibility-matrix.md)
|
|
164
177
|
- [Framework adapter options](references/framework-adapters.md)
|
|
178
|
+
- [Build tool options](references/bundlers.md)
|
|
165
179
|
- [Deployment provider options](references/deployment-providers.md)
|
|
166
180
|
- [Toolchain options](references/toolchains.md)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Build Tool Options
|
|
2
|
+
|
|
3
|
+
Targets `@tanstack/cli` v0.71.0.
|
|
4
|
+
|
|
5
|
+
## Supported values
|
|
6
|
+
|
|
7
|
+
- `vite` (default)
|
|
8
|
+
- `rsbuild`
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx @tanstack/cli create app --framework react --build-tool vite -y
|
|
14
|
+
npx @tanstack/cli create app --framework solid --build-tool rsbuild -y
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Rsbuild supports full TanStack Start and router-only projects, including the
|
|
18
|
+
standard and `--blank` presets, built-in example pages, Tailwind, ESLint, and
|
|
19
|
+
Biome. It does not currently support templates, deployment adapters, or
|
|
20
|
+
catalog business/example add-ons. `tanstack add` is limited to ESLint/Biome in
|
|
21
|
+
Rsbuild projects.
|
|
22
|
+
|
|
23
|
+
Use the build-tool-aware catalog view before constructing an Rsbuild command:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @tanstack/cli create --list-add-ons --build-tool rsbuild --json
|
|
27
|
+
```
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Create Flag Compatibility Matrix
|
|
2
2
|
|
|
3
|
-
Targets `@tanstack/cli` v0.
|
|
3
|
+
Targets `@tanstack/cli` v0.71.0.
|
|
4
4
|
|
|
5
5
|
## Compatibility
|
|
6
6
|
|
|
7
7
|
| Flag | Works with normal create | Works with `--router-only` | Notes |
|
|
8
8
|
|---|---|---|---|
|
|
9
9
|
| `--framework` | yes | yes | Framework is still honored in both modes. |
|
|
10
|
+
| `--build-tool` | yes | yes | `vite` is the default; `rsbuild` supports React and Solid. |
|
|
10
11
|
| `--toolchain` | yes | yes | Toolchain selection remains available. |
|
|
11
12
|
| `--add-ons` | yes | no | Ignored in router-only mode. |
|
|
12
13
|
| `--deployment` | yes | no | Ignored in router-only mode. |
|
|
@@ -15,14 +16,18 @@ Targets `@tanstack/cli` v0.70.0.
|
|
|
15
16
|
| `--blank` | yes | yes | Omits starter UI, examples, Tailwind, devtools, and test tooling unless an explicit integration requires them. Cannot be combined with a template, `--examples`, or `--tailwind`. |
|
|
16
17
|
| `--tailwind` / `--no-tailwind` | deprecated/ignored | deprecated/ignored | Standard scaffolds enable Tailwind; use `--blank` for the supported minimal preset. |
|
|
17
18
|
|
|
19
|
+
With `--build-tool rsbuild`, only toolchain catalog entries are compatible.
|
|
20
|
+
Templates, deployments, and business/example add-ons are rejected. Built-in
|
|
21
|
+
demo pages controlled by `--examples` remain available.
|
|
22
|
+
|
|
18
23
|
Source: `packages/cli/src/command-line.ts:337`
|
|
19
24
|
|
|
20
25
|
## Recommended command construction order
|
|
21
26
|
|
|
22
|
-
1. Choose
|
|
23
|
-
2.
|
|
24
|
-
3.
|
|
25
|
-
4.
|
|
27
|
+
1. Choose framework and build tool.
|
|
28
|
+
2. Choose mode (`--router-only` or full scaffold).
|
|
29
|
+
3. If using Vite full scaffold, resolve add-ons, template, and deployment.
|
|
30
|
+
4. Add the toolchain and use `-y` only after flags are final.
|
|
26
31
|
|
|
27
32
|
## Safe presets
|
|
28
33
|
|
|
@@ -35,4 +40,7 @@ npx @tanstack/cli create app --blank --framework react --deployment cloudflare -
|
|
|
35
40
|
|
|
36
41
|
# Router-only preset
|
|
37
42
|
npx @tanstack/cli create app --router-only --framework react --toolchain biome -y
|
|
43
|
+
|
|
44
|
+
# Rsbuild preset
|
|
45
|
+
npx @tanstack/cli create app --framework solid --build-tool rsbuild --toolchain biome -y
|
|
38
46
|
```
|