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

fix: use a recursive helper to find named parent package #507

Merged
merged 4 commits into from
Nov 23, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dry-seahorses-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/vite-plugin-svelte': patch
---

improve robustness of compile stats taking
2 changes: 1 addition & 1 deletion packages/vite-plugin-svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"kleur": "^4.1.5",
"magic-string": "^0.26.7",
"svelte-hmr": "^0.15.1",
"vitefu": "^0.2.1"
"vitefu": "^0.2.2"
},
"peerDependencies": {
"diff-match-patch": "^1.0.5",
Expand Down
89 changes: 50 additions & 39 deletions packages/vite-plugin-svelte/src/utils/vite-plugin-svelte-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { log } from './log';
//eslint-disable-next-line node/no-missing-import
import { findClosestPkgJsonPath } from 'vitefu';
import { readFileSync } from 'fs';
import { dirname } from 'path';
import { performance } from 'perf_hooks';
import { normalizePath } from 'vite';

interface Stat {
file: string;
Expand Down Expand Up @@ -85,6 +87,27 @@ function formatPackageStats(pkgStats: PackageStats[]) {
return table;
}

/**
* utility to get the package name a file belongs to
*
* @param {string} file to find package for
* @returns {path:string,name:string} tuple of path,name where name is the parsed package name and path is the normalized path to it
*/
async function getClosestNamedPackage(file: string): Promise<{ name: string; path: string }> {
let name = '$unknown';
let path = await findClosestPkgJsonPath(file, (pkgPath) => {
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
if (pkg.name != null) {
name = pkg.name;
return true;
}
return false;
});
// return normalized path with appended '/' so .startsWith works for future file checks
path = normalizePath(dirname(path ?? file)) + '/';
return { name, path };
}

export class VitePluginSvelteStats {
// package directory -> package name
private _packages: { path: string; name: string }[] = [];
Expand All @@ -108,6 +131,7 @@ export class VitePluginSvelteStats {
if (collection.finished) {
throw new Error('called after finish() has been used');
}
file = normalizePath(file);
const start = performance.now();
const stat: Stat = { file, start, end: start };
return () => {
Expand All @@ -133,54 +157,41 @@ export class VitePluginSvelteStats {
}

private async _finish(collection: StatCollection) {
collection.finished = true;
const now = performance.now();
collection.duration = now - collection.collectionStart;
const logResult = collection.options.logResult(collection);
if (logResult) {
await this._aggregateStatsResult(collection);
log.info(`${collection.name} done.`, formatPackageStats(collection.packageStats!));
}
// cut some ties to free it for garbage collection
const index = this._collections.indexOf(collection);
this._collections.splice(index, 1);
collection.stats.length = 0;
collection.stats = [];
if (collection.packageStats) {
collection.packageStats.length = 0;
collection.packageStats = [];
try {
collection.finished = true;
const now = performance.now();
collection.duration = now - collection.collectionStart;
const logResult = collection.options.logResult(collection);
if (logResult) {
await this._aggregateStatsResult(collection);
log.info(`${collection.name} done.`, formatPackageStats(collection.packageStats!));
}
// cut some ties to free it for garbage collection
const index = this._collections.indexOf(collection);
this._collections.splice(index, 1);
collection.stats.length = 0;
collection.stats = [];
if (collection.packageStats) {
collection.packageStats.length = 0;
collection.packageStats = [];
}
collection.start = () => () => {};
collection.finish = () => {};
} catch (e) {
// this should not happen, but stats taking also should not break the process
log.debug.once(`failed to finish stats for ${collection.name}`, e);
}
collection.start = () => () => {};
collection.finish = () => {};
}

private async _aggregateStatsResult(collection: StatCollection) {
const stats = collection.stats;
for (const stat of stats) {
let pkg = this._packages.find((p) => stat.file.startsWith(p.path));
if (!pkg) {
// check for package.json first
let pkgPath = await findClosestPkgJsonPath(stat.file);
if (pkgPath) {
let path = pkgPath?.replace(/package.json$/, '');
let name = JSON.parse(readFileSync(pkgPath, 'utf-8')).name;
if (!name) {
// some packages have nameless nested package.json
pkgPath = await findClosestPkgJsonPath(path);
if (pkgPath) {
path = pkgPath?.replace(/package.json$/, '');
name = JSON.parse(readFileSync(pkgPath, 'utf-8')).name;
}
}
if (path && name) {
pkg = { path, name };
this._packages.push(pkg);
}
}
pkg = await getClosestNamedPackage(stat.file);
this._packages.push(pkg);
}
// TODO is it possible that we want to track files where there is no named packge.json as parent?
// what do we want to do for that, try to find common root paths for different stats?
stat.pkg = pkg?.name ?? '$unknown';
stat.pkg = pkg.name;
}

// group stats
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.