嵌入式分析 SDK - 將 SDK 與 Next.js 搭配使用
⚠️ 此功能為 Beta 版。歡迎隨意試用,但請注意,內容可能會變更 (且可能無法如預期般運作)。
關於將嵌入式分析 SDK 與 Next.js 搭配使用的一些注意事項。SDK 經測試可在 Next.js 14 上運作,但也可能適用於其他版本。
具有伺服器端渲染 (SSR) 或 React 伺服器元件的 SDK 元件
目前,SDK 元件僅支援用戶端渲染。若要將 SDK 元件與伺服器端渲染或 React 伺服器元件搭配使用,您可以選擇使用相容性層或手動包裝元件。
伺服器端渲染 (SSR) 的相容性層 (實驗性)
若要將 SDK 元件與 Next.js 搭配使用,SDK 提供了一個實驗性相容性層,可使用動態匯入包裝所有元件並停用 SSR。為了與應用程式路由器搭配運作,此相容性層使用 use client
。
若要使用相容性層,請將您的匯入從 @metabase/embedding-sdk-react
變更為 @metabase/embedding-sdk-react/nextjs
。
手動包裝元件
如果您想要自訂元件的載入方式,您可以建立自己的包裝函式。
在您的應用程式中,建立一個 metabase
目錄,並在該目錄中新增一個 EmbeddingSdkProvider.tsx
檔案。此檔案將包含具有適當設定的提供者。
"use client";
import {
defineMetabaseAuthConfig,
MetabaseProvider,
} from "@metabase/embedding-sdk-react";
const authConfig = defineMetabaseAuthConfig({
metabaseInstanceUrl: process.env.NEXT_PUBLIC_METABASE_INSTANCE_URL,
authProviderUri: process.env.NEXT_PUBLIC_METABASE_AUTH_PROVIDER_URI,
});
export const EmbeddingSdkProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
return (
<MetabaseProvider authConfig={authConfig}>{children}</MetabaseProvider>
);
};
接下來,在該 metabase
目錄中新增一個 index.tsx
檔案。此檔案將包含 use client
指令,並且將匯出已停用 SSR 的 EmbeddingSdkProvider
延遲載入版本。
"use client";
import dynamic from "next/dynamic";
import React from "react";
// Lazy load the EmbeddingSdkProvider so and let it render children while it's being loaded
export const EmbeddingSdkProviderLazy = ({
children,
}: {
children: React.ReactNode;
}) => {
const EmbeddingSdkProvider = dynamic(
() =>
import("./EmbeddingSdkProvider").then(m => {
return { default: m.EmbeddingSdkProvider };
}),
{
ssr: false,
loading: () => {
// render children while loading
return <div>{children}</div>;
},
},
);
return <EmbeddingSdkProvider>{children}</EmbeddingSdkProvider>;
};
// Wrap all components that you need like this:
export const StaticQuestion = dynamic(
() => import("@metabase/embedding-sdk-react").then(m => m.StaticQuestion),
{
ssr: false,
loading: () => {
return <div>Loading...</div>;
},
},
);
export const StaticDashboard = dynamic(
() => import("@metabase/embedding-sdk-react").then(m => m.StaticDashboard),
{
ssr: false,
loading: () => {
return <div>Loading...</div>;
},
},
);
您現在可以像這樣匯入元件
import { StaticQuestion } from "@/metabase"; // path to the folder created earlier
export default function Home() {
return <StaticQuestion questionId={123} />;
}
處理身份驗證
應用程式路由器和頁面路由器定義 API 路由的方式不同。如果您想使用 JWT 從伺服器驗證使用者,您可以按照以下指示操作。但如果您想使用 API 金鑰進行本機開發驗證,請參閱「使用 API 金鑰在本機進行驗證」。
使用應用程式路由器
您可以建立一個路由處理程式,讓使用者登入 Metabase。
在您的 app/*
目錄中建立一個新的 route.ts
檔案,例如 app/sso/metabase/route.ts
,對應於 /sso/metabase 的端點。
import jwt from "jsonwebtoken";
const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET || "";
const METABASE_INSTANCE_URL = process.env.METABASE_INSTANCE_URL || "";
export async function GET() {
const token = jwt.sign(
{
email: user.email,
first_name: user.firstName,
last_name: user.lastName,
groups: [user.group],
exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes expiration
},
// This is the JWT signing secret in your Metabase JWT authentication setting
METABASE_JWT_SHARED_SECRET,
);
const ssoUrl = `${METABASE_INSTANCE_URL}/auth/sso?token=true&jwt=${token}`;
try {
const ssoResponse = await fetch(ssoUrl, { method: "GET" });
const ssoResponseBody = await ssoResponse.json();
return Response.json(ssoResponseBody);
} catch (error) {
if (error instanceof Error) {
return Response.json(
{
status: "error",
message: "authentication failed",
error: error.message,
},
{
status: 401,
},
);
}
}
}
然後,將此 authConfig
傳遞給 MetabaseProvider
import { defineMetabaseAuthConfig } from "@metabase/embedding-sdk-react";
const authConfig = defineMetabaseAuthConfig({
metabaseInstanceUrl: "https://metabase.example.com", // Required: Your Metabase instance URL
authProviderUri: "/sso/metabase", // Required: An endpoint in your app that signs the user in and returns a session
});
使用頁面路由器
您可以建立一個 API 路由,讓使用者登入 Metabase。
在您的 pages/api/*
目錄中建立一個新的 metabase.ts
檔案,例如 pages/api/sso/metabase.ts
,對應於 /api/sso/metabase 的端點。
import type { NextApiRequest, NextApiResponse } from "next";
import jwt from "jsonwebtoken";
const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET || "";
const METABASE_INSTANCE_URL = process.env.METABASE_INSTANCE_URL || "";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const token = jwt.sign(
{
email: user.email,
first_name: user.firstName,
last_name: user.lastName,
groups: [user.group],
exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes expiration
},
// This is the JWT signing secret in your Metabase JWT authentication setting
METABASE_JWT_SHARED_SECRET,
);
const ssoUrl = `${METABASE_INSTANCE_URL}/auth/sso?token=true&jwt=${token}`;
try {
const ssoResponse = await fetch(ssoUrl, { method: "GET" });
const ssoResponseBody = await ssoResponse.json();
res.status(200).json(ssoResponseBody);
} catch (error) {
if (error instanceof Error) {
res.status(401).json({
status: "error",
message: "authentication failed",
error: error.message,
});
}
}
}
然後,將此 authConfig
傳遞給 MetabaseProvider
import { defineMetabaseAuthConfig } from "@metabase/embedding-sdk-react/nextjs";
const authConfig = defineMetabaseAuthConfig({
metabaseInstanceUrl: "https://metabase.example.com", // Required: Your Metabase instance URL
authProviderUri: "/api/sso/metabase", // Required: An endpoint in your app that signs the user in and returns a session
});
閱讀其他版本的說明文件。