@deot/docs-playground 1.1.6 → 1.1.7

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.md CHANGED
@@ -159,6 +159,7 @@ const handleMessage = async () => {
159
159
  - 直接渲染时,宿主未提供且未配置的 npm 模块(含作用域包和子路径)自动从 jsDelivr 的 `/+esm` 入口加载;组件包的传递依赖也适用,`import()` 在调用时加载。可用 `options.builtinImportMap.imports` 指定依赖的版本和 URL。
160
160
  - Vue SFC 的 `<style lang="scss">` / `lang="sass"` 以及独立 `.scss` / `.sass` 文件会在浏览器里编译;`_partial.scss` 只作为 `@use` 依赖。
161
161
  - local 模式按模块识别显式 URL 覆盖,即使地址与内置默认相同也会加载该 URL。覆盖 `vue` 时,预览的编译产物、挂载、组件引用和注入使用这份 Vue;内置组件、hooks、locale、Pinia 和 vue-router 随之重新加载以匹配 Vue,未覆盖的普通工具模块继续复用宿主。不同预览的覆盖互不影响,显式覆盖的模块在各自预览内执行。
162
+ - local 模式在当前页面按 URL 缓存外部模块的下载和转换成果,并合并并发请求;切换文档时可复用,最多保留最近使用的 128 个模块。各预览仍独立执行模块并解析依赖覆盖;失败的加载不缓存,同源模块实时读取,刷新页面会清空缓存。
162
163
  - 每个 Playground 实例都使用自己的 preview 配置和 iframe 消息来源校验。
163
164
  - `local` 默认开启:同一份 `files` 在当前文档里编译。直接渲染不撑开预览高度,`expandable` 固定为关闭,`docs:playground.run` 不会申请临时高度;`<DocsLink>` 仍通过 `docs:navigate` 通知。`local: false` 改回 iframe Sandbox。
164
165
 
package/dist/index.cjs CHANGED
@@ -3054,6 +3054,43 @@ var linkPlayground = (compiled, files, options = {}) => {
3054
3054
  //#region packages/playground/src/core/runtime/local/remote.ts
3055
3055
  var HOST_VUE = /* @__PURE__ */ new Set(["vue", "vue/server-renderer"]);
3056
3056
  var moduleUrl = (url) => new URL(url, globalThis.location?.href).href;
3057
+ var REMOTE_SOURCE_CACHE_LIMIT = 128;
3058
+ var sourceCache = /* @__PURE__ */ new Map();
3059
+ var prepareRemoteSource = async (url) => {
3060
+ const response = await fetch(url);
3061
+ if (!response.ok) throw new Error(`${response.status} ${url}`);
3062
+ const text = await response.text();
3063
+ await (0, es_module_lexer.init)();
3064
+ const [specifiers] = (0, es_module_lexer.parse)(text);
3065
+ let source = text;
3066
+ for (const item of [...specifiers].reverse()) if (item.type === "dynamic") source = source.slice(0, item.importStart) + "__import" + source.slice(item.importStart + 6);
3067
+ const cjs = (0, sucrase.transform)(require_css.rewriteImportMeta(source, url), {
3068
+ transforms: ["imports"],
3069
+ disableESTransforms: true,
3070
+ production: true,
3071
+ filePath: url
3072
+ }).code;
3073
+ return {
3074
+ dependencies: specifiers.filter((item) => item.type === "static" || item.type === "reexport-star").map((item) => item.specifier),
3075
+ run: new Function("require", "module", "exports", "__import", cjs)
3076
+ };
3077
+ };
3078
+ var readRemoteSource = (url) => {
3079
+ if (new URL(url).origin === globalThis.location?.origin) return prepareRemoteSource(url);
3080
+ const cached = sourceCache.get(url);
3081
+ if (cached) {
3082
+ sourceCache.delete(url);
3083
+ sourceCache.set(url, cached);
3084
+ return cached;
3085
+ }
3086
+ const task = prepareRemoteSource(url).catch((error) => {
3087
+ if (sourceCache.get(url) === task) sourceCache.delete(url);
3088
+ throw error;
3089
+ });
3090
+ sourceCache.set(url, task);
3091
+ if (sourceCache.size > REMOTE_SOURCE_CACHE_LIMIT) sourceCache.delete(sourceCache.keys().next().value);
3092
+ return task;
3093
+ };
3057
3094
  /**
3058
3095
  * 把 CDN 上的 ESM 先拉完整张依赖图,再在当前页面里执行。
3059
3096
  * 裸导入优先走 import map,缺失的 npm 依赖回退到 CDN ESM;import() 按需加载。
@@ -3072,9 +3109,9 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
3072
3109
  "vue-router": builtins.vueRouter
3073
3110
  };
3074
3111
  const pendingBuiltins = /* @__PURE__ */ new Set();
3075
- const texts = /* @__PURE__ */ new Map();
3112
+ const sources = /* @__PURE__ */ new Map();
3113
+ const pendingSources = /* @__PURE__ */ new Map();
3076
3114
  const evaluated = /* @__PURE__ */ new Map();
3077
- const crawled = /* @__PURE__ */ new Set();
3078
3115
  const nativeModules = /* @__PURE__ */ new Map();
3079
3116
  const loadNative = (url) => {
3080
3117
  let pending = nativeModules.get(url);
@@ -3131,25 +3168,23 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
3131
3168
  }
3132
3169
  return moduleUrl(imports[target]);
3133
3170
  };
3134
- const crawl = async (url) => {
3171
+ const crawl = async (url, visited = /* @__PURE__ */ new Set()) => {
3135
3172
  if (!overrides.size && /\/\+esm(?:[?#]|$)/.test(url)) {
3136
3173
  await loadNative(url);
3137
3174
  return;
3138
3175
  }
3139
- if (crawled.has(url)) return;
3140
- crawled.add(url);
3141
- const response = await fetch(url);
3142
- if (!response.ok) throw new Error(`${response.status} ${url}`);
3143
- const text = await response.text();
3144
- await (0, es_module_lexer.init)();
3145
- const [specifiers] = (0, es_module_lexer.parse)(text);
3146
- let source = text;
3147
- for (const item of [...specifiers].reverse()) if (item.type === "dynamic") source = source.slice(0, item.importStart) + "__import" + source.slice(item.importStart + 6);
3148
- texts.set(url, source);
3149
- await Promise.all(specifiers.map(async (item) => {
3150
- if (item.type !== "static" && item.type !== "reexport-star") return;
3151
- const next = dependencyUrl(url, item.specifier);
3152
- if (next) await crawl(next);
3176
+ if (visited.has(url)) return;
3177
+ visited.add(url);
3178
+ let pending = pendingSources.get(url);
3179
+ if (!pending) {
3180
+ pending = readRemoteSource(url);
3181
+ pendingSources.set(url, pending);
3182
+ }
3183
+ const source = await pending;
3184
+ sources.set(url, source);
3185
+ await Promise.all(source.dependencies.map(async (specifier) => {
3186
+ const next = dependencyUrl(url, specifier);
3187
+ if (next) await crawl(next, visited);
3153
3188
  }));
3154
3189
  };
3155
3190
  const requireFrom = (from) => (specifier) => {
@@ -3169,17 +3204,12 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
3169
3204
  };
3170
3205
  const evaluate = (url) => {
3171
3206
  if (evaluated.has(url)) return evaluated.get(url);
3172
- const text = texts.get(url);
3173
- if (text == null) throw new Error(`[Playground] 远程模块尚未下载: ${url}`);
3174
- const cjs = (0, sucrase.transform)(require_css.rewriteImportMeta(text, url), {
3175
- transforms: ["imports"],
3176
- disableESTransforms: true,
3177
- production: true,
3178
- filePath: url
3179
- }).code;
3207
+ const source = sources.get(url);
3208
+ if (!source) throw new Error(`[Playground] 远程模块尚未下载: ${url}`);
3180
3209
  const module = { exports: {} };
3181
3210
  evaluated.set(url, module.exports);
3182
- new Function("require", "module", "exports", "__import", cjs)(requireFrom(url), module, module.exports, async (id) => {
3211
+ const runner = source.run;
3212
+ runner(requireFrom(url), module, module.exports, async (id) => {
3183
3213
  const next = dependencyUrl(url, id);
3184
3214
  if (next) await load(next);
3185
3215
  else {
package/dist/index.js CHANGED
@@ -3053,6 +3053,43 @@ var linkPlayground = (compiled, files, options = {}) => {
3053
3053
  //#region packages/playground/src/core/runtime/local/remote.ts
3054
3054
  var HOST_VUE = /* @__PURE__ */ new Set(["vue", "vue/server-renderer"]);
3055
3055
  var moduleUrl = (url) => new URL(url, globalThis.location?.href).href;
3056
+ var REMOTE_SOURCE_CACHE_LIMIT = 128;
3057
+ var sourceCache = /* @__PURE__ */ new Map();
3058
+ var prepareRemoteSource = async (url) => {
3059
+ const response = await fetch(url);
3060
+ if (!response.ok) throw new Error(`${response.status} ${url}`);
3061
+ const text = await response.text();
3062
+ await init();
3063
+ const [specifiers] = parse(text);
3064
+ let source = text;
3065
+ for (const item of [...specifiers].reverse()) if (item.type === "dynamic") source = source.slice(0, item.importStart) + "__import" + source.slice(item.importStart + 6);
3066
+ const cjs = transform(rewriteImportMeta(source, url), {
3067
+ transforms: ["imports"],
3068
+ disableESTransforms: true,
3069
+ production: true,
3070
+ filePath: url
3071
+ }).code;
3072
+ return {
3073
+ dependencies: specifiers.filter((item) => item.type === "static" || item.type === "reexport-star").map((item) => item.specifier),
3074
+ run: new Function("require", "module", "exports", "__import", cjs)
3075
+ };
3076
+ };
3077
+ var readRemoteSource = (url) => {
3078
+ if (new URL(url).origin === globalThis.location?.origin) return prepareRemoteSource(url);
3079
+ const cached = sourceCache.get(url);
3080
+ if (cached) {
3081
+ sourceCache.delete(url);
3082
+ sourceCache.set(url, cached);
3083
+ return cached;
3084
+ }
3085
+ const task = prepareRemoteSource(url).catch((error) => {
3086
+ if (sourceCache.get(url) === task) sourceCache.delete(url);
3087
+ throw error;
3088
+ });
3089
+ sourceCache.set(url, task);
3090
+ if (sourceCache.size > REMOTE_SOURCE_CACHE_LIMIT) sourceCache.delete(sourceCache.keys().next().value);
3091
+ return task;
3092
+ };
3056
3093
  /**
3057
3094
  * 把 CDN 上的 ESM 先拉完整张依赖图,再在当前页面里执行。
3058
3095
  * 裸导入优先走 import map,缺失的 npm 依赖回退到 CDN ESM;import() 按需加载。
@@ -3071,9 +3108,9 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
3071
3108
  "vue-router": builtins.vueRouter
3072
3109
  };
3073
3110
  const pendingBuiltins = /* @__PURE__ */ new Set();
3074
- const texts = /* @__PURE__ */ new Map();
3111
+ const sources = /* @__PURE__ */ new Map();
3112
+ const pendingSources = /* @__PURE__ */ new Map();
3075
3113
  const evaluated = /* @__PURE__ */ new Map();
3076
- const crawled = /* @__PURE__ */ new Set();
3077
3114
  const nativeModules = /* @__PURE__ */ new Map();
3078
3115
  const loadNative = (url) => {
3079
3116
  let pending = nativeModules.get(url);
@@ -3130,25 +3167,23 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
3130
3167
  }
3131
3168
  return moduleUrl(imports[target]);
3132
3169
  };
3133
- const crawl = async (url) => {
3170
+ const crawl = async (url, visited = /* @__PURE__ */ new Set()) => {
3134
3171
  if (!overrides.size && /\/\+esm(?:[?#]|$)/.test(url)) {
3135
3172
  await loadNative(url);
3136
3173
  return;
3137
3174
  }
3138
- if (crawled.has(url)) return;
3139
- crawled.add(url);
3140
- const response = await fetch(url);
3141
- if (!response.ok) throw new Error(`${response.status} ${url}`);
3142
- const text = await response.text();
3143
- await init();
3144
- const [specifiers] = parse(text);
3145
- let source = text;
3146
- for (const item of [...specifiers].reverse()) if (item.type === "dynamic") source = source.slice(0, item.importStart) + "__import" + source.slice(item.importStart + 6);
3147
- texts.set(url, source);
3148
- await Promise.all(specifiers.map(async (item) => {
3149
- if (item.type !== "static" && item.type !== "reexport-star") return;
3150
- const next = dependencyUrl(url, item.specifier);
3151
- if (next) await crawl(next);
3175
+ if (visited.has(url)) return;
3176
+ visited.add(url);
3177
+ let pending = pendingSources.get(url);
3178
+ if (!pending) {
3179
+ pending = readRemoteSource(url);
3180
+ pendingSources.set(url, pending);
3181
+ }
3182
+ const source = await pending;
3183
+ sources.set(url, source);
3184
+ await Promise.all(source.dependencies.map(async (specifier) => {
3185
+ const next = dependencyUrl(url, specifier);
3186
+ if (next) await crawl(next, visited);
3152
3187
  }));
3153
3188
  };
3154
3189
  const requireFrom = (from) => (specifier) => {
@@ -3168,17 +3203,12 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
3168
3203
  };
3169
3204
  const evaluate = (url) => {
3170
3205
  if (evaluated.has(url)) return evaluated.get(url);
3171
- const text = texts.get(url);
3172
- if (text == null) throw new Error(`[Playground] 远程模块尚未下载: ${url}`);
3173
- const cjs = transform(rewriteImportMeta(text, url), {
3174
- transforms: ["imports"],
3175
- disableESTransforms: true,
3176
- production: true,
3177
- filePath: url
3178
- }).code;
3206
+ const source = sources.get(url);
3207
+ if (!source) throw new Error(`[Playground] 远程模块尚未下载: ${url}`);
3179
3208
  const module = { exports: {} };
3180
3209
  evaluated.set(url, module.exports);
3181
- new Function("require", "module", "exports", "__import", cjs)(requireFrom(url), module, module.exports, async (id) => {
3210
+ const runner = source.run;
3211
+ runner(requireFrom(url), module, module.exports, async (id) => {
3182
3212
  const next = dependencyUrl(url, id);
3183
3213
  if (next) await load(next);
3184
3214
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deot/docs-playground",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {