working version with pages router
This commit is contained in:
parent
f4edab87af
commit
c3b93e592a
13 changed files with 193 additions and 3 deletions
|
@ -5,7 +5,7 @@ export default async function Home() {
|
||||||
await trackEvent('page_view', { page: 'home' });
|
await trackEvent('page_view', { page: 'home' });
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
Hello from Next.js App Router <br /> <Counter />
|
Aptabase + Next.js App Router <br /> <Counter />
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
5
examples/next-with-pages/next-env.d.ts
vendored
Normal file
5
examples/next-with-pages/next-env.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
9
examples/next-with-pages/next.config.js
Normal file
9
examples/next-with-pages/next.config.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
reactStrictMode: true,
|
||||||
|
experimental: {
|
||||||
|
instrumentationHook: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = nextConfig;
|
21
examples/next-with-pages/package.json
Normal file
21
examples/next-with-pages/package.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "next-with-pages",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev -p 4000",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "next lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "20.5.7",
|
||||||
|
"@types/react": "18.2.21",
|
||||||
|
"@types/react-dom": "18.2.7",
|
||||||
|
"next": "13.4.19",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"react-dom": "18.2.0",
|
||||||
|
"typescript": "5.2.2",
|
||||||
|
"@aptabase/nextjs": "*"
|
||||||
|
}
|
||||||
|
}
|
25
examples/next-with-pages/src/components/Counter.tsx
Normal file
25
examples/next-with-pages/src/components/Counter.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { useAptabase } from '@aptabase/nextjs';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
export function Counter() {
|
||||||
|
const { trackEvent } = useAptabase();
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
setCount((c) => c + 1);
|
||||||
|
trackEvent('increment');
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
setCount((c) => c - 1);
|
||||||
|
trackEvent('decrement');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Count: {count}</p>
|
||||||
|
<button onClick={increment}>Increment</button>
|
||||||
|
<button onClick={decrement}>Decrement</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
5
examples/next-with-pages/src/instrumentation.ts
Normal file
5
examples/next-with-pages/src/instrumentation.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { init } from '@aptabase/nextjs';
|
||||||
|
|
||||||
|
export function register() {
|
||||||
|
init('A-DEV-0000000000');
|
||||||
|
}
|
10
examples/next-with-pages/src/pages/_app.tsx
Normal file
10
examples/next-with-pages/src/pages/_app.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { AptabaseProvider } from '@aptabase/nextjs';
|
||||||
|
import type { AppProps } from 'next/app';
|
||||||
|
|
||||||
|
export default function App({ Component, pageProps }: AppProps) {
|
||||||
|
return (
|
||||||
|
<AptabaseProvider appKey="A-DEV-0000000000">
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</AptabaseProvider>
|
||||||
|
);
|
||||||
|
}
|
13
examples/next-with-pages/src/pages/_document.tsx
Normal file
13
examples/next-with-pages/src/pages/_document.tsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { Html, Head, Main, NextScript } from 'next/document'
|
||||||
|
|
||||||
|
export default function Document() {
|
||||||
|
return (
|
||||||
|
<Html lang="en">
|
||||||
|
<Head />
|
||||||
|
<body>
|
||||||
|
<Main />
|
||||||
|
<NextScript />
|
||||||
|
</body>
|
||||||
|
</Html>
|
||||||
|
)
|
||||||
|
}
|
12
examples/next-with-pages/src/pages/api/hello.ts
Normal file
12
examples/next-with-pages/src/pages/api/hello.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||||
|
import { trackEvent } from '@aptabase/nextjs/server';
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<Data>) {
|
||||||
|
await trackEvent('hello', { name: 'John Doe' }, req);
|
||||||
|
res.status(200).json({ name: 'John Doe' });
|
||||||
|
}
|
25
examples/next-with-pages/src/pages/index.tsx
Normal file
25
examples/next-with-pages/src/pages/index.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { Counter } from '@/components/Counter';
|
||||||
|
import { trackEvent } from '@aptabase/nextjs/server';
|
||||||
|
import { GetServerSideProps } from 'next';
|
||||||
|
import Head from 'next/head';
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
||||||
|
await trackEvent('page_view', { page: 'home' }, req);
|
||||||
|
return { props: {} };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>Create Next App</title>
|
||||||
|
<meta name="description" content="Generated by create next app" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
</Head>
|
||||||
|
<main>
|
||||||
|
Aptabase + Next.js Pages Router <br />
|
||||||
|
<Counter />
|
||||||
|
</main>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
22
examples/next-with-pages/tsconfig.json
Normal file
22
examples/next-with-pages/tsconfig.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
17
package-lock.json
generated
17
package-lock.json
generated
|
@ -33,6 +33,19 @@
|
||||||
"typescript": "5.2.2"
|
"typescript": "5.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"examples/next-with-pages": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@aptabase/nextjs": "*",
|
||||||
|
"@types/node": "20.5.7",
|
||||||
|
"@types/react": "18.2.21",
|
||||||
|
"@types/react-dom": "18.2.7",
|
||||||
|
"next": "13.4.19",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"react-dom": "18.2.0",
|
||||||
|
"typescript": "5.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@aptabase/nextjs": {
|
"node_modules/@aptabase/nextjs": {
|
||||||
"resolved": "packages/nextjs",
|
"resolved": "packages/nextjs",
|
||||||
"link": true
|
"link": true
|
||||||
|
@ -590,6 +603,10 @@
|
||||||
"resolved": "examples/next-with-approuter",
|
"resolved": "examples/next-with-approuter",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/next-with-pages": {
|
||||||
|
"resolved": "examples/next-with-pages",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
|
import { type NextIncomingMessage } from 'next/dist/server/request-meta';
|
||||||
import { headers } from 'next/headers';
|
import { headers } from 'next/headers';
|
||||||
|
|
||||||
export async function trackEvent(eventName: string, props?: Record<string, string | number | boolean>): Promise<void> {
|
export async function trackEvent(
|
||||||
|
eventName: string,
|
||||||
|
props?: Record<string, string | number | boolean>,
|
||||||
|
req?: NextIncomingMessage,
|
||||||
|
): Promise<void> {
|
||||||
const appKey = globalThis.__APTABASE__.appKey;
|
const appKey = globalThis.__APTABASE__.appKey;
|
||||||
if (!appKey) return Promise.resolve();
|
if (!appKey) return Promise.resolve();
|
||||||
|
|
||||||
|
const userAgent = getUserAgent(req);
|
||||||
|
if (!userAgent) return Promise.resolve();
|
||||||
|
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
sessionId: 'CHANGE-THIS',
|
sessionId: 'CHANGE-THIS',
|
||||||
|
@ -21,7 +29,7 @@ export async function trackEvent(eventName: string, props?: Record<string, strin
|
||||||
const response = await fetch('http://localhost:3000/api/v0/event', {
|
const response = await fetch('http://localhost:3000/api/v0/event', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': headers().get('User-Agent') ?? '',
|
'User-Agent': userAgent,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'App-Key': appKey,
|
'App-Key': appKey,
|
||||||
},
|
},
|
||||||
|
@ -37,3 +45,21 @@ export async function trackEvent(eventName: string, props?: Record<string, strin
|
||||||
console.warn(`Failed to send event "${eventName}": ${e}`);
|
console.warn(`Failed to send event "${eventName}": ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUserAgent(req?: NextIncomingMessage): string | undefined {
|
||||||
|
if (req) {
|
||||||
|
return req.headers['user-agent'] ?? 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
// headers() might throw an error if called outside of a request context.
|
||||||
|
try {
|
||||||
|
return headers().get('User-Agent') ?? 'Unknown';
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
// If we're here, we're probably using the Pages Router and the user forgot to pass the req parameter.
|
||||||
|
if (!req) {
|
||||||
|
console.warn("Aptabase: The 'req' parameter of trackEvent is required when using Pages Router.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue