IS_CLIENT

A client-environment flag whose value is typeof window !== 'undefined' && typeof document !== 'undefined'. The framework runtime uses it internally in place of import.meta.client; appliers may import and use it as well.

Why It Exists

Nuxt's injected import.meta.client behaves differently across three environments:

Environmentimport.meta.clientIS_CLIENT
Browser buildtrue (vite static replacement + DCE)true
Server buildfalsefalse
vitest 4.xundefined (vite define injection doesn't apply under the Rolldown backend)true (happy-dom has window)

Reading undefined under vitest makes every if (!import.meta.client) return guard permanently take the early-return path — composable main branches become impossible to unit-test. IS_CLIENT sidesteps this with a runtime typeof window check.

Example

SSR/CSR split visualized (before/after hydration)

加载中...
import { IS_CLIENT } from '@swift-web/framework'

if (IS_CLIENT) {
  // Client-only logic: window / localStorage / IndexedDB access etc.
  const plain = decryptBinary(buf, imgKey)
}

Both styles are fine in business code: Nuxt's official import.meta.client remains mainstream; switch to IS_CLIENT when your own composable unit tests hit the vitest 4.x define limitation.

Boundary with import.meta.server / import.meta.dev

FlagReplaceable by IS_CLIENT?Reason
import.meta.client✅IS_CLIENT is its unit-testable equivalent
import.meta.server❌ keepBound to Nitro SSR semantics; typeof window is equivalent but subtly different (server contexts may polyfill window)
import.meta.dev❌ must keepIt is a vite build-time DCE flag that lets prod builds strip dev-only code; a runtime check would break DCE

Caveats

  • Framework runtime code must use IS_CLIENT, never import.meta.client — the latter is undefined under vitest 4.x (vite's define injection doesn't apply with the Rolldown backend), which makes every if (!import.meta.client) return in the runtime always take the bail-out path — the main branches of useTheme / useModal / useAddToHomescreen and friends become untestable. This helper checks both typeof window and typeof document: true under happy-dom and real browsers, false under Node SSR.
  • Not pushed on appliers — application code can happily use Nuxt's official import.meta.client. Reach for this helper only when writing unit tests for your own composables and hitting the same vitest 4.x limitation (it's registered for auto-import).
  • Don't replace import.meta.server / import.meta.dev along with it — import.meta.server is bound to Nitro's SSR semantics (subtly different from typeof window), and import.meta.dev is a build-time DCE flag; swapping it for a runtime helper stops prod builds from stripping dev-only code.