diff --git a/.changeset/ten-kings-smash.md b/.changeset/ten-kings-smash.md new file mode 100644 index 000000000000..8dd84325711e --- /dev/null +++ b/.changeset/ten-kings-smash.md @@ -0,0 +1,5 @@ +--- +'create-astro': minor +--- + +Improve startup performance by removing dependencies, lazily initializing async contextual values diff --git a/packages/create-astro/create-astro.mjs b/packages/create-astro/create-astro.mjs index b7489a6b173d..f9df779d871c 100755 --- a/packages/create-astro/create-astro.mjs +++ b/packages/create-astro/create-astro.mjs @@ -4,7 +4,7 @@ const currentVersion = process.versions.node; const requiredMajorVersion = parseInt(currentVersion.split('.')[0], 10); -const minimumMajorVersion = 14; +const minimumMajorVersion = 18; if (requiredMajorVersion < minimumMajorVersion) { console.error(`Node.js v${currentVersion} is out of date and unsupported!`); diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json index 0eb08cdc755c..b9641b1d5b20 100644 --- a/packages/create-astro/package.json +++ b/packages/create-astro/package.json @@ -31,14 +31,10 @@ "//a": "MOST PACKAGES SHOULD GO IN DEV_DEPENDENCIES! THEY WILL BE BUNDLED.", "//b": "DEPENDENCIES IS FOR UNBUNDLED PACKAGES", "dependencies": { - "@astrojs/cli-kit": "^0.2.3", - "execa": "^8.0.1", - "giget": "1.1.2", - "node-fetch-native": "^1.4.0", - "which-pm-runs": "^1.1.0" + "@astrojs/cli-kit": "^0.2.5", + "giget": "1.1.2" }, "devDependencies": { - "@types/which-pm-runs": "^1.0.0", "arg": "^5.0.2", "astro-scripts": "workspace:*", "chai": "^4.3.7", diff --git a/packages/create-astro/src/actions/context.ts b/packages/create-astro/src/actions/context.ts index c91a0caae48c..ae720a1b3cd6 100644 --- a/packages/create-astro/src/actions/context.ts +++ b/packages/create-astro/src/actions/context.ts @@ -1,7 +1,7 @@ import { prompt } from '@astrojs/cli-kit'; +import { random } from '@astrojs/cli-kit/utils'; import arg from 'arg'; import os from 'node:os'; -import detectPackageManager from 'which-pm-runs'; import { getName, getVersion } from '../messages.js'; @@ -10,8 +10,8 @@ export interface Context { prompt: typeof prompt; cwd: string; packageManager: string; - username: string; - version: string; + username: Promise; + version: Promise; skipHouston: boolean; fancy?: boolean; dryRun?: boolean; @@ -25,6 +25,7 @@ export interface Context { stdin?: typeof process.stdin; stdout?: typeof process.stdout; exit(code: number): never; + hat?: string; } export async function getContext(argv: string[]): Promise { @@ -51,8 +52,7 @@ export async function getContext(argv: string[]): Promise { { argv, permissive: true } ); - const packageManager = detectPackageManager()?.name ?? 'npm'; - const [username, version] = await Promise.all([getName(), getVersion()]); + const packageManager = detectPackageManager() ?? 'npm'; let cwd = flags['_'][0]; let { '--help': help = false, @@ -86,14 +86,15 @@ export async function getContext(argv: string[]): Promise { help, prompt, packageManager, - username, - version, + username: getName(), + version: getVersion(packageManager), skipHouston, fancy, dryRun, projectName, template, ref: ref ?? 'latest', + hat: fancy ? random(['๐ŸŽฉ', '๐ŸŽฉ', '๐ŸŽฉ', '๐ŸŽฉ', '๐ŸŽ“', '๐Ÿ‘‘', '๐Ÿงข', '๐Ÿฆ']) : undefined, yes, install: install ?? (noInstall ? false : undefined), git: git ?? (noGit ? false : undefined), @@ -105,3 +106,10 @@ export async function getContext(argv: string[]): Promise { }; return context; } + +function detectPackageManager() { + if (!process.env.npm_config_user_agent) return; + const specifier = process.env.npm_config_user_agent.split(' ')[0]; + const name = specifier.substring(0, specifier.lastIndexOf('/')); + return name === 'npminstall' ? 'cnpm' : name; +} diff --git a/packages/create-astro/src/actions/intro.ts b/packages/create-astro/src/actions/intro.ts index a96c8e4346e6..9b2621ed85d9 100644 --- a/packages/create-astro/src/actions/intro.ts +++ b/packages/create-astro/src/actions/intro.ts @@ -4,24 +4,22 @@ import { color, label } from '@astrojs/cli-kit'; import { random } from '@astrojs/cli-kit/utils'; import { banner, say, welcome } from '../messages.js'; -export async function intro(ctx: Pick) { +export async function intro(ctx: Pick) { + banner(); + if (!ctx.skipHouston) { - const hat = ctx.fancy ? random(['๐ŸŽฉ', '๐ŸŽฉ', '๐Ÿ‘‘', '๐Ÿงข', '๐Ÿฆ']) : undefined; await say( [ [ 'Welcome', 'to', label('astro', color.bgGreen, color.black), - (ctx.version ? color.green(`v${ctx.version}`) : '') + ',', - `${ctx.username}!`, + Promise.resolve(ctx.version).then(version => ((version ? color.green(`v${version}`) : '') + ',')), + Promise.resolve(ctx.username).then(username => `${username}!`), ], random(welcome), ], - { hat } + { clear: true, hat: ctx.hat } ); - await banner(ctx.version); - } else { - await banner(ctx.version); } } diff --git a/packages/create-astro/src/actions/next-steps.ts b/packages/create-astro/src/actions/next-steps.ts index c79a80525428..ac69b7e9407a 100644 --- a/packages/create-astro/src/actions/next-steps.ts +++ b/packages/create-astro/src/actions/next-steps.ts @@ -3,7 +3,7 @@ import type { Context } from './context'; import { nextSteps, say } from '../messages.js'; -export async function next(ctx: Pick) { +export async function next(ctx: Pick) { let projectDir = path.relative(process.cwd(), ctx.cwd); const commandMap: { [key: string]: string } = { @@ -17,7 +17,7 @@ export async function next(ctx: Pick { - const packageManager = detectPackageManager()?.name || 'npm'; +async function getRegistry(packageManager: string): Promise { try { const { stdout } = await shell(packageManager, ['config', 'get', 'registry']); return stdout?.trim()?.replace(/\/$/, '') || 'https://registry.npmjs.org'; @@ -78,10 +75,10 @@ export const getName = () => }); let v: string; -export const getVersion = () => +export const getVersion = (packageManager: string) => new Promise(async (resolve) => { if (v) return resolve(v); - let registry = await getRegistry(); + let registry = await getRegistry(packageManager); const { version } = await fetch(`${registry}/astro/latest`, { redirect: 'follow' }).then( (res) => res.json(), () => ({ version: '' }) @@ -91,12 +88,11 @@ export const getVersion = () => }); export const log = (message: string) => stdout.write(message + '\n'); -export const banner = async (version: string) => - log( - `\n${label('astro', color.bgGreen, color.black)}${ - version ? ' ' + color.green(color.bold(`v${version}`)) : '' - } ${color.bold('Launch sequence initiated.')}` - ); +export const banner = () => { + const prefix = `astro`; + const suffix = `Launch sequence initiated.`; + log(`${label(prefix, color.bgGreen, color.black)} ${suffix}`); +} export const bannerAbort = () => log(`\n${label('astro', color.bgRed)} ${color.bold('Launch sequence aborted.')}`); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c005fdc9e81c..470bd046b480 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3566,24 +3566,12 @@ importers: packages/create-astro: dependencies: '@astrojs/cli-kit': - specifier: ^0.2.3 - version: 0.2.3 - execa: - specifier: ^8.0.1 - version: 8.0.1 + specifier: ^0.2.5 + version: 0.2.5 giget: specifier: 1.1.2 version: 1.1.2 - node-fetch-native: - specifier: ^1.4.0 - version: 1.4.0 - which-pm-runs: - specifier: ^1.1.0 - version: 1.1.0 devDependencies: - '@types/which-pm-runs': - specifier: ^1.0.0 - version: 1.0.0 arg: specifier: ^5.0.2 version: 5.0.2 @@ -5188,10 +5176,10 @@ packages: - prettier-plugin-astro dev: true - /@astrojs/cli-kit@0.2.3: - resolution: {integrity: sha512-MjB42mpIG/F2rFtdp4f3NylFCILuFSib2yITSq65fRaDFn8+UC8EMh6T7Jr3YqHAbUY5r8V8QWNgH4keOEO2BA==} + /@astrojs/cli-kit@0.2.5: + resolution: {integrity: sha512-j6zpNUjtHJGEIKkTrTPvQD3G/sJUKyseJty42iVR3HqytzqHwLK165vptdT4NZKfZ082yLnUtsOXxRyIdfm/AQ==} dependencies: - chalk: 5.2.0 + chalk: 5.3.0 log-update: 5.0.1 sisteransi: 1.0.5 dev: false @@ -10256,11 +10244,6 @@ packages: ansi-styles: 4.3.0 supports-color: 7.2.0 - /chalk@5.2.0: - resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: false - /chalk@5.3.0: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}