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
2 changes: 1 addition & 1 deletion apps/cli/ai/providers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { password } from '@inquirer/prompts';
import { validateAnthropicApiKey } from '@studio/common/ai/anthropic-key';
import { DEFAULT_MODEL, type AiModelId } from '@studio/common/ai/models';
import {
Expand All @@ -10,6 +9,7 @@ import {
import { persistAnthropicApiKey, readAnthropicApiKey } from '@studio/common/ai/settings-store';
import { readAuthToken } from '@studio/common/lib/shared-config';
import { __ } from '@wordpress/i18n';
import { password } from 'cli/lib/prompts';
import { LoggerError } from 'cli/logger';

export const AI_PROVIDERS: Record< AiProviderId, string > = {
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/commands/ai/sessions/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
import { select } from '@inquirer/prompts';
import { listAiSessions } from '@studio/common/ai/sessions/store';
import chalk from '@studio/common/lib/chalk';
import { getSessionsDirectory } from '@studio/common/lib/well-known-paths';
import { __ } from '@wordpress/i18n';
import { select } from 'cli/lib/prompts';
import type { AiSessionSummary } from '@studio/common/ai/sessions/types';

function formatSessionTimestamp( timestamp: string ): string {
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/commands/auth/login.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { input } from '@inquirer/prompts';
import { readAuthToken } from '@studio/common/lib/shared-config';
import { AuthCommandLoggerAction as LoggerAction } from '@studio/common/logger-actions';
import { __ } from '@wordpress/i18n';
import { openBrowser } from 'cli/lib/browser';
import { input } from 'cli/lib/prompts';
import { getCliAuthenticationUrl, storeAuthToken } from 'cli/lib/wpcom-auth';
import { Logger, LoggerError } from 'cli/logger';
import { StudioArgv } from 'cli/types';
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/commands/blueprint/use.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import fs from 'fs';
import path from 'path';
import { select, input } from '@inquirer/prompts';
import { DEFAULT_PHP_VERSION, DEFAULT_WORDPRESS_VERSION } from '@studio/common/constants';
import {
createBlueprintTempDir,
Expand All @@ -15,6 +14,7 @@ import { BlueprintCommandLoggerAction as LoggerAction } from '@studio/common/log
import { SupportedPHPVersions, type SupportedPHPVersion } from '@studio/common/types/php-versions';
import { __, _n, sprintf } from '@wordpress/i18n';
import { runCommand as runCreateSiteCommand } from 'cli/commands/site/create';
import { select, input } from 'cli/lib/prompts';
import { getDefaultSitePath } from 'cli/lib/site-paths';
import { untildify } from 'cli/lib/utils';
import {
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/commands/pull.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import fs from 'fs';
import os from 'os';
import path from 'path';
import { confirm } from '@inquirer/prompts';
import {
addConnectedWpcomSite,
markConnectedWpcomSiteSynced,
Expand All @@ -20,6 +19,7 @@ import { __, sprintf } from '@wordpress/i18n';
import { clearSiteLatestCliPid, getSiteByFolder } from 'cli/lib/cli-config/sites';
import { connectToDaemon, disconnectFromDaemon } from 'cli/lib/daemon-client';
import { DEFAULT_IMPORTER_OPTIONS, getImporter } from 'cli/lib/import-export/import/import-manager';
import { confirm } from 'cli/lib/prompts';
import { withSiteOperation } from 'cli/lib/site-operations';
import { exitOnCancel, reportSyncActivity } from 'cli/lib/sync-activity';
import {
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/commands/site/create.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import crypto from 'crypto';
import fs from 'fs';
import path from 'path';
import { confirm, input, password, select } from '@inquirer/prompts';
import { DEFAULT_WORDPRESS_VERSION } from '@studio/common/constants';
import { installAiInstructionsToSite } from '@studio/common/lib/agent-skills';
import {
Expand Down Expand Up @@ -69,6 +68,7 @@ import { updateServerFiles } from 'cli/lib/dependency-management/setup';
import { downloadWordPress } from 'cli/lib/dependency-management/wordpress';
import { copyLanguagePackToSite } from 'cli/lib/language-packs';
import { validateSupportedPhpVersion } from 'cli/lib/php-versions';
import { confirm, input, password, select } from 'cli/lib/prompts';
import { getPreferredSiteLanguage } from 'cli/lib/site-language';
import { generateSiteName } from 'cli/lib/site-name';
import { getDefaultSitePath } from 'cli/lib/site-paths';
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/commands/uninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { spawn } from 'node:child_process';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { confirm } from '@inquirer/prompts';
import { getConfigDirectory } from '@studio/common/lib/well-known-paths';
import { __, sprintf } from '@wordpress/i18n';
import trash from 'trash';
import { Mode, runCommand as stopSites } from 'cli/commands/site/stop';
import { confirm } from 'cli/lib/prompts';
import { getCliInstallKind } from 'cli/lib/update-notifier';
import { StudioArgv } from 'cli/types';

Expand Down
33 changes: 33 additions & 0 deletions apps/cli/lib/prompts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type * as Prompts from '@inquirer/prompts';

// `@inquirer/prompts` loads every prompt type, each with its own copy of `@inquirer/core`,
// so these load it when a prompt is shown instead of when `studio` starts.

export async function confirm( ...args: Parameters< typeof Prompts.confirm > ) {
const { confirm: prompt } = await import( '@inquirer/prompts' );
return prompt( ...args );
}

export async function input( ...args: Parameters< typeof Prompts.input > ) {
const { input: prompt } = await import( '@inquirer/prompts' );
return prompt( ...args );
}

export async function password( ...args: Parameters< typeof Prompts.password > ) {
const { password: prompt } = await import( '@inquirer/prompts' );
return prompt( ...args );
}

export async function select< const Value >(
...args: Parameters< typeof Prompts.select< Value > >
): Promise< Value > {
const { select: prompt } = await import( '@inquirer/prompts' );
return prompt< Value >( ...args );
}

export async function search< const Value >(
...args: Parameters< typeof Prompts.search< Value > >
): Promise< Value > {
const { search: prompt } = await import( '@inquirer/prompts' );
return prompt< Value >( ...args );
}
2 changes: 1 addition & 1 deletion apps/cli/lib/sync-site-picker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { search } from '@inquirer/prompts';
import chalk from '@studio/common/lib/chalk';
import { __, sprintf } from '@wordpress/i18n';
import { search } from 'cli/lib/prompts';
import { normalizeHostname } from 'cli/lib/utils';
import { LoggerError } from 'cli/logger';
import type { SyncSite } from '@studio/common/types/sync';
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/migrations/00-check-studio-compatibility.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { execFile } from 'child_process';
import fs from 'fs';
import path from 'path';
import { confirm } from '@inquirer/prompts';
import { getAppConfigPath } from '@studio/common/lib/well-known-paths';
import { __ } from '@wordpress/i18n';
import { getAppdataDirectory } from 'cli/lib/appdata';
import { confirm } from 'cli/lib/prompts';
import type { Migration } from '@studio/common/lib/migration';

function isInstalledOnMacOs() {
Expand Down
29 changes: 17 additions & 12 deletions apps/cli/tests/startup-imports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@ import { readFileSync } from 'fs';
import path from 'path';
import { describe, expect, it, vi } from 'vitest';

const agentRuntimeLoaded = vi.hoisted( () => ( { value: false } ) );
const dateFnsRootLoaded = vi.hoisted( () => ( { value: false } ) );
const loadedAtStartup = vi.hoisted( () => new Set< string >() );

// Modules that each cost hundreds of milliseconds to load in the packaged app, so only the
// code that uses them loads them.
// The agent runtime is large.
vi.mock( '@earendil-works/pi-coding-agent', () => {
agentRuntimeLoaded.value = true;
loadedAtStartup.add( '@earendil-works/pi-coding-agent' );
return {};
} );

// The `date-fns` root loads every one of its functions, about 300 modules, which took
// about 0.9 s in the packaged app. Each function has its own path, e.g. `date-fns/format`.
// The `date-fns` root loads every one of its functions, about 300 modules. Each function
// has its own path, e.g. `date-fns/format`.
vi.mock( 'date-fns', () => {
dateFnsRootLoaded.value = true;
loadedAtStartup.add( 'date-fns' );
return {};
} );
// `@inquirer/prompts` loads every prompt type, each with its own copy of `@inquirer/core`.
// `cli/lib/prompts` loads it when a prompt is shown.
vi.mock( '@inquirer/prompts', () => {
loadedAtStartup.add( '@inquirer/prompts' );
return {};
} );

// Every `studio` command loads what the CLI entry imports statically before it
// runs. The agent runtime is large, so only the commands that use it load it.
// Every `studio` command loads what the CLI entry imports statically before it runs.
describe( 'CLI startup', () => {
it( 'loads no agent runtime or date-fns root before a command runs', async () => {
it( 'loads no heavy module before a command runs', async () => {
const entry = readFileSync( path.join( import.meta.dirname, '..', 'index.ts' ), 'utf8' );
const staticImports = [ ...entry.matchAll( /^import [^;]*? from '(cli\/[^']+)';$/gm ) ].map(
( [ , specifier ] ) => specifier
Expand All @@ -31,7 +37,6 @@ describe( 'CLI startup', () => {
await import( /* @vite-ignore */ specifier );
}

expect( agentRuntimeLoaded.value ).toBe( false );
expect( dateFnsRootLoaded.value ).toBe( false );
expect( [ ...loadedAtStartup ] ).toEqual( [] );
} );
} );
Loading