fix(packages): add server-only bundles (#1349)

This commit is contained in:
rahim
2026-04-16 00:59:14 -07:00
committed by GitHub
parent 4ecc870685
commit 3331fdaf25
60 changed files with 654 additions and 215 deletions
+2 -1
View File
@@ -17,7 +17,8 @@
},
"./dom": {
"types": "./dist/dom.d.ts",
"default": "./dist/dom.js"
"browser": "./dist/dom.js",
"default": "./dist/server/dom.js"
},
"./events": {
"types": "./dist/events.d.ts",
+1
View File
@@ -1 +1,2 @@
declare const __DEV__: boolean;
declare const __BROWSER__: boolean;
+1 -1
View File
@@ -1,3 +1,3 @@
export function isMacOS(): boolean {
return typeof navigator !== 'undefined' && /mac/i.test(navigator.userAgent);
return __BROWSER__ && /mac/i.test(navigator.userAgent);
}
+7 -7
View File
@@ -2,17 +2,17 @@ export type ShadowStyle = CSSStyleSheet | string;
/** Inject a `<style>` tag into `document.head` once (idempotent by `id`). */
export function ensureGlobalStyle(id: string, css: string): void {
const doc = globalThis.document;
if (!doc || doc.getElementById(id)) return;
if (!__BROWSER__) return;
if (document.getElementById(id)) return;
const style = doc.createElement('style');
const style = document.createElement('style');
style.id = id;
style.textContent = css;
doc.head.appendChild(style);
document.head.appendChild(style);
}
function isConstructableStyleSheet(value: ShadowStyle): value is CSSStyleSheet {
return typeof globalThis.CSSStyleSheet !== 'undefined' && value instanceof globalThis.CSSStyleSheet;
return __BROWSER__ && typeof CSSStyleSheet !== 'undefined' && value instanceof CSSStyleSheet;
}
function getStyleText(style: ShadowStyle): string {
@@ -25,11 +25,11 @@ function getStyleText(style: ShadowStyle): string {
/** Create a constructable stylesheet when available, otherwise return raw CSS. */
export function createShadowStyle(css: string): ShadowStyle {
if (typeof globalThis.CSSStyleSheet === 'undefined') {
if (!__BROWSER__ || typeof CSSStyleSheet === 'undefined') {
return css;
}
const sheet = new globalThis.CSSStyleSheet();
const sheet = new CSSStyleSheet();
sheet.replaceSync(css);
return sheet;
}
+4 -4
View File
@@ -1,15 +1,15 @@
export function supportsIdleCallback(): boolean {
return typeof requestIdleCallback === 'function';
return __BROWSER__ && typeof requestIdleCallback === 'function';
}
export function supportsAnimationFrame(): boolean {
return typeof requestAnimationFrame === 'function';
return __BROWSER__ && typeof requestAnimationFrame === 'function';
}
export function supportsAnchorPositioning(): boolean {
return typeof CSS !== 'undefined' && CSS.supports('anchor-name: --a');
return __BROWSER__ && typeof CSS !== 'undefined' && CSS.supports('anchor-name: --a');
}
export function supportsPopoverAPI(): boolean {
return typeof HTMLElement !== 'undefined' && 'popover' in HTMLElement.prototype;
return __BROWSER__ && typeof HTMLElement !== 'undefined' && 'popover' in HTMLElement.prototype;
}
+2 -3
View File
@@ -1,9 +1,8 @@
/** Create an `HTMLTemplateElement` from an HTML string, or `null` when `document` is unavailable (SSR). */
export function createTemplate(html: string): HTMLTemplateElement | null {
const doc = globalThis.document;
if (!doc) return null;
if (!__BROWSER__) return null;
const template = doc.createElement('template');
const template = document.createElement('template');
template.innerHTML = html;
return template;
}
@@ -77,7 +77,6 @@ describe('applyShadowStyles', () => {
describe('ensureGlobalStyle', () => {
afterEach(() => {
vi.unstubAllGlobals();
document.head.innerHTML = '';
});
@@ -96,9 +95,4 @@ describe('ensureGlobalStyle', () => {
expect(document.querySelectorAll('#test-dedup').length).toBe(1);
expect(document.getElementById('test-dedup')!.textContent).toBe('a { color: red; }');
});
it('does nothing when document is unavailable', () => {
vi.stubGlobal('document', undefined);
expect(() => ensureGlobalStyle('ssr', 'body {}')).not.toThrow();
});
});
+1 -10
View File
@@ -1,11 +1,7 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { describe, expect, it } from 'vitest';
import { createTemplate, renderTemplate } from '../template';
describe('createTemplate', () => {
afterEach(() => {
vi.unstubAllGlobals();
});
it('returns an HTMLTemplateElement with parsed content', () => {
const template = createTemplate('<div class="root"><span>Hello</span></div>');
@@ -13,11 +9,6 @@ describe('createTemplate', () => {
expect(template!.content.querySelector('.root')).toBeTruthy();
expect(template!.content.querySelector('span')!.textContent).toBe('Hello');
});
it('returns null when document is unavailable', () => {
vi.stubGlobal('document', undefined);
expect(createTemplate('<div></div>')).toBeNull();
});
});
describe('renderTemplate', () => {
+32 -16
View File
@@ -1,24 +1,40 @@
import type { UserConfig } from 'tsdown';
import { defineConfig } from 'tsdown';
export default defineConfig({
entry: {
array: './src/array/index.ts',
dom: './src/dom/index.ts',
events: './src/events/index.ts',
function: './src/function/index.ts',
number: './src/number/index.ts',
object: './src/object/index.ts',
predicate: './src/predicate/index.ts',
string: './src/string/index.ts',
style: './src/style/index.ts',
time: './src/time/index.ts',
types: './src/types/index.ts',
},
platform: 'neutral',
type BuildMode = 'default' | 'server';
const buildModes: BuildMode[] = ['default', 'server'];
const isServer = (mode: BuildMode) => mode === 'server';
const entries = {
array: './src/array/index.ts',
dom: './src/dom/index.ts',
events: './src/events/index.ts',
function: './src/function/index.ts',
number: './src/number/index.ts',
object: './src/object/index.ts',
predicate: './src/predicate/index.ts',
string: './src/string/index.ts',
style: './src/style/index.ts',
time: './src/time/index.ts',
types: './src/types/index.ts',
};
const createConfig = (mode: BuildMode): UserConfig => ({
entry: entries,
platform: isServer(mode) ? 'node' : 'neutral',
format: 'es',
sourcemap: true,
clean: true,
hash: false,
unbundle: true,
dts: true,
outExtensions: isServer(mode) ? () => ({ js: '.js', dts: '.d.ts' }) : undefined,
outDir: isServer(mode) ? 'dist/server' : 'dist',
define: {
__BROWSER__: isServer(mode) ? 'false' : 'true',
},
dts: !isServer(mode),
});
export default defineConfig(buildModes.map((mode) => createConfig(mode)));
+3
View File
@@ -1,6 +1,9 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
define: {
__BROWSER__: 'true',
},
test: {
projects: [
{