Skip to content

Commit

Permalink
fix: next/jest does not support import.meta (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
feugy authored Nov 25, 2024
1 parent bb3d518 commit a6d59c6
Show file tree
Hide file tree
Showing 22 changed files with 244 additions and 115 deletions.
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vercel/analytics",
"version": "1.5.0-canary.2",
"version": "1.5.0-canary.3",
"description": "Gain real-time traffic insights with Vercel Web Analytics",
"keywords": [
"analytics",
Expand Down
14 changes: 14 additions & 0 deletions packages/web/src/astro/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ const paramsStr = JSON.stringify(Astro.params);
<script>
import { inject, pageview, computeRoute } from '../index.mjs';

function getBasePath(): string | undefined {
// !! important !!
// do not access env variables using import.meta.env[varname]
// some bundles won't replace the value at build time.
try {
return import.meta.env.PUBLIC_VERCEL_OBSERVABILITY_BASEPATH as
| string
| undefined;
} catch {
// do nothing
}
}

customElements.define(
'vercel-analytics',
class VercelAnalytics extends HTMLElement {
Expand All @@ -27,6 +40,7 @@ const paramsStr = JSON.stringify(Astro.params);
...props,
disableAutoTrack: true,
framework: 'astro',
basePath: getBasePath(),
beforeSend: window.webAnalyticsBeforeSend,
});
const path = this.dataset.pathname;
Expand Down
7 changes: 3 additions & 4 deletions packages/web/src/generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
isDevelopment,
isProduction,
computeRoute,
getBasePath,
getScriptSrc,
} from './utils';

Expand All @@ -34,6 +33,7 @@ function inject(
props: AnalyticsProps & {
framework?: string;
disableAutoTrack?: boolean;
basePath?: string;
} = {
debug: true,
}
Expand Down Expand Up @@ -62,11 +62,10 @@ function inject(
if (props.disableAutoTrack) {
script.dataset.disableAutoTrack = '1';
}
const basePath = getBasePath();
if (props.endpoint) {
script.dataset.endpoint = props.endpoint;
} else if (basePath) {
script.dataset.endpoint = `${basePath}/insights`;
} else if (props.basePath) {
script.dataset.endpoint = `${props.basePath}/insights`;
}
if (props.dsn) {
script.dataset.dsn = props.dsn;
Expand Down
10 changes: 8 additions & 2 deletions packages/web/src/nextjs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@
import React, { Suspense, type ReactNode } from 'react';
import { Analytics as AnalyticsScript } from '../react';
import type { AnalyticsProps, BeforeSend, BeforeSendEvent } from '../types';
import { useRoute } from './utils';
import { getBasePath, useRoute } from './utils';

type Props = Omit<AnalyticsProps, 'route' | 'disableAutoTrack'>;

function AnalyticsComponent(props: Props): ReactNode {
const { route, path } = useRoute();
return (
<AnalyticsScript path={path} route={route} {...props} framework="next" />
<AnalyticsScript
path={path}
route={route}
{...props}
basePath={getBasePath()}
framework="next"
/>
);
}

Expand Down
30 changes: 30 additions & 0 deletions packages/web/src/nextjs/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { afterEach, describe, it, expect } from 'vitest';
import { getBasePath } from './utils';

describe('getBasePath()', () => {
const processSave = { ...process };
const envSave = { ...process.env };

afterEach(() => {
global.process = { ...processSave };
process.env = { ...envSave };
});

it('returns null without process', () => {
// @ts-expect-error -- yes, we want to completely drop process for this test!!
global.process = undefined;
expect(getBasePath()).toBeUndefined();
});

it('returns null without process.env', () => {
// @ts-expect-error -- yes, we want to completely drop process.env for this test!!
process.env = undefined;
expect(getBasePath()).toBeUndefined();
});

it('returns basepath set for Nextjs', () => {
const basepath = `/_vercel-${Math.random()}/insights`;
process.env.NEXT_PUBLIC_VERCEL_OBSERVABILITY_BASEPATH = basepath;
expect(getBasePath()).toBe(basepath);
});
});
11 changes: 11 additions & 0 deletions packages/web/src/nextjs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,14 @@ export const useRoute = (): {
: Object.fromEntries(searchParams.entries());
return { route: computeRoute(path, finalParams), path };
};

export function getBasePath(): string | undefined {
// !! important !!
// do not access env variables using process.env[varname]
// some bundles won't replace the value at build time.
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- we can't use optionnal here, it'll break if process does not exist.
if (typeof process === 'undefined' || typeof process.env === 'undefined') {
return undefined;
}
return process.env.NEXT_PUBLIC_VERCEL_OBSERVABILITY_BASEPATH;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import { afterEach, beforeEach, describe, it, expect } from 'vitest';
import { cleanup, render } from '@testing-library/react';
import { Analytics, track } from './react';
import type { AllowedPropertyValues, AnalyticsProps, Mode } from './types';
import type { AllowedPropertyValues, AnalyticsProps, Mode } from '../types';
import { Analytics, track } from './index';

describe('<Analytics />', () => {
afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use client';
import { useEffect } from 'react';
import { inject, track, pageview } from './generic';
import type { AnalyticsProps, BeforeSend, BeforeSendEvent } from './types';
import { inject, track, pageview } from '../generic';
import type { AnalyticsProps, BeforeSend, BeforeSendEvent } from '../types';
import { getBasePath } from './utils';

/**
* Injects the Vercel Web Analytics script into the page head and starts tracking page views. Read more in our [documentation](https://vercel.com/docs/concepts/analytics/package).
Expand Down Expand Up @@ -31,6 +32,7 @@ function Analytics(
framework?: string;
route?: string | null;
path?: string | null;
basePath?: string;
}
): null {
useEffect(() => {
Expand All @@ -43,6 +45,7 @@ function Analytics(
useEffect(() => {
inject({
framework: props.framework || 'react',
basePath: props.basePath ?? getBasePath(),
...(props.route !== undefined && { disableAutoTrack: true }),
...props,
});
Expand Down
30 changes: 30 additions & 0 deletions packages/web/src/react/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { afterEach, describe, it, expect } from 'vitest';
import { getBasePath } from './utils';

describe('getBasePath()', () => {
const processSave = { ...process };
const envSave = { ...process.env };

afterEach(() => {
global.process = { ...processSave };
process.env = { ...envSave };
});

it('returns null without process', () => {
// @ts-expect-error -- yes, we want to completely drop process for this test!!
global.process = undefined;
expect(getBasePath()).toBeUndefined();
});

it('returns null without process.env', () => {
// @ts-expect-error -- yes, we want to completely drop process.env for this test!!
process.env = undefined;
expect(getBasePath()).toBeUndefined();
});

it('returns basepath set for CRA', () => {
const basepath = `/_vercel-${Math.random()}/insights`;
process.env.REACT_APP_VERCEL_OBSERVABILITY_BASEPATH = basepath;
expect(getBasePath()).toBe(basepath);
});
});
10 changes: 10 additions & 0 deletions packages/web/src/react/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function getBasePath(): string | undefined {
// !! important !!
// do not access env variables using process.env[varname]
// some bundles won't replace the value at build time.
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- we can't use optionnal here, it'll break if process does not exist.
if (typeof process === 'undefined' || typeof process.env === 'undefined') {
return undefined;
}
return process.env.REACT_APP_VERCEL_OBSERVABILITY_BASEPATH;
}
11 changes: 9 additions & 2 deletions packages/web/src/remix/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import React from 'react';
import { Analytics as AnalyticsScript } from '../react';
import type { AnalyticsProps, BeforeSend, BeforeSendEvent } from '../types';
import { useRoute } from './utils';
import { getBasePath, useRoute } from './utils';

export function Analytics(props: Omit<AnalyticsProps, 'route'>): JSX.Element {
return <AnalyticsScript {...useRoute()} {...props} framework="remix" />;
return (
<AnalyticsScript
{...useRoute()}
{...props}
basePath={getBasePath()}
framework="remix"
/>
);
}
export type { AnalyticsProps, BeforeSend, BeforeSendEvent };
24 changes: 24 additions & 0 deletions packages/web/src/remix/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { afterEach, describe, it, expect } from 'vitest';
import { getBasePath } from './utils';

describe('getBasePath()', () => {
const processSave = { ...process };
const envSave = { ...process.env };

afterEach(() => {
global.process = { ...processSave };
process.env = { ...envSave };
});

it('returns basepath set for Remix', () => {
const basepath = `/_vercel-${Math.random()}/insights`;
import.meta.env.VITE_VERCEL_OBSERVABILITY_BASEPATH = basepath;
expect(getBasePath()).toBe(basepath);
});

it('returns null without import.meta', () => {
// @ts-expect-error -- yes, we want to completely drop import.meta.env for this test!!
import.meta.env = undefined;
expect(getBasePath()).toBeUndefined();
});
});
13 changes: 13 additions & 0 deletions packages/web/src/remix/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,16 @@ export const useRoute = (): { route: string | null; path: string } => {
const { pathname: path } = useLocation();
return { route: computeRoute(path, params as never), path };
};

export function getBasePath(): string | undefined {
// !! important !!
// do not access env variables using import.meta.env[varname]
// some bundles won't replace the value at build time.
try {
return import.meta.env.VITE_VERCEL_OBSERVABILITY_BASEPATH as
| string
| undefined;
} catch {
// do nothing
}
}
2 changes: 2 additions & 0 deletions packages/web/src/sveltekit/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { inject, pageview, track } from '../generic';
import type { AnalyticsProps, BeforeSend, BeforeSendEvent } from '../types';
import { getBasePath } from './utils';
import { page } from '$app/stores';
import { browser } from '$app/environment';
import type {} from '@sveltejs/kit';
Expand All @@ -8,6 +9,7 @@ function injectAnalytics(props: Omit<AnalyticsProps, 'framework'> = {}): void {
if (browser) {
inject({
...props,
basePath: getBasePath(),
disableAutoTrack: true,
framework: 'sveltekit',
});
Expand Down
24 changes: 24 additions & 0 deletions packages/web/src/sveltekit/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { afterEach, describe, it, expect } from 'vitest';
import { getBasePath } from './utils';

describe('getBasePath()', () => {
const processSave = { ...process };
const envSave = { ...process.env };

afterEach(() => {
global.process = { ...processSave };
process.env = { ...envSave };
});

it('returns basepath set for Sveltekit', () => {
const basepath = `/_vercel-${Math.random()}/insights`;
import.meta.env.VITE_VERCEL_OBSERVABILITY_BASEPATH = basepath;
expect(getBasePath()).toBe(basepath);
});

it('returns null without import.meta', () => {
// @ts-expect-error -- yes, we want to completely drop import.meta.env for this test!!
import.meta.env = undefined;
expect(getBasePath()).toBeUndefined();
});
});
12 changes: 12 additions & 0 deletions packages/web/src/sveltekit/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function getBasePath(): string | undefined {
// !! important !!
// do not access env variables using import.meta.env[varname]
// some bundles won't replace the value at build time.
try {
return import.meta.env.VITE_VERCEL_OBSERVABILITY_BASEPATH as
| string
| undefined;
} catch {
// do nothing
}
}
Loading

0 comments on commit a6d59c6

Please sign in to comment.