diff --git a/.github/scripts/bundle-size.js b/.github/scripts/bundle-size.js index 3366dbd6..16dcc5e2 100644 --- a/.github/scripts/bundle-size.js +++ b/.github/scripts/bundle-size.js @@ -163,7 +163,6 @@ async function measure(entryPoints, external = []) { write: false, outdir: '/tmp/bundle-size-out', external, - conditions: ['browser'], logLevel: 'silent', }); @@ -200,7 +199,6 @@ async function measureVirtual(code, resolveDir, external = []) { write: false, outdir: '/tmp/bundle-size-out', external, - conditions: ['browser'], logLevel: 'silent', }); @@ -215,17 +213,12 @@ async function measureVirtual(code, resolveDir, external = []) { } /** - * Resolve the browser production path from an export value. - * - * Prefers `browser.default` (browser prod bundle) over top-level `default` - * (server bundle) so we measure the code consumers actually ship. + * Resolve the `default` condition from an export value. + * Handles both `{ default: "./dist/..." }` objects and plain string values. */ function resolveDefault(exportValue) { if (typeof exportValue === 'string') return exportValue; if (typeof exportValue === 'object' && exportValue !== null) { - if (typeof exportValue.browser === 'object' && exportValue.browser !== null) { - return exportValue.browser.default ?? exportValue.default ?? null; - } return exportValue.default ?? null; } return null; diff --git a/.github/scripts/ssr-check.js b/.github/scripts/ssr-check.js deleted file mode 100644 index 3e884ea3..00000000 --- a/.github/scripts/ssr-check.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Validates that all server entry points are safe to import in a non-browser - * environment. - * - * Auto-discovers packages from `packages/`, reads their `exports` field to find - * entries with a `browser`/`default` condition split, resolves the `default` - * (server) path, and dynamically imports each one. Any module that throws - * during evaluation (e.g. due to missing browser globals) is reported. - * - * Requires packages to be built first (`pnpm build:packages`). - * - * Usage: node .github/scripts/ssr-check.js - */ - -import { - existsSync, - readFileSync, - readdirSync, -} from 'node:fs'; -import { resolve, join } from 'node:path'; -import { pathToFileURL, fileURLToPath } from 'node:url'; - -const __dirname = fileURLToPath(new URL('.', import.meta.url)); -const ROOT = resolve(__dirname, '../..'); -const PACKAGES_DIR = join(ROOT, 'packages'); - -const SKIP_PACKAGES = new Set([ - 'react-native', - 'skins', - 'icons', -]); - -/** - * Resolve the server path from an export value. - * - * Only returns a path for entries with a `browser`/`default` split (these are - * the ones that have separate server builds). The top-level `default` is the - * server entry point. - */ -function resolveServerPath(exportValue) { - if (typeof exportValue !== 'object' || exportValue === null) return null; - if (!('browser' in exportValue)) return null; - return typeof exportValue.default === 'string' ? exportValue.default : null; -} - -/** - * Resolve a wildcard export key to actual server files on disk. - */ -function resolveWildcard(pkgDir, exportKey, exportValue) { - const serverPath = resolveServerPath(exportValue); - if (!serverPath) return []; - - const fullPattern = resolve(pkgDir, serverPath); - const starIdx = fullPattern.indexOf('*'); - if (starIdx === -1) return []; - - const lastSlash = fullPattern.lastIndexOf('/', starIdx); - const scanDir = fullPattern.slice(0, lastSlash); - const prefix = fullPattern.slice(lastSlash + 1, starIdx); - const suffix = fullPattern.slice(starIdx + 1); - - if (!existsSync(scanDir)) return []; - - const isDirectoryPattern = suffix.startsWith('/'); - - return readdirSync(scanDir, { withFileTypes: true }) - .filter((d) => { - if (!d.name.startsWith(prefix)) return false; - return isDirectoryPattern ? d.isDirectory() : d.isFile(); - }) - .filter((d) => { - if (isDirectoryPattern) return true; - return d.name.endsWith(suffix); - }) - .map((d) => { - const stem = isDirectoryPattern - ? d.name.slice(prefix.length) - : d.name.slice(prefix.length, d.name.length - suffix.length); - const fullPath = fullPattern.replace('*', stem); - return { stem, fullPath }; - }) - .filter(({ fullPath }) => { - if (!existsSync(fullPath)) return false; - return readFileSync(fullPath, 'utf8').trim().length > 0; - }) - .sort((a, b) => a.stem.localeCompare(b.stem)) - .map(({ stem, fullPath }) => ({ - label: `${exportKey.replace('*', stem)}`, - path: fullPath, - })); -} - -/** Discover all server entry points across packages. */ -function discoverServerEntries() { - const entries = []; - - for (const dirName of readdirSync(PACKAGES_DIR).sort()) { - if (SKIP_PACKAGES.has(dirName)) continue; - - const pkgJsonPath = join(PACKAGES_DIR, dirName, 'package.json'); - if (!existsSync(pkgJsonPath)) continue; - - const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8')); - if (!pkgJson.exports) continue; - - const pkgName = pkgJson.name; - const pkgDir = join(PACKAGES_DIR, dirName); - - for (const [key, value] of Object.entries(pkgJson.exports)) { - if (key.endsWith('.css')) continue; - - if (key.includes('*')) { - for (const r of resolveWildcard(pkgDir, key, value)) { - entries.push({ - name: `${pkgName}/${r.label.slice(2)}`, - path: r.path, - }); - } - continue; - } - - const serverPath = resolveServerPath(value); - if (!serverPath) continue; - - const absolutePath = resolve(pkgDir, serverPath); - if (!existsSync(absolutePath)) continue; - if (readFileSync(absolutePath, 'utf8').trim().length === 0) continue; - - const label = key === '.' ? pkgName : `${pkgName}/${key.slice(2)}`; - entries.push({ name: label, path: absolutePath }); - } - } - - return entries; -} - -const entries = discoverServerEntries(); - -if (entries.length === 0) { - console.error('No server entry points found. Are packages built?'); - process.exit(1); -} - -console.log(`Checking ${entries.length} server entry points...\n`); - -const failures = []; - -for (const entry of entries) { - const url = pathToFileURL(entry.path).href; - try { - await import(url); - console.log(` ✓ ${entry.name}`); - } catch (error) { - console.log(` ✗ ${entry.name}`); - failures.push({ name: entry.name, error }); - } -} - -console.log(); - -if (failures.length > 0) { - console.error(`${failures.length} entry point(s) failed:\n`); - for (const { name, error } of failures) { - console.error(` ${name}:`); - console.error(` ${error.message}\n`); - } - process.exit(1); -} - -console.log(`All ${entries.length} server entry points imported successfully.`); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12abefd6..7c771e28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -203,6 +203,3 @@ jobs: - name: Build CDN bundles run: pnpm build:cdn - - - name: Check SSR safety - run: pnpm check:ssr diff --git a/CLAUDE.md b/CLAUDE.md index 1cbecc49..4b91f64c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -113,9 +113,6 @@ pnpm clean # Validate workspace consistency (CI coverage, scopes, define imports, etc.) pnpm check:workspace -# Validate all server entry points are SSR-safe (requires build first) -pnpm check:ssr - # Measure bundle size (SPF only) pnpm -F @videojs/spf size # Public API (minified + gzipped) pnpm -F @videojs/spf size:all # All exports (minified + gzipped) diff --git a/build/scripts/check-workspace.mjs b/build/scripts/check-workspace.mjs index 904ae8b9..34c59469 100644 --- a/build/scripts/check-workspace.mjs +++ b/build/scripts/check-workspace.mjs @@ -11,7 +11,6 @@ * 4. Package metadata — non-private packages have required fields * 5. Release-please config — every versioned package is registered * 6. Define imports — no bare side-effect imports from relative paths - * 7. Server bundles — browser/default export conditions match tsdown config */ import { existsSync, readdirSync, readFileSync } from 'node:fs'; import { dirname, join, resolve } from 'node:path'; @@ -299,74 +298,6 @@ function checkDefineImports() { return { ok: warnings.length === 0, warnings }; } -// ── Check 7: Server bundles ────────────────────────────────────────────────── - -/** - * Packages with `browser` export conditions must have a matching server build - * in tsdown (build mode 'server', `__BROWSER__` define, `platform: 'node'`). - * - * For each export entry with a `browser` condition: - * - The sibling `default` path must point to `dist/server/` - * - The tsdown config must declare a `'server'` build mode - * - The tsdown config must define `__BROWSER__` - */ -function checkServerBundles() { - const warnings = []; - - for (const dir of getPackageDirs()) { - const pkg = readPackageJson(dir); - if (pkg.private) continue; - - const exports = pkg.exports; - if (!exports) continue; - - // Collect export keys that have a `browser` condition. - const browserExports = []; - - for (const [key, value] of Object.entries(exports)) { - if (typeof value !== 'object' || value === null) continue; - if ('browser' in value) { - browserExports.push(key); - - // The `default` sibling must resolve to dist/server/. - const serverPath = value.default; - if (typeof serverPath === 'string' && !serverPath.includes('dist/server/')) { - warnings.push( - `${pkg.name}: export "${key}" has \`browser\` condition but \`default\` path "${serverPath}" does not point to dist/server/` - ); - } - } - } - - if (browserExports.length === 0) continue; - - // Validate tsdown config has server build mode and __BROWSER__ define. - const tsdownPath = join(PACKAGES_DIR, dir, 'tsdown.config.ts'); - if (!existsSync(tsdownPath)) { - warnings.push(`${pkg.name}: has \`browser\` exports but no tsdown.config.ts`); - continue; - } - - const tsdownText = readText(tsdownPath); - - if (!/'server'/.test(tsdownText)) { - warnings.push(`${pkg.name}: has \`browser\` exports but tsdown.config.ts is missing 'server' build mode`); - } - - if (!/__BROWSER__/.test(tsdownText)) { - warnings.push(`${pkg.name}: has \`browser\` exports but tsdown.config.ts does not define __BROWSER__`); - } - - if (!/platform.*['"]node['"]/.test(tsdownText)) { - warnings.push( - `${pkg.name}: has \`browser\` exports but tsdown.config.ts does not set platform to 'node' for server builds` - ); - } - } - - return { ok: warnings.length === 0, warnings }; -} - // ── Main ──────────────────────────────────────────────────────────────────── const checks = [ @@ -376,7 +307,6 @@ const checks = [ { name: 'Package metadata', fn: checkPackageMetadata }, { name: 'Release-please config', fn: checkReleasePleaseConfig }, { name: 'Define imports', fn: checkDefineImports }, - { name: 'Server bundles', fn: checkServerBundles }, ]; let failed = 0; diff --git a/package.json b/package.json index 2f866daf..f0936b6f 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,7 @@ "format:astro": "prettier --write 'site/src/**/*.astro'", "typecheck": "tsc --build", "changelog": "git-cliff --config cliff.toml --output CHANGELOG.md", - "check:workspace": "node build/scripts/check-workspace.mjs", - "check:ssr": "node .github/scripts/ssr-check.js" + "check:workspace": "node build/scripts/check-workspace.mjs" }, "devDependencies": { "@actions/core": "^3.0.0", @@ -52,7 +51,6 @@ "@commitlint/cli": "^20.1.0", "@commitlint/config-conventional": "^20.0.0", "@commitlint/format": "^20.0.0", - "@edge-runtime/vm": "^5.0.0", "@types/node": "^22.18.6", "esbuild": "^0.27.3", "git-cliff": "^2.12.0", @@ -62,9 +60,9 @@ "prettier-plugin-astro": "^0.14.1", "prettier-plugin-tailwindcss": "^0.7.2", "react": "^18.0.0", + "rimraf": "^6.1.3", "react-compiler-runtime": "^1.0.0", "react-dom": "^18.0.0", - "rimraf": "^6.1.3", "simple-git-hooks": "^2.13.1", "tsx": "^4.21.0", "turbo": "^2.9.0", diff --git a/packages/core/package.json b/packages/core/package.json index ac30b51e..48a8853b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -28,12 +28,9 @@ "default": "./dist/default/dom.js" }, "./dom/media/*": { - "types": "./dist/dev/dom/media/*.d.ts", - "browser": { - "development": "./dist/dev/dom/media/*.js", - "default": "./dist/default/dom/media/*.js" - }, - "default": "./dist/server/dom/media/*.js" + "types": "./dist/dev/dom/media/*/index.d.ts", + "development": "./dist/dev/dom/media/*/index.js", + "default": "./dist/default/dom/media/*/index.js" } }, "main": "dist/default/index.js", diff --git a/packages/core/src/dom/globals.d.ts b/packages/core/src/dom/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/core/src/dom/globals.d.ts +++ b/packages/core/src/dom/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/core/src/dom/media/custom-media-element/browser.ts b/packages/core/src/dom/media/custom-media-element/index.ts similarity index 100% rename from packages/core/src/dom/media/custom-media-element/browser.ts rename to packages/core/src/dom/media/custom-media-element/index.ts diff --git a/packages/core/src/dom/media/custom-media-element/server.ts b/packages/core/src/dom/media/custom-media-element/server.ts deleted file mode 100644 index c1f66201..00000000 --- a/packages/core/src/dom/media/custom-media-element/server.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const VideoCSSVars = {} as const; - -export const AudioCSSVars = {} as const; - -export function CustomMediaElement(_tag: string, _MediaHost: any): any { - return class {}; -} diff --git a/packages/core/src/dom/media/custom-media-element/tests/custom-media-element.test.ts b/packages/core/src/dom/media/custom-media-element/tests/custom-media-element.test.ts index 900fbd26..791b12bb 100644 --- a/packages/core/src/dom/media/custom-media-element/tests/custom-media-element.test.ts +++ b/packages/core/src/dom/media/custom-media-element/tests/custom-media-element.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { HTMLAudioElementHost } from '../../audio-host'; import { HTMLVideoElementHost } from '../../video-host'; -import { CustomMediaElement } from '../browser'; +import { CustomMediaElement } from '../index'; afterEach(() => { document.body.innerHTML = ''; diff --git a/packages/core/src/dom/media/dash/browser.ts b/packages/core/src/dom/media/dash/index.ts similarity index 100% rename from packages/core/src/dom/media/dash/browser.ts rename to packages/core/src/dom/media/dash/index.ts diff --git a/packages/core/src/dom/media/dash/server.ts b/packages/core/src/dom/media/dash/server.ts deleted file mode 100644 index 8afc279f..00000000 --- a/packages/core/src/dom/media/dash/server.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { HTMLVideoElementHost } from '../video-host'; - -export class DashMedia extends HTMLVideoElementHost { - engine = null; - destroy(): void {} -} diff --git a/packages/core/src/dom/media/dash/tests/dash-media.test.ts b/packages/core/src/dom/media/dash/tests/dash-media.test.ts index 4e7b91af..19c54f4e 100644 --- a/packages/core/src/dom/media/dash/tests/dash-media.test.ts +++ b/packages/core/src/dom/media/dash/tests/dash-media.test.ts @@ -12,7 +12,7 @@ vi.mock('dashjs', () => { return { MediaPlayer: () => ({ create }), default: { MediaPlayer: () => ({ create }) } }; }); -import { DashMedia } from '../browser'; +import { DashMedia } from '../index'; afterEach(() => { document.body.innerHTML = ''; diff --git a/packages/core/src/dom/media/hls/browser.ts b/packages/core/src/dom/media/hls/index.ts similarity index 84% rename from packages/core/src/dom/media/hls/browser.ts rename to packages/core/src/dom/media/hls/index.ts index 0a843e34..67a28b9e 100644 --- a/packages/core/src/dom/media/hls/browser.ts +++ b/packages/core/src/dom/media/hls/index.ts @@ -1,20 +1,26 @@ import { shallowEqual } from '@videojs/utils/object'; import Hls from 'hls.js'; import { bridgeEvents } from '../../../core/utils/bridge-events'; -import { NativeHlsMedia } from '../native-hls/browser'; +import { NativeHlsMedia } from '../native-hls'; import { HTMLVideoElementHost } from '../video-host'; import { HlsJsMedia } from './hlsjs'; -import { - inferSourceType, - type PlaybackType, - PlaybackTypes, - type PreloadType, - type SourceType, - SourceTypes, -} from './types'; + +export type PreloadType = '' | 'none' | 'metadata' | 'auto'; export { Hls }; -export * from './types'; + +export type PlaybackType = (typeof PlaybackTypes)[keyof typeof PlaybackTypes]; +export type SourceType = (typeof SourceTypes)[keyof typeof SourceTypes]; + +export const PlaybackTypes = { + MSE: 'mse', + NATIVE: 'native', +}; + +export const SourceTypes = { + M3U8: 'application/vnd.apple.mpegurl', + MP4: 'video/mp4', +}; export class HlsMedia extends HTMLVideoElementHost { #delegate: HlsJsMedia | NativeHlsMedia | null = null; @@ -163,3 +169,9 @@ export class HlsMedia extends HTMLVideoElementHost { this.#loadRequested = null; } } + +function inferSourceType(src: string): SourceType { + const path = src.split(/[?#]/)[0] ?? ''; + if (path.endsWith('.mp4')) return SourceTypes.MP4; + return SourceTypes.M3U8; +} diff --git a/packages/core/src/dom/media/hls/server.ts b/packages/core/src/dom/media/hls/server.ts deleted file mode 100644 index 0c5f0a10..00000000 --- a/packages/core/src/dom/media/hls/server.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HTMLVideoElementHost } from '../video-host'; - -export * from './types'; - -export class HlsMedia extends HTMLVideoElementHost { - engine = null; - preferPlayback: string | undefined = 'mse'; - config: Record = {}; - debug = false; - preload = 'metadata'; - load(): void {} - destroy(): void {} -} diff --git a/packages/core/src/dom/media/hls/tests/hls-media.test.ts b/packages/core/src/dom/media/hls/tests/hls-media.test.ts index 05c10899..0cc3320e 100644 --- a/packages/core/src/dom/media/hls/tests/hls-media.test.ts +++ b/packages/core/src/dom/media/hls/tests/hls-media.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { MediaError } from '../../../../core/media/media-error'; -import { HlsMedia, SourceTypes } from '../browser'; +import { HlsMedia, SourceTypes } from '../index'; afterEach(() => { document.body.innerHTML = ''; diff --git a/packages/core/src/dom/media/hls/types.ts b/packages/core/src/dom/media/hls/types.ts index fe41ea42..1eef9b13 100644 --- a/packages/core/src/dom/media/hls/types.ts +++ b/packages/core/src/dom/media/hls/types.ts @@ -4,24 +4,3 @@ export interface HlsEngineHost extends EventTarget { readonly engine?: Hls | null; readonly target?: HTMLMediaElement | null; } - -export type PreloadType = '' | 'none' | 'metadata' | 'auto'; - -export type PlaybackType = (typeof PlaybackTypes)[keyof typeof PlaybackTypes]; -export type SourceType = (typeof SourceTypes)[keyof typeof SourceTypes]; - -export const PlaybackTypes = { - MSE: 'mse', - NATIVE: 'native', -}; - -export const SourceTypes = { - M3U8: 'application/vnd.apple.mpegurl', - MP4: 'video/mp4', -}; - -export function inferSourceType(src: string): SourceType { - const path = src.split(/[?#]/)[0] ?? ''; - if (path.endsWith('.mp4')) return SourceTypes.MP4; - return SourceTypes.M3U8; -} diff --git a/packages/core/src/dom/media/mux/browser.ts b/packages/core/src/dom/media/mux/index.ts similarity index 91% rename from packages/core/src/dom/media/mux/browser.ts rename to packages/core/src/dom/media/mux/index.ts index 05e66cfe..e7e424eb 100644 --- a/packages/core/src/dom/media/mux/browser.ts +++ b/packages/core/src/dom/media/mux/index.ts @@ -1,4 +1,4 @@ -import { HlsMedia } from '../hls/browser'; +import { HlsMedia } from '../hls'; import { MuxDataMediaMixin } from './mux-data'; export class MuxVideoMedia extends MuxDataMediaMixin(HlsMedia) { diff --git a/packages/core/src/dom/media/mux/mux-data.ts b/packages/core/src/dom/media/mux/mux-data.ts index 4e4c3e19..69157a59 100644 --- a/packages/core/src/dom/media/mux/mux-data.ts +++ b/packages/core/src/dom/media/mux/mux-data.ts @@ -1,7 +1,7 @@ import type { Mixin } from '@videojs/utils/types'; import Mux from 'mux-embed'; import type { MediaEngineHost } from '../../../core/media/types'; -import { Hls, type HlsMedia } from '../hls/browser'; +import { Hls, type HlsMedia } from '../hls'; import { getPlayerVersion } from './env'; import type { MuxDataOptions, MuxDataSdk } from './types'; @@ -198,7 +198,7 @@ export function toPlaybackIdFromSrc(src: string): string | undefined { export function isMuxVideoSrc({ src }: MuxVideoIdProps): boolean { if (typeof src !== 'string') return false; - const base = __BROWSER__ ? window.location.href : undefined; + const base = window?.location.href; const hostname = new URL(src, base).hostname.toLocaleLowerCase(); return hostname.includes(MUX_VIDEO_DOMAIN); } diff --git a/packages/core/src/dom/media/mux/server.ts b/packages/core/src/dom/media/mux/server.ts deleted file mode 100644 index 392a2a39..00000000 --- a/packages/core/src/dom/media/mux/server.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { HlsMedia } from '../hls/server'; - -export class MuxVideoMedia extends HlsMedia { - static PLAYER_SOFTWARE_NAME = 'mux-video'; -} - -export class MuxAudioMedia extends HlsMedia { - static PLAYER_SOFTWARE_NAME = 'mux-audio'; -} diff --git a/packages/core/src/dom/media/mux/tests/index.test.ts b/packages/core/src/dom/media/mux/tests/index.test.ts index a25ddbb5..41b56ccd 100644 --- a/packages/core/src/dom/media/mux/tests/index.test.ts +++ b/packages/core/src/dom/media/mux/tests/index.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { MuxVideoMedia } from '../browser'; +import { MuxVideoMedia } from '..'; describe('MuxVideoMedia', () => { it('accepts src directly', () => { diff --git a/packages/core/src/dom/media/native-hls/browser.ts b/packages/core/src/dom/media/native-hls/index.ts similarity index 100% rename from packages/core/src/dom/media/native-hls/browser.ts rename to packages/core/src/dom/media/native-hls/index.ts diff --git a/packages/core/src/dom/media/native-hls/server.ts b/packages/core/src/dom/media/native-hls/server.ts deleted file mode 100644 index 0462f30e..00000000 --- a/packages/core/src/dom/media/native-hls/server.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { HTMLVideoElementHost } from '../video-host'; - -export class NativeHlsMedia extends HTMLVideoElementHost { - engine = null; - preload = 'metadata'; - destroy(): void {} -} diff --git a/packages/core/src/dom/media/native-hls/tests/native-hls-custom-media.test.ts b/packages/core/src/dom/media/native-hls/tests/native-hls-custom-media.test.ts index 20c7cad0..a38f9c07 100644 --- a/packages/core/src/dom/media/native-hls/tests/native-hls-custom-media.test.ts +++ b/packages/core/src/dom/media/native-hls/tests/native-hls-custom-media.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { MediaError } from '../../../../core/media/media-error'; -import { NativeHlsMedia } from '../browser'; +import { NativeHlsMedia } from '../index'; afterEach(() => { document.body.innerHTML = ''; diff --git a/packages/core/src/dom/media/simple-hls/browser.ts b/packages/core/src/dom/media/simple-hls/index.ts similarity index 100% rename from packages/core/src/dom/media/simple-hls/browser.ts rename to packages/core/src/dom/media/simple-hls/index.ts diff --git a/packages/core/src/dom/media/simple-hls/server.ts b/packages/core/src/dom/media/simple-hls/server.ts deleted file mode 100644 index 5020d767..00000000 --- a/packages/core/src/dom/media/simple-hls/server.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { HTMLVideoElementHost } from '../video-host'; - -export class SimpleHlsMedia extends HTMLVideoElementHost { - engine = null; - destroy(): void {} -} diff --git a/packages/core/src/dom/ui/dismiss-layer.ts b/packages/core/src/dom/ui/dismiss-layer.ts index f937f993..4f0e0f52 100644 --- a/packages/core/src/dom/ui/dismiss-layer.ts +++ b/packages/core/src/dom/ui/dismiss-layer.ts @@ -63,7 +63,7 @@ export function createDismissLayer(options: DismissLayerOptions): DismissLayerAp function setupDocumentListeners(): void { cleanupDocumentListeners(); - if (!__BROWSER__) return; + if (typeof document === 'undefined') return; docAbort = new AbortController(); const { signal } = docAbort; diff --git a/packages/core/src/globals.d.ts b/packages/core/src/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/core/src/globals.d.ts +++ b/packages/core/src/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/core/tsdown.config.ts b/packages/core/tsdown.config.ts index cc179312..ceece40d 100644 --- a/packages/core/tsdown.config.ts +++ b/packages/core/tsdown.config.ts @@ -1,41 +1,31 @@ -import { globSync } from 'node:fs'; import type { UserConfig } from 'tsdown'; import { defineConfig } from 'tsdown'; import packageJson from './package.json' with { type: 'json' }; -type BuildMode = 'dev' | 'default' | 'server'; +type BuildMode = 'dev' | 'default'; -const buildModes: BuildMode[] = ['dev', 'default', 'server']; - -const isServer = (mode: BuildMode) => mode === 'server'; - -const mediaEntry = (mode: BuildMode) => { - const suffix = isServer(mode) ? 'server' : 'browser'; - return Object.fromEntries( - globSync(`src/dom/media/*/${suffix}.ts`).map((file) => { - const dir = file.split('/').at(-2)!; - return [`dom/media/${dir}`, `./${file}`]; - }) - ); -}; +const buildModes: BuildMode[] = ['dev', 'default']; const createConfig = (mode: BuildMode): UserConfig => ({ entry: { index: './src/core/index.ts', dom: './src/dom/index.ts', - ...mediaEntry(mode), + 'dom/media/dash/index': './src/dom/media/dash/index.ts', + 'dom/media/hls/index': './src/dom/media/hls/index.ts', + 'dom/media/custom-media-element/index': './src/dom/media/custom-media-element/index.ts', + 'dom/media/mux/index': './src/dom/media/mux/index.ts', + 'dom/media/native-hls/index': './src/dom/media/native-hls/index.ts', + 'dom/media/simple-hls/index': './src/dom/media/simple-hls/index.ts', }, - platform: isServer(mode) ? 'node' : 'neutral', + platform: 'neutral', format: 'es', sourcemap: true, clean: true, hash: false, unbundle: true, - outExtensions: isServer(mode) ? () => ({ js: '.js', dts: '.d.ts' }) : undefined, outDir: `dist/${mode}`, define: { - __DEV__: mode === 'dev' || isServer(mode) ? 'true' : 'false', - __BROWSER__: isServer(mode) ? 'false' : 'true', + __DEV__: mode === 'dev' ? 'true' : 'false', __PLAYER_VERSION__: JSON.stringify(packageJson.version), }, dts: diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts index dd9701bf..b87d2035 100644 --- a/packages/core/vitest.config.ts +++ b/packages/core/vitest.config.ts @@ -3,7 +3,6 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ define: { __DEV__: 'true', - __BROWSER__: 'true', }, test: { projects: [ diff --git a/packages/element/src/reactive-element.ts b/packages/element/src/reactive-element.ts index 49a5c409..e6cb965b 100644 --- a/packages/element/src/reactive-element.ts +++ b/packages/element/src/reactive-element.ts @@ -50,12 +50,7 @@ const propertyKeys = new Map(); * } * ``` */ -// Fallback to an empty class when `HTMLElement` is not available (SSR / Node). -// This allows the class definition to evaluate without throwing; instances -// are never created on the server. -const BaseElement = globalThis.HTMLElement ?? (class {} as unknown as typeof HTMLElement); - -export class ReactiveElement extends BaseElement { +export class ReactiveElement extends HTMLElement { /** * User-supplied object that maps property names to * {@linkcode PropertyDeclaration} objects containing options for configuring diff --git a/packages/html/package.json b/packages/html/package.json index e8c6526f..5e60fced 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -23,86 +23,56 @@ "exports": { ".": { "types": "./dist/dev/index.d.ts", - "browser": { - "development": "./dist/dev/index.js", - "default": "./dist/default/index.js" - }, - "default": "./dist/server/index.js" + "development": "./dist/dev/index.js", + "default": "./dist/default/index.js" }, "./video": { "types": "./dist/dev/presets/video.d.ts", - "browser": { - "development": "./dist/dev/presets/video.js", - "default": "./dist/default/presets/video.js" - }, - "default": "./dist/server/presets/video.js" + "development": "./dist/dev/presets/video.js", + "default": "./dist/default/presets/video.js" }, "./video/*.css": "./dist/default/define/video/*.css", "./video/*": { "types": "./dist/dev/define/video/*.d.ts", - "browser": { - "development": "./dist/dev/define/video/*.js", - "default": "./dist/default/define/video/*.js" - }, - "default": "./dist/server/define/video/*.js" + "development": "./dist/dev/define/video/*.js", + "default": "./dist/default/define/video/*.js" }, "./audio": { "types": "./dist/dev/presets/audio.d.ts", - "browser": { - "development": "./dist/dev/presets/audio.js", - "default": "./dist/default/presets/audio.js" - }, - "default": "./dist/server/presets/audio.js" + "development": "./dist/dev/presets/audio.js", + "default": "./dist/default/presets/audio.js" }, "./audio/*.css": "./dist/default/define/audio/*.css", "./audio/*": { "types": "./dist/dev/define/audio/*.d.ts", - "browser": { - "development": "./dist/dev/define/audio/*.js", - "default": "./dist/default/define/audio/*.js" - }, - "default": "./dist/server/define/audio/*.js" + "development": "./dist/dev/define/audio/*.js", + "default": "./dist/default/define/audio/*.js" }, "./background": { "types": "./dist/dev/presets/background.d.ts", - "browser": { - "development": "./dist/dev/presets/background.js", - "default": "./dist/default/presets/background.js" - }, - "default": "./dist/server/presets/background.js" + "development": "./dist/dev/presets/background.js", + "default": "./dist/default/presets/background.js" }, "./background/*.css": "./dist/default/define/background/*.css", "./background/*": { "types": "./dist/dev/define/background/*.d.ts", - "browser": { - "development": "./dist/dev/define/background/*.js", - "default": "./dist/default/define/background/*.js" - }, - "default": "./dist/server/define/background/*.js" + "development": "./dist/dev/define/background/*.js", + "default": "./dist/default/define/background/*.js" }, "./ui/*": { "types": "./dist/dev/define/ui/*.d.ts", - "browser": { - "development": "./dist/dev/define/ui/*.js", - "default": "./dist/default/define/ui/*.js" - }, - "default": "./dist/server/define/ui/*.js" + "development": "./dist/dev/define/ui/*.js", + "default": "./dist/default/define/ui/*.js" }, "./feature/*": { "types": "./dist/dev/define/feature/*.d.ts", - "browser": { - "development": "./dist/dev/define/feature/*.js", - "default": "./dist/default/define/feature/*.js" - }, - "default": "./dist/server/define/feature/*.js" + "development": "./dist/dev/define/feature/*.js", + "default": "./dist/default/define/feature/*.js" }, "./media/*": { "types": "./dist/dev/define/media/*.d.ts", - "browser": { - "development": "./dist/dev/define/media/*.js", - "default": "./dist/default/define/media/*.js" - }, - "default": "./dist/server/define/media/*.js" + "development": "./dist/dev/define/media/*.js", + "default": "./dist/default/define/media/*.js" }, "./cdn/media/*": { "types": "./cdn/media/*.dev.d.ts", @@ -117,11 +87,8 @@ "./*.css": "./dist/default/define/*.css", "./*": { "types": "./dist/dev/define/*.d.ts", - "browser": { - "development": "./dist/dev/define/*.js", - "default": "./dist/default/define/*.js" - }, - "default": "./dist/server/define/*.js" + "development": "./dist/dev/define/*.js", + "default": "./dist/default/define/*.js" } }, "scripts": { diff --git a/packages/html/src/define/safe-define.ts b/packages/html/src/define/safe-define.ts index 56138a1e..975fc2de 100644 --- a/packages/html/src/define/safe-define.ts +++ b/packages/html/src/define/safe-define.ts @@ -2,8 +2,8 @@ type DefinableElement = CustomElementConstructor & { tagName: string }; /** Define a custom element only if not already registered. */ export function safeDefine(element: DefinableElement): void { - if (!__BROWSER__) return; - if (customElements.get(element.tagName)) return; + const registry = globalThis.customElements; + if (!registry || registry.get(element.tagName)) return; - customElements.define(element.tagName, element); + registry.define(element.tagName, element); } diff --git a/packages/html/src/define/tests/safe-define.test.ts b/packages/html/src/define/tests/safe-define.test.ts index 646f3f66..2e87ac9b 100644 --- a/packages/html/src/define/tests/safe-define.test.ts +++ b/packages/html/src/define/tests/safe-define.test.ts @@ -1,7 +1,11 @@ -import { describe, expect, it } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { safeDefine } from '../safe-define'; describe('safeDefine', () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + it('registers a custom element', () => { class TestElement extends HTMLElement { static tagName = 'test-sd-register'; @@ -33,4 +37,14 @@ describe('safeDefine', () => { safeDefine(Replacement); expect(customElements.get('test-sd-no-replace')).toBe(Original); }); + + it('does nothing when customElements is unavailable', () => { + vi.stubGlobal('customElements', undefined); + + class TestElement extends HTMLElement { + static tagName = 'test-sd-ssr'; + } + + expect(() => safeDefine(TestElement)).not.toThrow(); + }); }); diff --git a/packages/html/src/define/tests/ssr-safety.test.ts b/packages/html/src/define/tests/ssr-safety.test.ts new file mode 100644 index 00000000..2c4a7dd3 --- /dev/null +++ b/packages/html/src/define/tests/ssr-safety.test.ts @@ -0,0 +1,21 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +describe('SSR-safe define imports', () => { + afterEach(() => { + vi.unstubAllGlobals(); + vi.resetModules(); + }); + + it('imports video skin without browser-only globals', async () => { + vi.stubGlobal('customElements', undefined); + vi.stubGlobal('CSSStyleSheet', undefined); + + await expect(import('../video/skin')).resolves.toBeDefined(); + }); + + it('imports simple-hls-video without customElements', async () => { + vi.stubGlobal('customElements', undefined); + + await expect(import('../media/simple-hls-video')).resolves.toBeDefined(); + }); +}); diff --git a/packages/html/src/globals.d.ts b/packages/html/src/globals.d.ts index bc438011..175e0a85 100644 --- a/packages/html/src/globals.d.ts +++ b/packages/html/src/globals.d.ts @@ -1,5 +1,4 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; declare module '*.css' { const content: string; diff --git a/packages/html/tsdown.cdn.config.ts b/packages/html/tsdown.cdn.config.ts index e9952838..eb7a1ce3 100644 --- a/packages/html/tsdown.cdn.config.ts +++ b/packages/html/tsdown.cdn.config.ts @@ -89,7 +89,6 @@ for (const mode of buildModes) { }, define: { __DEV__: isProd ? 'false' : 'true', - __BROWSER__: 'true', }, plugins: [ inlineCssPlugin({ skinsDir, minify: isProd }), diff --git a/packages/html/tsdown.config.ts b/packages/html/tsdown.config.ts index 081dcc81..8a63b024 100644 --- a/packages/html/tsdown.config.ts +++ b/packages/html/tsdown.config.ts @@ -1,4 +1,4 @@ -import { globSync, readFileSync } from 'node:fs'; +import { globSync } from 'node:fs'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import type { UserConfig } from 'tsdown'; @@ -7,51 +7,12 @@ import { copyCssPlugin } from '../../build/plugins/copy-css-plugin.ts'; import { inlineCssPlugin } from '../../build/plugins/inline-css-plugin.ts'; import { inlineTemplatePlugin } from '../../build/plugins/inline-template-plugin.ts'; -type BuildMode = 'dev' | 'default' | 'server'; +type BuildMode = 'dev' | 'default'; -const buildModes: BuildMode[] = ['dev', 'default', 'server']; - -const isServer = (mode: BuildMode) => mode === 'server'; +const buildModes: BuildMode[] = ['dev', 'default']; const skinsDir = resolve(dirname(fileURLToPath(import.meta.url)), '../skins/src'); -/** Stub `*.css?inline` imports with empty strings for the server build. */ -function stubCssInlinePlugin() { - return { - name: 'stub-css-inline', - resolveId(source: string) { - if (source.endsWith('.css?inline')) return { id: `\0stub-css:${source}`, external: false }; - }, - load(id: string) { - if (id.startsWith('\0stub-css:')) return 'export default ""'; - }, - }; -} - -/** - * Stub all `define/*` modules for the server build. - * - * Reads each source file, extracts `export class` names, and emits stub - * classes so that preset modules can still re-export them by name. - * Everything else (custom element registration, templates, styles) is dropped. - */ -function stubDefinePlugin() { - const defineDir = resolve(dirname(fileURLToPath(import.meta.url)), 'src/define'); - return { - name: 'stub-define', - load(id: string) { - if (!id.startsWith(defineDir) || id === defineDir) return; - - const source = readFileSync(id, 'utf8'); - const classNames = [...source.matchAll(/export class (\w+)/g)].map((m) => m[1]); - - if (classNames.length === 0) return 'export {}'; - - return classNames.map((name) => `export class ${name} {}`).join('\n'); - }, - }; -} - const defineEntries = Object.fromEntries( globSync('src/define/**/*.ts') .filter((file) => !file.includes('.test.')) @@ -74,36 +35,32 @@ const createConfig = (mode: BuildMode): UserConfig => ({ ...defineEntries, ...presetEntries, }, - platform: isServer(mode) ? 'node' : 'browser', + platform: 'browser', format: 'es', sourcemap: true, clean: true, hash: false, unbundle: true, - outExtensions: isServer(mode) ? () => ({ js: '.js', dts: '.d.ts' }) : undefined, treeshake: { // The sideEffects field in package.json uses dist paths, but the build // runs against source. Ensure define/* modules (which register custom // elements as a side effect) are never tree-shaken from skin bundles. moduleSideEffects: [{ test: /\/define\//, sideEffects: true }], }, - noExternal: isServer(mode) ? [] : [/^@videojs\/icons/, /^@videojs\/skins/], + noExternal: [/^@videojs\/icons/, /^@videojs\/skins/], alias: { '@': new URL('./src', import.meta.url).pathname, }, outDir: `dist/${mode}`, define: { - __DEV__: mode === 'dev' || isServer(mode) ? 'true' : 'false', - __BROWSER__: isServer(mode) ? 'false' : 'true', + __DEV__: mode === 'dev' ? 'true' : 'false', }, dts: mode === 'dev', - plugins: isServer(mode) - ? [stubCssInlinePlugin(), stubDefinePlugin()] - : [ - copyCssPlugin({ skinsDir, outDir: `dist/${mode}` }), - inlineCssPlugin({ skinsDir, minify: mode !== 'dev' }), - inlineTemplatePlugin({ minify: mode !== 'dev' }), - ], + plugins: [ + copyCssPlugin({ skinsDir, outDir: `dist/${mode}` }), + inlineCssPlugin({ skinsDir, minify: mode !== 'dev' }), + inlineTemplatePlugin({ minify: mode !== 'dev' }), + ], }); export default defineConfig(buildModes.map((mode) => createConfig(mode))); diff --git a/packages/html/vitest.config.ts b/packages/html/vitest.config.ts index a20b2493..6fc9357e 100644 --- a/packages/html/vitest.config.ts +++ b/packages/html/vitest.config.ts @@ -3,12 +3,10 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ define: { __DEV__: 'true', - __BROWSER__: 'true', }, test: { - include: ['src/**/*.test.ts'], passWithNoTests: true, - onConsoleLog: (log: string) => !log.includes('Lit is in dev mode'), + onConsoleLog: (log) => !log.includes('Lit is in dev mode'), environment: 'happy-dom', }, }); diff --git a/packages/react/package.json b/packages/react/package.json index 88566855..172a4448 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -19,70 +19,46 @@ "exports": { ".": { "types": "./dist/dev/index.d.ts", - "browser": { - "development": "./dist/dev/index.js", - "default": "./dist/default/index.js" - }, - "default": "./dist/server/index.js" + "development": "./dist/dev/index.js", + "default": "./dist/default/index.js" }, "./media/*": { "types": "./dist/dev/media/*/index.d.ts", - "browser": { - "development": "./dist/dev/media/*/index.js", - "default": "./dist/default/media/*/index.js" - }, - "default": "./dist/server/media/*/index.js" + "development": "./dist/dev/media/*/index.js", + "default": "./dist/default/media/*/index.js" }, "./video": { "types": "./dist/dev/presets/video/index.d.ts", - "browser": { - "development": "./dist/dev/presets/video/index.js", - "default": "./dist/default/presets/video/index.js" - }, - "default": "./dist/server/presets/video/index.js" + "development": "./dist/dev/presets/video/index.js", + "default": "./dist/default/presets/video/index.js" }, "./video/*.css": "./dist/default/presets/video/*.css", "./video/*": { "types": "./dist/dev/presets/video/*.d.ts", - "browser": { - "development": "./dist/dev/presets/video/*.js", - "default": "./dist/default/presets/video/*.js" - }, - "default": "./dist/server/presets/video/*.js" + "development": "./dist/dev/presets/video/*.js", + "default": "./dist/default/presets/video/*.js" }, "./audio": { "types": "./dist/dev/presets/audio/index.d.ts", - "browser": { - "development": "./dist/dev/presets/audio/index.js", - "default": "./dist/default/presets/audio/index.js" - }, - "default": "./dist/server/presets/audio/index.js" + "development": "./dist/dev/presets/audio/index.js", + "default": "./dist/default/presets/audio/index.js" }, "./audio/*.css": "./dist/default/presets/audio/*.css", "./audio/*": { "types": "./dist/dev/presets/audio/*.d.ts", - "browser": { - "development": "./dist/dev/presets/audio/*.js", - "default": "./dist/default/presets/audio/*.js" - }, - "default": "./dist/server/presets/audio/*.js" + "development": "./dist/dev/presets/audio/*.js", + "default": "./dist/default/presets/audio/*.js" }, "./background": { "types": "./dist/dev/presets/background/index.d.ts", - "browser": { - "development": "./dist/dev/presets/background/index.js", - "default": "./dist/default/presets/background/index.js" - }, - "default": "./dist/server/presets/background/index.js" + "development": "./dist/dev/presets/background/index.js", + "default": "./dist/default/presets/background/index.js" }, "./background/*.css": "./dist/default/presets/background/*.css", "./background/*": { "types": "./dist/dev/presets/background/*.d.ts", - "browser": { - "development": "./dist/dev/presets/background/*.js", - "default": "./dist/default/presets/background/*.js" - }, - "default": "./dist/server/presets/background/*.js" + "development": "./dist/dev/presets/background/*.js", + "default": "./dist/default/presets/background/*.js" } }, "scripts": { diff --git a/packages/react/src/globals.d.ts b/packages/react/src/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/react/src/globals.d.ts +++ b/packages/react/src/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/react/tsdown.config.ts b/packages/react/tsdown.config.ts index b9725550..26f43e44 100644 --- a/packages/react/tsdown.config.ts +++ b/packages/react/tsdown.config.ts @@ -4,34 +4,30 @@ import type { UserConfig } from 'tsdown'; import { defineConfig } from 'tsdown'; import { copyCssPlugin } from '../../build/plugins/copy-css-plugin.ts'; -type BuildMode = 'dev' | 'default' | 'server'; +type BuildMode = 'dev' | 'default'; -const buildModes: BuildMode[] = ['dev', 'default', 'server']; - -const isServer = (mode: BuildMode) => mode === 'server'; +const buildModes: BuildMode[] = ['dev', 'default']; const skinsDir = resolve(dirname(fileURLToPath(import.meta.url)), '../skins/src'); const createConfig = (mode: BuildMode): UserConfig => ({ entry: 'src/**/index.{ts,tsx}', - platform: isServer(mode) ? 'node' : 'browser', + platform: 'browser', format: 'es', sourcemap: true, clean: true, hash: false, unbundle: true, - outExtensions: isServer(mode) ? () => ({ js: '.js', dts: '.d.ts' }) : undefined, - noExternal: isServer(mode) ? [] : [/^@videojs\/skins/], + noExternal: [/^@videojs\/skins/], alias: { '@': new URL('./src', import.meta.url).pathname, }, outDir: `dist/${mode}`, define: { - __DEV__: mode === 'dev' || isServer(mode) ? 'true' : 'false', - __BROWSER__: isServer(mode) ? 'false' : 'true', + __DEV__: mode === 'dev' ? 'true' : 'false', }, dts: mode === 'dev', - plugins: isServer(mode) ? [] : [copyCssPlugin({ skinsDir, outDir: `dist/${mode}` })], + plugins: [copyCssPlugin({ skinsDir, outDir: `dist/${mode}` })], }); export default defineConfig(buildModes.map((mode) => createConfig(mode))); diff --git a/packages/react/vitest.config.ts b/packages/react/vitest.config.ts index 07a2d14f..4f425be6 100644 --- a/packages/react/vitest.config.ts +++ b/packages/react/vitest.config.ts @@ -3,10 +3,9 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ define: { __DEV__: 'true', - __BROWSER__: 'true', }, test: { - include: ['src/**/*.test.{ts,tsx}'], environment: 'jsdom', + include: ['src/**/*.test.{ts,tsx}'], }, }); diff --git a/packages/spf/src/globals.d.ts b/packages/spf/src/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/spf/src/globals.d.ts +++ b/packages/spf/src/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/store/src/core/globals.d.ts b/packages/store/src/core/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/store/src/core/globals.d.ts +++ b/packages/store/src/core/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/store/src/globals.d.ts b/packages/store/src/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/store/src/globals.d.ts +++ b/packages/store/src/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/store/src/html/globals.d.ts b/packages/store/src/html/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/store/src/html/globals.d.ts +++ b/packages/store/src/html/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/store/src/react/globals.d.ts b/packages/store/src/react/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/store/src/react/globals.d.ts +++ b/packages/store/src/react/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/utils/package.json b/packages/utils/package.json index d26c4890..c221c13d 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -17,8 +17,7 @@ }, "./dom": { "types": "./dist/dom.d.ts", - "browser": "./dist/dom.js", - "default": "./dist/server/dom.js" + "default": "./dist/dom.js" }, "./events": { "types": "./dist/events.d.ts", diff --git a/packages/utils/src/dom/globals.d.ts b/packages/utils/src/dom/globals.d.ts index 20f7f377..b867229b 100644 --- a/packages/utils/src/dom/globals.d.ts +++ b/packages/utils/src/dom/globals.d.ts @@ -1,2 +1 @@ declare const __DEV__: boolean; -declare const __BROWSER__: boolean; diff --git a/packages/utils/src/dom/platform.ts b/packages/utils/src/dom/platform.ts index f6f0be91..34b56a1a 100644 --- a/packages/utils/src/dom/platform.ts +++ b/packages/utils/src/dom/platform.ts @@ -1,3 +1,3 @@ export function isMacOS(): boolean { - return __BROWSER__ && /mac/i.test(navigator.userAgent); + return typeof navigator !== 'undefined' && /mac/i.test(navigator.userAgent); } diff --git a/packages/utils/src/dom/shadow-styles.ts b/packages/utils/src/dom/shadow-styles.ts index 1d7439df..717e19a6 100644 --- a/packages/utils/src/dom/shadow-styles.ts +++ b/packages/utils/src/dom/shadow-styles.ts @@ -2,17 +2,17 @@ export type ShadowStyle = CSSStyleSheet | string; /** Inject a `