Skip to main content

.client modules

还没翻译译自英文(reactrouter.com)本页 16 段都还没译

.client modules

Framework

Summary

You may have a file or dependency that uses module side effects in the browser. You can use *.client.ts on file names or nest files within .client directories to force them out of server bundles.

feature-check.client.ts
// this would break the server
export const supportsVibrationAPI =
  "vibrate" in window.navigator;

Note that values exported from this module will all be undefined on the server, so the only places to use them are in useEffect and user events like click handlers.

import { supportsVibrationAPI } from "./feature-check.client.ts";

console.log(supportsVibrationAPI);
// server: undefined
// client: true | false

Info

If you need more sophisticated control over what is included in the client/server bundles, check out the vite-env-only plugin.

Usage Patterns

Individual Files

Mark individual files as client-only by adding .client to the filename:

app/
├── utils.client.ts        👈 client-only file
├── feature-detection.client.ts
└── root.tsx

Client Directories

Mark entire directories as client-only by using .client in the directory name:

app/
├── .client/               👈 entire directory is client-only
│   ├── analytics.ts
│   ├── feature-detection.ts
│   └── browser-utils.ts
├── components/
└── root.tsx

Examples

Browser Feature Detection

app/utils/browser.client.ts
export const canUseDOM = typeof window !== "undefined";

export const hasWebGL = !!window.WebGLRenderingContext;

export const supportsVibrationAPI =
  "vibrate" in window.navigator;

Client-Only Libraries

app/analytics.client.ts
// This would break on the server
import { track } from "some-browser-only-analytics-lib";

export function trackEvent(eventName: string, data: any) {
  track(eventName, data);
}

Using Client Modules

app/routes/dashboard.tsx
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>;
}