mirror of
https://github.com/withastro/astro.git
synced 2025-01-20 22:12:38 -05:00
Improve create-astro
startup performance (#8456)
* feat(create-astro): improve performance * test: fix test by wrapping promise values * chore: remove uneeded deps * Update ten-kings-smash.md * chore: update lockfile
This commit is contained in:
parent
f02dc9f7bf
commit
ed952b4cea
10 changed files with 46 additions and 59 deletions
5
.changeset/ten-kings-smash.md
Normal file
5
.changeset/ten-kings-smash.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'create-astro': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve startup performance by removing dependencies, lazily initializing async contextual values
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
const currentVersion = process.versions.node;
|
const currentVersion = process.versions.node;
|
||||||
const requiredMajorVersion = parseInt(currentVersion.split('.')[0], 10);
|
const requiredMajorVersion = parseInt(currentVersion.split('.')[0], 10);
|
||||||
const minimumMajorVersion = 14;
|
const minimumMajorVersion = 18;
|
||||||
|
|
||||||
if (requiredMajorVersion < minimumMajorVersion) {
|
if (requiredMajorVersion < minimumMajorVersion) {
|
||||||
console.error(`Node.js v${currentVersion} is out of date and unsupported!`);
|
console.error(`Node.js v${currentVersion} is out of date and unsupported!`);
|
||||||
|
|
|
@ -31,14 +31,10 @@
|
||||||
"//a": "MOST PACKAGES SHOULD GO IN DEV_DEPENDENCIES! THEY WILL BE BUNDLED.",
|
"//a": "MOST PACKAGES SHOULD GO IN DEV_DEPENDENCIES! THEY WILL BE BUNDLED.",
|
||||||
"//b": "DEPENDENCIES IS FOR UNBUNDLED PACKAGES",
|
"//b": "DEPENDENCIES IS FOR UNBUNDLED PACKAGES",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cli-kit": "^0.2.3",
|
"@astrojs/cli-kit": "^0.2.5",
|
||||||
"execa": "^8.0.1",
|
"giget": "1.1.2"
|
||||||
"giget": "1.1.2",
|
|
||||||
"node-fetch-native": "^1.4.0",
|
|
||||||
"which-pm-runs": "^1.1.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/which-pm-runs": "^1.0.0",
|
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
"astro-scripts": "workspace:*",
|
"astro-scripts": "workspace:*",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { prompt } from '@astrojs/cli-kit';
|
import { prompt } from '@astrojs/cli-kit';
|
||||||
|
import { random } from '@astrojs/cli-kit/utils';
|
||||||
import arg from 'arg';
|
import arg from 'arg';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import detectPackageManager from 'which-pm-runs';
|
|
||||||
|
|
||||||
import { getName, getVersion } from '../messages.js';
|
import { getName, getVersion } from '../messages.js';
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ export interface Context {
|
||||||
prompt: typeof prompt;
|
prompt: typeof prompt;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
packageManager: string;
|
packageManager: string;
|
||||||
username: string;
|
username: Promise<string>;
|
||||||
version: string;
|
version: Promise<string>;
|
||||||
skipHouston: boolean;
|
skipHouston: boolean;
|
||||||
fancy?: boolean;
|
fancy?: boolean;
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
|
@ -25,6 +25,7 @@ export interface Context {
|
||||||
stdin?: typeof process.stdin;
|
stdin?: typeof process.stdin;
|
||||||
stdout?: typeof process.stdout;
|
stdout?: typeof process.stdout;
|
||||||
exit(code: number): never;
|
exit(code: number): never;
|
||||||
|
hat?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getContext(argv: string[]): Promise<Context> {
|
export async function getContext(argv: string[]): Promise<Context> {
|
||||||
|
@ -51,8 +52,7 @@ export async function getContext(argv: string[]): Promise<Context> {
|
||||||
{ argv, permissive: true }
|
{ argv, permissive: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const packageManager = detectPackageManager()?.name ?? 'npm';
|
const packageManager = detectPackageManager() ?? 'npm';
|
||||||
const [username, version] = await Promise.all([getName(), getVersion()]);
|
|
||||||
let cwd = flags['_'][0];
|
let cwd = flags['_'][0];
|
||||||
let {
|
let {
|
||||||
'--help': help = false,
|
'--help': help = false,
|
||||||
|
@ -86,14 +86,15 @@ export async function getContext(argv: string[]): Promise<Context> {
|
||||||
help,
|
help,
|
||||||
prompt,
|
prompt,
|
||||||
packageManager,
|
packageManager,
|
||||||
username,
|
username: getName(),
|
||||||
version,
|
version: getVersion(packageManager),
|
||||||
skipHouston,
|
skipHouston,
|
||||||
fancy,
|
fancy,
|
||||||
dryRun,
|
dryRun,
|
||||||
projectName,
|
projectName,
|
||||||
template,
|
template,
|
||||||
ref: ref ?? 'latest',
|
ref: ref ?? 'latest',
|
||||||
|
hat: fancy ? random(['🎩', '🎩', '🎩', '🎩', '🎓', '👑', '🧢', '🍦']) : undefined,
|
||||||
yes,
|
yes,
|
||||||
install: install ?? (noInstall ? false : undefined),
|
install: install ?? (noInstall ? false : undefined),
|
||||||
git: git ?? (noGit ? false : undefined),
|
git: git ?? (noGit ? false : undefined),
|
||||||
|
@ -105,3 +106,10 @@ export async function getContext(argv: string[]): Promise<Context> {
|
||||||
};
|
};
|
||||||
return context;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -4,24 +4,22 @@ import { color, label } from '@astrojs/cli-kit';
|
||||||
import { random } from '@astrojs/cli-kit/utils';
|
import { random } from '@astrojs/cli-kit/utils';
|
||||||
import { banner, say, welcome } from '../messages.js';
|
import { banner, say, welcome } from '../messages.js';
|
||||||
|
|
||||||
export async function intro(ctx: Pick<Context, 'skipHouston' | 'version' | 'username' | 'fancy'>) {
|
export async function intro(ctx: Pick<Context, 'hat' | 'skipHouston' | 'version' | 'username' | 'fancy'>) {
|
||||||
|
banner();
|
||||||
|
|
||||||
if (!ctx.skipHouston) {
|
if (!ctx.skipHouston) {
|
||||||
const hat = ctx.fancy ? random(['🎩', '🎩', '👑', '🧢', '🍦']) : undefined;
|
|
||||||
await say(
|
await say(
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
'Welcome',
|
'Welcome',
|
||||||
'to',
|
'to',
|
||||||
label('astro', color.bgGreen, color.black),
|
label('astro', color.bgGreen, color.black),
|
||||||
(ctx.version ? color.green(`v${ctx.version}`) : '') + ',',
|
Promise.resolve(ctx.version).then(version => ((version ? color.green(`v${version}`) : '') + ',')),
|
||||||
`${ctx.username}!`,
|
Promise.resolve(ctx.username).then(username => `${username}!`),
|
||||||
],
|
],
|
||||||
random(welcome),
|
random(welcome),
|
||||||
],
|
],
|
||||||
{ hat }
|
{ clear: true, hat: ctx.hat }
|
||||||
);
|
);
|
||||||
await banner(ctx.version);
|
|
||||||
} else {
|
|
||||||
await banner(ctx.version);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { Context } from './context';
|
||||||
|
|
||||||
import { nextSteps, say } from '../messages.js';
|
import { nextSteps, say } from '../messages.js';
|
||||||
|
|
||||||
export async function next(ctx: Pick<Context, 'cwd' | 'packageManager' | 'skipHouston'>) {
|
export async function next(ctx: Pick<Context, 'hat' | 'cwd' | 'packageManager' | 'skipHouston'>) {
|
||||||
let projectDir = path.relative(process.cwd(), ctx.cwd);
|
let projectDir = path.relative(process.cwd(), ctx.cwd);
|
||||||
|
|
||||||
const commandMap: { [key: string]: string } = {
|
const commandMap: { [key: string]: string } = {
|
||||||
|
@ -17,7 +17,7 @@ export async function next(ctx: Pick<Context, 'cwd' | 'packageManager' | 'skipHo
|
||||||
await nextSteps({ projectDir, devCmd });
|
await nextSteps({ projectDir, devCmd });
|
||||||
|
|
||||||
if (!ctx.skipHouston) {
|
if (!ctx.skipHouston) {
|
||||||
await say(['Good luck out there, astronaut! 🚀']);
|
await say(['Good luck out there, astronaut! 🚀'], { hat: ctx.hat });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import type { Context } from './context';
|
import type { Context } from './context';
|
||||||
|
|
||||||
import { color } from '@astrojs/cli-kit';
|
import { color } from '@astrojs/cli-kit';
|
||||||
import fetch from 'node-fetch-native';
|
|
||||||
import dns from 'node:dns/promises';
|
import dns from 'node:dns/promises';
|
||||||
import { bannerAbort, error, info, log } from '../messages.js';
|
import { bannerAbort, error, info, log } from '../messages.js';
|
||||||
import { getTemplateTarget } from './template.js';
|
import { getTemplateTarget } from './template.js';
|
||||||
|
|
|
@ -19,6 +19,8 @@ process.on('SIGTERM', exit);
|
||||||
// https://github.com/withastro/docs/blob/main/src/pages/en/install/auto.md
|
// https://github.com/withastro/docs/blob/main/src/pages/en/install/auto.md
|
||||||
// if you make any changes to the flow or wording here.
|
// if you make any changes to the flow or wording here.
|
||||||
export async function main() {
|
export async function main() {
|
||||||
|
// Clear console because PNPM startup is super ugly
|
||||||
|
console.clear();
|
||||||
// NOTE: In the v7.x version of npm, the default behavior of `npm init` was changed
|
// NOTE: In the v7.x version of npm, the default behavior of `npm init` was changed
|
||||||
// to no longer require `--` to pass args and instead pass `--` directly to us. This
|
// to no longer require `--` to pass args and instead pass `--` directly to us. This
|
||||||
// broke our arg parser, since `--` is a special kind of flag. Filtering for `--` here
|
// broke our arg parser, since `--` is a special kind of flag. Filtering for `--` here
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
/* eslint no-console: 'off' */
|
/* eslint no-console: 'off' */
|
||||||
import { color, say as houston, label, spinner as load } from '@astrojs/cli-kit';
|
import { color, say as houston, label, spinner as load } from '@astrojs/cli-kit';
|
||||||
import { align, sleep } from '@astrojs/cli-kit/utils';
|
import { align, sleep } from '@astrojs/cli-kit/utils';
|
||||||
import fetch from 'node-fetch-native';
|
|
||||||
import { exec } from 'node:child_process';
|
import { exec } from 'node:child_process';
|
||||||
import stripAnsi from 'strip-ansi';
|
import stripAnsi from 'strip-ansi';
|
||||||
import detectPackageManager from 'which-pm-runs';
|
|
||||||
import { shell } from './shell.js';
|
import { shell } from './shell.js';
|
||||||
|
|
||||||
// Users might lack access to the global npm registry, this function
|
// Users might lack access to the global npm registry, this function
|
||||||
// checks the user's project type and will return the proper npm registry
|
// checks the user's project type and will return the proper npm registry
|
||||||
//
|
//
|
||||||
// A copy of this function also exists in the astro package
|
// A copy of this function also exists in the astro package
|
||||||
async function getRegistry(): Promise<string> {
|
async function getRegistry(packageManager: string): Promise<string> {
|
||||||
const packageManager = detectPackageManager()?.name || 'npm';
|
|
||||||
try {
|
try {
|
||||||
const { stdout } = await shell(packageManager, ['config', 'get', 'registry']);
|
const { stdout } = await shell(packageManager, ['config', 'get', 'registry']);
|
||||||
return stdout?.trim()?.replace(/\/$/, '') || 'https://registry.npmjs.org';
|
return stdout?.trim()?.replace(/\/$/, '') || 'https://registry.npmjs.org';
|
||||||
|
@ -78,10 +75,10 @@ export const getName = () =>
|
||||||
});
|
});
|
||||||
|
|
||||||
let v: string;
|
let v: string;
|
||||||
export const getVersion = () =>
|
export const getVersion = (packageManager: string) =>
|
||||||
new Promise<string>(async (resolve) => {
|
new Promise<string>(async (resolve) => {
|
||||||
if (v) return resolve(v);
|
if (v) return resolve(v);
|
||||||
let registry = await getRegistry();
|
let registry = await getRegistry(packageManager);
|
||||||
const { version } = await fetch(`${registry}/astro/latest`, { redirect: 'follow' }).then(
|
const { version } = await fetch(`${registry}/astro/latest`, { redirect: 'follow' }).then(
|
||||||
(res) => res.json(),
|
(res) => res.json(),
|
||||||
() => ({ version: '' })
|
() => ({ version: '' })
|
||||||
|
@ -91,12 +88,11 @@ export const getVersion = () =>
|
||||||
});
|
});
|
||||||
|
|
||||||
export const log = (message: string) => stdout.write(message + '\n');
|
export const log = (message: string) => stdout.write(message + '\n');
|
||||||
export const banner = async (version: string) =>
|
export const banner = () => {
|
||||||
log(
|
const prefix = `astro`;
|
||||||
`\n${label('astro', color.bgGreen, color.black)}${
|
const suffix = `Launch sequence initiated.`;
|
||||||
version ? ' ' + color.green(color.bold(`v${version}`)) : ''
|
log(`${label(prefix, color.bgGreen, color.black)} ${suffix}`);
|
||||||
} ${color.bold('Launch sequence initiated.')}`
|
}
|
||||||
);
|
|
||||||
|
|
||||||
export const bannerAbort = () =>
|
export const bannerAbort = () =>
|
||||||
log(`\n${label('astro', color.bgRed)} ${color.bold('Launch sequence aborted.')}`);
|
log(`\n${label('astro', color.bgRed)} ${color.bold('Launch sequence aborted.')}`);
|
||||||
|
|
27
pnpm-lock.yaml
generated
27
pnpm-lock.yaml
generated
|
@ -3566,24 +3566,12 @@ importers:
|
||||||
packages/create-astro:
|
packages/create-astro:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/cli-kit':
|
'@astrojs/cli-kit':
|
||||||
specifier: ^0.2.3
|
specifier: ^0.2.5
|
||||||
version: 0.2.3
|
version: 0.2.5
|
||||||
execa:
|
|
||||||
specifier: ^8.0.1
|
|
||||||
version: 8.0.1
|
|
||||||
giget:
|
giget:
|
||||||
specifier: 1.1.2
|
specifier: 1.1.2
|
||||||
version: 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:
|
devDependencies:
|
||||||
'@types/which-pm-runs':
|
|
||||||
specifier: ^1.0.0
|
|
||||||
version: 1.0.0
|
|
||||||
arg:
|
arg:
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
|
@ -5188,10 +5176,10 @@ packages:
|
||||||
- prettier-plugin-astro
|
- prettier-plugin-astro
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@astrojs/cli-kit@0.2.3:
|
/@astrojs/cli-kit@0.2.5:
|
||||||
resolution: {integrity: sha512-MjB42mpIG/F2rFtdp4f3NylFCILuFSib2yITSq65fRaDFn8+UC8EMh6T7Jr3YqHAbUY5r8V8QWNgH4keOEO2BA==}
|
resolution: {integrity: sha512-j6zpNUjtHJGEIKkTrTPvQD3G/sJUKyseJty42iVR3HqytzqHwLK165vptdT4NZKfZ082yLnUtsOXxRyIdfm/AQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk: 5.2.0
|
chalk: 5.3.0
|
||||||
log-update: 5.0.1
|
log-update: 5.0.1
|
||||||
sisteransi: 1.0.5
|
sisteransi: 1.0.5
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -10256,11 +10244,6 @@ packages:
|
||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
supports-color: 7.2.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:
|
/chalk@5.3.0:
|
||||||
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
|
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
|
||||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||||
|
|
Loading…
Add table
Reference in a new issue