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:
| Environment | import.meta.client | IS_CLIENT |
|---|---|---|
| Browser build | true (vite static replacement + DCE) | true |
| Server build | false | false |
| vitest 4.x | undefined (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
| Flag | Replaceable by IS_CLIENT? | Reason |
|---|---|---|
import.meta.client | ✅ | IS_CLIENT is its unit-testable equivalent |
import.meta.server | ❌ keep | Bound to Nitro SSR semantics; typeof window is equivalent but subtly different (server contexts may polyfill window) |
import.meta.dev | ❌ must keep | It 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, neverimport.meta.client— the latter isundefinedunder vitest 4.x (vite's define injection doesn't apply with the Rolldown backend), which makes everyif (!import.meta.client) returnin the runtime always take the bail-out path — the main branches ofuseTheme/useModal/useAddToHomescreenand friends become untestable. This helper checks bothtypeof windowandtypeof document:trueunder happy-dom and real browsers,falseunder 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.devalong with it —import.meta.serveris bound to Nitro's SSR semantics (subtly different fromtypeof window), andimport.meta.devis a build-time DCE flag; swapping it for a runtime helper stops prod builds from stripping dev-only code.