嵌入式分析 SDK - 将 SDK 与 Next.js 结合使用
⚠️ 此功能为 Beta 版。欢迎试用,但请注意,功能可能会发生变化(并且可能无法按预期工作)。
嵌入式分析 SDK 仅在 Pro 和 Enterprise 计划(自托管和 Metabase 云)中可用。但是,您可以在本地计算机上使用 API 密钥进行身份验证,无需许可证即可试用 SDK。
关于将嵌入式分析 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>
);
};
接下来,将一个 index.tsx
文件添加到该 metabase
目录。此文件将包含 use client
指令,并且它将导出 EmbeddingSdkProvider
的禁用 SSR 的延迟加载版本。
"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
});
阅读其他Metabase 版本的文档。