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: migrate to cloudflare pages and vite (Work in progress) #81

Closed
wants to merge 14 commits into from
Closed
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
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20.14
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps=true
24 changes: 12 additions & 12 deletions app/analytics/collect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ describe("collectRequestHandler", () => {
const env = {
WEB_COUNTER_AE: {
writeDataPoint: vi.fn(),
} as CFAnalyticsEngine,
} as Environment;
} as AnalyticsEngineDataset,
} as Env;

// @ts-expect-error - we're mocking the request object
const request = httpMocks.createRequest(defaultRequestParams);
Expand Down Expand Up @@ -80,8 +80,8 @@ describe("collectRequestHandler", () => {
const env = {
WEB_COUNTER_AE: {
writeDataPoint: vi.fn(),
} as CFAnalyticsEngine,
} as Environment;
} as AnalyticsEngineDataset,
} as Env;

// @ts-expect-error - we're mocking the request object
const request = httpMocks.createRequest(generateRequestParams({}));
Expand All @@ -102,8 +102,8 @@ describe("collectRequestHandler", () => {
const env = {
WEB_COUNTER_AE: {
writeDataPoint: vi.fn(),
} as CFAnalyticsEngine,
} as Environment;
} as AnalyticsEngineDataset,
} as Env;

const request = httpMocks.createRequest(
// @ts-expect-error - we're mocking the request object
Expand All @@ -130,8 +130,8 @@ describe("collectRequestHandler", () => {
const env = {
WEB_COUNTER_AE: {
writeDataPoint: vi.fn(),
} as CFAnalyticsEngine,
} as Environment;
} as AnalyticsEngineDataset,
} as Env;

// intentionally set system time as 00:15:00
// if the user last visited ~30 minutes ago, that occurred during
Expand Down Expand Up @@ -164,8 +164,8 @@ describe("collectRequestHandler", () => {
const env = {
WEB_COUNTER_AE: {
writeDataPoint: vi.fn(),
} as CFAnalyticsEngine,
} as Environment;
} as AnalyticsEngineDataset,
} as Env;

const request = httpMocks.createRequest(
// @ts-expect-error - we're mocking the request object
Expand All @@ -192,8 +192,8 @@ describe("collectRequestHandler", () => {
const env = {
WEB_COUNTER_AE: {
writeDataPoint: vi.fn(),
} as CFAnalyticsEngine,
} as Environment;
} as AnalyticsEngineDataset,
} as Env;

const request = httpMocks.createRequest(
// @ts-expect-error - we're mocking the request object
Expand Down
4 changes: 2 additions & 2 deletions app/analytics/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function extractParamsFromQueryString(requestUrl: string): {
return params;
}

export function collectRequestHandler(request: Request, env: Environment) {
export function collectRequestHandler(request: Request, env: Env) {
const params = extractParamsFromQueryString(request.url);

const userAgent = request.headers.get("user-agent") || undefined;
Expand Down Expand Up @@ -130,7 +130,7 @@ interface DataPoint {
// More here: https://developers.cloudflare.com/analytics/analytics-engine/get-started/#limits

export function writeDataPoint(
analyticsEngine: CFAnalyticsEngine,
analyticsEngine: AnalyticsEngineDataset,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think generally speaking, this change isn't really related to migrating to vite, and more of a separate personal choice that's been inserted (same with renaming Environment to Env).

I'll keep it (it's more clear I suppose) but generally it's best to not to couple these changes.

Copy link
Contributor Author

@BhanuNexus BhanuNexus Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, this AnalyticsEngineDataset type is directly from @cloudflare/workers-types
So, syntaxes and change tracking are aligned with CF.

Regarding Env, I personally prefer Environment whatever you have set but cloudflare auto generates types from wrangler.toml to worker-configuration.d.ts by using wrangler types, that is the reason I have removed Environment and reused Env from worker-configuration.d.ts

data: DataPoint,
) {
const datapoint = {
Expand Down
2 changes: 1 addition & 1 deletion app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import type { AppLoadContext, EntryContext } from "@remix-run/cloudflare";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { isbot } from "isbot";
import { renderToReadableStream } from "react-dom/server";

export default async function handleRequest(
Expand Down
54 changes: 41 additions & 13 deletions app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
import styles from "./globals.css";
import styles from "./globals.css?url";
import {
json,
LoaderFunctionArgs,
type LinksFunction,
} from "@remix-run/cloudflare";
import { cssBundleHref } from "@remix-run/css-bundle";

import {
isRouteErrorResponse,
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
useLoaderData,
useRouteError,
useRouteLoaderData,
} from "@remix-run/react";

export const links: LinksFunction = () => [
{ rel: "stylesheet", href: styles },
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
];
export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }];

export const loader = ({ context, request }: LoaderFunctionArgs) => {
const url = new URL(request.url);
return json({
version: context.env.VERSION,
version: context.cloudflare.env.CF_PAGES_COMMIT_SHA,
origin: url.origin,
url: request.url,
});
};

export default function App() {
const data = useLoaderData<typeof loader>();
export const Layout = ({ children }: { children: React.ReactNode }) => {
const data = useRouteLoaderData<typeof loader>("root") ?? {
version: "unknown",
origin: "counterscale.dev",
url: "https://counterscale.dev/",
};
// const error = useRouteError();

return (
<html lang="en">
Expand Down Expand Up @@ -111,7 +114,7 @@ export default function App() {
</nav>
</header>
<main role="main" className="w-full">
<Outlet />
{children}
</main>

<footer className="py-4 flex justify-end text-s">
Expand All @@ -127,7 +130,6 @@ export default function App() {
</div>
<ScrollRestoration />
<Scripts />
<LiveReload />
<script
dangerouslySetInnerHTML={{
__html: "window.counterscale = {'q': [['set', 'siteId', 'counterscale-dev'], ['trackPageview']] };",
Expand All @@ -137,4 +139,30 @@ export default function App() {
</body>
</html>
);
};

export default function App() {
return <Outlet />;
}

export const ErrorBoundary = () => {
const error = useRouteError();

if (isRouteErrorResponse(error)) {
return (
<>
<h1>
{error.status} {error.statusText}
</h1>
<p>{error.data}</p>
</>
);
}

return (
<>
<h1>Error!</h1>
<p>{(error as { message?: string })?.message ?? "Unknown error"}</p>
</>
);
};
2 changes: 1 addition & 1 deletion app/routes/admin-redirect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { LoaderFunctionArgs, redirect } from "@remix-run/cloudflare";

export const loader = async ({ context }: LoaderFunctionArgs) => {
return redirect(
`https://dash.cloudflare.com/${context.env.CF_ACCOUNT_ID}/workers/services/view/counterscale/production`,
`https://dash.cloudflare.com/${context.cloudflare.env.CF_ACCOUNT_ID}/workers/services/view/counterscale/production`,
);
};
6 changes: 6 additions & 0 deletions app/routes/collect-beta.tsx
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @benvinegar, I have previously added this endpoint to test movement of /collect from CF function to remix.

I have tested this with mine https://cs.usevega.com and seems to be working fine, do you want to have this change included with this PR or may be in later iteration?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BhanuNexus I started the v2 branch for this ongoing migration (here). I'd make a new PR targeting that.

I'm going to close this PR in the meantime.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { LoaderFunctionArgs } from "@remix-run/cloudflare";
import { collectRequestHandler } from "~/analytics/collect";

export async function loader({ request, context }: LoaderFunctionArgs) {
return collectRequestHandler(request, context.cloudflare.env);
}
53 changes: 33 additions & 20 deletions app/routes/dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ describe("Dashboard route", () => {
"testAccountId",
"testApiToken",
),
env: {
VERSION: "",
CF_BEARER_TOKEN: "",
CF_ACCOUNT_ID: "",
cloudflare: {
// @ts-expect-error we don't need to provide all the properties of the cloudflare object
env: {
CF_BEARER_TOKEN: "",
CF_ACCOUNT_ID: "",
},
},
},
// @ts-expect-error we don't need to provide all the properties of the request object
Expand All @@ -79,10 +81,13 @@ describe("Dashboard route", () => {
"testAccountId",
"testApiToken",
),
env: {
VERSION: "",
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
cloudflare: {
// @ts-expect-error we don't need to provide all the properties of the cloudflare object
env: {
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
},
cf: {} as any,
},
},
// @ts-expect-error we don't need to provide all the properties of the request object
Expand Down Expand Up @@ -112,10 +117,12 @@ describe("Dashboard route", () => {
"testAccountId",
"testApiToken",
),
env: {
VERSION: "",
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
cloudflare: {
// @ts-expect-error we don't need to provide all the properties of the cloudflare object
env: {
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
},
},
},
// @ts-expect-error we don't need to provide all the properties of the request object
Expand Down Expand Up @@ -165,10 +172,13 @@ describe("Dashboard route", () => {
"testAccountId",
"testApiToken",
),
env: {
VERSION: "",
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
cloudflare: {
// @ts-expect-error we don't need to provide all the properties of the cloudflare object
env: {
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
},
cf: {} as any,
},
},
// @ts-expect-error we don't need to provide all the properties of the request object
Expand Down Expand Up @@ -213,10 +223,13 @@ describe("Dashboard route", () => {
"testAccountId",
"testApiToken",
),
env: {
VERSION: "",
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
cloudflare: {
// @ts-expect-error we don't need to provide all the properties of the cloudflare object
env: {
CF_BEARER_TOKEN: "fake",
CF_ACCOUNT_ID: "fake",
},
cf: {} as any,
},
},
// @ts-expect-error we don't need to provide all the properties of the request object
Expand Down
26 changes: 7 additions & 19 deletions app/routes/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import {
useSearchParams,
} from "@remix-run/react";

import { AnalyticsEngineAPI } from "../analytics/query";

import { ReferrerCard } from "./resources.referrer";
import { PathsCard } from "./resources.paths";
import { BrowserCard } from "./resources.browser";
Expand All @@ -35,26 +33,16 @@ export const meta: MetaFunction = () => {

const MAX_RETENTION_DAYS = 90;

declare module "@remix-run/server-runtime" {
export interface AppLoadContext {
analyticsEngine: AnalyticsEngineAPI;
env: {
VERSION: string;
CF_BEARER_TOKEN: string;
CF_ACCOUNT_ID: string;
};
}
}

export const loader = async ({ context, request }: LoaderFunctionArgs) => {
if (!context.env.CF_BEARER_TOKEN || !context.env.CF_ACCOUNT_ID) {
// NOTE: probably duped from getLoadContext / need to de-duplicate
if (
!context.cloudflare.env.CF_BEARER_TOKEN ||
!context.cloudflare.env.CF_ACCOUNT_ID
) {
throw new Error("Missing Cloudflare credentials");
}

const analyticsEngine = new AnalyticsEngineAPI(
context.env.CF_ACCOUNT_ID,
context.env.CF_BEARER_TOKEN,
);
const { analyticsEngine } = context;

const url = new URL(request.url);

Expand All @@ -81,7 +69,7 @@ export const loader = async ({ context, request }: LoaderFunctionArgs) => {
const siteId = url.searchParams.get("site") || "";
const actualSiteId = siteId == "@unknown" ? "" : siteId;

const tz = context.requestTimezone as string;
const tz = context.cloudflare.cf.timezone as string;

// initiate requests to AE in parallel

Expand Down
2 changes: 1 addition & 1 deletion app/routes/resources.browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) {
const { analyticsEngine } = context;

const { interval, site, page = 1 } = paramsFromUrl(request.url);
const tz = context.requestTimezone as string;
const tz = context.cloudflare.cf.timezone as string;

return json({
countsByProperty: await analyticsEngine.getCountByBrowser(
Expand Down
2 changes: 1 addition & 1 deletion app/routes/resources.country.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) {
const { analyticsEngine } = context;

const { interval, site, page = 1 } = paramsFromUrl(request.url);
const tz = context.requestTimezone as string;
const tz = context.cloudflare.cf.timezone as string;

const countByCountry = await analyticsEngine.getCountByCountry(
site,
Expand Down
2 changes: 1 addition & 1 deletion app/routes/resources.device.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) {
const { analyticsEngine } = context;

const { interval, site, page = 1 } = paramsFromUrl(request.url);
const tz = context.requestTimezone as string;
const tz = context.cloudflare.cf.timezone as string;

return json({
countsByProperty: await analyticsEngine.getCountByDevice(
Expand Down
2 changes: 1 addition & 1 deletion app/routes/resources.paths.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) {
const { analyticsEngine } = context;

const { interval, site, page = 1 } = paramsFromUrl(request.url);
const tz = context.requestTimezone as string;
const tz = context.cloudflare.cf.timezone as string;

return json({
countsByProperty: await analyticsEngine.getCountByPath(
Expand Down
2 changes: 1 addition & 1 deletion app/routes/resources.referrer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) {
const { analyticsEngine } = context;

const { interval, site, page = 1 } = paramsFromUrl(request.url);
const tz = context.requestTimezone as string;
const tz = context.cloudflare.cf.timezone as string;

return json({
countsByProperty: await analyticsEngine.getCountByReferrer(
Expand Down
2 changes: 2 additions & 0 deletions env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="@remix-run/cloudflare" />
/// <reference types="vite/client" />
Loading