You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(create): support @org default templates via createConfig.templates
Extend `vp create` so an organization can expose a curated set of
templates through a single entry point: `vp create @your-org` opens an
interactive picker over the org's manifest, `vp create @your-org:web`
runs a specific entry directly, and `create.defaultTemplate` in
`vite.config.ts` makes an org the default for bare `vp create`.
The manifest lives in `@your-org/create`'s `package.json` under
`createConfig.templates` (tool-neutral key, parallel to `publishConfig`).
Each entry carries `{ name, description, template, monorepo? }`. The
`template` field accepts npm specifiers, GitHub URLs, `vite:*`
builtins, local workspace packages, or relative paths
(`./templates/foo`) that resolve against the extracted `@org/create`
tarball — letting an org ship N templates from one package.
Highlights:
- Spec syntax: `@scope` (picker), `@scope:name` (direct entry),
`@scope@version` / `@scope:name@version` (pinned). The colon
separator avoids collision with real `@org/package` npm specifiers
and the existing `@org/create-name` shorthand.
- Bundled subdirectory templates: tarball downloaded once over HTTPS,
SHA-512 integrity-verified, extracted via nanotar to
`$VP_HOME/tmp/create-org/<host>/<scope>/create/<version>/`. The
`<host>` segment (sanitized for Windows-illegal characters) keeps
cross-registry resolutions from sharing a slot. Extracts atomically
via `<dir>.tmp-…` staging + rename; sibling staging older than 24h
is pruned at the start of each fresh extract.
- `.npmrc` registry/auth: walk-up parser that layers user → project
→ env, honoring `@scope:registry=...` overrides and resolving
credentials via `_authToken` / `_auth` / username:_password.
Retries with auth only on 401/403 — public registries never see a
token.
- `monorepo: true` entries are filtered from the picker inside an
existing monorepo and rejected on direct selection there. When a
bundled monorepo entry scaffolds successfully outside one, the
generated `vite.config.ts` gains
`create: { defaultTemplate: '@scope' }` so a bare `vp create` from
inside the new workspace opens the same org's picker.
- Builtin escape hatch: the org picker always appends a "Vite+
built-in templates" entry routing to the standard
`getInitialTemplateOptions` flow.
- `--no-interactive` prints the manifest as a fixed-column table so
agents and CI scripts can recover available names.
- Git-init prompt unified across the `vite:monorepo` and
bundled-`@org`-monorepo paths in `bin.ts`. After `git init` succeeds,
`ensureGitignoreNodeModules` writes / appends `node_modules` so
bundled templates without their own `.gitignore` don't track
installed deps on the first commit.
- Schema rules: names are kebab-case, must be unique, and the `__vp_`
prefix is reserved for internal sentinels (e.g. the picker's
per-call escape-hatch UUID). Bundled paths that escape the package
root are rejected at validation time, before any tarball fetch.
- Tar entries preserve their stored mode (so `gradlew` and friends
stay executable); setuid/setgid/sticky bits are stripped.
Net change: 4132 insertions across 70 files. Ships
`packages/cli/src/create/org-{manifest,resolve,picker,tarball}.ts`,
`packages/cli/src/create/templates/bundled.ts`, the new
`packages/cli/src/utils/npm-config.ts` module, the
`UserConfig.create.defaultTemplate` augmentation, the
`injectCreateDefaultTemplate` and `ensureGitignoreNodeModules`
helpers, plus the integration in `bin.ts` and the `discoverTemplate`
manifest branch.
Tests: 12 new unit-test files (~230 specs) covering schema parsing,
version pinning, scope/auth resolution, picker filtering + escape
hatch, tarball cache key + extract atomicity, gitignore edge cases,
and the migrator helper. Eight snap-test fixtures under
`packages/cli/snap-tests/create-org-*` exercise the end-to-end flow
through a shared mock npm registry, including the new
`create-org-bundled-monorepo` case that verifies
`create.defaultTemplate` injection and `git init` for bundled
monorepo templates.
Docs: new `docs/guide/create.md § Organization Templates`, new
`docs/config/create.md` reference, README pointer to viteplus.dev,
and a fully-revised RFC at `rfcs/create-org-default-templates.md`
documenting the design as shipped.
`vp create` reads the `create` block in `vite.config.ts` to set per-repo defaults. See the [Creating a Project guide](/guide/create#organization-templates) for the full `@org` template workflow.
4
+
5
+
## `create.defaultTemplate`
6
+
7
+
When `vp create` is invoked with no `TEMPLATE` argument, Vite+ uses this value as if the user had typed it. Typically set to an npm scope whose `@scope/create` package publishes a `createConfig.templates` manifest — so bare `vp create` drops into the org picker.
8
+
9
+
```ts
10
+
import { defineConfig } from'vite-plus';
11
+
12
+
exportdefaultdefineConfig({
13
+
create: {
14
+
defaultTemplate: '@your-org',
15
+
},
16
+
});
17
+
```
18
+
19
+
Any value accepted by `vp create` as a first argument works here — `@your-org` for an org picker, `@your-org:web` for a direct manifest entry, `vite:application` for a built-in, etc.
20
+
21
+
## Precedence
22
+
23
+
CLI argument > `create.defaultTemplate` > the standard built-in picker.
24
+
25
+
Explicit specifiers always win, so scripts and CI can bypass the configured default:
26
+
27
+
```bash
28
+
# Uses create.defaultTemplate
29
+
vp create
30
+
31
+
# Explicitly ignores the default
32
+
vp create vite:library
33
+
```
34
+
35
+
The org picker also appends a trailing "Vite+ built-in templates" entry — selecting it routes to the `vite:monorepo` / `vite:application` / `vite:library` / `vite:generator` flow, so built-ins stay reachable interactively even when a default is configured.
Copy file name to clipboardExpand all lines: docs/guide/create.md
+148-1Lines changed: 148 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,7 +35,7 @@ Vite+ ships with these built-in templates:
35
35
36
36
- Use shorthand templates like `vite`, `@tanstack/start`, `svelte`, `next-app`, `nuxt`, `react-router`, and `vue`
37
37
- Use full package names like `create-vite` or `create-next-app`
38
-
- Use local templates such as `./tools/create-ui-component` or `@acme/generator-*`
38
+
- Use local templates such as `./tools/create-ui-component` or `@your-org/generator-*`
39
39
- Use remote templates such as `github:user/repo` or `https://github.com/user/template-repo`
40
40
41
41
Run `vp create --list` to see the built-in templates and the common shorthand templates Vite+ recognizes.
@@ -86,3 +86,150 @@ vp create create-next-app
86
86
vp create github:user/repo
87
87
vp create https://github.com/user/template-repo
88
88
```
89
+
90
+
## Organization Templates
91
+
92
+
An organization can publish a curated set of templates under a single npm scope by shipping an `@org/create` package whose `package.json` carries a `createConfig.templates` manifest. Once published, `vp create @org` opens an interactive picker over those templates.
93
+
94
+
### Pick from an org
95
+
96
+
```bash
97
+
# Open an interactive picker over @your-org/create's manifest
98
+
vp create @your-org
99
+
100
+
# Run a specific manifest entry directly
101
+
vp create @your-org:web
102
+
103
+
# Pin to an exact version or a dist-tag
104
+
vp create @your-org@1.2.3
105
+
vp create @your-org:web@next
106
+
107
+
# Set the org as the default for a repo (see create.defaultTemplate config)
108
+
vp create
109
+
```
110
+
111
+
Behind the scenes, `vp create @org` maps to `@org/create` (the existing npm `create-*` convention). If that package has no `createConfig.templates` field, Vite+ falls back to running the package normally — so adopting the manifest is zero-risk for orgs that already publish `@org/create`.
112
+
113
+
Private registries work automatically: Vite+ reads `.npmrc` files from the project root and `~/`, honoring `@your-org:registry=...` scope mappings and `//host/:_authToken=...` credentials.
114
+
115
+
### Authoring `@org/create`
116
+
117
+
There are two common layouts. Pick the one that matches the org's template count and release cadence.
118
+
119
+
**Bundled (recommended for most orgs).** All templates live as subdirectories of `@org/create` itself. Manifest entries use relative `./path` values. One repo, one publish, one versioning story — the same pattern used by `create-vite` and `create-next-app`.
The two layouts can be mixed — a manifest can point most entries at external packages and keep a few as bundled subdirectories.
141
+
142
+
Optionally, provide a `bin` script so `npm create @org` (the legacy path) keeps working for non-Vite+ users. `vp create @org` reads the manifest directly and never runs the `bin`.
143
+
144
+
### Manifest schema
145
+
146
+
The manifest lives at `createConfig.templates` in `@org/create`'s `package.json`:
|`name`| yes | Kebab-case identifier. Used by `vp create @org:<name>` for direct selection. Must be unique within the array. |
180
+
|`description`| yes | One-line description shown in the picker. |
181
+
|`template`| yes | An npm specifier (`@org/template-foo`, optionally `@version`), a GitHub URL (`github:user/repo`), a `vite:*` builtin, a local workspace package name, or a relative path (`./templates/foo`) that resolves against the `@org/create` root. |
182
+
|`monorepo`| no | If `true`, marks this entry as a monorepo-creating template. Hidden from the picker when `vp create` runs inside an existing monorepo, mirroring the built-in `vite:monorepo` filter. |
183
+
184
+
An invalid manifest is a hard error, not a silent fall-through — a maintainer who shipped a manifest should hear about the offending field, e.g. `@your-org/create: createConfig.templates[2].template must be a non-empty string`.
185
+
186
+
### Bundled subdirectory templates
187
+
188
+
Relative `./...` paths resolve against the enclosing `@org/create` package root — **not** the user's cwd. The referenced directory is copied verbatim into the target project (no template-engine processing). Paths that escape the package root are rejected.
189
+
190
+
### Make the org the default in a repo
191
+
192
+
Commit this in `vite.config.ts` at the project root:
193
+
194
+
```ts
195
+
import { defineConfig } from'vite-plus';
196
+
197
+
exportdefaultdefineConfig({
198
+
create: { defaultTemplate: '@your-org' },
199
+
});
200
+
```
201
+
202
+
Now `vp create` (with no argument) drops straight into the `@your-org` picker. See [`create.defaultTemplate`](/config/create) for details.
203
+
204
+
The picker always appends a trailing **Vite+ built-in templates** entry so `vite:monorepo` / `vite:application` / `vite:library` / `vite:generator` stay reachable from the picker — selecting it routes to the standard built-in flow. For scripts and CI, explicit specifiers (`vp create vite:library`) bypass the configured default.
205
+
206
+
### Non-interactive inspection
207
+
208
+
`vp create @org --no-interactive` prints the manifest as a table and exits 1:
209
+
210
+
```
211
+
A template name is required when running `vp create @your-org` in non-interactive mode.
212
+
213
+
Available templates in @your-org/create:
214
+
215
+
NAME DESCRIPTION TEMPLATE
216
+
web Web app template (Vite + React) @your-org/template-web
0 commit comments