From e339cba62b3b72e72788a43904ba87959b72969e Mon Sep 17 00:00:00 2001 From: sunlei Date: Sat, 16 May 2026 10:55:46 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20Playground=20CDN=20?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/import-map.ts | 22 +++++++++++++--------- src/monaco/env.ts | 24 ++++++++++++++---------- src/monaco/resource.ts | 25 ++++++++++++++++++++++--- src/output/Sandbox.vue | 2 +- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/import-map.ts b/src/import-map.ts index 5a14db6..fd3a17f 100644 --- a/src/import-map.ts +++ b/src/import-map.ts @@ -10,18 +10,22 @@ export function isVaporSupported(version: string): boolean{ return major > 3 || (major === 3 && minor >= 6) } +const esmBundle = (pkgName: string, externalVue = false) => + `https://esm.sh/${pkgName}?bundle${externalVue ? '&external=vue' : ''}` + +// The preview iframe imports these packages on every run. Prefer bundled CDN +// entries to avoid hundreds of tiny ESM/icon requests exhausting the browser. export const builtinLibraryImports: Record = { - echarts: 'https://esm.sh/echarts@latest', + echarts: esmBundle('echarts@latest'), 'echarts/': 'https://esm.sh/echarts@latest/', - 'ant-design-vue': 'https://esm.sh/ant-design-vue@latest?external=vue', - 'ant-design-vue/': 'https://esm.sh/ant-design-vue@latest/', - '@ant-design/icons-vue': - 'https://esm.sh/@ant-design/icons-vue@latest?external=vue', - '@ant-design/icons-vue/': 'https://esm.sh/@ant-design/icons-vue@latest/', - 'element-plus': 'https://esm.sh/element-plus@latest?external=vue', + 'ant-design-vue': + 'https://cdn.jsdelivr.net/npm/ant-design-vue@4.2.6/dist/antd.esm.min.js', + 'ant-design-vue/': 'https://esm.sh/ant-design-vue@4.2.6/', + '@ant-design/icons-vue': esmBundle('@ant-design/icons-vue@7.0.1', true), + '@ant-design/icons-vue/': 'https://esm.sh/@ant-design/icons-vue@7.0.1/', + 'element-plus': esmBundle('element-plus@latest', true), 'element-plus/': 'https://esm.sh/element-plus@latest/', - '@element-plus/icons-vue': - 'https://esm.sh/@element-plus/icons-vue@latest?external=vue', + '@element-plus/icons-vue': esmBundle('@element-plus/icons-vue@latest', true), '@element-plus/icons-vue/': 'https://esm.sh/@element-plus/icons-vue@latest/', } diff --git a/src/monaco/env.ts b/src/monaco/env.ts index 2fc0263..57e983e 100644 --- a/src/monaco/env.ts +++ b/src/monaco/env.ts @@ -56,18 +56,22 @@ export async function reloadLanguageTools(store: Store) { ...store.dependencyVersion, } - if (store.vueVersion) { + const vueDependencyVersion = store.vueVersion || store.compiler?.version + + if (vueDependencyVersion) { + // Monaco's virtual node_modules needs a concrete Vue version; falling back + // to "latest" adds an extra CDN metadata request in production. dependencies = { ...dependencies, - vue: store.vueVersion, - '@vue/compiler-core': store.vueVersion, - '@vue/compiler-dom': store.vueVersion, - '@vue/compiler-sfc': store.vueVersion, - '@vue/compiler-ssr': store.vueVersion, - '@vue/reactivity': store.vueVersion, - '@vue/runtime-core': store.vueVersion, - '@vue/runtime-dom': store.vueVersion, - '@vue/shared': store.vueVersion, + vue: vueDependencyVersion, + '@vue/compiler-core': vueDependencyVersion, + '@vue/compiler-dom': vueDependencyVersion, + '@vue/compiler-sfc': vueDependencyVersion, + '@vue/compiler-ssr': vueDependencyVersion, + '@vue/reactivity': vueDependencyVersion, + '@vue/runtime-core': vueDependencyVersion, + '@vue/runtime-dom': vueDependencyVersion, + '@vue/shared': vueDependencyVersion, } } diff --git a/src/monaco/resource.ts b/src/monaco/resource.ts index fc6d053..2db2e95 100644 --- a/src/monaco/resource.ts +++ b/src/monaco/resource.ts @@ -8,6 +8,23 @@ import type { URI } from 'vscode-uri' const textCache = new Map>() const jsonCache = new Map>() +function trimUrlPath(path: string) { + return path.replace(/^\/+|\/+$/g, '') +} + +function getUnpkgPackageUrl( + pkgName: string, + pkgVersion: string | undefined, + pkgPath = '', +) { + const versionedPackage = `${pkgName}@${pkgVersion || 'latest'}` + const normalizedPath = trimUrlPath(pkgPath) + + return normalizedPath + ? `https://unpkg.com/${versionedPackage}/${normalizedPath}` + : `https://unpkg.com/${versionedPackage}` +} + export type CreateNpmFileSystemOptions = { getPackageLatestVersionUrl?: (pkgName: string) => string getPackageDirectoryUrl?: ( @@ -24,11 +41,13 @@ export type CreateNpmFileSystemOptions = { const defaultUnpkgOptions: Required = { getPackageLatestVersionUrl: (pkgName) => - `https://unpkg.com/${pkgName}@latest/package.json`, + getUnpkgPackageUrl(pkgName, 'latest', 'package.json'), getPackageDirectoryUrl: (pkgName, pkgVersion, pkgPath) => - `https://unpkg.com/${pkgName}@${pkgVersion}/${pkgPath}/?meta`, + // Root package lookups must be `pkg@version/?meta`; `pkg@version//?meta` + // can be handled as a different URL by the CDN and lose CORS headers. + `${getUnpkgPackageUrl(pkgName, pkgVersion, pkgPath)}/?meta`, getPackageFileTextUrl: (pkgName, pkgVersion, pkgPath) => - `https://unpkg.com/${pkgName}@${pkgVersion || 'latest'}/${pkgPath}`, + getUnpkgPackageUrl(pkgName, pkgVersion, pkgPath), } export function createNpmFileSystem( diff --git a/src/output/Sandbox.vue b/src/output/Sandbox.vue index 7374e4a..5aa0ff0 100644 --- a/src/output/Sandbox.vue +++ b/src/output/Sandbox.vue @@ -63,7 +63,7 @@ let proxy: PreviewProxy let stopUpdateWatcher: WatchStopHandle | undefined const builtinLibraryHeadHTML = ` - + `