Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/domscribe-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"access": "restricted"
},
"distExports": {
"./runtime": "./runtime/index.js",
"./auto-init": "./auto-init/index.js",
"./noop/overlay": "./noop/overlay.js"
},
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
// @vitest-environment jsdom
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';

// Track the latest effect callback registered via useEffect
let capturedEffect: (() => void) | undefined;

vi.mock('react', () => ({
useEffect: (fn: () => void) => {
capturedEffect = fn;
},
}));

const mockInitialize = vi.fn();
const mockGetInstance = vi.fn(() => ({ initialize: mockInitialize }));
const mockCreateReactAdapter = vi.fn(() => ({ name: 'react-adapter' }));
Expand All @@ -26,51 +18,20 @@ vi.mock('@domscribe/overlay', () => ({
initOverlay: mockInitOverlay,
}));

import { DomscribeDevProvider } from './domscribe-provider.js';

describe('DomscribeDevProvider', () => {
describe('auto-init', () => {
beforeEach(() => {
capturedEffect = undefined;
vi.clearAllMocks();
vi.resetModules();
});

afterEach(() => {
vi.unstubAllEnvs();
delete (globalThis as Record<string, unknown>)[
'__DOMSCRIBE_OVERLAY_OPTIONS__'
];
});

it('should return null (renders nothing)', () => {
const result = DomscribeDevProvider();

expect(result).toBeNull();
});

it('should register a useEffect with empty dependency array', () => {
DomscribeDevProvider();

expect(capturedEffect).toBeDefined();
});

it('should skip initialization in production', () => {
vi.stubEnv('NODE_ENV', 'production');

DomscribeDevProvider();
capturedEffect?.();

// Should not attempt to import runtime or react adapter
expect(mockGetInstance).not.toHaveBeenCalled();
expect(mockCreateReactAdapter).not.toHaveBeenCalled();
});

it('should initialize runtime and react adapter in development', async () => {
vi.stubEnv('NODE_ENV', 'development');

DomscribeDevProvider();
capturedEffect?.();

// Allow dynamic import promises to resolve
it('should initialize runtime and react adapter', async () => {
await import('./index.js');
await vi.dynamicImportSettled();

expect(mockGetInstance).toHaveBeenCalled();
Expand All @@ -81,25 +42,18 @@ describe('DomscribeDevProvider', () => {
});

it('should initialize overlay when __DOMSCRIBE_OVERLAY_OPTIONS__ is set', async () => {
vi.stubEnv('NODE_ENV', 'development');
(globalThis as Record<string, unknown>)['__DOMSCRIBE_OVERLAY_OPTIONS__'] = {
initialMode: 'collapsed',
};

DomscribeDevProvider();
capturedEffect?.();

await import('./index.js');
await vi.dynamicImportSettled();

expect(mockInitOverlay).toHaveBeenCalled();
});

it('should not initialize overlay when __DOMSCRIBE_OVERLAY_OPTIONS__ is not set', async () => {
vi.stubEnv('NODE_ENV', 'development');

DomscribeDevProvider();
capturedEffect?.();

await import('./index.js');
await vi.dynamicImportSettled();

expect(mockInitOverlay).not.toHaveBeenCalled();
Expand Down
36 changes: 36 additions & 0 deletions packages/domscribe-next/src/auto-init/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Auto-initialize Domscribe runtime + overlay from the loader preamble.
*
* This module replaces DomscribeDevProvider — it runs at module load time
* instead of requiring a React component in the tree. The turbopack loader
* injects `import('@domscribe/next/auto-init').catch(function(){})` into
* every transformed file, guarded by a `__DOMSCRIBE_AUTO_INIT__` flag to
* ensure it only executes once.
*
* @module @domscribe/next/auto-init
*/

if (typeof window !== 'undefined') {
// Initialize runtime + React adapter
Promise.all([import('@domscribe/runtime'), import('@domscribe/react')])
.then(([{ RuntimeManager }, { createReactAdapter }]) => {
RuntimeManager.getInstance().initialize({
adapter: createReactAdapter(),
});
})
.catch(() => {
// Never break the app
});

// Initialize overlay if configured (globals set by loader preamble)
const win = globalThis as Record<string, unknown>;
if (win['__DOMSCRIBE_OVERLAY_OPTIONS__']) {
import('@domscribe/overlay')
.then(({ initOverlay }) => {
initOverlay();
})
.catch(() => {
// Overlay is optional
});
}
}
2 changes: 1 addition & 1 deletion packages/domscribe-next/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* Zero-config Next.js integration that provides:
* - Build-time AST injection of stable element IDs (Turbopack + Webpack)
* - DomscribeDevProvider component for runtime initialization
* - Auto-initialization of runtime + overlay via loader preamble
* - Relay auto-start and overlay injection via loader-injected window globals
*
* @module @domscribe/next
Expand Down
70 changes: 0 additions & 70 deletions packages/domscribe-next/src/runtime/domscribe-provider.ts

This file was deleted.

5 changes: 0 additions & 5 deletions packages/domscribe-next/src/runtime/index.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/domscribe-next/src/with-domscribe.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,15 +378,15 @@ describe('withDomscribe', () => {
expect(options['debug']).toBe(false);
});

it('should default overlay to false', () => {
it('should default overlay to true', () => {
const result = withDomscribe()({});

const turbopack = result.turbopack as Record<string, unknown>;
const rules = turbopack['rules'] as Record<string, unknown>;
const jsxRule = rules['*.jsx'] as Record<string, unknown>;
const loaders = jsxRule['loaders'] as Array<Record<string, unknown>>;
const options = loaders[0]['options'] as Record<string, unknown>;
expect(options['overlay']).toBe(false);
expect(options['overlay']).toBe(true);
});

it('should default relay to empty object', () => {
Expand Down
13 changes: 5 additions & 8 deletions packages/domscribe-next/src/with-domscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ const DEFAULT_EXCLUDE = /node_modules|\.test\.|\.spec\./i;
* Next.js 16+ Turbopack).
*
* In production, injects resolve aliases that replace @domscribe/overlay
* with a no-op stub so DomscribeDevProvider is safe to leave in the
* component tree without bloating the bundle.
* with a no-op stub as a safety net against accidental imports.
*
* @example
* ```js
Expand Down Expand Up @@ -96,11 +95,9 @@ function resolveNoopOverlay(): string {
/**
* Replace @domscribe/overlay with a no-op stub in production builds.
*
* DomscribeDevProvider lives in the component tree unconditionally (so
* users don't need conditional imports in their layout). In production
* the provider is inert, but bundlers still trace its dynamic import()
* and pull in the full overlay package. Aliasing it to a tiny stub
* keeps the production bundle clean.
* Safety net: if any code path accidentally imports @domscribe/overlay
* in production, this alias ensures the bundle gets a tiny stub instead
* of the full overlay package.
*/
function applyProductionAliases(nextConfig: NextConfig): NextConfig {
const noopOverlay = resolveNoopOverlay();
Expand Down Expand Up @@ -144,7 +141,7 @@ function applyDevTransforms(
exclude = DEFAULT_EXCLUDE,
debug = false,
relay = {},
overlay = false,
overlay = true,
} = options;

return {
Expand Down
11 changes: 11 additions & 0 deletions packages/domscribe-next/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { defineConfig } from 'vitest/config';
import path from 'path';

export default defineConfig({
resolve: {
alias: {
// auto-init dynamically imports @domscribe/overlay which isn't a direct
// dependency — help Vite resolve it for tests (vi.mock intercepts at runtime)
'@domscribe/overlay': path.resolve(
__dirname,
'../domscribe-overlay/src/index.ts',
),
},
},
test: {
name: '@domscribe/next',
watch: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Metadata } from 'next';
import { DomscribeDevProvider } from '@domscribe/next/runtime';
import './globals.css';

export const metadata: Metadata = {
Expand All @@ -15,7 +14,6 @@ export default function RootLayout({
return (
<html lang="en">
<body>
<DomscribeDevProvider />
{children}
</body>
</html>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Metadata } from 'next';
import { DomscribeDevProvider } from '@domscribe/next/runtime';
import './globals.css';

export const metadata: Metadata = {
Expand All @@ -14,10 +13,7 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body>
<DomscribeDevProvider />
{children}
</body>
<body>{children}</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Metadata } from 'next';
import { DomscribeDevProvider } from '@domscribe/next/runtime';
import './globals.css';

export const metadata: Metadata = {
Expand All @@ -14,10 +13,7 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body>
<DomscribeDevProvider />
{children}
</body>
<body>{children}</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Metadata } from 'next';
import { DomscribeDevProvider } from '@domscribe/next/runtime';
import './globals.css';

export const metadata: Metadata = {
Expand All @@ -14,10 +13,7 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body>
<DomscribeDevProvider />
{children}
</body>
<body>{children}</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Metadata } from 'next';
import { DomscribeDevProvider } from '@domscribe/next/runtime';
import './globals.css';

export const metadata: Metadata = {
Expand All @@ -14,10 +13,7 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body>
<DomscribeDevProvider />
{children}
</body>
<body>{children}</body>
</html>
);
}
Loading
Loading