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' });
|
||||
return (
|
||||
<main>
|
||||
Hello from Next.js App Router <br /> <Counter />
|
||||
Aptabase + Next.js App Router <br /> <Counter />
|
||||
</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"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"resolved": "packages/nextjs",
|
||||
"link": true
|
||||
|
@ -590,6 +603,10 @@
|
|||
"resolved": "examples/next-with-approuter",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/next-with-pages": {
|
||||
"resolved": "examples/next-with-pages",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"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';
|
||||
|
||||
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;
|
||||
if (!appKey) return Promise.resolve();
|
||||
|
||||
const userAgent = getUserAgent(req);
|
||||
if (!userAgent) return Promise.resolve();
|
||||
|
||||
const body = JSON.stringify({
|
||||
timestamp: new Date().toISOString(),
|
||||
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', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': headers().get('User-Agent') ?? '',
|
||||
'User-Agent': userAgent,
|
||||
'Content-Type': 'application/json',
|
||||
'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}`);
|
||||
}
|
||||
}
|
||||
|
||||
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