@wcstack/server 1.25.0 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -305,7 +305,7 @@ const ssrBody = await renderToString(template, {
|
|
|
305
305
|
const page = `<!DOCTYPE html>
|
|
306
306
|
<html lang="ja">
|
|
307
307
|
<head>
|
|
308
|
-
<script type="module" src="/packages/state/dist/auto.js"></script>
|
|
308
|
+
<script type="module" src="/packages/state/dist/auto.min.js"></script>
|
|
309
309
|
</head>
|
|
310
310
|
<body>${ssrBody}</body>
|
|
311
311
|
</html>`;
|
package/README.md
CHANGED
|
@@ -305,7 +305,7 @@ const ssrBody = await renderToString(template, {
|
|
|
305
305
|
const page = `<!DOCTYPE html>
|
|
306
306
|
<html lang="en">
|
|
307
307
|
<head>
|
|
308
|
-
<script type="module" src="/packages/state/dist/auto.js"></script>
|
|
308
|
+
<script type="module" src="/packages/state/dist/auto.min.js"></script>
|
|
309
309
|
</head>
|
|
310
310
|
<body>${ssrBody}</body>
|
|
311
311
|
</html>`;
|
package/dist/index.d.ts
CHANGED
|
@@ -101,7 +101,7 @@ interface RenderOptions {
|
|
|
101
101
|
* const page = `<!DOCTYPE html>
|
|
102
102
|
* <html lang="ja">
|
|
103
103
|
* <head>
|
|
104
|
-
* <script type="module" src="/packages/state/dist/auto.js"></script>
|
|
104
|
+
* <script type="module" src="/packages/state/dist/auto.min.js"></script>
|
|
105
105
|
* </head>
|
|
106
106
|
* <body>${ssrBody}</body>
|
|
107
107
|
* </html>`;
|
package/dist/index.esm.js
CHANGED
|
@@ -166,7 +166,7 @@ async function loadDefaultBootstraps() {
|
|
|
166
166
|
* const page = `<!DOCTYPE html>
|
|
167
167
|
* <html lang="ja">
|
|
168
168
|
* <head>
|
|
169
|
-
* <script type="module" src="/packages/state/dist/auto.js"></script>
|
|
169
|
+
* <script type="module" src="/packages/state/dist/auto.min.js"></script>
|
|
170
170
|
* </head>
|
|
171
171
|
* <body>${ssrBody}</body>
|
|
172
172
|
* </html>`;
|
|
@@ -233,7 +233,7 @@ async function renderToString(html, options) {
|
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
var version = "1.
|
|
236
|
+
var version = "1.26.0";
|
|
237
237
|
var pkg = {
|
|
238
238
|
version: version};
|
|
239
239
|
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../../src/render.ts","../../src/version.ts","../../src/RenderCore.ts"],"sourcesContent":["import { Window } from 'happy-dom';\n\n/**\n * globalThis を差し替える renderToString の並列実行を防止する Mutex。\n * 同一 Node プロセス内で複数リクエストが同時に renderToString を呼んでも\n * シリアライズされ、グローバル状態の衝突を防ぐ。\n */\nclass Mutex {\n private _queue: (() => void)[] = [];\n private _locked = false;\n\n async acquire(): Promise<() => void> {\n if (this._locked) {\n await new Promise<void>(resolve => this._queue.push(resolve));\n }\n this._locked = true;\n return () => {\n this._locked = false;\n this._queue.shift()?.();\n };\n }\n}\n\nconst renderMutex = new Mutex();\n\nexport const GLOBALS_KEYS = [\n 'document', 'customElements', 'HTMLElement',\n 'DocumentFragment', 'Node', 'NodeFilter', 'Comment', 'Text',\n 'MutationObserver', 'ShadowRoot', 'Element', 'HTMLTemplateElement',\n];\n\nexport function installGlobals(window: Window): () => void {\n const saved: Record<string, any> = {};\n for (const key of GLOBALS_KEYS) {\n saved[key] = (globalThis as any)[key];\n (globalThis as any)[key] = (window as any)[key];\n }\n // URL.createObjectURL を無効化して、\n // loadFromInnerScript が base64 data: URL フォールバックを使うようにする\n const origCreateObjectURL = URL.createObjectURL;\n (URL as any).createObjectURL = undefined;\n return () => {\n URL.createObjectURL = origCreateObjectURL;\n for (const key of GLOBALS_KEYS) {\n (globalThis as any)[key] = saved[key];\n }\n };\n}\n\nexport function installBaseUrl(baseUrl: string): () => void {\n const OrigURL = globalThis.URL;\n const base = baseUrl;\n globalThis.URL = class extends OrigURL {\n constructor(input: string | URL, inputBase?: string | URL) {\n if (typeof input === 'string' && input.startsWith('/') && inputBase === undefined) {\n super(input, base);\n } else {\n super(input as string, inputBase);\n }\n }\n } as typeof URL;\n // 静的メソッドを引き継ぐ\n globalThis.URL.createObjectURL = OrigURL.createObjectURL;\n globalThis.URL.revokeObjectURL = OrigURL.revokeObjectURL;\n return () => { globalThis.URL = OrigURL; };\n}\n\n/** @deprecated Use Ssr.extractStateData() from @wcstack/state instead */\nexport function extractStateData(stateEl: any): Record<string, any> {\n const raw = (stateEl as any).__state;\n if (!raw || typeof raw !== 'object') return {};\n const data: Record<string, any> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!key.startsWith('$') && typeof value !== 'function') {\n data[key] = value;\n }\n }\n return data;\n}\n\nexport type BootstrapFunction = () => void;\n\nexport interface RenderOptions {\n /** 相対 URL を解決するベース URL (例: \"http://localhost:3001\") */\n baseUrl?: string;\n /** bootstrap 関数の配列。省略時は @wcstack/state を自動ロード */\n bootstraps?: BootstrapFunction[];\n}\n\nasync function loadDefaultBootstraps(): Promise<BootstrapFunction[]> {\n const { bootstrapState } = await import('@wcstack/state');\n return [bootstrapState];\n}\n\n\n/**\n * HTML 文字列を SSR レンダリングして返す。\n *\n * ## 入力 HTML のルール\n * - `<body>` の中身だけを渡す(`<html>`, `<head>`, `<body>` タグは含めない)\n * - `<script>` / `<link>` による外部リソース読み込みは実行されない\n * → 必要なパッケージは `options.bootstraps` で明示的に渡す\n *\n * ## SSR でできること\n *\n * ### 状態の初期化とデータ取得\n * - `<wcs-state>` の状態ロード(json 属性, src 属性, inline `<script type=\"module\">`)\n * - `$connectedCallback` でのサーバーサイド fetch(API 呼び出し、DB 問い合わせ等)\n *\n * ```html\n * <!-- JSON 直接指定 -->\n * <wcs-state enable-ssr json='{\"title\":\"Hello\"}'></wcs-state>\n *\n * <!-- $connectedCallback で API からデータ取得 -->\n * <!-- $connectedCallback は状態オブジェクトのメソッドとして定義し、this が state proxy -->\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const res = await fetch('/api/users');\n * this.users = await res.json();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n *\n * ### wcs-fetch を使ったサーバー通信\n * - `<wcs-fetch>` の auto-fetch(`manual` なし)はサーバーでも実行される\n * - `manual` + `$connectedCallback` で明示的に制御する場合:\n *\n * ```html\n * <wcs-fetch id=\"api\" url=\"/api/users\" manual></wcs-fetch>\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const el = document.getElementById('api');\n * this.users = await el.fetch();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n * ※ `bootstraps` に `bootstrapFetch` を含める必要あり\n *\n * ### バインディングと構造レンダリング\n * - `data-wcs` バインディングの適用(text, attribute, class, style, property)\n * - `<template data-wcs=\"for:\">` / `if:` / `elseif:` / `else:` の構造レンダリング\n *\n * ```html\n * <ul>\n * <template data-wcs=\"for: users\">\n * <li data-wcs=\"textContent: .name\"></li>\n * </template>\n * </ul>\n * <template data-wcs=\"if: isAdmin\">\n * <div class=\"admin-panel\">...</div>\n * </template>\n * ```\n *\n * ### ハイドレーション\n * - `enable-ssr` 付き `<wcs-state>` の `<wcs-ssr>` メタデータ自動生成\n * - クライアント側でのハイドレーション(再レンダリングなしでバインディング復元)\n * - `enable-ssr` を外した `<wcs-state>` はクライアントのみで動作(部分 CSR)\n *\n * ### カスタム要素の待機\n * - `static hasConnectedCallbackPromise = true` プロトコル準拠の全カスタム要素を自動待機\n * - `$connectedCallback` 中に動的追加されたカスタム要素も安定化ループで検出・待機(最大 10 回)\n *\n * ## SSR でできないこと\n * - `<head>` 内の `<script src=\"...\">` や `<link>` の自動実行\n * - ブラウザ固有 API(localStorage, sessionStorage, navigator 等)\n * - Shadow DOM のレンダリング(Declarative Shadow DOM 非対応)\n * - イベントハンドラの登録(クライアント側のハイドレーションで復元)\n * - `<wcs-autoloader>` による動的コンポーネント読み込み\n *\n * ## HTML の分割パターン\n * ```\n * // server.js\n * const ssrBody = await renderToString(template, { ... });\n * const page = `<!DOCTYPE html>\n * <html lang=\"ja\">\n * <head>\n * <script type=\"module\" src=\"/packages/state/dist/auto.js\"></script>\n * </head>\n * <body>${ssrBody}</body>\n * </html>`;\n * ```\n * `renderToString` には `<body>` の中身だけを渡し、\n * `<head>` や `<script>` タグは外側のテンプレートで囲む。\n */\nexport async function renderToString(html: string, options?: RenderOptions): Promise<string> {\n // globalThis を差し替えるため、同時に1つしか実行できない\n const releaseMutex = await renderMutex.acquire();\n\n const window = new Window();\n const restoreGlobals = installGlobals(window);\n const document = window.document;\n\n // 相対 URL を baseUrl で解決する URL コンストラクタパッチをインストール\n const restoreBaseUrl = options?.baseUrl\n ? installBaseUrl(options.baseUrl)\n : null;\n\n // bootstrap の解決\n const bootstraps = options?.bootstraps ?? await loadDefaultBootstraps();\n\n for (const bootstrap of bootstraps) {\n bootstrap();\n }\n\n try {\n\n // SSR モードを html 要素に設定\n document.documentElement.setAttribute('data-wcs-server', '');\n\n // HTML をパース\n // connectedCallback が自動発火 → state ロード → $connectedCallback 実行\n document.body.innerHTML = html;\n\n // connectedCallbackPromise / getBindingsReady プロトコルを自動検出\n // $connectedCallback が動的にカスタム要素を追加する場合があるため、\n // 新しい要素が見つからなくなるまで走査を繰り返す(安定化ループ)\n const MAX_ITERATIONS = 10;\n const awaitedElements = new WeakSet();\n const readyCtors = new Set<any>();\n const readyPromises: Promise<void>[] = [];\n\n for (let i = 0; i < MAX_ITERATIONS; i++) {\n const connectedPromises: Promise<void>[] = [];\n\n for (const el of document.querySelectorAll('*-*')) {\n if (awaitedElements.has(el)) continue;\n const ctor = el.constructor as any;\n if (ctor.hasConnectedCallbackPromise) {\n awaitedElements.add(el);\n connectedPromises.push((el as any).connectedCallbackPromise);\n }\n if (!readyCtors.has(ctor) && typeof ctor.getBindingsReady === 'function') {\n readyCtors.add(ctor);\n readyPromises.push(ctor.getBindingsReady(document));\n }\n }\n\n if (connectedPromises.length === 0) break;\n await Promise.all(connectedPromises);\n }\n\n // 非同期初期化の完了を待機\n await Promise.all(readyPromises);\n\n return document.body.innerHTML;\n } finally {\n restoreBaseUrl?.();\n restoreGlobals();\n await window.close();\n releaseMutex();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\nexport const VERSION = pkg.version;\n","import { renderToString } from \"./render.js\";\nimport { IWcBindable } from \"./types.js\";\n\nexport class RenderCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"html\", event: \"wcs-render:html-changed\", semantics: \"state\" },\n { name: \"loading\", event: \"wcs-render:loading-changed\", semantics: \"state\" },\n { name: \"error\", event: \"wcs-render:error\", semantics: \"state\" },\n ],\n };\n\n private _html: string | null = null;\n private _loading: boolean = false;\n private _error: Error | null = null;\n\n get html(): string | null {\n return this._html;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): Error | null {\n return this._error;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this.dispatchEvent(new CustomEvent(\"wcs-render:loading-changed\", {\n detail: loading,\n }));\n }\n\n private _setHtml(html: string): void {\n this._html = html;\n this.dispatchEvent(new CustomEvent(\"wcs-render:html-changed\", {\n detail: html,\n }));\n }\n\n private _setError(error: Error | null): void {\n this._error = error;\n this.dispatchEvent(new CustomEvent(\"wcs-render:error\", {\n detail: error,\n }));\n }\n\n async render(html: string): Promise<string | null> {\n this._setLoading(true);\n this._setError(null);\n\n try {\n const result = await renderToString(html);\n this._setHtml(result);\n this._setLoading(false);\n return this._html;\n } catch (e: any) {\n this._setError(e instanceof Error ? e : new Error(String(e)));\n this._setLoading(false);\n return null;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../src/render.ts","../../src/version.ts","../../src/RenderCore.ts"],"sourcesContent":["import { Window } from 'happy-dom';\n\n/**\n * globalThis を差し替える renderToString の並列実行を防止する Mutex。\n * 同一 Node プロセス内で複数リクエストが同時に renderToString を呼んでも\n * シリアライズされ、グローバル状態の衝突を防ぐ。\n */\nclass Mutex {\n private _queue: (() => void)[] = [];\n private _locked = false;\n\n async acquire(): Promise<() => void> {\n if (this._locked) {\n await new Promise<void>(resolve => this._queue.push(resolve));\n }\n this._locked = true;\n return () => {\n this._locked = false;\n this._queue.shift()?.();\n };\n }\n}\n\nconst renderMutex = new Mutex();\n\nexport const GLOBALS_KEYS = [\n 'document', 'customElements', 'HTMLElement',\n 'DocumentFragment', 'Node', 'NodeFilter', 'Comment', 'Text',\n 'MutationObserver', 'ShadowRoot', 'Element', 'HTMLTemplateElement',\n];\n\nexport function installGlobals(window: Window): () => void {\n const saved: Record<string, any> = {};\n for (const key of GLOBALS_KEYS) {\n saved[key] = (globalThis as any)[key];\n (globalThis as any)[key] = (window as any)[key];\n }\n // URL.createObjectURL を無効化して、\n // loadFromInnerScript が base64 data: URL フォールバックを使うようにする\n const origCreateObjectURL = URL.createObjectURL;\n (URL as any).createObjectURL = undefined;\n return () => {\n URL.createObjectURL = origCreateObjectURL;\n for (const key of GLOBALS_KEYS) {\n (globalThis as any)[key] = saved[key];\n }\n };\n}\n\nexport function installBaseUrl(baseUrl: string): () => void {\n const OrigURL = globalThis.URL;\n const base = baseUrl;\n globalThis.URL = class extends OrigURL {\n constructor(input: string | URL, inputBase?: string | URL) {\n if (typeof input === 'string' && input.startsWith('/') && inputBase === undefined) {\n super(input, base);\n } else {\n super(input as string, inputBase);\n }\n }\n } as typeof URL;\n // 静的メソッドを引き継ぐ\n globalThis.URL.createObjectURL = OrigURL.createObjectURL;\n globalThis.URL.revokeObjectURL = OrigURL.revokeObjectURL;\n return () => { globalThis.URL = OrigURL; };\n}\n\n/** @deprecated Use Ssr.extractStateData() from @wcstack/state instead */\nexport function extractStateData(stateEl: any): Record<string, any> {\n const raw = (stateEl as any).__state;\n if (!raw || typeof raw !== 'object') return {};\n const data: Record<string, any> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!key.startsWith('$') && typeof value !== 'function') {\n data[key] = value;\n }\n }\n return data;\n}\n\nexport type BootstrapFunction = () => void;\n\nexport interface RenderOptions {\n /** 相対 URL を解決するベース URL (例: \"http://localhost:3001\") */\n baseUrl?: string;\n /** bootstrap 関数の配列。省略時は @wcstack/state を自動ロード */\n bootstraps?: BootstrapFunction[];\n}\n\nasync function loadDefaultBootstraps(): Promise<BootstrapFunction[]> {\n const { bootstrapState } = await import('@wcstack/state');\n return [bootstrapState];\n}\n\n\n/**\n * HTML 文字列を SSR レンダリングして返す。\n *\n * ## 入力 HTML のルール\n * - `<body>` の中身だけを渡す(`<html>`, `<head>`, `<body>` タグは含めない)\n * - `<script>` / `<link>` による外部リソース読み込みは実行されない\n * → 必要なパッケージは `options.bootstraps` で明示的に渡す\n *\n * ## SSR でできること\n *\n * ### 状態の初期化とデータ取得\n * - `<wcs-state>` の状態ロード(json 属性, src 属性, inline `<script type=\"module\">`)\n * - `$connectedCallback` でのサーバーサイド fetch(API 呼び出し、DB 問い合わせ等)\n *\n * ```html\n * <!-- JSON 直接指定 -->\n * <wcs-state enable-ssr json='{\"title\":\"Hello\"}'></wcs-state>\n *\n * <!-- $connectedCallback で API からデータ取得 -->\n * <!-- $connectedCallback は状態オブジェクトのメソッドとして定義し、this が state proxy -->\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const res = await fetch('/api/users');\n * this.users = await res.json();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n *\n * ### wcs-fetch を使ったサーバー通信\n * - `<wcs-fetch>` の auto-fetch(`manual` なし)はサーバーでも実行される\n * - `manual` + `$connectedCallback` で明示的に制御する場合:\n *\n * ```html\n * <wcs-fetch id=\"api\" url=\"/api/users\" manual></wcs-fetch>\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const el = document.getElementById('api');\n * this.users = await el.fetch();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n * ※ `bootstraps` に `bootstrapFetch` を含める必要あり\n *\n * ### バインディングと構造レンダリング\n * - `data-wcs` バインディングの適用(text, attribute, class, style, property)\n * - `<template data-wcs=\"for:\">` / `if:` / `elseif:` / `else:` の構造レンダリング\n *\n * ```html\n * <ul>\n * <template data-wcs=\"for: users\">\n * <li data-wcs=\"textContent: .name\"></li>\n * </template>\n * </ul>\n * <template data-wcs=\"if: isAdmin\">\n * <div class=\"admin-panel\">...</div>\n * </template>\n * ```\n *\n * ### ハイドレーション\n * - `enable-ssr` 付き `<wcs-state>` の `<wcs-ssr>` メタデータ自動生成\n * - クライアント側でのハイドレーション(再レンダリングなしでバインディング復元)\n * - `enable-ssr` を外した `<wcs-state>` はクライアントのみで動作(部分 CSR)\n *\n * ### カスタム要素の待機\n * - `static hasConnectedCallbackPromise = true` プロトコル準拠の全カスタム要素を自動待機\n * - `$connectedCallback` 中に動的追加されたカスタム要素も安定化ループで検出・待機(最大 10 回)\n *\n * ## SSR でできないこと\n * - `<head>` 内の `<script src=\"...\">` や `<link>` の自動実行\n * - ブラウザ固有 API(localStorage, sessionStorage, navigator 等)\n * - Shadow DOM のレンダリング(Declarative Shadow DOM 非対応)\n * - イベントハンドラの登録(クライアント側のハイドレーションで復元)\n * - `<wcs-autoloader>` による動的コンポーネント読み込み\n *\n * ## HTML の分割パターン\n * ```\n * // server.js\n * const ssrBody = await renderToString(template, { ... });\n * const page = `<!DOCTYPE html>\n * <html lang=\"ja\">\n * <head>\n * <script type=\"module\" src=\"/packages/state/dist/auto.min.js\"></script>\n * </head>\n * <body>${ssrBody}</body>\n * </html>`;\n * ```\n * `renderToString` には `<body>` の中身だけを渡し、\n * `<head>` や `<script>` タグは外側のテンプレートで囲む。\n */\nexport async function renderToString(html: string, options?: RenderOptions): Promise<string> {\n // globalThis を差し替えるため、同時に1つしか実行できない\n const releaseMutex = await renderMutex.acquire();\n\n const window = new Window();\n const restoreGlobals = installGlobals(window);\n const document = window.document;\n\n // 相対 URL を baseUrl で解決する URL コンストラクタパッチをインストール\n const restoreBaseUrl = options?.baseUrl\n ? installBaseUrl(options.baseUrl)\n : null;\n\n // bootstrap の解決\n const bootstraps = options?.bootstraps ?? await loadDefaultBootstraps();\n\n for (const bootstrap of bootstraps) {\n bootstrap();\n }\n\n try {\n\n // SSR モードを html 要素に設定\n document.documentElement.setAttribute('data-wcs-server', '');\n\n // HTML をパース\n // connectedCallback が自動発火 → state ロード → $connectedCallback 実行\n document.body.innerHTML = html;\n\n // connectedCallbackPromise / getBindingsReady プロトコルを自動検出\n // $connectedCallback が動的にカスタム要素を追加する場合があるため、\n // 新しい要素が見つからなくなるまで走査を繰り返す(安定化ループ)\n const MAX_ITERATIONS = 10;\n const awaitedElements = new WeakSet();\n const readyCtors = new Set<any>();\n const readyPromises: Promise<void>[] = [];\n\n for (let i = 0; i < MAX_ITERATIONS; i++) {\n const connectedPromises: Promise<void>[] = [];\n\n for (const el of document.querySelectorAll('*-*')) {\n if (awaitedElements.has(el)) continue;\n const ctor = el.constructor as any;\n if (ctor.hasConnectedCallbackPromise) {\n awaitedElements.add(el);\n connectedPromises.push((el as any).connectedCallbackPromise);\n }\n if (!readyCtors.has(ctor) && typeof ctor.getBindingsReady === 'function') {\n readyCtors.add(ctor);\n readyPromises.push(ctor.getBindingsReady(document));\n }\n }\n\n if (connectedPromises.length === 0) break;\n await Promise.all(connectedPromises);\n }\n\n // 非同期初期化の完了を待機\n await Promise.all(readyPromises);\n\n return document.body.innerHTML;\n } finally {\n restoreBaseUrl?.();\n restoreGlobals();\n await window.close();\n releaseMutex();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\nexport const VERSION = pkg.version;\n","import { renderToString } from \"./render.js\";\nimport { IWcBindable } from \"./types.js\";\n\nexport class RenderCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"html\", event: \"wcs-render:html-changed\", semantics: \"state\" },\n { name: \"loading\", event: \"wcs-render:loading-changed\", semantics: \"state\" },\n { name: \"error\", event: \"wcs-render:error\", semantics: \"state\" },\n ],\n };\n\n private _html: string | null = null;\n private _loading: boolean = false;\n private _error: Error | null = null;\n\n get html(): string | null {\n return this._html;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): Error | null {\n return this._error;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this.dispatchEvent(new CustomEvent(\"wcs-render:loading-changed\", {\n detail: loading,\n }));\n }\n\n private _setHtml(html: string): void {\n this._html = html;\n this.dispatchEvent(new CustomEvent(\"wcs-render:html-changed\", {\n detail: html,\n }));\n }\n\n private _setError(error: Error | null): void {\n this._error = error;\n this.dispatchEvent(new CustomEvent(\"wcs-render:error\", {\n detail: error,\n }));\n }\n\n async render(html: string): Promise<string | null> {\n this._setLoading(true);\n this._setError(null);\n\n try {\n const result = await renderToString(html);\n this._setHtml(result);\n this._setLoading(false);\n return this._html;\n } catch (e: any) {\n this._setError(e instanceof Error ? e : new Error(String(e)));\n this._setLoading(false);\n return null;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.esm.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Window as t}from"happy-dom";const e=new class{_queue=[];_locked=!1;async acquire(){return this._locked&&await new Promise(t=>this._queue.push(t)),this._locked=!0,()=>{this._locked=!1,this._queue.shift()?.()}}},n=["document","customElements","HTMLElement","DocumentFragment","Node","NodeFilter","Comment","Text","MutationObserver","ShadowRoot","Element","HTMLTemplateElement"];function r(t){const e={};for(const r of n)e[r]=globalThis[r],globalThis[r]=t[r];const r=URL.createObjectURL;return URL.createObjectURL=void 0,()=>{URL.createObjectURL=r;for(const t of n)globalThis[t]=e[t]}}function s(t){const e=globalThis.URL,n=t;return globalThis.URL=class extends e{constructor(t,e){"string"==typeof t&&t.startsWith("/")&&void 0===e?super(t,n):super(t,e)}},globalThis.URL.createObjectURL=e.createObjectURL,globalThis.URL.revokeObjectURL=e.revokeObjectURL,()=>{globalThis.URL=e}}function o(t){const e=t.__state;if(!e||"object"!=typeof e)return{};const n={};for(const[t,r]of Object.entries(e))t.startsWith("$")||"function"==typeof r||(n[t]=r);return n}async function a(n,o){const a=await e.acquire(),i=new t,c=r(i),l=i.document,d=o?.baseUrl?s(o.baseUrl):null,h=o?.bootstraps??await async function(){const{bootstrapState:t}=await import("@wcstack/state");return[t]}();for(const t of h)t();try{l.documentElement.setAttribute("data-wcs-server",""),l.body.innerHTML=n;const t=10,e=new WeakSet,r=new Set,s=[];for(let n=0;n<t;n++){const t=[];for(const n of l.querySelectorAll("*-*")){if(e.has(n))continue;const o=n.constructor;o.hasConnectedCallbackPromise&&(e.add(n),t.push(n.connectedCallbackPromise)),r.has(o)||"function"!=typeof o.getBindingsReady||(r.add(o),s.push(o.getBindingsReady(l)))}if(0===t.length)break;await Promise.all(t)}return await Promise.all(s),l.body.innerHTML}finally{d?.(),c(),await i.close(),a()}}const i="1.
|
|
1
|
+
import{Window as t}from"happy-dom";const e=new class{_queue=[];_locked=!1;async acquire(){return this._locked&&await new Promise(t=>this._queue.push(t)),this._locked=!0,()=>{this._locked=!1,this._queue.shift()?.()}}},n=["document","customElements","HTMLElement","DocumentFragment","Node","NodeFilter","Comment","Text","MutationObserver","ShadowRoot","Element","HTMLTemplateElement"];function r(t){const e={};for(const r of n)e[r]=globalThis[r],globalThis[r]=t[r];const r=URL.createObjectURL;return URL.createObjectURL=void 0,()=>{URL.createObjectURL=r;for(const t of n)globalThis[t]=e[t]}}function s(t){const e=globalThis.URL,n=t;return globalThis.URL=class extends e{constructor(t,e){"string"==typeof t&&t.startsWith("/")&&void 0===e?super(t,n):super(t,e)}},globalThis.URL.createObjectURL=e.createObjectURL,globalThis.URL.revokeObjectURL=e.revokeObjectURL,()=>{globalThis.URL=e}}function o(t){const e=t.__state;if(!e||"object"!=typeof e)return{};const n={};for(const[t,r]of Object.entries(e))t.startsWith("$")||"function"==typeof r||(n[t]=r);return n}async function a(n,o){const a=await e.acquire(),i=new t,c=r(i),l=i.document,d=o?.baseUrl?s(o.baseUrl):null,h=o?.bootstraps??await async function(){const{bootstrapState:t}=await import("@wcstack/state");return[t]}();for(const t of h)t();try{l.documentElement.setAttribute("data-wcs-server",""),l.body.innerHTML=n;const t=10,e=new WeakSet,r=new Set,s=[];for(let n=0;n<t;n++){const t=[];for(const n of l.querySelectorAll("*-*")){if(e.has(n))continue;const o=n.constructor;o.hasConnectedCallbackPromise&&(e.add(n),t.push(n.connectedCallbackPromise)),r.has(o)||"function"!=typeof o.getBindingsReady||(r.add(o),s.push(o.getBindingsReady(l)))}if(0===t.length)break;await Promise.all(t)}return await Promise.all(s),l.body.innerHTML}finally{d?.(),c(),await i.close(),a()}}const i="1.26.0";class c extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"html",event:"wcs-render:html-changed",semantics:"state"},{name:"loading",event:"wcs-render:loading-changed",semantics:"state"},{name:"error",event:"wcs-render:error",semantics:"state"}]};_html=null;_loading=!1;_error=null;get html(){return this._html}get loading(){return this._loading}get error(){return this._error}_setLoading(t){this._loading=t,this.dispatchEvent(new CustomEvent("wcs-render:loading-changed",{detail:t}))}_setHtml(t){this._html=t,this.dispatchEvent(new CustomEvent("wcs-render:html-changed",{detail:t}))}_setError(t){this._error=t,this.dispatchEvent(new CustomEvent("wcs-render:error",{detail:t}))}async render(t){this._setLoading(!0),this._setError(null);try{const e=await a(t);return this._setHtml(e),this._setLoading(!1),this._html}catch(t){return this._setError(t instanceof Error?t:new Error(String(t))),this._setLoading(!1),null}}}export{n as GLOBALS_KEYS,c as RenderCore,i as VERSION,o as extractStateData,s as installBaseUrl,r as installGlobals,a as renderToString};
|
|
2
2
|
//# sourceMappingURL=index.esm.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.min.js","sources":["../../src/render.ts","../../src/version.ts","../../src/RenderCore.ts"],"sourcesContent":["import { Window } from 'happy-dom';\n\n/**\n * globalThis を差し替える renderToString の並列実行を防止する Mutex。\n * 同一 Node プロセス内で複数リクエストが同時に renderToString を呼んでも\n * シリアライズされ、グローバル状態の衝突を防ぐ。\n */\nclass Mutex {\n private _queue: (() => void)[] = [];\n private _locked = false;\n\n async acquire(): Promise<() => void> {\n if (this._locked) {\n await new Promise<void>(resolve => this._queue.push(resolve));\n }\n this._locked = true;\n return () => {\n this._locked = false;\n this._queue.shift()?.();\n };\n }\n}\n\nconst renderMutex = new Mutex();\n\nexport const GLOBALS_KEYS = [\n 'document', 'customElements', 'HTMLElement',\n 'DocumentFragment', 'Node', 'NodeFilter', 'Comment', 'Text',\n 'MutationObserver', 'ShadowRoot', 'Element', 'HTMLTemplateElement',\n];\n\nexport function installGlobals(window: Window): () => void {\n const saved: Record<string, any> = {};\n for (const key of GLOBALS_KEYS) {\n saved[key] = (globalThis as any)[key];\n (globalThis as any)[key] = (window as any)[key];\n }\n // URL.createObjectURL を無効化して、\n // loadFromInnerScript が base64 data: URL フォールバックを使うようにする\n const origCreateObjectURL = URL.createObjectURL;\n (URL as any).createObjectURL = undefined;\n return () => {\n URL.createObjectURL = origCreateObjectURL;\n for (const key of GLOBALS_KEYS) {\n (globalThis as any)[key] = saved[key];\n }\n };\n}\n\nexport function installBaseUrl(baseUrl: string): () => void {\n const OrigURL = globalThis.URL;\n const base = baseUrl;\n globalThis.URL = class extends OrigURL {\n constructor(input: string | URL, inputBase?: string | URL) {\n if (typeof input === 'string' && input.startsWith('/') && inputBase === undefined) {\n super(input, base);\n } else {\n super(input as string, inputBase);\n }\n }\n } as typeof URL;\n // 静的メソッドを引き継ぐ\n globalThis.URL.createObjectURL = OrigURL.createObjectURL;\n globalThis.URL.revokeObjectURL = OrigURL.revokeObjectURL;\n return () => { globalThis.URL = OrigURL; };\n}\n\n/** @deprecated Use Ssr.extractStateData() from @wcstack/state instead */\nexport function extractStateData(stateEl: any): Record<string, any> {\n const raw = (stateEl as any).__state;\n if (!raw || typeof raw !== 'object') return {};\n const data: Record<string, any> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!key.startsWith('$') && typeof value !== 'function') {\n data[key] = value;\n }\n }\n return data;\n}\n\nexport type BootstrapFunction = () => void;\n\nexport interface RenderOptions {\n /** 相対 URL を解決するベース URL (例: \"http://localhost:3001\") */\n baseUrl?: string;\n /** bootstrap 関数の配列。省略時は @wcstack/state を自動ロード */\n bootstraps?: BootstrapFunction[];\n}\n\nasync function loadDefaultBootstraps(): Promise<BootstrapFunction[]> {\n const { bootstrapState } = await import('@wcstack/state');\n return [bootstrapState];\n}\n\n\n/**\n * HTML 文字列を SSR レンダリングして返す。\n *\n * ## 入力 HTML のルール\n * - `<body>` の中身だけを渡す(`<html>`, `<head>`, `<body>` タグは含めない)\n * - `<script>` / `<link>` による外部リソース読み込みは実行されない\n * → 必要なパッケージは `options.bootstraps` で明示的に渡す\n *\n * ## SSR でできること\n *\n * ### 状態の初期化とデータ取得\n * - `<wcs-state>` の状態ロード(json 属性, src 属性, inline `<script type=\"module\">`)\n * - `$connectedCallback` でのサーバーサイド fetch(API 呼び出し、DB 問い合わせ等)\n *\n * ```html\n * <!-- JSON 直接指定 -->\n * <wcs-state enable-ssr json='{\"title\":\"Hello\"}'></wcs-state>\n *\n * <!-- $connectedCallback で API からデータ取得 -->\n * <!-- $connectedCallback は状態オブジェクトのメソッドとして定義し、this が state proxy -->\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const res = await fetch('/api/users');\n * this.users = await res.json();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n *\n * ### wcs-fetch を使ったサーバー通信\n * - `<wcs-fetch>` の auto-fetch(`manual` なし)はサーバーでも実行される\n * - `manual` + `$connectedCallback` で明示的に制御する場合:\n *\n * ```html\n * <wcs-fetch id=\"api\" url=\"/api/users\" manual></wcs-fetch>\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const el = document.getElementById('api');\n * this.users = await el.fetch();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n * ※ `bootstraps` に `bootstrapFetch` を含める必要あり\n *\n * ### バインディングと構造レンダリング\n * - `data-wcs` バインディングの適用(text, attribute, class, style, property)\n * - `<template data-wcs=\"for:\">` / `if:` / `elseif:` / `else:` の構造レンダリング\n *\n * ```html\n * <ul>\n * <template data-wcs=\"for: users\">\n * <li data-wcs=\"textContent: .name\"></li>\n * </template>\n * </ul>\n * <template data-wcs=\"if: isAdmin\">\n * <div class=\"admin-panel\">...</div>\n * </template>\n * ```\n *\n * ### ハイドレーション\n * - `enable-ssr` 付き `<wcs-state>` の `<wcs-ssr>` メタデータ自動生成\n * - クライアント側でのハイドレーション(再レンダリングなしでバインディング復元)\n * - `enable-ssr` を外した `<wcs-state>` はクライアントのみで動作(部分 CSR)\n *\n * ### カスタム要素の待機\n * - `static hasConnectedCallbackPromise = true` プロトコル準拠の全カスタム要素を自動待機\n * - `$connectedCallback` 中に動的追加されたカスタム要素も安定化ループで検出・待機(最大 10 回)\n *\n * ## SSR でできないこと\n * - `<head>` 内の `<script src=\"...\">` や `<link>` の自動実行\n * - ブラウザ固有 API(localStorage, sessionStorage, navigator 等)\n * - Shadow DOM のレンダリング(Declarative Shadow DOM 非対応)\n * - イベントハンドラの登録(クライアント側のハイドレーションで復元)\n * - `<wcs-autoloader>` による動的コンポーネント読み込み\n *\n * ## HTML の分割パターン\n * ```\n * // server.js\n * const ssrBody = await renderToString(template, { ... });\n * const page = `<!DOCTYPE html>\n * <html lang=\"ja\">\n * <head>\n * <script type=\"module\" src=\"/packages/state/dist/auto.js\"></script>\n * </head>\n * <body>${ssrBody}</body>\n * </html>`;\n * ```\n * `renderToString` には `<body>` の中身だけを渡し、\n * `<head>` や `<script>` タグは外側のテンプレートで囲む。\n */\nexport async function renderToString(html: string, options?: RenderOptions): Promise<string> {\n // globalThis を差し替えるため、同時に1つしか実行できない\n const releaseMutex = await renderMutex.acquire();\n\n const window = new Window();\n const restoreGlobals = installGlobals(window);\n const document = window.document;\n\n // 相対 URL を baseUrl で解決する URL コンストラクタパッチをインストール\n const restoreBaseUrl = options?.baseUrl\n ? installBaseUrl(options.baseUrl)\n : null;\n\n // bootstrap の解決\n const bootstraps = options?.bootstraps ?? await loadDefaultBootstraps();\n\n for (const bootstrap of bootstraps) {\n bootstrap();\n }\n\n try {\n\n // SSR モードを html 要素に設定\n document.documentElement.setAttribute('data-wcs-server', '');\n\n // HTML をパース\n // connectedCallback が自動発火 → state ロード → $connectedCallback 実行\n document.body.innerHTML = html;\n\n // connectedCallbackPromise / getBindingsReady プロトコルを自動検出\n // $connectedCallback が動的にカスタム要素を追加する場合があるため、\n // 新しい要素が見つからなくなるまで走査を繰り返す(安定化ループ)\n const MAX_ITERATIONS = 10;\n const awaitedElements = new WeakSet();\n const readyCtors = new Set<any>();\n const readyPromises: Promise<void>[] = [];\n\n for (let i = 0; i < MAX_ITERATIONS; i++) {\n const connectedPromises: Promise<void>[] = [];\n\n for (const el of document.querySelectorAll('*-*')) {\n if (awaitedElements.has(el)) continue;\n const ctor = el.constructor as any;\n if (ctor.hasConnectedCallbackPromise) {\n awaitedElements.add(el);\n connectedPromises.push((el as any).connectedCallbackPromise);\n }\n if (!readyCtors.has(ctor) && typeof ctor.getBindingsReady === 'function') {\n readyCtors.add(ctor);\n readyPromises.push(ctor.getBindingsReady(document));\n }\n }\n\n if (connectedPromises.length === 0) break;\n await Promise.all(connectedPromises);\n }\n\n // 非同期初期化の完了を待機\n await Promise.all(readyPromises);\n\n return document.body.innerHTML;\n } finally {\n restoreBaseUrl?.();\n restoreGlobals();\n await window.close();\n releaseMutex();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\nexport const VERSION = pkg.version;\n","import { renderToString } from \"./render.js\";\nimport { IWcBindable } from \"./types.js\";\n\nexport class RenderCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"html\", event: \"wcs-render:html-changed\", semantics: \"state\" },\n { name: \"loading\", event: \"wcs-render:loading-changed\", semantics: \"state\" },\n { name: \"error\", event: \"wcs-render:error\", semantics: \"state\" },\n ],\n };\n\n private _html: string | null = null;\n private _loading: boolean = false;\n private _error: Error | null = null;\n\n get html(): string | null {\n return this._html;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): Error | null {\n return this._error;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this.dispatchEvent(new CustomEvent(\"wcs-render:loading-changed\", {\n detail: loading,\n }));\n }\n\n private _setHtml(html: string): void {\n this._html = html;\n this.dispatchEvent(new CustomEvent(\"wcs-render:html-changed\", {\n detail: html,\n }));\n }\n\n private _setError(error: Error | null): void {\n this._error = error;\n this.dispatchEvent(new CustomEvent(\"wcs-render:error\", {\n detail: error,\n }));\n }\n\n async render(html: string): Promise<string | null> {\n this._setLoading(true);\n this._setError(null);\n\n try {\n const result = await renderToString(html);\n this._setHtml(result);\n this._setLoading(false);\n return this._html;\n } catch (e: any) {\n this._setError(e instanceof Error ? e : new Error(String(e)));\n this._setLoading(false);\n return null;\n }\n }\n}\n"],"names":["renderMutex","_queue","_locked","acquire","this","Promise","resolve","push","shift","GLOBALS_KEYS","installGlobals","window","saved","key","globalThis","origCreateObjectURL","URL","createObjectURL","undefined","installBaseUrl","baseUrl","OrigURL","base","constructor","input","inputBase","startsWith","super","revokeObjectURL","extractStateData","stateEl","raw","__state","data","value","Object","entries","async","renderToString","html","options","releaseMutex","Window","restoreGlobals","document","restoreBaseUrl","bootstraps","bootstrapState","import","loadDefaultBootstraps","bootstrap","documentElement","setAttribute","body","innerHTML","MAX_ITERATIONS","awaitedElements","WeakSet","readyCtors","Set","readyPromises","i","connectedPromises","el","querySelectorAll","has","ctor","hasConnectedCallbackPromise","add","connectedCallbackPromise","getBindingsReady","length","all","close","VERSION","RenderCore","EventTarget","static","protocol","version","properties","name","event","semantics","_html","_loading","_error","loading","error","_setLoading","dispatchEvent","CustomEvent","detail","_setHtml","_setError","render","result","e","Error","String"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.min.js","sources":["../../src/render.ts","../../src/version.ts","../../src/RenderCore.ts"],"sourcesContent":["import { Window } from 'happy-dom';\n\n/**\n * globalThis を差し替える renderToString の並列実行を防止する Mutex。\n * 同一 Node プロセス内で複数リクエストが同時に renderToString を呼んでも\n * シリアライズされ、グローバル状態の衝突を防ぐ。\n */\nclass Mutex {\n private _queue: (() => void)[] = [];\n private _locked = false;\n\n async acquire(): Promise<() => void> {\n if (this._locked) {\n await new Promise<void>(resolve => this._queue.push(resolve));\n }\n this._locked = true;\n return () => {\n this._locked = false;\n this._queue.shift()?.();\n };\n }\n}\n\nconst renderMutex = new Mutex();\n\nexport const GLOBALS_KEYS = [\n 'document', 'customElements', 'HTMLElement',\n 'DocumentFragment', 'Node', 'NodeFilter', 'Comment', 'Text',\n 'MutationObserver', 'ShadowRoot', 'Element', 'HTMLTemplateElement',\n];\n\nexport function installGlobals(window: Window): () => void {\n const saved: Record<string, any> = {};\n for (const key of GLOBALS_KEYS) {\n saved[key] = (globalThis as any)[key];\n (globalThis as any)[key] = (window as any)[key];\n }\n // URL.createObjectURL を無効化して、\n // loadFromInnerScript が base64 data: URL フォールバックを使うようにする\n const origCreateObjectURL = URL.createObjectURL;\n (URL as any).createObjectURL = undefined;\n return () => {\n URL.createObjectURL = origCreateObjectURL;\n for (const key of GLOBALS_KEYS) {\n (globalThis as any)[key] = saved[key];\n }\n };\n}\n\nexport function installBaseUrl(baseUrl: string): () => void {\n const OrigURL = globalThis.URL;\n const base = baseUrl;\n globalThis.URL = class extends OrigURL {\n constructor(input: string | URL, inputBase?: string | URL) {\n if (typeof input === 'string' && input.startsWith('/') && inputBase === undefined) {\n super(input, base);\n } else {\n super(input as string, inputBase);\n }\n }\n } as typeof URL;\n // 静的メソッドを引き継ぐ\n globalThis.URL.createObjectURL = OrigURL.createObjectURL;\n globalThis.URL.revokeObjectURL = OrigURL.revokeObjectURL;\n return () => { globalThis.URL = OrigURL; };\n}\n\n/** @deprecated Use Ssr.extractStateData() from @wcstack/state instead */\nexport function extractStateData(stateEl: any): Record<string, any> {\n const raw = (stateEl as any).__state;\n if (!raw || typeof raw !== 'object') return {};\n const data: Record<string, any> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!key.startsWith('$') && typeof value !== 'function') {\n data[key] = value;\n }\n }\n return data;\n}\n\nexport type BootstrapFunction = () => void;\n\nexport interface RenderOptions {\n /** 相対 URL を解決するベース URL (例: \"http://localhost:3001\") */\n baseUrl?: string;\n /** bootstrap 関数の配列。省略時は @wcstack/state を自動ロード */\n bootstraps?: BootstrapFunction[];\n}\n\nasync function loadDefaultBootstraps(): Promise<BootstrapFunction[]> {\n const { bootstrapState } = await import('@wcstack/state');\n return [bootstrapState];\n}\n\n\n/**\n * HTML 文字列を SSR レンダリングして返す。\n *\n * ## 入力 HTML のルール\n * - `<body>` の中身だけを渡す(`<html>`, `<head>`, `<body>` タグは含めない)\n * - `<script>` / `<link>` による外部リソース読み込みは実行されない\n * → 必要なパッケージは `options.bootstraps` で明示的に渡す\n *\n * ## SSR でできること\n *\n * ### 状態の初期化とデータ取得\n * - `<wcs-state>` の状態ロード(json 属性, src 属性, inline `<script type=\"module\">`)\n * - `$connectedCallback` でのサーバーサイド fetch(API 呼び出し、DB 問い合わせ等)\n *\n * ```html\n * <!-- JSON 直接指定 -->\n * <wcs-state enable-ssr json='{\"title\":\"Hello\"}'></wcs-state>\n *\n * <!-- $connectedCallback で API からデータ取得 -->\n * <!-- $connectedCallback は状態オブジェクトのメソッドとして定義し、this が state proxy -->\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const res = await fetch('/api/users');\n * this.users = await res.json();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n *\n * ### wcs-fetch を使ったサーバー通信\n * - `<wcs-fetch>` の auto-fetch(`manual` なし)はサーバーでも実行される\n * - `manual` + `$connectedCallback` で明示的に制御する場合:\n *\n * ```html\n * <wcs-fetch id=\"api\" url=\"/api/users\" manual></wcs-fetch>\n * <wcs-state enable-ssr>\n * <script type=\"module\">\n * export default {\n * async $connectedCallback() {\n * const el = document.getElementById('api');\n * this.users = await el.fetch();\n * }\n * };\n * </script>\n * </wcs-state>\n * ```\n * ※ `bootstraps` に `bootstrapFetch` を含める必要あり\n *\n * ### バインディングと構造レンダリング\n * - `data-wcs` バインディングの適用(text, attribute, class, style, property)\n * - `<template data-wcs=\"for:\">` / `if:` / `elseif:` / `else:` の構造レンダリング\n *\n * ```html\n * <ul>\n * <template data-wcs=\"for: users\">\n * <li data-wcs=\"textContent: .name\"></li>\n * </template>\n * </ul>\n * <template data-wcs=\"if: isAdmin\">\n * <div class=\"admin-panel\">...</div>\n * </template>\n * ```\n *\n * ### ハイドレーション\n * - `enable-ssr` 付き `<wcs-state>` の `<wcs-ssr>` メタデータ自動生成\n * - クライアント側でのハイドレーション(再レンダリングなしでバインディング復元)\n * - `enable-ssr` を外した `<wcs-state>` はクライアントのみで動作(部分 CSR)\n *\n * ### カスタム要素の待機\n * - `static hasConnectedCallbackPromise = true` プロトコル準拠の全カスタム要素を自動待機\n * - `$connectedCallback` 中に動的追加されたカスタム要素も安定化ループで検出・待機(最大 10 回)\n *\n * ## SSR でできないこと\n * - `<head>` 内の `<script src=\"...\">` や `<link>` の自動実行\n * - ブラウザ固有 API(localStorage, sessionStorage, navigator 等)\n * - Shadow DOM のレンダリング(Declarative Shadow DOM 非対応)\n * - イベントハンドラの登録(クライアント側のハイドレーションで復元)\n * - `<wcs-autoloader>` による動的コンポーネント読み込み\n *\n * ## HTML の分割パターン\n * ```\n * // server.js\n * const ssrBody = await renderToString(template, { ... });\n * const page = `<!DOCTYPE html>\n * <html lang=\"ja\">\n * <head>\n * <script type=\"module\" src=\"/packages/state/dist/auto.min.js\"></script>\n * </head>\n * <body>${ssrBody}</body>\n * </html>`;\n * ```\n * `renderToString` には `<body>` の中身だけを渡し、\n * `<head>` や `<script>` タグは外側のテンプレートで囲む。\n */\nexport async function renderToString(html: string, options?: RenderOptions): Promise<string> {\n // globalThis を差し替えるため、同時に1つしか実行できない\n const releaseMutex = await renderMutex.acquire();\n\n const window = new Window();\n const restoreGlobals = installGlobals(window);\n const document = window.document;\n\n // 相対 URL を baseUrl で解決する URL コンストラクタパッチをインストール\n const restoreBaseUrl = options?.baseUrl\n ? installBaseUrl(options.baseUrl)\n : null;\n\n // bootstrap の解決\n const bootstraps = options?.bootstraps ?? await loadDefaultBootstraps();\n\n for (const bootstrap of bootstraps) {\n bootstrap();\n }\n\n try {\n\n // SSR モードを html 要素に設定\n document.documentElement.setAttribute('data-wcs-server', '');\n\n // HTML をパース\n // connectedCallback が自動発火 → state ロード → $connectedCallback 実行\n document.body.innerHTML = html;\n\n // connectedCallbackPromise / getBindingsReady プロトコルを自動検出\n // $connectedCallback が動的にカスタム要素を追加する場合があるため、\n // 新しい要素が見つからなくなるまで走査を繰り返す(安定化ループ)\n const MAX_ITERATIONS = 10;\n const awaitedElements = new WeakSet();\n const readyCtors = new Set<any>();\n const readyPromises: Promise<void>[] = [];\n\n for (let i = 0; i < MAX_ITERATIONS; i++) {\n const connectedPromises: Promise<void>[] = [];\n\n for (const el of document.querySelectorAll('*-*')) {\n if (awaitedElements.has(el)) continue;\n const ctor = el.constructor as any;\n if (ctor.hasConnectedCallbackPromise) {\n awaitedElements.add(el);\n connectedPromises.push((el as any).connectedCallbackPromise);\n }\n if (!readyCtors.has(ctor) && typeof ctor.getBindingsReady === 'function') {\n readyCtors.add(ctor);\n readyPromises.push(ctor.getBindingsReady(document));\n }\n }\n\n if (connectedPromises.length === 0) break;\n await Promise.all(connectedPromises);\n }\n\n // 非同期初期化の完了を待機\n await Promise.all(readyPromises);\n\n return document.body.innerHTML;\n } finally {\n restoreBaseUrl?.();\n restoreGlobals();\n await window.close();\n releaseMutex();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\nexport const VERSION = pkg.version;\n","import { renderToString } from \"./render.js\";\nimport { IWcBindable } from \"./types.js\";\n\nexport class RenderCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"html\", event: \"wcs-render:html-changed\", semantics: \"state\" },\n { name: \"loading\", event: \"wcs-render:loading-changed\", semantics: \"state\" },\n { name: \"error\", event: \"wcs-render:error\", semantics: \"state\" },\n ],\n };\n\n private _html: string | null = null;\n private _loading: boolean = false;\n private _error: Error | null = null;\n\n get html(): string | null {\n return this._html;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): Error | null {\n return this._error;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this.dispatchEvent(new CustomEvent(\"wcs-render:loading-changed\", {\n detail: loading,\n }));\n }\n\n private _setHtml(html: string): void {\n this._html = html;\n this.dispatchEvent(new CustomEvent(\"wcs-render:html-changed\", {\n detail: html,\n }));\n }\n\n private _setError(error: Error | null): void {\n this._error = error;\n this.dispatchEvent(new CustomEvent(\"wcs-render:error\", {\n detail: error,\n }));\n }\n\n async render(html: string): Promise<string | null> {\n this._setLoading(true);\n this._setError(null);\n\n try {\n const result = await renderToString(html);\n this._setHtml(result);\n this._setLoading(false);\n return this._html;\n } catch (e: any) {\n this._setError(e instanceof Error ? e : new Error(String(e)));\n this._setLoading(false);\n return null;\n }\n }\n}\n"],"names":["renderMutex","_queue","_locked","acquire","this","Promise","resolve","push","shift","GLOBALS_KEYS","installGlobals","window","saved","key","globalThis","origCreateObjectURL","URL","createObjectURL","undefined","installBaseUrl","baseUrl","OrigURL","base","constructor","input","inputBase","startsWith","super","revokeObjectURL","extractStateData","stateEl","raw","__state","data","value","Object","entries","async","renderToString","html","options","releaseMutex","Window","restoreGlobals","document","restoreBaseUrl","bootstraps","bootstrapState","import","loadDefaultBootstraps","bootstrap","documentElement","setAttribute","body","innerHTML","MAX_ITERATIONS","awaitedElements","WeakSet","readyCtors","Set","readyPromises","i","connectedPromises","el","querySelectorAll","has","ctor","hasConnectedCallbackPromise","add","connectedCallbackPromise","getBindingsReady","length","all","close","VERSION","RenderCore","EventTarget","static","protocol","version","properties","name","event","semantics","_html","_loading","_error","loading","error","_setLoading","dispatchEvent","CustomEvent","detail","_setHtml","_setError","render","result","e","Error","String"],"mappings":"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"}
|