Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "website",
"version": "0.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "test-monorepo",
"version": "0.0.0",
"private": true,
"packageManager": "pnpm@10.12.1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
packages:
- apps/*
- packages/*
- tools/*
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "helper",
"version": "0.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
> cd apps/website && vp create --no-interactive vite:generator # from workspace subdir
> test -f tools/vite-plus-generator/package.json && echo 'Created at tools/vite-plus-generator' || echo 'NOT at tools/'
Created at tools/vite-plus-generator

> test ! -f apps/website/tools/vite-plus-generator/package.json && echo 'Not in apps/website/' || echo 'BUG: in apps/website/'
Not in apps/website/

> cd apps && vp create --no-interactive vite:application # from workspace parent dir
> test -f apps/vite-plus-application/package.json && echo 'Created at apps/vite-plus-application' || echo 'NOT at apps/'
Created at apps/vite-plus-application

> cd scripts/helper && vp create --no-interactive vite:library # from non-workspace dir
> test -f packages/vite-plus-library/package.json && echo 'Created at packages/vite-plus-library' || echo 'NOT at packages/'
Created at packages/vite-plus-library

> test ! -f scripts/helper/packages/vite-plus-library/package.json && echo 'Not in scripts/helper/' || echo 'BUG: in scripts/helper/'
Not in scripts/helper/

> cd scripts/helper && vp create --no-interactive vite:application --directory apps/custom-app # --directory from non-workspace dir
> test -f apps/custom-app/package.json && echo 'Created at apps/custom-app with --directory' || echo 'NOT at apps/custom-app'
Created at apps/custom-app with --directory
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"commands": [
{
"command": "cd apps/website && vp create --no-interactive vite:generator # from workspace subdir",
"ignoreOutput": true
},
"test -f tools/vite-plus-generator/package.json && echo 'Created at tools/vite-plus-generator' || echo 'NOT at tools/'",
"test ! -f apps/website/tools/vite-plus-generator/package.json && echo 'Not in apps/website/' || echo 'BUG: in apps/website/'",

{
"command": "cd apps && vp create --no-interactive vite:application # from workspace parent dir",
"ignoreOutput": true
},
"test -f apps/vite-plus-application/package.json && echo 'Created at apps/vite-plus-application' || echo 'NOT at apps/'",

{
"command": "cd scripts/helper && vp create --no-interactive vite:library # from non-workspace dir",
"ignoreOutput": true
},
"test -f packages/vite-plus-library/package.json && echo 'Created at packages/vite-plus-library' || echo 'NOT at packages/'",
"test ! -f scripts/helper/packages/vite-plus-library/package.json && echo 'Not in scripts/helper/' || echo 'BUG: in scripts/helper/'",

{
"command": "cd scripts/helper && vp create --no-interactive vite:application --directory apps/custom-app # --directory from non-workspace dir",
"ignoreOutput": true
},
"test -f apps/custom-app/package.json && echo 'Created at apps/custom-app with --directory' || echo 'NOT at apps/custom-app'"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "parent-project",
"version": "0.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
> cd scripts && vp create --no-interactive vite:application # from non-monorepo subdir
> test -f scripts/vite-plus-application/package.json && echo 'Created at scripts/vite-plus-application' || echo 'NOT at scripts/'
Created at scripts/vite-plus-application

> test ! -f vite-plus-application/package.json && echo 'Not at parent root' || echo 'BUG: created at parent root'
Not at parent root
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"commands": [
{
"command": "cd scripts && vp create --no-interactive vite:application # from non-monorepo subdir",
"ignoreOutput": true
},
"test -f scripts/vite-plus-application/package.json && echo 'Created at scripts/vite-plus-application' || echo 'NOT at scripts/'",
"test ! -f vite-plus-application/package.json && echo 'Not at parent root' || echo 'BUG: created at parent root'"
]
}
76 changes: 58 additions & 18 deletions packages/cli/src/create/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
selectAgentTargetPath,
writeAgentInstructions,
} from '../utils/agent.js';
import { displayRelative } from '../utils/path.js';
import {
defaultInteractive,
downloadPackageManager,
Expand Down Expand Up @@ -184,9 +185,28 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
packageName = formatted.packageName;
}

const workspaceInfoOptional = await detectWorkspace(process.cwd());
const cwd = process.cwd();
const workspaceInfoOptional = await detectWorkspace(cwd);
const isMonorepo = workspaceInfoOptional.isMonorepo;

// For non-monorepo, always use cwd as rootDir.
// detectWorkspace walks up to find the nearest package.json, but for `vp create`
// in standalone mode, the project should be created relative to where the user is.
if (!isMonorepo) {
workspaceInfoOptional.rootDir = cwd;
}
const cwdRelativeToRoot =
isMonorepo && workspaceInfoOptional.rootDir !== cwd
? displayRelative(cwd, workspaceInfoOptional.rootDir)
: '';
const isInSubdirectory = cwdRelativeToRoot !== '';
const cwdUnderParentDir = isInSubdirectory
? workspaceInfoOptional.parentDirs.some(
(dir) => cwdRelativeToRoot === dir || cwdRelativeToRoot.startsWith(`${dir}/`),
)
: true;
const shouldOfferCwdOption = isInSubdirectory && !cwdUnderParentDir;

// Interactive mode: prompt for template if not provided
let selectedTemplateName = templateName as string;
let selectedTemplateArgs = [...templateArgs];
Expand Down Expand Up @@ -287,27 +307,44 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
cancelAndExit('Cannot create a monorepo inside an existing monorepo', 1);
}

if (isInSubdirectory) {
prompts.log.info(`Detected monorepo root at ${accent(workspaceInfoOptional.rootDir)}`);
}

if (isMonorepo && options.interactive && !targetDir) {
let parentDir: string | undefined;
if (workspaceInfoOptional.parentDirs.length > 0) {
const defaultParentDir =
inferParentDir(selectedTemplateName, workspaceInfoOptional) ??
workspaceInfoOptional.parentDirs[0];
const hasParentDirs = workspaceInfoOptional.parentDirs.length > 0;

if (hasParentDirs || isInSubdirectory) {
const dirOptions: { label: string; value: string; hint: string }[] =
workspaceInfoOptional.parentDirs.map((dir) => ({
label: `${dir}/`,
value: dir,
hint: '',
}));

if (shouldOfferCwdOption) {
dirOptions.push({
label: `${cwdRelativeToRoot}/ (current directory)`,
value: cwdRelativeToRoot,
hint: '',
});
}

dirOptions.push({
label: 'other directory',
value: 'other',
hint: 'Enter a custom target directory',
});

const defaultParentDir = shouldOfferCwdOption
? cwdRelativeToRoot
: (inferParentDir(selectedTemplateName, workspaceInfoOptional) ??
workspaceInfoOptional.parentDirs[0]);

const selected = await prompts.select({
message: 'Where should the new package be added to the monorepo:',
options: workspaceInfoOptional.parentDirs
.map((dir) => ({
label: `${dir}/`,
value: dir,
hint: ``,
}))
.concat([
{
label: 'other',
value: 'other',
hint: 'Enter a custom target directory',
},
]),
options: dirOptions,
initialValue: defaultParentDir,
});

Expand Down Expand Up @@ -339,6 +376,9 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
selectedParentDir = parentDir;
}
if (isMonorepo && !options.interactive && !targetDir) {
if (isInSubdirectory) {
prompts.log.info(`Use ${accent('--directory')} to specify a different target location.`);
}
const inferredParentDir =
inferParentDir(selectedTemplateName, workspaceInfoOptional) ??
workspaceInfoOptional.parentDirs[0];
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/create/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function promptPackageNameAndTargetDir(
placeholder: defaultPackageName,
defaultValue: defaultPackageName,
validate: (value) => {
if (value != null && value.length === 0) {
if (value == null || value.length === 0) {
return;
}

Expand Down
Loading