Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Performance improvements #432

Merged
merged 4 commits into from
Feb 10, 2025
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
5 changes: 5 additions & 0 deletions .changeset/eight-moons-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"jsrepo": minor
---

perf: Cache git provider state to improve time it takes to fetch the manifest. (This behavior can be disabled with the `--no-cache` flag)
4 changes: 2 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@
"package-manager-detector": "^0.2.9",
"parse5": "^7.2.1",
"pathe": "^2.0.2",
"prettier": "^3.4.2",
"prettier": "^3.5.0",
"semver": "^7.7.1",
"svelte": "^5.19.9",
"ts-morph": "^25.0.1",
"valibot": "1.0.0-beta.15",
"valibot": "1.0.0-rc.0",
"validate-npm-package-name": "^6.0.0",
"vue": "^3.5.13"
}
Expand Down
40 changes: 5 additions & 35 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,11 @@
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';
import { program } from 'commander';
import path from 'pathe';
import pkg from '../package.json';
import * as commands from './commands';
import type { CLIContext } from './utils/context';
import { getLatestVersion } from './utils/get-latest-version';

const resolveRelativeToRoot = (p: string): string => {
const dirname = fileURLToPath(import.meta.url);
return path.join(dirname, '../..', p);
};

// get version from package.json
const { version, name, description, repository } = JSON.parse(
fs.readFileSync(resolveRelativeToRoot('package.json'), 'utf-8')
);

const latestVersion = (await getLatestVersion()).match(
(val) => val,
() => undefined
);

const context: CLIContext = {
package: {
name,
description,
version,
repository,
latestVersion,
},
resolveRelativeToRoot,
};

const cli = program
.name(name)
.description(description)
.version(version)
.name(pkg.name)
.description(pkg.description)
.version(pkg.version)
.addCommand(commands.add)
.addCommand(commands.auth)
.addCommand(commands.build)
Expand All @@ -44,4 +14,4 @@ const cli = program
.addCommand(commands.test)
.addCommand(commands.update);

export { cli, context };
export { cli };
9 changes: 5 additions & 4 deletions packages/cli/src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { resolveCommand } from 'package-manager-detector/commands';
import { detect } from 'package-manager-detector/detect';
import path from 'pathe';
import * as v from 'valibot';
import { context } from '../cli';
import * as ascii from '../utils/ascii';
import { getInstalled, resolveTree } from '../utils/blocks';
import * as url from '../utils/blocks/ts/url';
Expand Down Expand Up @@ -48,6 +47,7 @@ const schema = v.object({
repo: v.optional(v.string()),
allow: v.boolean(),
yes: v.boolean(),
cache: v.boolean(),
verbose: v.boolean(),
cwd: v.string(),
});
Expand All @@ -63,12 +63,13 @@ const add = new Command('add')
.option('--repo <repo>', 'Repository to download the blocks from.')
.option('-A, --allow', 'Allow jsrepo to download code from the provided repo.', false)
.option('-y, --yes', 'Skip confirmation prompt.', false)
.option('--no-cache', 'Disable caching of resolved git urls.')
.option('--verbose', 'Include debug logs.', false)
.option('--cwd <path>', 'The current working directory.', process.cwd())
.action(async (blockNames, opts) => {
const options = v.parse(schema, opts);

intro(context);
await intro();

await _add(blockNames, options);

Expand Down Expand Up @@ -216,7 +217,7 @@ const _add = async (blockNames: string[], options: Options) => {
if (!options.verbose) loading.start(`Fetching blocks from ${color.cyan(repoPaths.join(', '))}`);

const resolvedRepos: registry.RegistryProviderState[] = (
await registry.forEachPathGetProviderState(...repoPaths)
await registry.forEachPathGetProviderState(repoPaths, { noCache: !options.cache })
).match(
(val) => val,
({ repo, message }) => {
Expand Down Expand Up @@ -417,7 +418,7 @@ const _add = async (blockNames: string[], options: Options) => {
for (const { block } of installingBlocks) {
const fullSpecifier = url.join(block.sourceRepo.url, block.category, block.name);
const shortSpecifier = `${block.category}/${block.name}`;
const watermark = getWatermark(context.package.version, block.sourceRepo.url);
const watermark = getWatermark(block.sourceRepo.url);

const providerInfo = block.sourceRepo;

Expand Down
3 changes: 1 addition & 2 deletions packages/cli/src/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { cancel, confirm, isCancel, outro, password, select } from '@clack/promp
import color from 'chalk';
import { Command, Option } from 'commander';
import * as v from 'valibot';
import { context } from '../cli';
import * as ascii from '../utils/ascii';
import * as persisted from '../utils/persisted';
import { intro } from '../utils/prompts';
Expand Down Expand Up @@ -30,7 +29,7 @@ const auth = new Command('auth')
.action(async (opts) => {
const options = v.parse(schema, opts);

intro(context);
await intro();

await _auth(options);

Expand Down
3 changes: 1 addition & 2 deletions packages/cli/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Command, program } from 'commander';
import ignore from 'ignore';
import path from 'pathe';
import * as v from 'valibot';
import { context } from '../cli';
import { MANIFEST_FILE } from '../constants';
import type { Category, Manifest } from '../types';
import * as ascii from '../utils/ascii';
Expand Down Expand Up @@ -72,7 +71,7 @@ const build = new Command('build')
.action(async (opts) => {
const options = v.parse(schema, opts);

intro(context);
await intro();

await _build(options);

Expand Down
7 changes: 4 additions & 3 deletions packages/cli/src/commands/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { resolveCommand } from 'package-manager-detector/commands';
import { detect } from 'package-manager-detector/detect';
import path from 'pathe';
import * as v from 'valibot';
import { context } from '../cli';
import * as ascii from '../utils/ascii';
import { resolveTree } from '../utils/blocks';
import * as url from '../utils/blocks/ts/url';
Expand All @@ -21,6 +20,7 @@ const schema = v.objectWithRest(
{
repo: v.optional(v.string()),
allow: v.boolean(),
cache: v.boolean(),
cwd: v.string(),
},
v.unknown()
Expand All @@ -39,13 +39,14 @@ const exec = new Command('exec')
)
.option('--repo <repo>', 'Repository to download and run the script from.')
.option('-A, --allow', 'Allow jsrepo to download code from the provided repo.', false)
.option('--no-cache', 'Disable caching of resolved git urls.')
.option('--cwd <path>', 'The current working directory.', process.cwd())
.allowExcessArguments()
.allowUnknownOption()
.action(async (script, opts, command) => {
const options = v.parse(schema, opts);

intro(context);
await intro();

await _exec(script, options, command);
});
Expand Down Expand Up @@ -141,7 +142,7 @@ const _exec = async (s: string | undefined, options: Options, command: any) => {
loading.start(`Fetching scripts from ${color.cyan(repoPaths.join(', '))}`);

const resolvedRepos: registry.RegistryProviderState[] = (
await registry.forEachPathGetProviderState(...repoPaths)
await registry.forEachPathGetProviderState(repoPaths, { noCache: !options.cache })
).match(
(val) => val,
({ repo, message }) => {
Expand Down
12 changes: 7 additions & 5 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { createPathsMatcher } from 'get-tsconfig';
import { detect, resolveCommand } from 'package-manager-detector';
import path from 'pathe';
import * as v from 'valibot';
import { context } from '../cli';
import { type ModelName, models } from '../utils/ai';
import * as ascii from '../utils/ascii';
import {
Expand All @@ -31,6 +30,7 @@ import {
getProjectConfig,
getRegistryConfig,
} from '../utils/config';
import { packageJson } from '../utils/context';
import { installDependencies } from '../utils/dependencies';
import { formatDiff } from '../utils/diff';
import { formatFile, matchJSDescendant, tryGetTsconfig } from '../utils/files';
Expand All @@ -52,6 +52,7 @@ const schema = v.object({
expand: v.boolean(),
maxUnchanged: v.number(),
yes: v.boolean(),
cache: v.boolean(),
cwd: v.string(),
});

Expand Down Expand Up @@ -87,11 +88,12 @@ const init = new Command('init')
3
)
.option('-y, --yes', 'Skip confirmation prompt.', false)
.option('--no-cache', 'Disable caching of resolved git urls.')
.option('--cwd <path>', 'The current working directory.', process.cwd())
.action(async (registries, opts) => {
const options = v.parse(schema, opts);

intro(context);
await intro();

if (options.registry !== undefined && options.project !== undefined) {
program.error(
Expand Down Expand Up @@ -315,7 +317,7 @@ const _initProject = async (registries: string[], options: Options) => {
}

const config: ProjectConfig = {
$schema: `https://unpkg.com/jsrepo@${context.package.version}/schemas/project-config.json`,
$schema: `https://unpkg.com/jsrepo@${packageJson.version}/schemas/project-config.json`,
repos,
includeTests:
initialConfig.isOk() && options.tests === undefined
Expand Down Expand Up @@ -527,7 +529,7 @@ const promptForProviderConfig = async ({

loading.start(`Fetching manifest from ${color.cyan(repo)}`);

const providerState = await registry.getProviderState(repo);
const providerState = await registry.getProviderState(repo, { noCache: !options.cache });

if (providerState.isErr()) {
program.error(color.red(providerState.unwrapErr()));
Expand Down Expand Up @@ -874,7 +876,7 @@ const _initRegistry = async (options: Options) => {
};
}

config.$schema = `https://unpkg.com/jsrepo@${context.package.version}/schemas/registry-config.json`;
config.$schema = `https://unpkg.com/jsrepo@${packageJson.version}/schemas/registry-config.json`;

while (true) {
if (config.dirs.length > 0) {
Expand Down
7 changes: 4 additions & 3 deletions packages/cli/src/commands/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { detect } from 'package-manager-detector/detect';
import path from 'pathe';
import { Project } from 'ts-morph';
import * as v from 'valibot';
import { context } from '../cli';
import * as ascii from '../utils/ascii';
import { getInstalled } from '../utils/blocks';
import * as url from '../utils/blocks/ts/url';
Expand All @@ -21,6 +20,7 @@ const schema = v.object({
repo: v.optional(v.string()),
allow: v.boolean(),
debug: v.boolean(),
cache: v.boolean(),
verbose: v.boolean(),
cwd: v.string(),
});
Expand All @@ -33,12 +33,13 @@ const test = new Command('test')
.option('--repo <repo>', 'Repository to download the blocks from.')
.option('-A, --allow', 'Allow jsrepo to download code from the provided repo.', false)
.option('--debug', 'Leaves the temp test file around for debugging upon failure.', false)
.option('--no-cache', 'Disable caching of resolved git urls.')
.option('--verbose', 'Include debug logs.', false)
.option('--cwd <path>', 'The current working directory.', process.cwd())
.action(async (blockNames, opts) => {
const options = v.parse(schema, opts);

intro(context);
await intro();

await _test(blockNames, options);

Expand Down Expand Up @@ -81,7 +82,7 @@ const _test = async (blockNames: string[], options: Options) => {
if (!options.verbose) loading.start(`Fetching blocks from ${color.cyan(repoPaths.join(', '))}`);

const resolvedRepos: registry.RegistryProviderState[] = (
await registry.forEachPathGetProviderState(...repoPaths)
await registry.forEachPathGetProviderState(repoPaths, { noCache: !options.cache })
).match(
(val) => val,
({ repo, message }) => {
Expand Down
9 changes: 5 additions & 4 deletions packages/cli/src/commands/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { resolveCommand } from 'package-manager-detector/commands';
import { detect } from 'package-manager-detector/detect';
import path from 'pathe';
import * as v from 'valibot';
import { context } from '../cli';
import { type ModelName, models } from '../utils/ai';
import * as ascii from '../utils/ascii';
import { getInstalled, resolveTree } from '../utils/blocks';
Expand All @@ -40,6 +39,7 @@ const schema = v.object({
repo: v.optional(v.string()),
allow: v.boolean(),
yes: v.boolean(),
cache: v.boolean(),
verbose: v.boolean(),
cwd: v.string(),
});
Expand All @@ -61,12 +61,13 @@ const update = new Command('update')
.option('--repo <repo>', 'Repository to download the blocks from.')
.option('-A, --allow', 'Allow jsrepo to download code from the provided repo.', false)
.option('-y, --yes', 'Skip confirmation prompt.', false)
.option('--no-cache', 'Disable caching of resolved git urls.')
.option('--verbose', 'Include debug logs.', false)
.option('--cwd <path>', 'The current working directory.', process.cwd())
.action(async (blockNames, opts) => {
const options = v.parse(schema, opts);

intro(context);
await intro();

await _update(blockNames, options);

Expand Down Expand Up @@ -122,7 +123,7 @@ const _update = async (blockNames: string[], options: Options) => {
if (!options.verbose) loading.start(`Fetching blocks from ${color.cyan(repoPaths.join(', '))}`);

const resolvedRepos: registry.RegistryProviderState[] = (
await registry.forEachPathGetProviderState(...repoPaths)
await registry.forEachPathGetProviderState(repoPaths, { noCache: !options.cache })
).match(
(val) => val,
({ repo, message }) => {
Expand Down Expand Up @@ -220,7 +221,7 @@ const _update = async (blockNames: string[], options: Options) => {
for (const { block } of updatingBlocks) {
const fullSpecifier = url.join(block.sourceRepo.url, block.category, block.name);

const watermark = getWatermark(context.package.version, block.sourceRepo.url);
const watermark = getWatermark(block.sourceRepo.url);

const providerState = block.sourceRepo;

Expand Down
22 changes: 4 additions & 18 deletions packages/cli/src/utils/context.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
export interface CLIContext {
/** The package.json of the CLI */
package: {
name: string;
version: string;
description: string;
repository: {
url: string;
};
latestVersion?: string;
};
/** Resolves the path relative to the root of the application
*
* @param path
* @returns
*/
resolveRelativeToRoot: (path: string) => string;
}
import pkg from '../../package.json';
import type { PackageJson } from './package';

export const packageJson = pkg as PackageJson;
Loading
Loading