Skip to content
Open
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
105 changes: 0 additions & 105 deletions src/app/[...parts]/page.tsx

This file was deleted.

23 changes: 23 additions & 0 deletions src/app/api/-/destination/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type NextRequest, NextResponse } from "next/server";
import destination from "^/lib/destination";

function assureArrayLength(specs: string[]) {
if (specs.length < 3) {
return specs as [string] | [string, string];
}
throw new Error("Too many specs");
}

export async function GET(req: NextRequest, {}: { params: {} }) {
const { searchParams } = new URL(req.url);

const specsOrVersions = assureArrayLength(
searchParams.getAll("specs") ?? "",
);

console.log("[api/-/destination] running", specsOrVersions);

const result = await destination(specsOrVersions);

return NextResponse.json(result);
}
File renamed without changes.
87 changes: 87 additions & 0 deletions src/app/diff/[a]/[b]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { type ViewType } from "react-diff-view";
import { createSimplePackageSpec } from "^/lib/createSimplePackageSpec";
import { DEFAULT_DIFF_FILES_GLOB } from "^/lib/default-diff-files";
import { parseQuery, type QueryParams } from "^/lib/query";
import { simplePackageSpecToString } from "^/lib/SimplePackageSpec";
import BundlephobiaDiff from "./_page/BundlephobiaDiff";
import DiffIntro from "./_page/DiffIntro";
import NpmDiff from "./_page/NpmDiff";
import PackagephobiaDiff from "./_page/PackagephobiaDiff";
import { type DIFF_TYPE_PARAM_NAME } from "./_page/paramNames";

export interface DiffPageProps {
params: {
a: string;
b: string;
};
searchParams: QueryParams & {
[DIFF_TYPE_PARAM_NAME]: ViewType;
};
}

export function generateMetadata({ params: { a: _a, b: _b } }: DiffPageProps) {
const a = createSimplePackageSpec(decodeURIComponent(_a));
const b = createSimplePackageSpec(decodeURIComponent(_b));

return {
title: `Comparing ${simplePackageSpecToString(a)}...${simplePackageSpecToString(b)}`,
description: `A diff between the npm packages "${simplePackageSpecToString(a)}" and "${simplePackageSpecToString(b)}"`,
};
}

const DiffPage = async ({
params: { a: _a, b: _b },
searchParams,
}: DiffPageProps): Promise<JSX.Element> => {
const { diffFiles, ...optionsQuery } = searchParams;

const options = parseQuery({
// If no diffFiles is passed, use the default.
// This is done here, since we don't want a fall back in the API
diffFiles: diffFiles ?? DEFAULT_DIFF_FILES_GLOB,
...optionsQuery,
});

_a = decodeURIComponent(_a);
_b = decodeURIComponent(_b);

const specs = [_a, _b] as [string, string];
const a = createSimplePackageSpec(_a);
const b = createSimplePackageSpec(_b);

return (
<>
<DiffIntro
className="self-stretch"
a={a}
b={b}
services={
<>
<BundlephobiaDiff
a={a}
b={b}
specs={specs}
key={"bundlephobia-" + specs.join("...")}
/>
<PackagephobiaDiff
a={a}
b={b}
specs={specs}
key={"packagephobia-" + specs.join("...")}
/>
</>
}
options={options}
/>
<NpmDiff
a={a}
b={b}
specs={specs}
options={options}
key={JSON.stringify([specs, options])}
/>
</>
);
};

export default DiffPage;
2 changes: 1 addition & 1 deletion src/lib/utils/useViewType.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useSearchParams } from "next/navigation";
import { type ViewType } from "react-diff-view";
import { useMedia } from "react-use";
import { DIFF_TYPE_PARAM_NAME } from "^/app/[...parts]/_page/paramNames";
import { DIFF_TYPE_PARAM_NAME } from "^/app/diff/[a]/[b]/_page/paramNames";

export default function useViewType(): ViewType {
const searchParams = useSearchParams();
Expand Down
51 changes: 51 additions & 0 deletions src/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { type NextRequest, NextResponse } from "next/server";
import type { Destination } from "./lib/destination";
import specsToDiff from "./lib/utils/specsToDiff";
import splitParts from "./lib/utils/splitParts";

enum STATUS_CODES {
TEMPORARY_REDIRECT = 307,
PERMANENT_REDIRECT = 308,
}

export const config = {
matcher: "/((?!(?:about|api|_next|diff)(?:/.*)?|favicon.ico|icon.png).+)",
};

export async function middleware(request: NextRequest) {
console.log("[middleware]", request.nextUrl.pathname);

const parts = request.nextUrl.pathname.split("/")[1];

const specsOrVersions = splitParts(parts);

const url = new URL(`/api/-/destination`, request.url);
specsOrVersions.forEach((spec) => url.searchParams.append("specs", spec));

console.log("[middleware] fetching", url.toString());

const { redirect: red, canonicalSpecs }: Destination = await fetch(
url.toString(),
).then((res) => res.json());

if (red) {
console.log("[middleware] redirecting to", red);
return NextResponse.redirect(
new URL(`/${specsToDiff(canonicalSpecs)}`, request.nextUrl),
red === "permanent"
? STATUS_CODES.PERMANENT_REDIRECT
: STATUS_CODES.TEMPORARY_REDIRECT,
);
} else {
const url = new URL(
`/diff/${encodeURIComponent(
canonicalSpecs[0],
)}/${encodeURIComponent(canonicalSpecs[1])}`,
request.url,
);
console.log("[middleware] rewriting", url.toString());
return NextResponse.rewrite(url.toString());
}

return NextResponse.next();
}