Skip to content

Commit c6fe0a4

Browse files
perf!: re-refactor code to get back to 2.0 speed
I had to make big changes to the loading mechanism to support loading (all packages) releases for the sidebar component in #56. This change led to the page relying on the sidebar loading to get its own data. Unfortunately, this led to significant slowdowns when navigating through packages (I'm still not sure _why_ thought). This commit makes the page completely independent from the sidebar, bringing back it's 2.0-release speed (and it's so good to get it back). HOWEVER, initial page loads seem a bit slower than right before this commit, but in my opinion it's a fair trade-off and it's not even that visible. From a user point of view, it's also more often more acceptable to wait a bit more for the initial data loading than between in-site navigation.
1 parent 24238b3 commit c6fe0a4

File tree

3 files changed

+126
-124
lines changed

3 files changed

+126
-124
lines changed

src/routes/package/+layout.server.ts

Lines changed: 1 addition & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,6 @@
1-
import semver from "semver";
2-
import { gitHubCache, type GitHubRelease } from "$lib/server/github-cache";
31
import { discoverer } from "$lib/server/package-discoverer";
4-
import type { Repository } from "$lib/repositories";
5-
import type { Prettify } from "$lib/types";
62
import type { PostHog } from "posthog-node";
7-
8-
/**
9-
* Get all the releases for a single package.
10-
*
11-
* @param packageName the package to get the releases for
12-
* @param allPackages all the known packages
13-
* @param posthog the optional PostHog instance
14-
* @returns the package's repository alongside its releases, or
15-
* undefined if not found
16-
*/
17-
async function getPackageReleases(
18-
packageName: string,
19-
allPackages: Awaited<ReturnType<typeof discoverer.getOrDiscoverCategorized>>,
20-
posthog?: PostHog
21-
) {
22-
let currentPackage:
23-
| Prettify<
24-
Omit<Repository, "dataFilter" | "metadataFromTag" | "changelogContentsReplacer"> &
25-
Pick<(typeof allPackages)[number]["packages"][number], "pkg">
26-
>
27-
| undefined = undefined;
28-
const foundVersions = new Set<string>();
29-
const releases: ({ cleanName: string; cleanVersion: string } & GitHubRelease)[] = [];
30-
31-
// Discover releases
32-
console.log("Starting loading releases...");
33-
for (const { category, packages } of allPackages) {
34-
for (const { pkg, ...repo } of packages) {
35-
if (pkg.name.localeCompare(packageName, undefined, { sensitivity: "base" }) !== 0) continue;
36-
37-
// 1. Get releases
38-
const cachedReleases = await gitHubCache.getReleases({ ...repo, category });
39-
console.log(
40-
`${cachedReleases.length} releases found for repo ${repo.owner}/${repo.repoName}`
41-
);
42-
43-
// 2. Filter out invalid ones
44-
const validReleases = cachedReleases
45-
.filter(release => {
46-
if (!release.tag_name) {
47-
posthog?.captureException(new Error("Release with null tag_name"), undefined, {
48-
release
49-
});
50-
console.warn(`Empty release tag name: ${release}`);
51-
return false;
52-
}
53-
const [name] = repo.metadataFromTag(release.tag_name);
54-
return (
55-
(repo.dataFilter?.(release) ?? true) &&
56-
pkg.name.localeCompare(name, undefined, { sensitivity: "base" }) === 0
57-
);
58-
})
59-
.sort((a, b) => {
60-
const [, firstVersion] = repo.metadataFromTag(a.tag_name);
61-
const [, secondVersion] = repo.metadataFromTag(b.tag_name);
62-
return semver.rcompare(firstVersion, secondVersion);
63-
});
64-
console.log("Final filtered count:", validReleases.length);
65-
66-
// 3. For each release, check if it is already found, searching by versions
67-
const { dataFilter, metadataFromTag, changelogContentsReplacer, ...rest } = repo;
68-
for (const release of validReleases) {
69-
if (!release.tag_name) {
70-
posthog?.captureException(new Error("Release with null tag_name"), undefined, {
71-
release
72-
});
73-
console.warn(`Empty release tag name: ${release}`);
74-
continue;
75-
}
76-
const [cleanName, cleanVersion] = repo.metadataFromTag(release.tag_name);
77-
console.log(`Release ${release.tag_name}, extracted version: ${cleanVersion}`);
78-
if (foundVersions.has(cleanVersion)) continue;
79-
80-
// If not, add its version to the set and itself to the final version
81-
const currentNewestVersion = [...foundVersions].sort(semver.rcompare)[0];
82-
console.log("Current newest version", currentNewestVersion);
83-
foundVersions.add(cleanVersion);
84-
releases.push({ cleanName, cleanVersion, ...release });
85-
86-
// If it is newer than the newest we got, set this repo as the "final repo"
87-
if (!currentNewestVersion || semver.gt(cleanVersion, currentNewestVersion)) {
88-
console.log(
89-
`Current newest version "${currentNewestVersion}" doesn't exist or is lesser than ${cleanVersion}, setting ${repo.owner}/${repo.repoName} as final repo`
90-
);
91-
currentPackage = {
92-
category,
93-
pkg,
94-
...rest
95-
};
96-
}
97-
}
98-
console.log("Done");
99-
}
100-
}
101-
102-
return currentPackage
103-
? {
104-
releasesRepo: currentPackage,
105-
releases: releases.toSorted(
106-
(a, b) =>
107-
new Date(b.published_at ?? b.created_at).getTime() -
108-
new Date(a.published_at ?? a.created_at).getTime()
109-
)
110-
}
111-
: undefined;
112-
}
3+
import { getPackageReleases } from "./releases";
1134

1145
/**
1156
* Get all the repositories and releases for all the
Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
import { error } from "@sveltejs/kit";
2+
import { getPackageReleases } from "../releases";
3+
import { discoverer } from "$lib/server/package-discoverer";
24

3-
export async function load({ params, parent }) {
5+
export async function load({ params, locals }) {
46
const { package: slugPackage } = params;
5-
// 1. Get the promise array from the layout
6-
const { allReleases } = await parent();
7+
// 1. Get all the discovered packages
8+
const categorizedPackages = await discoverer.getOrDiscoverCategorized();
79

8-
// 2. Find the package slug in there
9-
const matchingEntry = Object.entries(allReleases).find(
10-
([p]) => p.localeCompare(slugPackage, undefined, { sensitivity: "base" }) === 0
10+
// 2. Get the releases and package info
11+
const packageReleases = await getPackageReleases(
12+
slugPackage,
13+
categorizedPackages,
14+
locals.posthog
1115
);
12-
if (!matchingEntry) error(404);
16+
if (!packageReleases) error(404);
1317

14-
// 3. Try to await the releases
15-
const [, matchingPromise] = matchingEntry;
16-
const computedReleases = await matchingPromise;
17-
if (!computedReleases) error(404);
18-
19-
// 4. Return the right data
20-
const { releasesRepo: currentPackage, releases } = computedReleases;
18+
// 3. Return the data
19+
const { releasesRepo: currentPackage, releases } = packageReleases;
2120
return { currentPackage, releases };
2221
}

src/routes/package/releases.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import type { PostHog } from "posthog-node";
2+
import semver from "semver";
3+
import { gitHubCache, type GitHubRelease } from "$lib/server/github-cache";
4+
import type { discoverer } from "$lib/server/package-discoverer";
5+
import type { Prettify } from "$lib/types";
6+
import type { Repository } from "$lib/repositories";
7+
8+
/**
9+
* Get all the releases for a single package.
10+
*
11+
* @param packageName the package to get the releases for
12+
* @param allPackages all the known packages
13+
* @param posthog the optional PostHog instance
14+
* @returns the package's repository alongside its releases, or
15+
* undefined if not found
16+
*/
17+
export async function getPackageReleases(
18+
packageName: string,
19+
allPackages: Awaited<ReturnType<typeof discoverer.getOrDiscoverCategorized>>,
20+
posthog?: PostHog
21+
) {
22+
let currentPackage:
23+
| Prettify<
24+
Omit<Repository, "dataFilter" | "metadataFromTag" | "changelogContentsReplacer"> &
25+
Pick<(typeof allPackages)[number]["packages"][number], "pkg">
26+
>
27+
| undefined = undefined;
28+
const foundVersions = new Set<string>();
29+
const releases: ({ cleanName: string; cleanVersion: string } & GitHubRelease)[] = [];
30+
31+
// Discover releases
32+
console.log("Starting loading releases...");
33+
for (const { category, packages } of allPackages) {
34+
for (const { pkg, ...repo } of packages) {
35+
if (pkg.name.localeCompare(packageName, undefined, { sensitivity: "base" }) !== 0) continue;
36+
37+
// 1. Get releases
38+
const cachedReleases = await gitHubCache.getReleases({ ...repo, category });
39+
console.log(
40+
`${cachedReleases.length} releases found for repo ${repo.owner}/${repo.repoName}`
41+
);
42+
43+
// 2. Filter out invalid ones
44+
const validReleases = cachedReleases
45+
.filter(release => {
46+
if (!release.tag_name) {
47+
posthog?.captureException(new Error("Release with null tag_name"), undefined, {
48+
release
49+
});
50+
console.warn(`Empty release tag name: ${release}`);
51+
return false;
52+
}
53+
const [name] = repo.metadataFromTag(release.tag_name);
54+
return (
55+
(repo.dataFilter?.(release) ?? true) &&
56+
pkg.name.localeCompare(name, undefined, { sensitivity: "base" }) === 0
57+
);
58+
})
59+
.sort((a, b) => {
60+
const [, firstVersion] = repo.metadataFromTag(a.tag_name);
61+
const [, secondVersion] = repo.metadataFromTag(b.tag_name);
62+
return semver.rcompare(firstVersion, secondVersion);
63+
});
64+
console.log("Final filtered count:", validReleases.length);
65+
66+
// 3. For each release, check if it is already found, searching by versions
67+
const { dataFilter, metadataFromTag, changelogContentsReplacer, ...rest } = repo;
68+
for (const release of validReleases) {
69+
if (!release.tag_name) {
70+
posthog?.captureException(new Error("Release with null tag_name"), undefined, {
71+
release
72+
});
73+
console.warn(`Empty release tag name: ${release}`);
74+
continue;
75+
}
76+
const [cleanName, cleanVersion] = repo.metadataFromTag(release.tag_name);
77+
console.log(`Release ${release.tag_name}, extracted version: ${cleanVersion}`);
78+
if (foundVersions.has(cleanVersion)) continue;
79+
80+
// If not, add its version to the set and itself to the final version
81+
const currentNewestVersion = [...foundVersions].sort(semver.rcompare)[0];
82+
console.log("Current newest version", currentNewestVersion);
83+
foundVersions.add(cleanVersion);
84+
releases.push({ cleanName, cleanVersion, ...release });
85+
86+
// If it is newer than the newest we got, set this repo as the "final repo"
87+
if (!currentNewestVersion || semver.gt(cleanVersion, currentNewestVersion)) {
88+
console.log(
89+
`Current newest version "${currentNewestVersion}" doesn't exist or is lesser than ${cleanVersion}, setting ${repo.owner}/${repo.repoName} as final repo`
90+
);
91+
currentPackage = {
92+
category,
93+
pkg,
94+
...rest
95+
};
96+
}
97+
}
98+
console.log("Done");
99+
}
100+
}
101+
102+
return currentPackage
103+
? {
104+
releasesRepo: currentPackage,
105+
releases: releases.toSorted(
106+
(a, b) =>
107+
new Date(b.published_at ?? b.created_at).getTime() -
108+
new Date(a.published_at ?? a.created_at).getTime()
109+
)
110+
}
111+
: undefined;
112+
}

0 commit comments

Comments
 (0)