@jogak/core 0.1.0-alpha.7.1 → 0.1.0-alpha.9
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/CHANGELOG.md +23 -0
- package/dist/adapter.d.ts +80 -0
- package/dist/builder-detect.d.ts +9 -0
- package/dist/config.d.ts +27 -1
- package/dist/detect-global-css-CDcuUAYE.cjs +1 -0
- package/dist/detect-global-css-CIVMmgzy.js +33 -0
- package/dist/index.cjs +43 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.mjs +210 -162
- package/dist/preview-entry/protocol.d.ts +29 -0
- package/dist/preview-entry/source.d.ts +30 -0
- package/dist/server.cjs +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.mjs +45 -0
- package/dist/types.d.ts +85 -28
- package/dist/vite/index.cjs +118 -0
- package/dist/vite/index.mjs +274 -196
- package/dist/vite/plugin.d.ts +1 -0
- package/dist/vite/preview-frame-plugin.d.ts +21 -0
- package/dist/vite/virtual-ids.d.ts +14 -0
- package/package.json +8 -3
- package/dist/index.js +0 -1
- package/dist/vite/index.js +0 -47
- /package/dist/build/{index.js → index.cjs} +0 -0
- /package/dist/meta/{extractor-child.js → extractor-child.cjs} +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 알파.9: jogak chrome ↔ preview iframe 간 postMessage 통신 프로토콜.
|
|
3
|
+
*
|
|
4
|
+
* 모든 어댑터(vite/next/webpack/standalone)가 동일 프로토콜 사용. iframe 안 entry source는
|
|
5
|
+
* cross-origin 환경에서도 작동하도록 `targetOrigin: '*'`. preview는 사용자 본인 컴포넌트만
|
|
6
|
+
* mount하는 신뢰 환경이므로 origin 검증은 README 명시 후 생략.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 부모(jogak SPA) → iframe (preview entry).
|
|
10
|
+
*/
|
|
11
|
+
export type JogakMessageToFrame = {
|
|
12
|
+
readonly type: 'jogak:setProps';
|
|
13
|
+
readonly entryId: string;
|
|
14
|
+
readonly args: Readonly<Record<string, unknown>>;
|
|
15
|
+
} | {
|
|
16
|
+
readonly type: 'jogak:unmount';
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* iframe (preview entry) → 부모(jogak SPA).
|
|
20
|
+
*/
|
|
21
|
+
export type JogakMessageFromFrame = {
|
|
22
|
+
readonly type: 'jogak:ready';
|
|
23
|
+
} | {
|
|
24
|
+
readonly type: 'jogak:rendered';
|
|
25
|
+
readonly entryId: string;
|
|
26
|
+
} | {
|
|
27
|
+
readonly type: 'jogak:error';
|
|
28
|
+
readonly message: string;
|
|
29
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 알파.9: 모든 빌더 어댑터가 공통으로 사용하는 preview entry source.
|
|
3
|
+
*
|
|
4
|
+
* 빌더에 무관하게 다음 책임:
|
|
5
|
+
* 1. `defaultRegistry.requestEntry(entryId)`로 사용자 컴포넌트 dynamic import
|
|
6
|
+
* 2. `reactAdapter.render`로 mount
|
|
7
|
+
* 3. postMessage 프로토콜 (`@jogak/core/preview-entry/protocol`)로 부모와 통신
|
|
8
|
+
*
|
|
9
|
+
* 어댑터별 차이는 `extraImports` 배열뿐:
|
|
10
|
+
* - vite-adapter: `['virtual:jogak/preview-global-css']`
|
|
11
|
+
* - next-adapter: 사용자 globalCss 절대 경로 직접 inject
|
|
12
|
+
* - webpack-adapter: 사용자 globalCss 절대 경로
|
|
13
|
+
* - standalone-adapter: 사용자 사전 빌드 css 절대 경로
|
|
14
|
+
*/
|
|
15
|
+
export interface RenderPreviewEntryOptions {
|
|
16
|
+
/**
|
|
17
|
+
* 어댑터별 추가 import 라인. 라인 순서대로 emit되어 cascade order 결정.
|
|
18
|
+
*
|
|
19
|
+
* @example vite-adapter
|
|
20
|
+
* ['virtual:jogak/preview-global-css']
|
|
21
|
+
*
|
|
22
|
+
* @example next-adapter
|
|
23
|
+
* ['/abs/path/src/index.css']
|
|
24
|
+
*/
|
|
25
|
+
readonly extraImports?: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 어댑터가 호출 — 자기 scope에 맞는 추가 import 라인 주입.
|
|
29
|
+
*/
|
|
30
|
+
export declare function renderPreviewEntrySource(opts?: RenderPreviewEntryOptions): string;
|
package/dist/server.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("node:fs"),l=require("node:path"),u=require("./detect-global-css-CDcuUAYE.cjs"),d=["ts","js","mjs","cjs"],b=["ts","js","mjs","cjs"],j=["ts","mts","js","mjs","cjs"];function h(s){const e=C(s),n={...(e==null?void 0:e.dependencies)??{},...(e==null?void 0:e.devDependencies)??{}},t=a(s,d,"next.config"),f="next"in n,p="react-scripts"in n,i=a(s,b,"webpack.config"),g="webpack"in n,r=a(s,j,"vite.config");if(t||f){const c=[];return r&&c.push("vite.config.* (마이그레이션 중?)"),{name:"next",signal:t?"next.config.*":"package.json: next dep",...c.length>0?{ambiguous:c}:{}}}return p?{name:"webpack",signal:"package.json: react-scripts dep (CRA)"}:i||g?{name:"webpack",signal:i?"webpack.config.*":"package.json: webpack dep"}:r?{name:"vite",signal:"vite.config.*"}:{name:"standalone",signal:"(no builder signals)"}}function a(s,e,n){for(const t of e)if(o.existsSync(l.resolve(s,`${n}.${t}`)))return!0;return!1}function C(s){const e=l.resolve(s,"package.json");if(o.existsSync(e))try{const n=o.readFileSync(e,"utf-8");return JSON.parse(n)}catch{return}}exports.detectUserGlobalCss=u.detectUserGlobalCss;exports.resolveGlobalCssPaths=u.resolveGlobalCssPaths;exports.detectBuilder=h;
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 알파.9: server-only 유틸리티 (Node.js only).
|
|
3
|
+
*
|
|
4
|
+
* 본 subpath의 함수들은 `node:fs`/`node:path`를 사용하므로 브라우저 client 번들에
|
|
5
|
+
* 포함되어서는 안 된다. CLI / 어댑터 / Vite plugin 등 Node 환경에서만 import.
|
|
6
|
+
*
|
|
7
|
+
* 사용처:
|
|
8
|
+
* - `@jogak/cli`: detectBuilder
|
|
9
|
+
* - `@jogak/vite-adapter` / `@jogak/next-adapter` / `@jogak/webpack-adapter`: resolveGlobalCssPaths
|
|
10
|
+
*/
|
|
11
|
+
export { detectBuilder, type DetectBuilderResult, } from './builder-detect.js';
|
|
12
|
+
export { detectUserGlobalCss, resolveGlobalCssPaths, } from './vite/detect-global-css.js';
|
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { existsSync as r, readFileSync as u } from "node:fs";
|
|
2
|
+
import { resolve as f } from "node:path";
|
|
3
|
+
import { d as N, r as S } from "./detect-global-css-CIVMmgzy.js";
|
|
4
|
+
const m = ["ts", "js", "mjs", "cjs"], d = ["ts", "js", "mjs", "cjs"], j = ["ts", "mts", "js", "mjs", "cjs"];
|
|
5
|
+
function k(n) {
|
|
6
|
+
const e = b(n), s = {
|
|
7
|
+
...(e == null ? void 0 : e.dependencies) ?? {},
|
|
8
|
+
...(e == null ? void 0 : e.devDependencies) ?? {}
|
|
9
|
+
}, t = c(n, m, "next.config"), p = "next" in s, g = "react-scripts" in s, o = c(n, d, "webpack.config"), l = "webpack" in s, i = c(n, j, "vite.config");
|
|
10
|
+
if (t || p) {
|
|
11
|
+
const a = [];
|
|
12
|
+
return i && a.push("vite.config.* (마이그레이션 중?)"), {
|
|
13
|
+
name: "next",
|
|
14
|
+
signal: t ? "next.config.*" : "package.json: next dep",
|
|
15
|
+
...a.length > 0 ? { ambiguous: a } : {}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return g ? {
|
|
19
|
+
name: "webpack",
|
|
20
|
+
signal: "package.json: react-scripts dep (CRA)"
|
|
21
|
+
} : o || l ? {
|
|
22
|
+
name: "webpack",
|
|
23
|
+
signal: o ? "webpack.config.*" : "package.json: webpack dep"
|
|
24
|
+
} : i ? { name: "vite", signal: "vite.config.*" } : { name: "standalone", signal: "(no builder signals)" };
|
|
25
|
+
}
|
|
26
|
+
function c(n, e, s) {
|
|
27
|
+
for (const t of e)
|
|
28
|
+
if (r(f(n, `${s}.${t}`))) return !0;
|
|
29
|
+
return !1;
|
|
30
|
+
}
|
|
31
|
+
function b(n) {
|
|
32
|
+
const e = f(n, "package.json");
|
|
33
|
+
if (r(e))
|
|
34
|
+
try {
|
|
35
|
+
const s = u(e, "utf-8");
|
|
36
|
+
return JSON.parse(s);
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
k as detectBuilder,
|
|
43
|
+
N as detectUserGlobalCss,
|
|
44
|
+
S as resolveGlobalCssPaths
|
|
45
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -209,38 +209,95 @@ export interface JogakPluginOptions {
|
|
|
209
209
|
*/
|
|
210
210
|
readonly globalCss?: boolean | string | readonly string[];
|
|
211
211
|
/**
|
|
212
|
-
* Preview 영역의 격리 모드 (알파.7 도입, 알파.
|
|
212
|
+
* Preview 영역의 격리 모드 (알파.7 도입, 알파.8에서 default `'iframe'`로 변경).
|
|
213
213
|
*
|
|
214
|
-
* 사용자
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
214
|
+
* 알파.8의 default `'iframe'`은 사용자 vite 인스턴스를 spawn하여 그 vite의 정상 client에
|
|
215
|
+
* iframe document를 마운트한다. 사용자 plugins(@tailwindcss/vite 등)이 그대로 작동하므로
|
|
216
|
+
* **사용자 컴포넌트가 사용자 디자인 시스템 그대로 보인다**. 동시에 outer document의
|
|
217
|
+
* jogak chrome은 iframe 외부라 사용자 css 영향 zero (양방향 격리).
|
|
218
218
|
*
|
|
219
219
|
* 모드:
|
|
220
|
-
* - `'
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* 사용자 globalCss를 outer document에 inject. 사용자 reset/preflight가 jogak
|
|
232
|
-
* chrome에 침범 가능. 사용자가 침범을 의도적으로 허용하는 경우만 사용.
|
|
233
|
-
*
|
|
234
|
-
* @default 'shadow'
|
|
235
|
-
*
|
|
236
|
-
* @example 양방향 격리 (default — 미지정 시 적용)
|
|
237
|
-
* jogak({ globalCss: true }) // previewIsolation 'shadow' 자동 적용
|
|
238
|
-
*
|
|
239
|
-
* @example 사용자 reset이 chrome에도 영향을 주길 원하는 경우
|
|
240
|
-
* jogak({ globalCss: true, previewIsolation: 'none' })
|
|
220
|
+
* - `'iframe'` (default, 알파.8): Preview를 사용자 vite의 정상 client(iframe)에 마운트.
|
|
221
|
+
* 사용자 utility 정상 컴파일 + 사용자 globalCss 적용 + Radix Portal 정상 (iframe document.body).
|
|
222
|
+
* chrome 침범 zero. cross-origin postMessage로 entry/args 전달.
|
|
223
|
+
* `userVite` 옵션으로 spawn 동작 제어.
|
|
224
|
+
* - `'shadow'` (deprecated, 알파.9 부활 검토): Preview를 ShadowRoot에 마운트. 알파.8 v1에서는
|
|
225
|
+
* 사용자 vite 산출물을 shadow에 inject하는 통로가 미구현 — 사용자 utility 미적용 한계.
|
|
226
|
+
* chrome 침범은 zero지만 사용자 컴포넌트 시각이 raw에 가까움.
|
|
227
|
+
* - `'none'` (deprecated, 알파.10 제거 검토): 사용자 globalCss를 outer document에 inject.
|
|
228
|
+
* jogak chrome이 사용자 reset/preflight 영향을 받음 (back-compat).
|
|
229
|
+
*
|
|
230
|
+
* @default 'iframe'
|
|
241
231
|
*
|
|
242
|
-
* @example
|
|
243
|
-
* jogak({ globalCss: true
|
|
232
|
+
* @example 사용자 vite 자동 spawn + iframe 모드 (default — 미지정 시 적용)
|
|
233
|
+
* jogak({ globalCss: true }) // previewIsolation 'iframe', 사용자 vite 자동 탐지
|
|
234
|
+
*
|
|
235
|
+
* @example 사용자 vite 스폰 비활성 + 사용자 reset이 chrome에도 영향 (back-compat)
|
|
236
|
+
* jogak({ globalCss: true, previewIsolation: 'none' })
|
|
244
237
|
*/
|
|
245
238
|
readonly previewIsolation?: 'none' | 'shadow' | 'iframe';
|
|
239
|
+
/**
|
|
240
|
+
* 알파.8 internal: 본 jogak() plugin이 사용자 vite scope의 preview-frame entry용으로
|
|
241
|
+
* 동작하는지. CLI의 spawnUserVite가 사용자 vite에 jogak()을 mergeConfig로 inject할 때
|
|
242
|
+
* `previewFrame: true`를 함께 설정한다.
|
|
243
|
+
*
|
|
244
|
+
* `previewFrame: true`일 때:
|
|
245
|
+
* - jogak SPA chrome 가상 모듈(`_jogakCodeTheme`/`_jogakPreviewIsolation`/`_jogakUserViteUrl`/
|
|
246
|
+
* `_jogakMetas`) emit 비활성화
|
|
247
|
+
* - entry 가상 모듈(`virtual:jogak/entry/<slug>`)은 그대로 emit (preview-entry가 사용)
|
|
248
|
+
* - 사용자 측 vite plugins(@tailwindcss/vite 등)와 공존
|
|
249
|
+
*
|
|
250
|
+
* 사용자가 직접 설정하는 옵션이 아니다.
|
|
251
|
+
*/
|
|
252
|
+
readonly previewFrame?: boolean;
|
|
253
|
+
/**
|
|
254
|
+
* @deprecated 알파.10 제거 예정. `userPreviewUrl` 사용.
|
|
255
|
+
*
|
|
256
|
+
* 알파.8 internal: jogak SPA가 iframe src로 사용할 사용자 vite의 base URL.
|
|
257
|
+
*/
|
|
258
|
+
readonly userViteUrl?: string;
|
|
259
|
+
/**
|
|
260
|
+
* 알파.9 internal: jogak SPA가 iframe src로 사용할 어댑터 dev URL
|
|
261
|
+
* (예: `http://localhost:5174`). CLI의 어댑터 dispatch 결과가 host 통해 plugin에 전달.
|
|
262
|
+
*
|
|
263
|
+
* 빈 문자열 시 fallback (jogak SPA Vite scope의 preview-frame).
|
|
264
|
+
*
|
|
265
|
+
* 사용자가 직접 설정하는 옵션이 아니다.
|
|
266
|
+
*/
|
|
267
|
+
readonly userPreviewUrl?: string;
|
|
268
|
+
/**
|
|
269
|
+
* 알파.9 internal: iframe src의 path (예: `/__jogak_preview__/index.html`).
|
|
270
|
+
* `BuilderAdapter.previewEntryMeta.devEntryPath` 값. 어댑터별 routing.
|
|
271
|
+
*
|
|
272
|
+
* 사용자가 직접 설정하는 옵션이 아니다.
|
|
273
|
+
*/
|
|
274
|
+
readonly previewEntryPath?: string;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* 알파.8: 사용자 vite 인스턴스 spawn 옵션.
|
|
278
|
+
*
|
|
279
|
+
* jogak CLI는 사용자 cwd의 `vite.config.{ts,mts,js,mjs,cjs}`를 자동 탐지해 별도
|
|
280
|
+
* vite dev server를 spawn한다. iframe 모드의 src로 사용되어 사용자 컴포넌트가
|
|
281
|
+
* 사용자 vite plugins(@tailwindcss/vite, custom alias 등)의 정상 client에서
|
|
282
|
+
* 평가된다.
|
|
283
|
+
*/
|
|
284
|
+
export interface UserViteOptions {
|
|
285
|
+
/**
|
|
286
|
+
* 사용자 vite.config.ts 절대/상대 경로. 미지정 시 cwd에서 자동 탐지
|
|
287
|
+
* (`vite.config.ts` > `vite.config.mts` > `vite.config.js` > `vite.config.mjs` > `vite.config.cjs`).
|
|
288
|
+
*/
|
|
289
|
+
readonly configFile?: string;
|
|
290
|
+
/**
|
|
291
|
+
* 사용자 vite dev server 포트. 미지정 시 0(free port).
|
|
292
|
+
*/
|
|
293
|
+
readonly port?: number;
|
|
294
|
+
/**
|
|
295
|
+
* 사용자 vite dev server host. 미지정 시 'localhost'.
|
|
296
|
+
*/
|
|
297
|
+
readonly host?: string | boolean;
|
|
298
|
+
/**
|
|
299
|
+
* 사용자 vite spawn을 비활성화. 알파.7.1 동등 fallback 동작
|
|
300
|
+
* (사용자 utility 미컴파일).
|
|
301
|
+
*/
|
|
302
|
+
readonly disabled?: boolean;
|
|
246
303
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";var Z=Object.create;var U=Object.defineProperty;var ee=Object.getOwnPropertyDescriptor;var te=Object.getOwnPropertyNames;var re=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var ne=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of te(t))!oe.call(e,a)&&a!==o&&U(e,a,{get:()=>t[a],enumerable:!(n=ee(t,a))||n.enumerable});return e};var ae=(e,t,o)=>(o=e!=null?Z(re(e)):{},ne(t||!e||!e.__esModule?U(o,"default",{value:e,enumerable:!0}):o,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("node:path"),S=require("node:fs"),E=require("node:fs/promises"),B=require("../detect-global-css-CDcuUAYE.cjs"),$=require("../extractor-client-CiWszHel.cjs"),se=["@jogak/core","@jogak/react","@jogak/web-components","@jogak/next"];async function W(e){try{const n=await E.stat(e);if(!n.isDirectory())return n.mtimeMs}catch{return 0}let t=0,o;try{o=await E.readdir(e)}catch{return 0}for(const n of o){const a=v.join(e,n);try{const l=await E.stat(a);if(l.isDirectory()){const g=await W(a);g>t&&(t=g)}else l.mtimeMs>t&&(t=l.mtimeMs)}catch{continue}}return t}async function ie(e){const t=v.resolve(e.root,"node_modules/.vite/deps");if(!S.existsSync(t))return{purged:!1};const o=v.join(t,"_metadata.json");if(!S.existsSync(o))return{purged:!1};let n;try{n=(await E.stat(o)).mtimeMs}catch(l){return e.logger.warn(`[jogak] cache validation: failed to stat _metadata.json (${l.message})`),{purged:!1}}const a=e.packages??se;for(const l of a){const g=v.resolve(e.root,"node_modules",l,"dist");if(!S.existsSync(g))continue;let y;try{y=await W(g)}catch(h){e.logger.warn(`[jogak] cache validation: failed to walk ${l}/dist (${h.message})`);continue}if(y>n+1e3)try{return await E.rm(t,{recursive:!0,force:!0}),e.logger.info(`[jogak] vite deps cache invalidated (stale): ${l} dist newer than cache`),{purged:!0,reason:l}}catch(h){return e.logger.warn(`[jogak] cache validation: failed to purge ${t} (${h.message})`),{purged:!1}}}return{purged:!1}}function ce(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*\/\/.*$/gm,"")}function le(e){if(S.existsSync(e))try{const t=S.readFileSync(e,"utf8");return JSON.parse(ce(t))}catch{return}}function ue(e,t,o){if(!e.endsWith("/*")||!t.endsWith("/*"))return;const n=e.slice(0,-2),a=v.resolve(o,t.slice(0,-2));return[n,a]}function de(e,t){var a,l;const o={},n=new Set([e,v.resolve(t,"tsconfig.app.json")]);for(const g of n){const y=le(g);if(y===void 0)continue;const h=(a=y.compilerOptions)==null?void 0:a.paths;if(h===void 0)continue;const T=((l=y.compilerOptions)==null?void 0:l.baseUrl)??".",R=v.resolve(v.dirname(g),T);for(const[b,d]of Object.entries(h)){const f=d[0];if(f===void 0)continue;const _=ue(b,f,R);if(_===void 0)continue;const[k,C]=_;o[k]===void 0&&(o[k]=C)}}return o}const K="virtual:jogak",O="\0"+K,H="virtual:jogak/entry/",L="\0"+H,Y="virtual:jogak/global-css",D="\0"+Y,M="virtual:jogak/preview-entry",F="\0"+M,q="virtual:jogak/preview-global-css",G="\0"+q;function ge(e){return Buffer.from(e,"utf8").toString("base64url")}function fe(e){return Buffer.from(e,"base64url").toString("utf8")}const me="/__jogak_preview__/index.html";function pe(e){return{name:"vite-plugin-jogak-preview-frame",enforce:"pre",configureServer(t){t.middlewares.use((o,n,a)=>{if(o.url===void 0||o.url.split("?")[0]!==me||o.method!=="GET")return a();const g=ve();t.transformIndexHtml(o.url,g).then(y=>{n.statusCode=200,n.setHeader("Content-Type","text/html; charset=utf-8"),n.end(y)}).catch(a)})},resolveId(t){if(t===M)return F;if(t===q)return G},load(t){if(t===G){const o=B.resolveGlobalCssPaths(e.globalCss,e.userRoot);return o.length===0?`// [jogak] preview-global-css: no candidates
|
|
2
|
+
export {}
|
|
3
|
+
`:o.map(n=>`import ${JSON.stringify(n)}`).join(`
|
|
4
|
+
`)+`
|
|
5
|
+
export {}
|
|
6
|
+
`}if(t===F)return ye}}}function ve(){return`<!doctype html>
|
|
7
|
+
<html lang="en">
|
|
8
|
+
<head>
|
|
9
|
+
<meta charset="UTF-8" />
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
11
|
+
<title>jogak preview</title>
|
|
12
|
+
<style>
|
|
13
|
+
html, body { margin: 0; padding: 0; }
|
|
14
|
+
#jogak-preview-root { display: block; }
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<div id="jogak-preview-root"></div>
|
|
19
|
+
<script type="module" src="/@id/${M}"><\/script>
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
22
|
+
`}const ye=`
|
|
23
|
+
import { reactAdapter } from '@jogak/react'
|
|
24
|
+
import { defaultRegistry } from '@jogak/core'
|
|
25
|
+
import 'virtual:jogak'
|
|
26
|
+
import 'virtual:jogak/preview-global-css'
|
|
27
|
+
|
|
28
|
+
const rootEl = document.getElementById('jogak-preview-root')
|
|
29
|
+
if (rootEl === null) throw new Error('[jogak] #jogak-preview-root not found')
|
|
30
|
+
|
|
31
|
+
let currentContainer = null
|
|
32
|
+
let currentArgs = {}
|
|
33
|
+
let currentEntryId = null
|
|
34
|
+
|
|
35
|
+
async function renderEntry(entryId, args) {
|
|
36
|
+
currentEntryId = entryId
|
|
37
|
+
currentArgs = args
|
|
38
|
+
const entry = await defaultRegistry.requestEntry(entryId)
|
|
39
|
+
if (currentContainer === null) {
|
|
40
|
+
currentContainer = document.createElement('div')
|
|
41
|
+
rootEl.replaceChildren(currentContainer)
|
|
42
|
+
}
|
|
43
|
+
reactAdapter.render(entry, args, currentContainer)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function unmount() {
|
|
47
|
+
if (currentContainer !== null) {
|
|
48
|
+
reactAdapter.unmount(currentContainer)
|
|
49
|
+
currentContainer = null
|
|
50
|
+
currentEntryId = null
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
window.addEventListener('message', (event) => {
|
|
55
|
+
const data = event.data
|
|
56
|
+
if (data == null || typeof data !== 'object') return
|
|
57
|
+
if (data.type === 'jogak:setProps') {
|
|
58
|
+
void renderEntry(data.entryId, data.args ?? {}).then(() => {
|
|
59
|
+
window.parent.postMessage({ type: 'jogak:rendered', entryId: data.entryId }, '*')
|
|
60
|
+
}).catch((err) => {
|
|
61
|
+
window.parent.postMessage({ type: 'jogak:error', message: String(err?.message ?? err) }, '*')
|
|
62
|
+
})
|
|
63
|
+
} else if (data.type === 'jogak:unmount') {
|
|
64
|
+
unmount()
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
window.parent.postMessage({ type: 'jogak:ready' }, '*')
|
|
69
|
+
`;function J(e){return{title:e.title,jogakNamesKey:[...e.jogakNames].sort().join("|")}}function we(e,t){return e!==void 0&&e.title===t.title&&e.jogakNamesKey===t.jogakNamesKey}function he(e={}){const{patterns:t=["src/**/*.jogak.ts","src/**/*.jogak.tsx"],codeTheme:o="vsDark"}=e,n=e.cwd,a=e.tsConfigFilePath,l=e.disableCacheValidation===!0,g=e.resolveAlias,y=e.globalCss,h=e.previewIsolation??"iframe",T=e.previewFrame===!0,R=e.userPreviewUrl??e.userViteUrl??"",b=e.previewEntryPath??"/__jogak_preview__/index.html";let d,f,_;const k=new Map,C=new Map,x=new Map;async function N(){const{glob:r}=await import("glob"),m=_??process.cwd(),s=(await r(t,{cwd:m,absolute:!0})).sort(),u=[];k.clear(),C.clear();for(const i of s){let w="";try{w=await E.readFile(i,"utf8")}catch{continue}let j={},c=null;if(f!==void 0){try{j=await f.extract(i)}catch{j={}}try{c=await f.extractMeta(i)}catch{c=null}}if(c===null)continue;const p=c.title;k.set(p,i),C.set(i,p);const I={id:p,title:c.title,jogakNames:c.jogakNames,autoArgTypes:j,userArgTypes:c.userArgTypes,source:w,filePath:i,metaExtras:c.metaExtras};x.set(i,J(I)),u.push({id:p,filePath:i,meta:I})}return u}return{name:"vite-plugin-jogak",config(){const r=n??process.cwd(),m=a??v.resolve(r,"tsconfig.json"),s=de(m,r),u={};if(g!==void 0)for(const[w,j]of Object.entries(g))u[w]=v.resolve(r,j);const i={...s,...u};if(Object.keys(i).length!==0)return{resolve:{alias:i}}},async configResolved(r){_=n??r.root,r.command==="serve"&&!l&&await ie({root:r.root,logger:{info:s=>r.logger.info(s),warn:s=>r.logger.warn(s)}});const m=a??v.resolve(_,"tsconfig.json");f=S.existsSync(m)?$.createPropsExtractor({tsConfigFilePath:m}):$.createPropsExtractor()},configureServer(r){d=r},buildEnd(){f==null||f.releaseCache()},resolveId(r){if(r===K)return O;if(r===Y)return D;if(r.startsWith(H))return"\0"+r},async load(r){if(r===D){const m=_??process.cwd(),s=B.resolveGlobalCssPaths(y,m);return s.length===0?`// [jogak] globalCss not configured or no candidates found.
|
|
70
|
+
export {}
|
|
71
|
+
`:`${s.map(i=>`import ${JSON.stringify(i)}`).join(`
|
|
72
|
+
`)}
|
|
73
|
+
export {}
|
|
74
|
+
`}if(r===O){const s=(await N()).map(i=>i.meta),u=T?"":`
|
|
75
|
+
export const _jogakCodeTheme = ${JSON.stringify(o)}
|
|
76
|
+
export const _jogakPreviewIsolation = ${JSON.stringify(h)}
|
|
77
|
+
export const _jogakUserPreviewUrl = ${JSON.stringify(R)}
|
|
78
|
+
export const _jogakPreviewEntryPath = ${JSON.stringify(b)}
|
|
79
|
+
export const _jogakUserViteUrl = ${JSON.stringify(R)}
|
|
80
|
+
export const _jogakMetas = _metas
|
|
81
|
+
`;return`import { defaultRegistry } from '@jogak/core'
|
|
82
|
+
|
|
83
|
+
const _entryLoader = (slug) =>
|
|
84
|
+
import(/* @vite-ignore */ '/@id/__x00__virtual:jogak/entry/' + slug)
|
|
85
|
+
defaultRegistry.setEntryLoader((id) => {
|
|
86
|
+
const slug = ${je()}
|
|
87
|
+
return _entryLoader(slug(id))
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const _metas = ${JSON.stringify(s)}
|
|
91
|
+
|
|
92
|
+
for (const m of _metas) defaultRegistry.registerMeta(m)
|
|
93
|
+
${u}`}if(r.startsWith(L)){const m=r.slice(L.length),s=fe(m);let u=k.get(s);return u===void 0&&(await N(),u=k.get(s)),u===void 0?`// [jogak] unknown entry id: ${JSON.stringify(s)}
|
|
94
|
+
export {}
|
|
95
|
+
`:`import * as _user from ${JSON.stringify(u)}
|
|
96
|
+
import { defaultRegistry } from '@jogak/core'
|
|
97
|
+
|
|
98
|
+
const _meta = _user.default
|
|
99
|
+
const _named = { ..._user }
|
|
100
|
+
delete _named.default
|
|
101
|
+
const _jogaks = Object.values(_named).filter(
|
|
102
|
+
(v) => v !== null && typeof v === 'object' && typeof v.name === 'string'
|
|
103
|
+
)
|
|
104
|
+
defaultRegistry.hydrateEntry(${JSON.stringify(s)}, _jogaks, _meta?.component)
|
|
105
|
+
|
|
106
|
+
if (import.meta.hot) {
|
|
107
|
+
import.meta.hot.accept()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export {}
|
|
111
|
+
`}},async handleHotUpdate({file:r,modules:m}){const s=/\.jogak\.(tsx?|jsx?)$/.test(r),u=/\.(tsx?|jsx?)$/.test(r)&&!s;if(!s&&!u||d===void 0||!s)return;const i=d.moduleGraph.getModuleById(O),w=C.get(r),j=w!==void 0?L+ge(w):void 0,c=j!==void 0?d.moduleGraph.getModuleById(j):void 0;let p=null,I={},P="";if(f!==void 0){try{p=await f.extractMeta(r)}catch{p=null}try{I=await f.extract(r)}catch{I={}}try{P=await E.readFile(r,"utf8")}catch{P=""}}if(p===null){i!==void 0&&d.moduleGraph.invalidateModule(i),c!==void 0&&d.moduleGraph.invalidateModule(c),d.ws.send({type:"full-reload"});return}const V=J(p),X=x.get(r),z=we(X,V);if(x.set(r,V),!z||w===void 0){i!==void 0&&d.moduleGraph.invalidateModule(i),c!==void 0&&d.moduleGraph.invalidateModule(c),d.ws.send({type:"full-reload"});return}const Q={id:w,title:p.title,jogakNames:p.jogakNames,autoArgTypes:I,userArgTypes:p.userArgTypes,source:P,filePath:r,metaExtras:p.metaExtras};c!==void 0&&d.moduleGraph.invalidateModule(c),d.ws.send({type:"custom",event:"jogak:meta-update",data:{id:w,meta:Q}});const A=[...m];return c!==void 0&&!A.includes(c)&&A.push(c),A}}}function je(){return`(rawId) => {
|
|
112
|
+
if (typeof Buffer !== 'undefined') return Buffer.from(rawId, 'utf8').toString('base64url')
|
|
113
|
+
// 브라우저 폴백: btoa는 binary string 기준이라 UTF-8을 한번 인코딩해야 한다.
|
|
114
|
+
const enc = new TextEncoder().encode(rawId)
|
|
115
|
+
let bin = ''
|
|
116
|
+
for (let i = 0; i < enc.length; i++) bin += String.fromCharCode(enc[i])
|
|
117
|
+
return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')
|
|
118
|
+
}`}exports.jogak=he;exports.jogakPreviewFramePlugin=pe;
|