@deot/docs-playground 1.1.6 → 1.1.8
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 +5 -3
- package/dist/{compile-CM_OyqYN.js → compile-BHlM2G35.js} +1 -1
- package/dist/{compile-29EUKPOy.cjs → compile-QZ6cd8o0.cjs} +1 -1
- package/dist/{css-DleINdoA.js → css-C25yWQa_.js} +47 -2
- package/dist/{css-DpqJBQ5c.cjs → css-O1VYXZtT.cjs} +70 -1
- package/dist/index.cjs +114 -51
- package/dist/index.d.ts +13 -0
- package/dist/index.js +114 -52
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -145,6 +145,7 @@ const handleMessage = async () => {
|
|
|
145
145
|
| `slugifyPlaygroundTitle(title)` / `resolvePlaygroundTitleId(title, id?)` | 标题锚点 id,规则对齐 markdown-it-anchor。 |
|
|
146
146
|
| `DEFAULT_CDN_URL` | 默认 CDN 根地址(jsDelivr)。 |
|
|
147
147
|
| `createBuiltinImports(cdnURL?)` / `createBuiltinStyles(cdnURL?)` | 按 CDN 生成内置 import map 与预览样式表 URL。 |
|
|
148
|
+
| `resolveCdnURL(url, cdnURL?, config?)` | 内置转换后调用可选 `resolve.cdn`;默认读取当前站点配置。 |
|
|
148
149
|
| `normalizeCdnURL(value?)` | 规范化 CDN 根地址。 |
|
|
149
150
|
|
|
150
151
|
同时导出 `PlaygroundFiles`、`PlaygroundView`、`PlaygroundViewport`、`PlaygroundOptions`、`PlaygroundPreviewOptions`、`EditorFilesChange` 和 `EditorFilesChangeAction` 类型。
|
|
@@ -154,11 +155,12 @@ const handleMessage = async () => {
|
|
|
154
155
|
## 运行环境
|
|
155
156
|
|
|
156
157
|
- iframe 运行时通过公共 CDN 加载 Vue 和默认 import map 中的依赖;local 运行时加载 URL 覆盖或宿主未提供的模块时也需要网络访问。
|
|
157
|
-
- 默认 CDN 为 `https://cdn.jsdelivr.net/npm
|
|
158
|
-
- `
|
|
159
|
-
- 直接渲染时,宿主未提供且未配置的 npm
|
|
158
|
+
- 默认 CDN 为 `https://cdn.jsdelivr.net/npm`;未使用 launch 时可通过 `options.cdnURL` 调整默认节点。launch 已选点时统一使用 `$docs.runtime.cdn`,优先于实例 `cdnURL`。
|
|
159
|
+
- jsDelivr npm、旧 `unpkg.com` 和 `esm.unpkg.com` 地址在实际加载时转换,再经过可选 `$docs.resolve.cdn({ url })`。jsDelivr 转换入口使用 `/+esm`,ESM UNPKG 使用包或文件入口。预览 CSS、import map、裸包回退和 Sass 共用该规则;原始映射与缓存不被改写。
|
|
160
|
+
- 直接渲染时,宿主未提供且未配置的 npm 模块(含作用域包和子路径)自动通过上述 ESM 规则加载;组件包的传递依赖也适用,`import()` 在调用时加载。可用 `options.builtinImportMap.imports` 指定依赖的版本和 URL。
|
|
160
161
|
- Vue SFC 的 `<style lang="scss">` / `lang="sass"` 以及独立 `.scss` / `.sass` 文件会在浏览器里编译;`_partial.scss` 只作为 `@use` 依赖。
|
|
161
162
|
- local 模式按模块识别显式 URL 覆盖,即使地址与内置默认相同也会加载该 URL。覆盖 `vue` 时,预览的编译产物、挂载、组件引用和注入使用这份 Vue;内置组件、hooks、locale、Pinia 和 vue-router 随之重新加载以匹配 Vue,未覆盖的普通工具模块继续复用宿主。不同预览的覆盖互不影响,显式覆盖的模块在各自预览内执行。
|
|
163
|
+
- local 模式在当前页面按 URL 缓存外部模块的下载和转换成果,并合并并发请求;切换文档时可复用,最多保留最近使用的 128 个模块。各预览仍独立执行模块并解析依赖覆盖;失败的加载不缓存,同源模块实时读取,刷新页面会清空缓存。
|
|
162
164
|
- 每个 Playground 实例都使用自己的 preview 配置和 iframe 消息来源校验。
|
|
163
165
|
- `local` 默认开启:同一份 `files` 在当前文档里编译。直接渲染不撑开预览高度,`expandable` 固定为关闭,`docs:playground.run` 不会申请临时高度;`<DocsLink>` 仍通过 `docs:navigate` 通知。`local: false` 改回 iframe Sandbox。
|
|
164
166
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as transformScript, c as createFileIndex, h as resolveEntry, m as normalizeVirtualPath, s as collectReachableFilenames, t as collectCss, u as getExtension, v as compileScssSource, y as extractScssExports } from "./css-
|
|
1
|
+
import { a as transformScript, c as createFileIndex, h as resolveEntry, m as normalizeVirtualPath, s as collectReachableFilenames, t as collectCss, u as getExtension, v as compileScssSource, y as extractScssExports } from "./css-C25yWQa_.js";
|
|
2
2
|
import { compileString } from "sass";
|
|
3
3
|
//#region packages/playground/src/core/runtime/local/compile/scss.ts
|
|
4
4
|
/**
|
|
@@ -53,6 +53,51 @@ var createBuiltinImports = (cdnURL = DEFAULT_CDN_URL) => ({
|
|
|
53
53
|
});
|
|
54
54
|
var createBuiltinStyles = (cdnURL = DEFAULT_CDN_URL) => Object.fromEntries(PREVIEW_STYLE_ASSETS.map((asset) => [asset, cdnAsset(cdnURL, asset)]));
|
|
55
55
|
var resolveNpmImport = (specifier) => /^https?:\/\//.test(specifier) ? specifier : jsdelivrEsmURL(`${specifier}/+esm`);
|
|
56
|
+
var docsCdnConfig = () => globalThis.window?.$docs || {};
|
|
57
|
+
var npmCdnUrl = (value) => {
|
|
58
|
+
if (!/^https?:\/\//i.test(value)) return null;
|
|
59
|
+
const url = new URL(value);
|
|
60
|
+
const prefix = /(?:^|\.)jsdelivr\.net$/u.test(url.hostname) && url.pathname.startsWith("/npm/") ? "/npm/" : /^(?:esm\.)?unpkg\.com$/u.test(url.hostname) ? "/" : null;
|
|
61
|
+
if (!prefix) return null;
|
|
62
|
+
const asset = url.pathname.slice(prefix.length);
|
|
63
|
+
const match = asset.match(/^((?:@[^/]+\/)?[^/]+)(.*)$/u);
|
|
64
|
+
return match ? {
|
|
65
|
+
url,
|
|
66
|
+
asset,
|
|
67
|
+
name: match[1].replace(/@[^/@]+$/u, ""),
|
|
68
|
+
path: match[2]
|
|
69
|
+
} : null;
|
|
70
|
+
};
|
|
71
|
+
var cdnModuleName = (url) => {
|
|
72
|
+
const parsed = npmCdnUrl(url);
|
|
73
|
+
return parsed && (!parsed.path || parsed.path === "/+esm" || /^\/(?:es\d+|esnext)\/[^/]+\.m?js$/u.test(parsed.path)) ? parsed.name : null;
|
|
74
|
+
};
|
|
75
|
+
var isCdnEsmURL = (url) => /\/\+esm(?:[?#]|$)/u.test(url) || npmCdnUrl(url)?.url.hostname === "esm.unpkg.com";
|
|
76
|
+
var resolveCdnURL = (url, cdnURL, config = docsCdnConfig()) => {
|
|
77
|
+
const parsed = npmCdnUrl(url);
|
|
78
|
+
const target = config.runtime?.cdn || cdnURL;
|
|
79
|
+
let converted = url;
|
|
80
|
+
if (parsed && target) {
|
|
81
|
+
const origin = normalizeCdnURL(target);
|
|
82
|
+
const unpkg = new URL(origin).hostname === "esm.unpkg.com";
|
|
83
|
+
let asset = parsed.asset;
|
|
84
|
+
if (unpkg) asset = asset.replace(/\/\+esm$/u, "");
|
|
85
|
+
else if (!parsed.path.endsWith("/+esm") && (!parsed.path || !/\.[^/]+$/u.test(parsed.path) || /unpkg\.com$/u.test(parsed.url.hostname) && /\.[cm]?[jt]sx?$/u.test(parsed.path))) asset = `${asset.replace(/\/+$/u, "")}/+esm`;
|
|
86
|
+
converted = `${origin}/${asset}${parsed.url.search}${parsed.url.hash}`;
|
|
87
|
+
}
|
|
88
|
+
return config.resolve?.cdn?.({ url: converted }) || converted;
|
|
89
|
+
};
|
|
90
|
+
var createCdnResolver = (cdnURL) => {
|
|
91
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
92
|
+
return (url) => {
|
|
93
|
+
if (!resolved.has(url)) {
|
|
94
|
+
const target = resolveCdnURL(url, cdnURL);
|
|
95
|
+
resolved.set(url, target);
|
|
96
|
+
resolved.set(target, target);
|
|
97
|
+
}
|
|
98
|
+
return resolved.get(url);
|
|
99
|
+
};
|
|
100
|
+
};
|
|
56
101
|
//#endregion
|
|
57
102
|
//#region packages/playground/src/core/scss.ts
|
|
58
103
|
var SCHEME = "docs-playground";
|
|
@@ -84,7 +129,7 @@ var resolveSassModule = async (url) => {
|
|
|
84
129
|
return sass;
|
|
85
130
|
};
|
|
86
131
|
var loadSass = () => {
|
|
87
|
-
loadPromise ??= (() => resolveSassModule(SASS_CDN_URL))().then((sass) => {
|
|
132
|
+
loadPromise ??= (() => resolveSassModule(resolveCdnURL(SASS_CDN_URL)))().then((sass) => {
|
|
88
133
|
loadedSass = sass;
|
|
89
134
|
return sass;
|
|
90
135
|
});
|
|
@@ -577,4 +622,4 @@ var removeStyle = (id) => {
|
|
|
577
622
|
document.querySelector(`style[data-playground-id="${id}"]`)?.remove();
|
|
578
623
|
};
|
|
579
624
|
//#endregion
|
|
580
|
-
export {
|
|
625
|
+
export { DEFAULT_ENTRY as A, createBuiltinStyles as C, resolveCdnURL as D, normalizeCdnURL as E, resolveNpmImport as O, createBuiltinImports as S, isCdnEsmURL as T, bindPlaygroundScss as _, transformScript as a, whenSassReady as b, createFileIndex as c, isIgnoredFilename as d, isInsideRoot as f, resolveModulePath as g, resolveEntry as h, rewriteImportMeta as i, NEW_SFC_CODE as j, DEFAULT_CDN_URL as k, getCommonRoot as l, normalizeVirtualPath as m, injectStyle as n, collectBareSpecifiers as o, isRelativeSpecifier as p, removeStyle as r, collectReachableFilenames as s, collectCss as t, getExtension as u, compileScssSource as v, createCdnResolver as w, cdnModuleName as x, extractScssExports as y };
|
|
@@ -85,6 +85,51 @@ var createBuiltinImports = (cdnURL = DEFAULT_CDN_URL) => ({
|
|
|
85
85
|
});
|
|
86
86
|
var createBuiltinStyles = (cdnURL = DEFAULT_CDN_URL) => Object.fromEntries(PREVIEW_STYLE_ASSETS.map((asset) => [asset, cdnAsset(cdnURL, asset)]));
|
|
87
87
|
var resolveNpmImport = (specifier) => /^https?:\/\//.test(specifier) ? specifier : jsdelivrEsmURL(`${specifier}/+esm`);
|
|
88
|
+
var docsCdnConfig = () => globalThis.window?.$docs || {};
|
|
89
|
+
var npmCdnUrl = (value) => {
|
|
90
|
+
if (!/^https?:\/\//i.test(value)) return null;
|
|
91
|
+
const url = new URL(value);
|
|
92
|
+
const prefix = /(?:^|\.)jsdelivr\.net$/u.test(url.hostname) && url.pathname.startsWith("/npm/") ? "/npm/" : /^(?:esm\.)?unpkg\.com$/u.test(url.hostname) ? "/" : null;
|
|
93
|
+
if (!prefix) return null;
|
|
94
|
+
const asset = url.pathname.slice(prefix.length);
|
|
95
|
+
const match = asset.match(/^((?:@[^/]+\/)?[^/]+)(.*)$/u);
|
|
96
|
+
return match ? {
|
|
97
|
+
url,
|
|
98
|
+
asset,
|
|
99
|
+
name: match[1].replace(/@[^/@]+$/u, ""),
|
|
100
|
+
path: match[2]
|
|
101
|
+
} : null;
|
|
102
|
+
};
|
|
103
|
+
var cdnModuleName = (url) => {
|
|
104
|
+
const parsed = npmCdnUrl(url);
|
|
105
|
+
return parsed && (!parsed.path || parsed.path === "/+esm" || /^\/(?:es\d+|esnext)\/[^/]+\.m?js$/u.test(parsed.path)) ? parsed.name : null;
|
|
106
|
+
};
|
|
107
|
+
var isCdnEsmURL = (url) => /\/\+esm(?:[?#]|$)/u.test(url) || npmCdnUrl(url)?.url.hostname === "esm.unpkg.com";
|
|
108
|
+
var resolveCdnURL = (url, cdnURL, config = docsCdnConfig()) => {
|
|
109
|
+
const parsed = npmCdnUrl(url);
|
|
110
|
+
const target = config.runtime?.cdn || cdnURL;
|
|
111
|
+
let converted = url;
|
|
112
|
+
if (parsed && target) {
|
|
113
|
+
const origin = normalizeCdnURL(target);
|
|
114
|
+
const unpkg = new URL(origin).hostname === "esm.unpkg.com";
|
|
115
|
+
let asset = parsed.asset;
|
|
116
|
+
if (unpkg) asset = asset.replace(/\/\+esm$/u, "");
|
|
117
|
+
else if (!parsed.path.endsWith("/+esm") && (!parsed.path || !/\.[^/]+$/u.test(parsed.path) || /unpkg\.com$/u.test(parsed.url.hostname) && /\.[cm]?[jt]sx?$/u.test(parsed.path))) asset = `${asset.replace(/\/+$/u, "")}/+esm`;
|
|
118
|
+
converted = `${origin}/${asset}${parsed.url.search}${parsed.url.hash}`;
|
|
119
|
+
}
|
|
120
|
+
return config.resolve?.cdn?.({ url: converted }) || converted;
|
|
121
|
+
};
|
|
122
|
+
var createCdnResolver = (cdnURL) => {
|
|
123
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
124
|
+
return (url) => {
|
|
125
|
+
if (!resolved.has(url)) {
|
|
126
|
+
const target = resolveCdnURL(url, cdnURL);
|
|
127
|
+
resolved.set(url, target);
|
|
128
|
+
resolved.set(target, target);
|
|
129
|
+
}
|
|
130
|
+
return resolved.get(url);
|
|
131
|
+
};
|
|
132
|
+
};
|
|
88
133
|
//#endregion
|
|
89
134
|
//#region packages/playground/src/core/scss.ts
|
|
90
135
|
var SCHEME = "docs-playground";
|
|
@@ -117,7 +162,7 @@ var resolveSassModule = async (url) => {
|
|
|
117
162
|
return sass;
|
|
118
163
|
};
|
|
119
164
|
var loadSass = () => {
|
|
120
|
-
loadPromise ??= (testLoader ?? (() => resolveSassModule(SASS_CDN_URL)))().then((sass) => {
|
|
165
|
+
loadPromise ??= (testLoader ?? (() => resolveSassModule(resolveCdnURL(SASS_CDN_URL))))().then((sass) => {
|
|
121
166
|
loadedSass = sass;
|
|
122
167
|
return sass;
|
|
123
168
|
});
|
|
@@ -646,6 +691,12 @@ Object.defineProperty(exports, "bindPlaygroundScss", {
|
|
|
646
691
|
return bindPlaygroundScss;
|
|
647
692
|
}
|
|
648
693
|
});
|
|
694
|
+
Object.defineProperty(exports, "cdnModuleName", {
|
|
695
|
+
enumerable: true,
|
|
696
|
+
get: function() {
|
|
697
|
+
return cdnModuleName;
|
|
698
|
+
}
|
|
699
|
+
});
|
|
649
700
|
Object.defineProperty(exports, "collectBareSpecifiers", {
|
|
650
701
|
enumerable: true,
|
|
651
702
|
get: function() {
|
|
@@ -682,6 +733,12 @@ Object.defineProperty(exports, "createBuiltinStyles", {
|
|
|
682
733
|
return createBuiltinStyles;
|
|
683
734
|
}
|
|
684
735
|
});
|
|
736
|
+
Object.defineProperty(exports, "createCdnResolver", {
|
|
737
|
+
enumerable: true,
|
|
738
|
+
get: function() {
|
|
739
|
+
return createCdnResolver;
|
|
740
|
+
}
|
|
741
|
+
});
|
|
685
742
|
Object.defineProperty(exports, "createFileIndex", {
|
|
686
743
|
enumerable: true,
|
|
687
744
|
get: function() {
|
|
@@ -712,6 +769,12 @@ Object.defineProperty(exports, "injectStyle", {
|
|
|
712
769
|
return injectStyle;
|
|
713
770
|
}
|
|
714
771
|
});
|
|
772
|
+
Object.defineProperty(exports, "isCdnEsmURL", {
|
|
773
|
+
enumerable: true,
|
|
774
|
+
get: function() {
|
|
775
|
+
return isCdnEsmURL;
|
|
776
|
+
}
|
|
777
|
+
});
|
|
715
778
|
Object.defineProperty(exports, "isIgnoredFilename", {
|
|
716
779
|
enumerable: true,
|
|
717
780
|
get: function() {
|
|
@@ -748,6 +811,12 @@ Object.defineProperty(exports, "removeStyle", {
|
|
|
748
811
|
return removeStyle;
|
|
749
812
|
}
|
|
750
813
|
});
|
|
814
|
+
Object.defineProperty(exports, "resolveCdnURL", {
|
|
815
|
+
enumerable: true,
|
|
816
|
+
get: function() {
|
|
817
|
+
return resolveCdnURL;
|
|
818
|
+
}
|
|
819
|
+
});
|
|
751
820
|
Object.defineProperty(exports, "resolveEntry", {
|
|
752
821
|
enumerable: true,
|
|
753
822
|
get: function() {
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_css = require("./css-
|
|
2
|
+
const require_css = require("./css-O1VYXZtT.cjs");
|
|
3
3
|
let vue = require("vue");
|
|
4
4
|
vue = require_css.__toESM(vue);
|
|
5
5
|
let _deot_vc = require("@deot/vc");
|
|
@@ -2066,14 +2066,16 @@ var moduleSpecifier = (item) => item.type === "import-meta" || !item.specifier |
|
|
|
2066
2066
|
* 发现自定义 ESM 的传递引用;缺失的 npm 包映射到 CDN,动态依赖只登记地址。
|
|
2067
2067
|
* @param imports 当前预览的模块覆盖。
|
|
2068
2068
|
* @param specifiers 源文件实际引用的模块。
|
|
2069
|
+
* @param resolve 本次预览共用的最终 URL 转换。
|
|
2069
2070
|
* @returns 补齐后的 import map。
|
|
2070
2071
|
*/
|
|
2071
|
-
var resolveReplImports = async (imports, specifiers) => {
|
|
2072
|
+
var resolveReplImports = async (imports, specifiers, resolve = require_css.createCdnResolver()) => {
|
|
2072
2073
|
const resolved = { ...imports };
|
|
2073
2074
|
const visited = /* @__PURE__ */ new Set();
|
|
2074
2075
|
const visit = async (specifier, importer) => {
|
|
2075
|
-
const
|
|
2076
|
-
|
|
2076
|
+
const source = require_css.isRelativeSpecifier(specifier) || /^https?:\/\//.test(specifier) ? new URL(specifier, importer || location.href).href : resolved[specifier] ||= require_css.resolveNpmImport(specifier);
|
|
2077
|
+
const url = resolve(source);
|
|
2078
|
+
if (visited.has(url) || require_css.isCdnEsmURL(source)) return;
|
|
2077
2079
|
visited.add(url);
|
|
2078
2080
|
const response = await fetch(url);
|
|
2079
2081
|
if (!response.ok) throw new Error(`${response.status} ${url}`);
|
|
@@ -2138,8 +2140,10 @@ var rewriteImportedExports = (code) => {
|
|
|
2138
2140
|
/**
|
|
2139
2141
|
* REPL 将 ./ 引用按 src 根目录解析,编译结果需要先转成文件表中的完整路径。
|
|
2140
2142
|
* @param store iframe 预览的文件和编译结果。
|
|
2143
|
+
* @param getImportMap 未转换的原始 import map。
|
|
2144
|
+
* @param resolve 本次预览共用的最终 URL 转换。
|
|
2141
2145
|
*/
|
|
2142
|
-
var bindReplModules = (store) => {
|
|
2146
|
+
var bindReplModules = (store, getImportMap = store.getImportMap.bind(store), resolve = require_css.createCdnResolver()) => {
|
|
2143
2147
|
(0, vue.watch)(() => Object.values(store.files).map((file) => [
|
|
2144
2148
|
file.filename,
|
|
2145
2149
|
file.code,
|
|
@@ -2147,7 +2151,7 @@ var bindReplModules = (store) => {
|
|
|
2147
2151
|
file.compiled.ssr
|
|
2148
2152
|
]), () => {
|
|
2149
2153
|
const files = require_css.createFileIndex(Object.fromEntries(Object.entries(store.files).map(([name, file]) => [name, file.code])));
|
|
2150
|
-
const importMap =
|
|
2154
|
+
const importMap = getImportMap();
|
|
2151
2155
|
const imports = { ...importMap.imports };
|
|
2152
2156
|
let importsChanged = false;
|
|
2153
2157
|
for (const file of Object.values(store.files)) for (const output of ["js", "ssr"]) {
|
|
@@ -2167,7 +2171,11 @@ var bindReplModules = (store) => {
|
|
|
2167
2171
|
const target = `./${resolved.replace(/^\/?src\//, "")}`;
|
|
2168
2172
|
const text = item.type === "dynamic" ? JSON.stringify(target) : target;
|
|
2169
2173
|
code = code.slice(0, item.start) + text + code.slice(item.end);
|
|
2170
|
-
} else if (
|
|
2174
|
+
} else if (/^https?:\/\//.test(specifier)) {
|
|
2175
|
+
const target = resolve(specifier);
|
|
2176
|
+
const text = item.type === "dynamic" ? JSON.stringify(target) : target;
|
|
2177
|
+
code = code.slice(0, item.start) + text + code.slice(item.end);
|
|
2178
|
+
} else if (!imports[specifier]) {
|
|
2171
2179
|
imports[specifier] = require_css.resolveNpmImport(specifier);
|
|
2172
2180
|
importsChanged = true;
|
|
2173
2181
|
}
|
|
@@ -2204,13 +2212,14 @@ var escapeHtmlAttr = (value) => value.replace(/&/gu, "&").replace(/"/gu, "&q
|
|
|
2204
2212
|
* `--vc-background-color-lightest` 不同,否则会出现色带割裂。
|
|
2205
2213
|
*/
|
|
2206
2214
|
var PLAYGROUND_RUNTIME_CANVAS_BACKGROUND = "var(--vc-background-color-lightest, var(--docs-background-color, #fff))";
|
|
2207
|
-
var createRuntimePreviewOptions = (cdnURL
|
|
2215
|
+
var createRuntimePreviewOptions = (cdnURL, options = {}) => {
|
|
2208
2216
|
const previewScroller = options.previewScroller === true;
|
|
2217
|
+
const resolve = require_css.createCdnResolver(cdnURL);
|
|
2209
2218
|
const hrefs = Object.values({
|
|
2210
2219
|
...require_css.createBuiltinStyles(cdnURL),
|
|
2211
2220
|
...getPlaygroundSiteStyles(),
|
|
2212
2221
|
...getPlaygroundStyleOverrides()
|
|
2213
|
-
});
|
|
2222
|
+
}).map(resolve);
|
|
2214
2223
|
const styleBlocks = [
|
|
2215
2224
|
`html,body{height:auto;min-height:0;background:${PLAYGROUND_RUNTIME_CANVAS_BACKGROUND}}`,
|
|
2216
2225
|
"body{color:var(--vc-foreground-color,#080f20)}",
|
|
@@ -2254,7 +2263,7 @@ var createRuntimeImportOverrides = (builtinImportMap) => ({
|
|
|
2254
2263
|
* @param cdnURL
|
|
2255
2264
|
* @param builtinImportMap
|
|
2256
2265
|
*/
|
|
2257
|
-
var createRuntimeImports = (cdnURL
|
|
2266
|
+
var createRuntimeImports = (cdnURL, builtinImportMap) => ({
|
|
2258
2267
|
...require_css.createBuiltinImports(cdnURL),
|
|
2259
2268
|
...createRuntimeImportOverrides(builtinImportMap)
|
|
2260
2269
|
});
|
|
@@ -2268,8 +2277,14 @@ var createRuntimeStore = (files, entry, options) => {
|
|
|
2268
2277
|
const mainFile = (0, vue.ref)(toReplFilename(entry));
|
|
2269
2278
|
const activeFilename = (0, vue.ref)(toReplFilename(entry));
|
|
2270
2279
|
const imports = createRuntimeImports(cdnURL, builtinImportMap);
|
|
2280
|
+
const resolve = require_css.createCdnResolver(cdnURL);
|
|
2281
|
+
const resourceLinks = (0, vue.unref)(storeOptions.resourceLinks);
|
|
2271
2282
|
const store = (0, _vue_repl.useStore)({
|
|
2272
2283
|
...storeOptions,
|
|
2284
|
+
resourceLinks: (0, vue.ref)({
|
|
2285
|
+
...resourceLinks,
|
|
2286
|
+
esModuleShims: resolve(resourceLinks?.esModuleShims || "https://cdn.jsdelivr.net/npm/es-module-shims@1.5.18/dist/es-module-shims.wasm.js?raw")
|
|
2287
|
+
}),
|
|
2273
2288
|
files: replFiles,
|
|
2274
2289
|
mainFile,
|
|
2275
2290
|
activeFilename,
|
|
@@ -2288,7 +2303,17 @@ var createRuntimeStore = (files, entry, options) => {
|
|
|
2288
2303
|
"import-map.json": store.files["import-map.json"].code,
|
|
2289
2304
|
...nextFiles
|
|
2290
2305
|
}, nextEntry);
|
|
2291
|
-
|
|
2306
|
+
const getImportMap = store.getImportMap.bind(store);
|
|
2307
|
+
bindReplModules(store, getImportMap, resolve);
|
|
2308
|
+
store.getImportMap = () => {
|
|
2309
|
+
const map = getImportMap();
|
|
2310
|
+
const convert = (items = {}) => Object.fromEntries(Object.entries(items).filter((item) => typeof item[1] === "string").map(([id, url]) => [id, resolve(url)]));
|
|
2311
|
+
return {
|
|
2312
|
+
...map,
|
|
2313
|
+
imports: convert(map.imports),
|
|
2314
|
+
scopes: map.scopes && Object.fromEntries(Object.entries(map.scopes).map(([scope, items]) => [resolve(scope), convert(items)]))
|
|
2315
|
+
};
|
|
2316
|
+
};
|
|
2292
2317
|
require_css.whenSassReady(files, () => {
|
|
2293
2318
|
const specifiers = require_css.collectBareSpecifiers(files, Object.keys(files));
|
|
2294
2319
|
if (!specifiers.length) {
|
|
@@ -2296,8 +2321,12 @@ var createRuntimeStore = (files, entry, options) => {
|
|
|
2296
2321
|
return;
|
|
2297
2322
|
}
|
|
2298
2323
|
store.loading = true;
|
|
2299
|
-
|
|
2300
|
-
|
|
2324
|
+
const currentImports = {
|
|
2325
|
+
...imports,
|
|
2326
|
+
...filterSafeHrefs(getImportMap().imports)
|
|
2327
|
+
};
|
|
2328
|
+
resolveReplImports(currentImports, specifiers, resolve).then((resolved) => {
|
|
2329
|
+
if (Object.keys(resolved).length !== Object.keys(currentImports).length) store.setImportMap({ imports: resolved }, true);
|
|
2301
2330
|
store.init();
|
|
2302
2331
|
}).catch((error) => {
|
|
2303
2332
|
store.errors.push(error);
|
|
@@ -3054,6 +3083,43 @@ var linkPlayground = (compiled, files, options = {}) => {
|
|
|
3054
3083
|
//#region packages/playground/src/core/runtime/local/remote.ts
|
|
3055
3084
|
var HOST_VUE = /* @__PURE__ */ new Set(["vue", "vue/server-renderer"]);
|
|
3056
3085
|
var moduleUrl = (url) => new URL(url, globalThis.location?.href).href;
|
|
3086
|
+
var REMOTE_SOURCE_CACHE_LIMIT = 128;
|
|
3087
|
+
var sourceCache = /* @__PURE__ */ new Map();
|
|
3088
|
+
var prepareRemoteSource = async (url) => {
|
|
3089
|
+
const response = await fetch(url);
|
|
3090
|
+
if (!response.ok) throw new Error(`${response.status} ${url}`);
|
|
3091
|
+
const text = await response.text();
|
|
3092
|
+
await (0, es_module_lexer.init)();
|
|
3093
|
+
const [specifiers] = (0, es_module_lexer.parse)(text);
|
|
3094
|
+
let source = text;
|
|
3095
|
+
for (const item of [...specifiers].reverse()) if (item.type === "dynamic") source = source.slice(0, item.importStart) + "__import" + source.slice(item.importStart + 6);
|
|
3096
|
+
const cjs = (0, sucrase.transform)(require_css.rewriteImportMeta(source, url), {
|
|
3097
|
+
transforms: ["imports"],
|
|
3098
|
+
disableESTransforms: true,
|
|
3099
|
+
production: true,
|
|
3100
|
+
filePath: url
|
|
3101
|
+
}).code;
|
|
3102
|
+
return {
|
|
3103
|
+
dependencies: specifiers.filter((item) => item.type === "static" || item.type === "reexport-star").map((item) => item.specifier),
|
|
3104
|
+
run: new Function("require", "module", "exports", "__import", cjs)
|
|
3105
|
+
};
|
|
3106
|
+
};
|
|
3107
|
+
var readRemoteSource = (url) => {
|
|
3108
|
+
if (new URL(url).origin === globalThis.location?.origin) return prepareRemoteSource(url);
|
|
3109
|
+
const cached = sourceCache.get(url);
|
|
3110
|
+
if (cached) {
|
|
3111
|
+
sourceCache.delete(url);
|
|
3112
|
+
sourceCache.set(url, cached);
|
|
3113
|
+
return cached;
|
|
3114
|
+
}
|
|
3115
|
+
const task = prepareRemoteSource(url).catch((error) => {
|
|
3116
|
+
if (sourceCache.get(url) === task) sourceCache.delete(url);
|
|
3117
|
+
throw error;
|
|
3118
|
+
});
|
|
3119
|
+
sourceCache.set(url, task);
|
|
3120
|
+
if (sourceCache.size > REMOTE_SOURCE_CACHE_LIMIT) sourceCache.delete(sourceCache.keys().next().value);
|
|
3121
|
+
return task;
|
|
3122
|
+
};
|
|
3057
3123
|
/**
|
|
3058
3124
|
* 把 CDN 上的 ESM 先拉完整张依赖图,再在当前页面里执行。
|
|
3059
3125
|
* 裸导入优先走 import map,缺失的 npm 依赖回退到 CDN ESM;import() 按需加载。
|
|
@@ -3061,20 +3127,23 @@ var moduleUrl = (url) => new URL(url, globalThis.location?.href).href;
|
|
|
3061
3127
|
* @param builtins 宿主 Vue 与 vue-router。
|
|
3062
3128
|
* @param overrides 显式配置的模块名,与自动补齐的默认地址区分。
|
|
3063
3129
|
* @param importModule 浏览器原生 ESM 加载器。
|
|
3130
|
+
* @param cdnURL 没有 launch 选点结果时使用的实例 CDN。
|
|
3064
3131
|
* @returns 按 URL 加载并执行远程模块的加载器。
|
|
3065
3132
|
*/
|
|
3066
3133
|
var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imports)), importModule = (url) => import(
|
|
3067
3134
|
/* @vite-ignore */
|
|
3068
3135
|
url
|
|
3069
|
-
)) => {
|
|
3136
|
+
), cdnURL) => {
|
|
3137
|
+
const resolve = require_css.createCdnResolver(cdnURL);
|
|
3138
|
+
const resolveUrl = (url) => resolve(moduleUrl(url));
|
|
3070
3139
|
const hostModules = {
|
|
3071
3140
|
"vue": builtins.vue,
|
|
3072
3141
|
"vue-router": builtins.vueRouter
|
|
3073
3142
|
};
|
|
3074
3143
|
const pendingBuiltins = /* @__PURE__ */ new Set();
|
|
3075
|
-
const
|
|
3144
|
+
const sources = /* @__PURE__ */ new Map();
|
|
3145
|
+
const pendingSources = /* @__PURE__ */ new Map();
|
|
3076
3146
|
const evaluated = /* @__PURE__ */ new Map();
|
|
3077
|
-
const crawled = /* @__PURE__ */ new Set();
|
|
3078
3147
|
const nativeModules = /* @__PURE__ */ new Map();
|
|
3079
3148
|
const loadNative = (url) => {
|
|
3080
3149
|
let pending = nativeModules.get(url);
|
|
@@ -3103,16 +3172,16 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3103
3172
|
const dependencySpecifier = (from, specifier) => {
|
|
3104
3173
|
if (require_css.isRelativeSpecifier(specifier) || /^https?:\/\//.test(specifier)) {
|
|
3105
3174
|
const url = new URL(specifier, from);
|
|
3106
|
-
const
|
|
3107
|
-
if (
|
|
3175
|
+
const name = require_css.cdnModuleName(url.href);
|
|
3176
|
+
if (name && (imports[name] || localBuiltinIds.has(name))) return name;
|
|
3108
3177
|
return url.href;
|
|
3109
3178
|
}
|
|
3110
3179
|
return specifier;
|
|
3111
3180
|
};
|
|
3112
3181
|
const dependencyUrl = (from, id) => {
|
|
3113
3182
|
const specifier = dependencySpecifier(from, id);
|
|
3114
|
-
if (/^https?:\/\//.test(specifier)) return specifier;
|
|
3115
|
-
if (imports[specifier] && !prefersLocalBuiltin(specifier, imports, overrides)) return
|
|
3183
|
+
if (/^https?:\/\//.test(specifier)) return resolveUrl(specifier);
|
|
3184
|
+
if (imports[specifier] && !prefersLocalBuiltin(specifier, imports, overrides)) return resolveUrl(imports[specifier]);
|
|
3116
3185
|
if (HOST_VUE.has(specifier) && prefersLocalBuiltin(specifier, imports, overrides)) return null;
|
|
3117
3186
|
let cursor = specifier;
|
|
3118
3187
|
while (cursor) {
|
|
@@ -3127,29 +3196,27 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3127
3196
|
const target = imports[specifier] ? specifier : resolveImportTarget(specifier, imports);
|
|
3128
3197
|
if (!target) {
|
|
3129
3198
|
imports[specifier] = require_css.resolveNpmImport(specifier);
|
|
3130
|
-
return imports[specifier];
|
|
3199
|
+
return resolveUrl(imports[specifier]);
|
|
3131
3200
|
}
|
|
3132
|
-
return
|
|
3201
|
+
return resolveUrl(imports[target]);
|
|
3133
3202
|
};
|
|
3134
|
-
const crawl = async (url) => {
|
|
3135
|
-
if (!overrides.size &&
|
|
3203
|
+
const crawl = async (url, visited = /* @__PURE__ */ new Set()) => {
|
|
3204
|
+
if (!overrides.size && require_css.isCdnEsmURL(url)) {
|
|
3136
3205
|
await loadNative(url);
|
|
3137
3206
|
return;
|
|
3138
3207
|
}
|
|
3139
|
-
if (
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
if (!
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
if (
|
|
3151
|
-
const next = dependencyUrl(url, item.specifier);
|
|
3152
|
-
if (next) await crawl(next);
|
|
3208
|
+
if (visited.has(url)) return;
|
|
3209
|
+
visited.add(url);
|
|
3210
|
+
let pending = pendingSources.get(url);
|
|
3211
|
+
if (!pending) {
|
|
3212
|
+
pending = readRemoteSource(url);
|
|
3213
|
+
pendingSources.set(url, pending);
|
|
3214
|
+
}
|
|
3215
|
+
const source = await pending;
|
|
3216
|
+
sources.set(url, source);
|
|
3217
|
+
await Promise.all(source.dependencies.map(async (specifier) => {
|
|
3218
|
+
const next = dependencyUrl(url, specifier);
|
|
3219
|
+
if (next) await crawl(next, visited);
|
|
3153
3220
|
}));
|
|
3154
3221
|
};
|
|
3155
3222
|
const requireFrom = (from) => (specifier) => {
|
|
@@ -3160,7 +3227,7 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3160
3227
|
if (require_css.isRelativeSpecifier(id) || /^https?:\/\//.test(id)) return evaluate(dependencyUrl(from, id));
|
|
3161
3228
|
const target = imports[id] ? id : resolveImportTarget(id, imports);
|
|
3162
3229
|
if (!target || !imports[target]) throw new Error(`[Playground] 未注册的模块 "${id}"`);
|
|
3163
|
-
const loaded = evaluate(
|
|
3230
|
+
const loaded = evaluate(resolveUrl(imports[target]));
|
|
3164
3231
|
if (target === id) return loaded;
|
|
3165
3232
|
if (!resolveHostModule(id, { [target]: loaded }))
|
|
3166
3233
|
/* istanbul ignore next -- 父包没有对应导出时才拒绝 */
|
|
@@ -3169,17 +3236,12 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3169
3236
|
};
|
|
3170
3237
|
const evaluate = (url) => {
|
|
3171
3238
|
if (evaluated.has(url)) return evaluated.get(url);
|
|
3172
|
-
const
|
|
3173
|
-
if (
|
|
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;
|
|
3239
|
+
const source = sources.get(url);
|
|
3240
|
+
if (!source) throw new Error(`[Playground] 远程模块尚未下载: ${url}`);
|
|
3180
3241
|
const module = { exports: {} };
|
|
3181
3242
|
evaluated.set(url, module.exports);
|
|
3182
|
-
|
|
3243
|
+
const runner = source.run;
|
|
3244
|
+
runner(requireFrom(url), module, module.exports, async (id) => {
|
|
3183
3245
|
const next = dependencyUrl(url, id);
|
|
3184
3246
|
if (next) await load(next);
|
|
3185
3247
|
else {
|
|
@@ -3193,7 +3255,7 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3193
3255
|
};
|
|
3194
3256
|
const loading = /* @__PURE__ */ new Map();
|
|
3195
3257
|
const load = (sourceUrl) => {
|
|
3196
|
-
const url =
|
|
3258
|
+
const url = resolveUrl(sourceUrl);
|
|
3197
3259
|
const pending = loading.get(url);
|
|
3198
3260
|
if (pending) return pending;
|
|
3199
3261
|
const task = (async () => {
|
|
@@ -3353,7 +3415,7 @@ var local_sandbox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0
|
|
|
3353
3415
|
publishError();
|
|
3354
3416
|
destroyPreview();
|
|
3355
3417
|
try {
|
|
3356
|
-
const { compilePlayground } = await Promise.resolve().then(() => require("./compile-
|
|
3418
|
+
const { compilePlayground } = await Promise.resolve().then(() => require("./compile-QZ6cd8o0.cjs"));
|
|
3357
3419
|
/* istanbul ignore if -- 并发编译时只保留最后一次 */
|
|
3358
3420
|
if (current !== version) return;
|
|
3359
3421
|
const compiled = await compilePlayground(props.files, { entry: props.entry });
|
|
@@ -3372,7 +3434,7 @@ var local_sandbox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0
|
|
|
3372
3434
|
const remote = createRemoteLoader(imports, {
|
|
3373
3435
|
vue,
|
|
3374
3436
|
vueRouter: vue_router
|
|
3375
|
-
}, overrides);
|
|
3437
|
+
}, overrides, void 0, props.options.cdnURL);
|
|
3376
3438
|
const loaded = await loadLocalModules(specifiers, imports, {
|
|
3377
3439
|
vue,
|
|
3378
3440
|
vueRouter: vue_router
|
|
@@ -4247,6 +4309,7 @@ exports.normalizeCdnURL = require_css.normalizeCdnURL;
|
|
|
4247
4309
|
exports.registerVueHighlight = registerVueHighlight;
|
|
4248
4310
|
exports.removePlaygroundImportMapOverride = removePlaygroundImportMapOverride;
|
|
4249
4311
|
exports.removePlaygroundStyleOverride = removePlaygroundStyleOverride;
|
|
4312
|
+
exports.resolveCdnURL = require_css.resolveCdnURL;
|
|
4250
4313
|
exports.resolveHighlightLanguage = resolveHighlightLanguage;
|
|
4251
4314
|
exports.resolvePlaygroundTitleId = resolvePlaygroundTitleId;
|
|
4252
4315
|
exports.setPlaygroundImportMapOverrides = setPlaygroundImportMapOverrides;
|
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,17 @@ export declare const applyPlaygroundStyleOverride: (alias: string, url: string)
|
|
|
81
81
|
[x: string]: string;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
declare interface CdnConfig {
|
|
85
|
+
runtime?: {
|
|
86
|
+
cdn?: string;
|
|
87
|
+
};
|
|
88
|
+
resolve?: {
|
|
89
|
+
cdn?: (context: {
|
|
90
|
+
url: string;
|
|
91
|
+
}) => string | null | undefined;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
84
95
|
export declare const clearPlaygroundMaps: () => void;
|
|
85
96
|
|
|
86
97
|
export declare const CodePreview: typeof __VLS_export;
|
|
@@ -250,6 +261,8 @@ export declare const removePlaygroundStyleOverride: (alias: string) => {
|
|
|
250
261
|
[x: string]: string;
|
|
251
262
|
};
|
|
252
263
|
|
|
264
|
+
export declare const resolveCdnURL: (url: string, cdnURL?: string, config?: CdnConfig) => string;
|
|
265
|
+
|
|
253
266
|
export declare const resolveHighlightLanguage: (filename: string) => "xml" | "javascript" | "typescript" | "css" | "scss" | "vue" | "json" | "plaintext";
|
|
254
267
|
|
|
255
268
|
export declare const resolvePlaygroundTitleId: (title: string, explicitId?: string, isOccupied?: (id: string) => boolean) => string;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { A as DEFAULT_ENTRY, C as createBuiltinStyles, D as resolveCdnURL, E as normalizeCdnURL, O as resolveNpmImport, S as createBuiltinImports, T as isCdnEsmURL, _ as bindPlaygroundScss, a as transformScript, b as whenSassReady, c as createFileIndex, d as isIgnoredFilename, f as isInsideRoot, g as resolveModulePath, i as rewriteImportMeta, j as NEW_SFC_CODE, k as DEFAULT_CDN_URL, l as getCommonRoot, m as normalizeVirtualPath, n as injectStyle, o as collectBareSpecifiers, p as isRelativeSpecifier, r as removeStyle, s as collectReachableFilenames, w as createCdnResolver, x as cdnModuleName } from "./css-C25yWQa_.js";
|
|
2
2
|
import * as Vue from "vue";
|
|
3
3
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineAsyncComponent, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, shallowRef, toDisplayString, unref, vModelText, vShow, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
4
4
|
import * as Vc from "@deot/vc";
|
|
@@ -2068,14 +2068,16 @@ var moduleSpecifier = (item) => item.type === "import-meta" || !item.specifier |
|
|
|
2068
2068
|
* 发现自定义 ESM 的传递引用;缺失的 npm 包映射到 CDN,动态依赖只登记地址。
|
|
2069
2069
|
* @param imports 当前预览的模块覆盖。
|
|
2070
2070
|
* @param specifiers 源文件实际引用的模块。
|
|
2071
|
+
* @param resolve 本次预览共用的最终 URL 转换。
|
|
2071
2072
|
* @returns 补齐后的 import map。
|
|
2072
2073
|
*/
|
|
2073
|
-
var resolveReplImports = async (imports, specifiers) => {
|
|
2074
|
+
var resolveReplImports = async (imports, specifiers, resolve = createCdnResolver()) => {
|
|
2074
2075
|
const resolved = { ...imports };
|
|
2075
2076
|
const visited = /* @__PURE__ */ new Set();
|
|
2076
2077
|
const visit = async (specifier, importer) => {
|
|
2077
|
-
const
|
|
2078
|
-
|
|
2078
|
+
const source = isRelativeSpecifier(specifier) || /^https?:\/\//.test(specifier) ? new URL(specifier, importer || location.href).href : resolved[specifier] ||= resolveNpmImport(specifier);
|
|
2079
|
+
const url = resolve(source);
|
|
2080
|
+
if (visited.has(url) || isCdnEsmURL(source)) return;
|
|
2079
2081
|
visited.add(url);
|
|
2080
2082
|
const response = await fetch(url);
|
|
2081
2083
|
if (!response.ok) throw new Error(`${response.status} ${url}`);
|
|
@@ -2140,8 +2142,10 @@ var rewriteImportedExports = (code) => {
|
|
|
2140
2142
|
/**
|
|
2141
2143
|
* REPL 将 ./ 引用按 src 根目录解析,编译结果需要先转成文件表中的完整路径。
|
|
2142
2144
|
* @param store iframe 预览的文件和编译结果。
|
|
2145
|
+
* @param getImportMap 未转换的原始 import map。
|
|
2146
|
+
* @param resolve 本次预览共用的最终 URL 转换。
|
|
2143
2147
|
*/
|
|
2144
|
-
var bindReplModules = (store) => {
|
|
2148
|
+
var bindReplModules = (store, getImportMap = store.getImportMap.bind(store), resolve = createCdnResolver()) => {
|
|
2145
2149
|
watch(() => Object.values(store.files).map((file) => [
|
|
2146
2150
|
file.filename,
|
|
2147
2151
|
file.code,
|
|
@@ -2149,7 +2153,7 @@ var bindReplModules = (store) => {
|
|
|
2149
2153
|
file.compiled.ssr
|
|
2150
2154
|
]), () => {
|
|
2151
2155
|
const files = createFileIndex(Object.fromEntries(Object.entries(store.files).map(([name, file]) => [name, file.code])));
|
|
2152
|
-
const importMap =
|
|
2156
|
+
const importMap = getImportMap();
|
|
2153
2157
|
const imports = { ...importMap.imports };
|
|
2154
2158
|
let importsChanged = false;
|
|
2155
2159
|
for (const file of Object.values(store.files)) for (const output of ["js", "ssr"]) {
|
|
@@ -2169,7 +2173,11 @@ var bindReplModules = (store) => {
|
|
|
2169
2173
|
const target = `./${resolved.replace(/^\/?src\//, "")}`;
|
|
2170
2174
|
const text = item.type === "dynamic" ? JSON.stringify(target) : target;
|
|
2171
2175
|
code = code.slice(0, item.start) + text + code.slice(item.end);
|
|
2172
|
-
} else if (
|
|
2176
|
+
} else if (/^https?:\/\//.test(specifier)) {
|
|
2177
|
+
const target = resolve(specifier);
|
|
2178
|
+
const text = item.type === "dynamic" ? JSON.stringify(target) : target;
|
|
2179
|
+
code = code.slice(0, item.start) + text + code.slice(item.end);
|
|
2180
|
+
} else if (!imports[specifier]) {
|
|
2173
2181
|
imports[specifier] = resolveNpmImport(specifier);
|
|
2174
2182
|
importsChanged = true;
|
|
2175
2183
|
}
|
|
@@ -2206,13 +2214,14 @@ var escapeHtmlAttr = (value) => value.replace(/&/gu, "&").replace(/"/gu, "&q
|
|
|
2206
2214
|
* `--vc-background-color-lightest` 不同,否则会出现色带割裂。
|
|
2207
2215
|
*/
|
|
2208
2216
|
var PLAYGROUND_RUNTIME_CANVAS_BACKGROUND = "var(--vc-background-color-lightest, var(--docs-background-color, #fff))";
|
|
2209
|
-
var createRuntimePreviewOptions = (cdnURL
|
|
2217
|
+
var createRuntimePreviewOptions = (cdnURL, options = {}) => {
|
|
2210
2218
|
const previewScroller = options.previewScroller === true;
|
|
2219
|
+
const resolve = createCdnResolver(cdnURL);
|
|
2211
2220
|
const hrefs = Object.values({
|
|
2212
2221
|
...createBuiltinStyles(cdnURL),
|
|
2213
2222
|
...getPlaygroundSiteStyles(),
|
|
2214
2223
|
...getPlaygroundStyleOverrides()
|
|
2215
|
-
});
|
|
2224
|
+
}).map(resolve);
|
|
2216
2225
|
const styleBlocks = [
|
|
2217
2226
|
`html,body{height:auto;min-height:0;background:${PLAYGROUND_RUNTIME_CANVAS_BACKGROUND}}`,
|
|
2218
2227
|
"body{color:var(--vc-foreground-color,#080f20)}",
|
|
@@ -2256,7 +2265,7 @@ var createRuntimeImportOverrides = (builtinImportMap) => ({
|
|
|
2256
2265
|
* @param cdnURL
|
|
2257
2266
|
* @param builtinImportMap
|
|
2258
2267
|
*/
|
|
2259
|
-
var createRuntimeImports = (cdnURL
|
|
2268
|
+
var createRuntimeImports = (cdnURL, builtinImportMap) => ({
|
|
2260
2269
|
...createBuiltinImports(cdnURL),
|
|
2261
2270
|
...createRuntimeImportOverrides(builtinImportMap)
|
|
2262
2271
|
});
|
|
@@ -2270,8 +2279,14 @@ var createRuntimeStore = (files, entry, options) => {
|
|
|
2270
2279
|
const mainFile = ref(toReplFilename(entry));
|
|
2271
2280
|
const activeFilename = ref(toReplFilename(entry));
|
|
2272
2281
|
const imports = createRuntimeImports(cdnURL, builtinImportMap);
|
|
2282
|
+
const resolve = createCdnResolver(cdnURL);
|
|
2283
|
+
const resourceLinks = unref(storeOptions.resourceLinks);
|
|
2273
2284
|
const store = useStore({
|
|
2274
2285
|
...storeOptions,
|
|
2286
|
+
resourceLinks: ref({
|
|
2287
|
+
...resourceLinks,
|
|
2288
|
+
esModuleShims: resolve(resourceLinks?.esModuleShims || "https://cdn.jsdelivr.net/npm/es-module-shims@1.5.18/dist/es-module-shims.wasm.js?raw")
|
|
2289
|
+
}),
|
|
2275
2290
|
files: replFiles,
|
|
2276
2291
|
mainFile,
|
|
2277
2292
|
activeFilename,
|
|
@@ -2290,7 +2305,17 @@ var createRuntimeStore = (files, entry, options) => {
|
|
|
2290
2305
|
"import-map.json": store.files["import-map.json"].code,
|
|
2291
2306
|
...nextFiles
|
|
2292
2307
|
}, nextEntry);
|
|
2293
|
-
|
|
2308
|
+
const getImportMap = store.getImportMap.bind(store);
|
|
2309
|
+
bindReplModules(store, getImportMap, resolve);
|
|
2310
|
+
store.getImportMap = () => {
|
|
2311
|
+
const map = getImportMap();
|
|
2312
|
+
const convert = (items = {}) => Object.fromEntries(Object.entries(items).filter((item) => typeof item[1] === "string").map(([id, url]) => [id, resolve(url)]));
|
|
2313
|
+
return {
|
|
2314
|
+
...map,
|
|
2315
|
+
imports: convert(map.imports),
|
|
2316
|
+
scopes: map.scopes && Object.fromEntries(Object.entries(map.scopes).map(([scope, items]) => [resolve(scope), convert(items)]))
|
|
2317
|
+
};
|
|
2318
|
+
};
|
|
2294
2319
|
whenSassReady(files, () => {
|
|
2295
2320
|
const specifiers = collectBareSpecifiers(files, Object.keys(files));
|
|
2296
2321
|
if (!specifiers.length) {
|
|
@@ -2298,8 +2323,12 @@ var createRuntimeStore = (files, entry, options) => {
|
|
|
2298
2323
|
return;
|
|
2299
2324
|
}
|
|
2300
2325
|
store.loading = true;
|
|
2301
|
-
|
|
2302
|
-
|
|
2326
|
+
const currentImports = {
|
|
2327
|
+
...imports,
|
|
2328
|
+
...filterSafeHrefs(getImportMap().imports)
|
|
2329
|
+
};
|
|
2330
|
+
resolveReplImports(currentImports, specifiers, resolve).then((resolved) => {
|
|
2331
|
+
if (Object.keys(resolved).length !== Object.keys(currentImports).length) store.setImportMap({ imports: resolved }, true);
|
|
2303
2332
|
store.init();
|
|
2304
2333
|
}).catch((error) => {
|
|
2305
2334
|
store.errors.push(error);
|
|
@@ -3053,6 +3082,43 @@ var linkPlayground = (compiled, files, options = {}) => {
|
|
|
3053
3082
|
//#region packages/playground/src/core/runtime/local/remote.ts
|
|
3054
3083
|
var HOST_VUE = /* @__PURE__ */ new Set(["vue", "vue/server-renderer"]);
|
|
3055
3084
|
var moduleUrl = (url) => new URL(url, globalThis.location?.href).href;
|
|
3085
|
+
var REMOTE_SOURCE_CACHE_LIMIT = 128;
|
|
3086
|
+
var sourceCache = /* @__PURE__ */ new Map();
|
|
3087
|
+
var prepareRemoteSource = async (url) => {
|
|
3088
|
+
const response = await fetch(url);
|
|
3089
|
+
if (!response.ok) throw new Error(`${response.status} ${url}`);
|
|
3090
|
+
const text = await response.text();
|
|
3091
|
+
await init();
|
|
3092
|
+
const [specifiers] = parse(text);
|
|
3093
|
+
let source = text;
|
|
3094
|
+
for (const item of [...specifiers].reverse()) if (item.type === "dynamic") source = source.slice(0, item.importStart) + "__import" + source.slice(item.importStart + 6);
|
|
3095
|
+
const cjs = transform(rewriteImportMeta(source, url), {
|
|
3096
|
+
transforms: ["imports"],
|
|
3097
|
+
disableESTransforms: true,
|
|
3098
|
+
production: true,
|
|
3099
|
+
filePath: url
|
|
3100
|
+
}).code;
|
|
3101
|
+
return {
|
|
3102
|
+
dependencies: specifiers.filter((item) => item.type === "static" || item.type === "reexport-star").map((item) => item.specifier),
|
|
3103
|
+
run: new Function("require", "module", "exports", "__import", cjs)
|
|
3104
|
+
};
|
|
3105
|
+
};
|
|
3106
|
+
var readRemoteSource = (url) => {
|
|
3107
|
+
if (new URL(url).origin === globalThis.location?.origin) return prepareRemoteSource(url);
|
|
3108
|
+
const cached = sourceCache.get(url);
|
|
3109
|
+
if (cached) {
|
|
3110
|
+
sourceCache.delete(url);
|
|
3111
|
+
sourceCache.set(url, cached);
|
|
3112
|
+
return cached;
|
|
3113
|
+
}
|
|
3114
|
+
const task = prepareRemoteSource(url).catch((error) => {
|
|
3115
|
+
if (sourceCache.get(url) === task) sourceCache.delete(url);
|
|
3116
|
+
throw error;
|
|
3117
|
+
});
|
|
3118
|
+
sourceCache.set(url, task);
|
|
3119
|
+
if (sourceCache.size > REMOTE_SOURCE_CACHE_LIMIT) sourceCache.delete(sourceCache.keys().next().value);
|
|
3120
|
+
return task;
|
|
3121
|
+
};
|
|
3056
3122
|
/**
|
|
3057
3123
|
* 把 CDN 上的 ESM 先拉完整张依赖图,再在当前页面里执行。
|
|
3058
3124
|
* 裸导入优先走 import map,缺失的 npm 依赖回退到 CDN ESM;import() 按需加载。
|
|
@@ -3060,20 +3126,23 @@ var moduleUrl = (url) => new URL(url, globalThis.location?.href).href;
|
|
|
3060
3126
|
* @param builtins 宿主 Vue 与 vue-router。
|
|
3061
3127
|
* @param overrides 显式配置的模块名,与自动补齐的默认地址区分。
|
|
3062
3128
|
* @param importModule 浏览器原生 ESM 加载器。
|
|
3129
|
+
* @param cdnURL 没有 launch 选点结果时使用的实例 CDN。
|
|
3063
3130
|
* @returns 按 URL 加载并执行远程模块的加载器。
|
|
3064
3131
|
*/
|
|
3065
3132
|
var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imports)), importModule = (url) => import(
|
|
3066
3133
|
/* @vite-ignore */
|
|
3067
3134
|
url
|
|
3068
|
-
)) => {
|
|
3135
|
+
), cdnURL) => {
|
|
3136
|
+
const resolve = createCdnResolver(cdnURL);
|
|
3137
|
+
const resolveUrl = (url) => resolve(moduleUrl(url));
|
|
3069
3138
|
const hostModules = {
|
|
3070
3139
|
"vue": builtins.vue,
|
|
3071
3140
|
"vue-router": builtins.vueRouter
|
|
3072
3141
|
};
|
|
3073
3142
|
const pendingBuiltins = /* @__PURE__ */ new Set();
|
|
3074
|
-
const
|
|
3143
|
+
const sources = /* @__PURE__ */ new Map();
|
|
3144
|
+
const pendingSources = /* @__PURE__ */ new Map();
|
|
3075
3145
|
const evaluated = /* @__PURE__ */ new Map();
|
|
3076
|
-
const crawled = /* @__PURE__ */ new Set();
|
|
3077
3146
|
const nativeModules = /* @__PURE__ */ new Map();
|
|
3078
3147
|
const loadNative = (url) => {
|
|
3079
3148
|
let pending = nativeModules.get(url);
|
|
@@ -3102,16 +3171,16 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3102
3171
|
const dependencySpecifier = (from, specifier) => {
|
|
3103
3172
|
if (isRelativeSpecifier(specifier) || /^https?:\/\//.test(specifier)) {
|
|
3104
3173
|
const url = new URL(specifier, from);
|
|
3105
|
-
const
|
|
3106
|
-
if (
|
|
3174
|
+
const name = cdnModuleName(url.href);
|
|
3175
|
+
if (name && (imports[name] || localBuiltinIds.has(name))) return name;
|
|
3107
3176
|
return url.href;
|
|
3108
3177
|
}
|
|
3109
3178
|
return specifier;
|
|
3110
3179
|
};
|
|
3111
3180
|
const dependencyUrl = (from, id) => {
|
|
3112
3181
|
const specifier = dependencySpecifier(from, id);
|
|
3113
|
-
if (/^https?:\/\//.test(specifier)) return specifier;
|
|
3114
|
-
if (imports[specifier] && !prefersLocalBuiltin(specifier, imports, overrides)) return
|
|
3182
|
+
if (/^https?:\/\//.test(specifier)) return resolveUrl(specifier);
|
|
3183
|
+
if (imports[specifier] && !prefersLocalBuiltin(specifier, imports, overrides)) return resolveUrl(imports[specifier]);
|
|
3115
3184
|
if (HOST_VUE.has(specifier) && prefersLocalBuiltin(specifier, imports, overrides)) return null;
|
|
3116
3185
|
let cursor = specifier;
|
|
3117
3186
|
while (cursor) {
|
|
@@ -3126,29 +3195,27 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3126
3195
|
const target = imports[specifier] ? specifier : resolveImportTarget(specifier, imports);
|
|
3127
3196
|
if (!target) {
|
|
3128
3197
|
imports[specifier] = resolveNpmImport(specifier);
|
|
3129
|
-
return imports[specifier];
|
|
3198
|
+
return resolveUrl(imports[specifier]);
|
|
3130
3199
|
}
|
|
3131
|
-
return
|
|
3200
|
+
return resolveUrl(imports[target]);
|
|
3132
3201
|
};
|
|
3133
|
-
const crawl = async (url) => {
|
|
3134
|
-
if (!overrides.size &&
|
|
3202
|
+
const crawl = async (url, visited = /* @__PURE__ */ new Set()) => {
|
|
3203
|
+
if (!overrides.size && isCdnEsmURL(url)) {
|
|
3135
3204
|
await loadNative(url);
|
|
3136
3205
|
return;
|
|
3137
3206
|
}
|
|
3138
|
-
if (
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
if (!
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
if (
|
|
3150
|
-
const next = dependencyUrl(url, item.specifier);
|
|
3151
|
-
if (next) await crawl(next);
|
|
3207
|
+
if (visited.has(url)) return;
|
|
3208
|
+
visited.add(url);
|
|
3209
|
+
let pending = pendingSources.get(url);
|
|
3210
|
+
if (!pending) {
|
|
3211
|
+
pending = readRemoteSource(url);
|
|
3212
|
+
pendingSources.set(url, pending);
|
|
3213
|
+
}
|
|
3214
|
+
const source = await pending;
|
|
3215
|
+
sources.set(url, source);
|
|
3216
|
+
await Promise.all(source.dependencies.map(async (specifier) => {
|
|
3217
|
+
const next = dependencyUrl(url, specifier);
|
|
3218
|
+
if (next) await crawl(next, visited);
|
|
3152
3219
|
}));
|
|
3153
3220
|
};
|
|
3154
3221
|
const requireFrom = (from) => (specifier) => {
|
|
@@ -3159,7 +3226,7 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3159
3226
|
if (isRelativeSpecifier(id) || /^https?:\/\//.test(id)) return evaluate(dependencyUrl(from, id));
|
|
3160
3227
|
const target = imports[id] ? id : resolveImportTarget(id, imports);
|
|
3161
3228
|
if (!target || !imports[target]) throw new Error(`[Playground] 未注册的模块 "${id}"`);
|
|
3162
|
-
const loaded = evaluate(
|
|
3229
|
+
const loaded = evaluate(resolveUrl(imports[target]));
|
|
3163
3230
|
if (target === id) return loaded;
|
|
3164
3231
|
if (!resolveHostModule(id, { [target]: loaded }))
|
|
3165
3232
|
/* istanbul ignore next -- 父包没有对应导出时才拒绝 */
|
|
@@ -3168,17 +3235,12 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3168
3235
|
};
|
|
3169
3236
|
const evaluate = (url) => {
|
|
3170
3237
|
if (evaluated.has(url)) return evaluated.get(url);
|
|
3171
|
-
const
|
|
3172
|
-
if (
|
|
3173
|
-
const cjs = transform(rewriteImportMeta(text, url), {
|
|
3174
|
-
transforms: ["imports"],
|
|
3175
|
-
disableESTransforms: true,
|
|
3176
|
-
production: true,
|
|
3177
|
-
filePath: url
|
|
3178
|
-
}).code;
|
|
3238
|
+
const source = sources.get(url);
|
|
3239
|
+
if (!source) throw new Error(`[Playground] 远程模块尚未下载: ${url}`);
|
|
3179
3240
|
const module = { exports: {} };
|
|
3180
3241
|
evaluated.set(url, module.exports);
|
|
3181
|
-
|
|
3242
|
+
const runner = source.run;
|
|
3243
|
+
runner(requireFrom(url), module, module.exports, async (id) => {
|
|
3182
3244
|
const next = dependencyUrl(url, id);
|
|
3183
3245
|
if (next) await load(next);
|
|
3184
3246
|
else {
|
|
@@ -3192,7 +3254,7 @@ var createRemoteLoader = (imports, builtins, overrides = new Set(Object.keys(imp
|
|
|
3192
3254
|
};
|
|
3193
3255
|
const loading = /* @__PURE__ */ new Map();
|
|
3194
3256
|
const load = (sourceUrl) => {
|
|
3195
|
-
const url =
|
|
3257
|
+
const url = resolveUrl(sourceUrl);
|
|
3196
3258
|
const pending = loading.get(url);
|
|
3197
3259
|
if (pending) return pending;
|
|
3198
3260
|
const task = (async () => {
|
|
@@ -3352,7 +3414,7 @@ var local_sandbox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
3352
3414
|
publishError();
|
|
3353
3415
|
destroyPreview();
|
|
3354
3416
|
try {
|
|
3355
|
-
const { compilePlayground } = await import("./compile-
|
|
3417
|
+
const { compilePlayground } = await import("./compile-BHlM2G35.js");
|
|
3356
3418
|
/* istanbul ignore if -- 并发编译时只保留最后一次 */
|
|
3357
3419
|
if (current !== version) return;
|
|
3358
3420
|
const compiled = await compilePlayground(props.files, { entry: props.entry });
|
|
@@ -3371,7 +3433,7 @@ var local_sandbox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
3371
3433
|
const remote = createRemoteLoader(imports, {
|
|
3372
3434
|
vue: Vue,
|
|
3373
3435
|
vueRouter: VueRouter
|
|
3374
|
-
}, overrides);
|
|
3436
|
+
}, overrides, void 0, props.options.cdnURL);
|
|
3375
3437
|
const loaded = await loadLocalModules(specifiers, imports, {
|
|
3376
3438
|
vue: Vue,
|
|
3377
3439
|
vueRouter: VueRouter
|
|
@@ -4221,4 +4283,4 @@ var playground_default = /* @__PURE__ */ defineComponent({
|
|
|
4221
4283
|
}
|
|
4222
4284
|
});
|
|
4223
4285
|
//#endregion
|
|
4224
|
-
export { code_preview_default as CodePreview, DEFAULT_CDN_URL, Editor, PREVIEW_SCROLLER_USE_CODE, PREVIEW_SCROLL_CONTENT_CLASS, PREVIEW_SCROLL_HTML_CLASS, playground_default as Playground, PlaygroundService, applyPlaygroundImportMapOverride, applyPlaygroundStyleOverride, clearPlaygroundMaps, createBuiltinImports, createBuiltinStyles, createRuntimePreviewOptions, getPlaygroundImportMapOverrides, getPlaygroundSiteModules, getPlaygroundSiteStyles, getPlaygroundStyleOverrides, highlightCode, highlightCodeByLanguage, isSafePlaygroundHref, normalizeCdnURL, registerVueHighlight, removePlaygroundImportMapOverride, removePlaygroundStyleOverride, resolveHighlightLanguage, resolvePlaygroundTitleId, setPlaygroundImportMapOverrides, setPlaygroundSiteModules, setPlaygroundSiteStyles, setPlaygroundStyleOverrides, slugifyPlaygroundTitle, vueHighlight };
|
|
4286
|
+
export { code_preview_default as CodePreview, DEFAULT_CDN_URL, Editor, PREVIEW_SCROLLER_USE_CODE, PREVIEW_SCROLL_CONTENT_CLASS, PREVIEW_SCROLL_HTML_CLASS, playground_default as Playground, PlaygroundService, applyPlaygroundImportMapOverride, applyPlaygroundStyleOverride, clearPlaygroundMaps, createBuiltinImports, createBuiltinStyles, createRuntimePreviewOptions, getPlaygroundImportMapOverrides, getPlaygroundSiteModules, getPlaygroundSiteStyles, getPlaygroundStyleOverrides, highlightCode, highlightCodeByLanguage, isSafePlaygroundHref, normalizeCdnURL, registerVueHighlight, removePlaygroundImportMapOverride, removePlaygroundStyleOverride, resolveCdnURL, resolveHighlightLanguage, resolvePlaygroundTitleId, setPlaygroundImportMapOverrides, setPlaygroundSiteModules, setPlaygroundSiteStyles, setPlaygroundStyleOverrides, slugifyPlaygroundTitle, vueHighlight };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deot/docs-playground",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@deot/docs-locale": "^1.1.
|
|
22
|
-
"@deot/docs-theme": "^1.1.
|
|
21
|
+
"@deot/docs-locale": "^1.1.5",
|
|
22
|
+
"@deot/docs-theme": "^1.1.5",
|
|
23
23
|
"@deot/helper": "^1.1.21",
|
|
24
24
|
"@deot/http": "^1.1.10",
|
|
25
25
|
"@deot/vc": "^1.2.3",
|