From 1673f3daa0147b2afa546648ec913837402fec21 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Fri, 26 Aug 2022 22:20:43 +0800 Subject: [PATCH] feat(create-vite): add support for custom init commands (`create-vue`, Nuxt, and SvelteKit) (#9406) --- packages/create-vite/index.js | 73 ++++++++++++++++++++++++++++--- packages/create-vite/package.json | 1 + pnpm-lock.yaml | 8 +--- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/packages/create-vite/index.js b/packages/create-vite/index.js index 6ba1214a1829bb..d602eea2b3e57a 100755 --- a/packages/create-vite/index.js +++ b/packages/create-vite/index.js @@ -4,12 +4,14 @@ import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' +import spawn from 'cross-spawn' import minimist from 'minimist' import prompts from 'prompts' import { blue, cyan, green, + lightGreen, lightRed, magenta, red, @@ -25,6 +27,7 @@ const cwd = process.cwd() const FRAMEWORKS = [ { name: 'vanilla', + display: 'Vanilla', color: yellow, variants: [ { @@ -41,6 +44,7 @@ const FRAMEWORKS = [ }, { name: 'vue', + display: 'Vue', color: green, variants: [ { @@ -52,11 +56,24 @@ const FRAMEWORKS = [ name: 'vue-ts', display: 'TypeScript', color: blue + }, + { + name: 'custom-create-vue', + display: 'Customize with create-vue', + color: green, + customCommand: 'npm create vue@latest TARGET_DIR' + }, + { + name: 'custom-nuxt', + display: 'Nuxt', + color: lightGreen, + customCommand: 'npm exec nuxi init TARGET_DIR' } ] }, { name: 'react', + display: 'React', color: cyan, variants: [ { @@ -73,6 +90,7 @@ const FRAMEWORKS = [ }, { name: 'preact', + display: 'Preact', color: magenta, variants: [ { @@ -89,6 +107,7 @@ const FRAMEWORKS = [ }, { name: 'lit', + display: 'Lit', color: lightRed, variants: [ { @@ -105,6 +124,7 @@ const FRAMEWORKS = [ }, { name: 'svelte', + display: 'Svelte', color: red, variants: [ { @@ -116,6 +136,12 @@ const FRAMEWORKS = [ name: 'svelte-ts', display: 'TypeScript', color: blue + }, + { + name: 'custom-svelte-kit', + display: 'SvelteKit', + color: red, + customCommand: 'npm create svelte@latest TARGET_DIR' } ] } @@ -191,7 +217,7 @@ async function init() { choices: FRAMEWORKS.map((framework) => { const frameworkColor = framework.color return { - title: frameworkColor(framework.name), + title: frameworkColor(framework.display || framework.name), value: framework } }) @@ -206,7 +232,7 @@ async function init() { framework.variants.map((variant) => { const variantColor = variant.color return { - title: variantColor(variant.name), + title: variantColor(variant.display || variant.name), value: variant.name } }) @@ -237,6 +263,46 @@ async function init() { // determine template template = variant || framework || template + const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent) + const pkgManager = pkgInfo ? pkgInfo.name : 'npm' + const isYarn1 = pkgManager === 'yarn' && pkgInfo?.version.startsWith('1.') + + if (template.startsWith('custom-')) { + const getCustomCommand = (name) => { + for (const f of FRAMEWORKS) { + for (const v of f.variants || []) { + if (v.name === name) { + return v.customCommand + } + } + } + } + const customCommand = getCustomCommand(template) + const fullCustomCommand = customCommand + .replace('TARGET_DIR', targetDir) + .replace(/^npm create/, `${pkgManager} create`) + // Only Yarn 1.x doesn't support `@version` in the `create` command + .replace('@latest', () => (isYarn1 ? '' : '@latest')) + .replace(/^npm exec/, () => { + // Prefer `pnpm dlx` or `yarn dlx` + if (pkgManager === 'pnpm') { + return 'pnpm dlx' + } + if (pkgManager === 'yarn' && !isYarn1) { + return 'yarn dlx' + } + // Use `npm exec` in all other cases, + // including Yarn 1.x and other custom npm clients. + return 'npm exec' + }) + + const [command, ...args] = fullCustomCommand.split(' ') + const { status } = spawn.sync(command, args, { + stdio: 'inherit' + }) + process.exit(status ?? 0) + } + console.log(`\nScaffolding project in ${root}...`) const templateDir = path.resolve( @@ -269,9 +335,6 @@ async function init() { write('package.json', JSON.stringify(pkg, null, 2)) - const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent) - const pkgManager = pkgInfo ? pkgInfo.name : 'npm' - console.log(`\nDone. Now run:\n`) if (root !== cwd) { console.log(` cd ${path.relative(cwd, root)}`) diff --git a/packages/create-vite/package.json b/packages/create-vite/package.json index 7c47e2601ab124..a52fa837d977ab 100644 --- a/packages/create-vite/package.json +++ b/packages/create-vite/package.json @@ -26,6 +26,7 @@ }, "homepage": "https://github.com/vitejs/vite/tree/main/packages/create-vite#readme", "dependencies": { + "cross-spawn": "^7.0.3", "kolorist": "^1.5.1", "minimist": "^1.2.6", "prompts": "^2.4.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d00347c90e12fd..8774b7f10651ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -118,10 +118,12 @@ importers: packages/create-vite: specifiers: + cross-spawn: ^7.0.3 kolorist: ^1.5.1 minimist: ^1.2.6 prompts: ^2.4.2 dependencies: + cross-spawn: 7.0.3 kolorist: 1.5.1 minimist: 1.2.6 prompts: 2.4.2 @@ -3979,7 +3981,6 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true /crosspath/0.0.8: resolution: {integrity: sha512-IKlS3MpP0fhJ50M6ltyLO7Q4NzwfhafpmolMH0EDKyyaY81HutF2mH4hLpCdm3fKZ/TSTW5qPIdTy62YnefEyQ==} @@ -6114,7 +6115,6 @@ packages: /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /jiti/1.14.0: resolution: {integrity: sha512-4IwstlaKQc9vCTC+qUXLM1hajy2ImiL9KnLvVYiaHOtS/v3wRjhLlGl121AmgDgx/O43uKmxownJghS5XMya2A==} @@ -7116,7 +7116,6 @@ packages: /path-key/3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: true /path-key/4.0.0: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} @@ -8057,7 +8056,6 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: true /shebang-regex/1.0.0: resolution: {integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=} @@ -8067,7 +8065,6 @@ packages: /shebang-regex/3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: true /shell-exec/1.0.2: resolution: {integrity: sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==} @@ -9077,7 +9074,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: true /wide-align/1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}