.client
模块您可能有一个文件或依赖项在浏览器中使用了模块副作用。您可以在文件名上使用 *.client.ts
或将文件嵌套在 .client
目录中,以强制将它们从服务器捆绑包中移除。
// this would break the server
export const supportsVibrationAPI =
"vibrate" in window.navigator;
请注意,从此模块导出的值在服务器上都将是 undefined
,因此唯一可以使用它们的地方是在 useEffect
和用户事件(如点击处理程序)中。
import { supportsVibrationAPI } from "./feature-check.client.ts";
console.log(supportsVibrationAPI);
// server: undefined
// client: true | false
如果您需要对客户端/服务器捆绑包中包含的内容进行更复杂的控制,请查看 vite-env-only
插件。
通过在文件名中添加 .client
将单个文件标记为仅客户端
app/
├── utils.client.ts 👈 client-only file
├── feature-detection.client.ts
└── root.tsx
通过在目录名中使用 .client
将整个目录标记为仅客户端
app/
├── .client/ 👈 entire directory is client-only
│ ├── analytics.ts
│ ├── feature-detection.ts
│ └── browser-utils.ts
├── components/
└── root.tsx
export const canUseDOM = typeof window !== "undefined";
export const hasWebGL = !!window.WebGLRenderingContext;
export const supportsVibrationAPI =
"vibrate" in window.navigator;
// This would break on the server
import { track } from "some-browser-only-analytics-lib";
export function trackEvent(eventName: string, data: any) {
track(eventName, data);
}
import { useEffect } from "react";
import {
canUseDOM,
supportsLocalStorage,
supportsVibrationAPI,
} from "../utils/browser.client.ts";
import { trackEvent } from "../analytics.client.ts";
export default function Dashboard() {
useEffect(() => {
// These values are undefined on the server
if (canUseDOM && supportsVibrationAPI) {
console.log("Device supports vibration");
}
// Safe localStorage usage
const savedTheme =
supportsLocalStorage.getItem("theme");
if (savedTheme) {
document.body.className = savedTheme;
}
trackEvent("dashboard_viewed", {
timestamp: Date.now(),
});
}, []);
return <div>Dashboard</div>;
}