fix: 修复 Playground CDN 资源加载

This commit is contained in:
sunlei 2026-05-16 10:55:46 +08:00
parent 16ffee28dd
commit e339cba62b
4 changed files with 50 additions and 23 deletions

View File

@ -10,18 +10,22 @@ export function isVaporSupported(version: string): boolean{
return major > 3 || (major === 3 && minor >= 6) 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<string, string> = { export const builtinLibraryImports: Record<string, string> = {
echarts: 'https://esm.sh/echarts@latest', echarts: esmBundle('echarts@latest'),
'echarts/': 'https://esm.sh/echarts@latest/', 'echarts/': 'https://esm.sh/echarts@latest/',
'ant-design-vue': 'https://esm.sh/ant-design-vue@latest?external=vue', 'ant-design-vue':
'ant-design-vue/': 'https://esm.sh/ant-design-vue@latest/', 'https://cdn.jsdelivr.net/npm/ant-design-vue@4.2.6/dist/antd.esm.min.js',
'@ant-design/icons-vue': 'ant-design-vue/': 'https://esm.sh/ant-design-vue@4.2.6/',
'https://esm.sh/@ant-design/icons-vue@latest?external=vue', '@ant-design/icons-vue': esmBundle('@ant-design/icons-vue@7.0.1', true),
'@ant-design/icons-vue/': 'https://esm.sh/@ant-design/icons-vue@latest/', '@ant-design/icons-vue/': 'https://esm.sh/@ant-design/icons-vue@7.0.1/',
'element-plus': 'https://esm.sh/element-plus@latest?external=vue', 'element-plus': esmBundle('element-plus@latest', true),
'element-plus/': 'https://esm.sh/element-plus@latest/', 'element-plus/': 'https://esm.sh/element-plus@latest/',
'@element-plus/icons-vue': '@element-plus/icons-vue': esmBundle('@element-plus/icons-vue@latest', true),
'https://esm.sh/@element-plus/icons-vue@latest?external=vue',
'@element-plus/icons-vue/': '@element-plus/icons-vue/':
'https://esm.sh/@element-plus/icons-vue@latest/', 'https://esm.sh/@element-plus/icons-vue@latest/',
} }

View File

@ -56,18 +56,22 @@ export async function reloadLanguageTools(store: Store) {
...store.dependencyVersion, ...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 = {
...dependencies, ...dependencies,
vue: store.vueVersion, vue: vueDependencyVersion,
'@vue/compiler-core': store.vueVersion, '@vue/compiler-core': vueDependencyVersion,
'@vue/compiler-dom': store.vueVersion, '@vue/compiler-dom': vueDependencyVersion,
'@vue/compiler-sfc': store.vueVersion, '@vue/compiler-sfc': vueDependencyVersion,
'@vue/compiler-ssr': store.vueVersion, '@vue/compiler-ssr': vueDependencyVersion,
'@vue/reactivity': store.vueVersion, '@vue/reactivity': vueDependencyVersion,
'@vue/runtime-core': store.vueVersion, '@vue/runtime-core': vueDependencyVersion,
'@vue/runtime-dom': store.vueVersion, '@vue/runtime-dom': vueDependencyVersion,
'@vue/shared': store.vueVersion, '@vue/shared': vueDependencyVersion,
} }
} }

View File

@ -8,6 +8,23 @@ import type { URI } from 'vscode-uri'
const textCache = new Map<string, Promise<string | undefined>>() const textCache = new Map<string, Promise<string | undefined>>()
const jsonCache = new Map<string, Promise<any>>() const jsonCache = new Map<string, Promise<any>>()
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 = { export type CreateNpmFileSystemOptions = {
getPackageLatestVersionUrl?: (pkgName: string) => string getPackageLatestVersionUrl?: (pkgName: string) => string
getPackageDirectoryUrl?: ( getPackageDirectoryUrl?: (
@ -24,11 +41,13 @@ export type CreateNpmFileSystemOptions = {
const defaultUnpkgOptions: Required<CreateNpmFileSystemOptions> = { const defaultUnpkgOptions: Required<CreateNpmFileSystemOptions> = {
getPackageLatestVersionUrl: (pkgName) => getPackageLatestVersionUrl: (pkgName) =>
`https://unpkg.com/${pkgName}@latest/package.json`, getUnpkgPackageUrl(pkgName, 'latest', 'package.json'),
getPackageDirectoryUrl: (pkgName, pkgVersion, pkgPath) => 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) => getPackageFileTextUrl: (pkgName, pkgVersion, pkgPath) =>
`https://unpkg.com/${pkgName}@${pkgVersion || 'latest'}/${pkgPath}`, getUnpkgPackageUrl(pkgName, pkgVersion, pkgPath),
} }
export function createNpmFileSystem( export function createNpmFileSystem(

View File

@ -63,7 +63,7 @@ let proxy: PreviewProxy
let stopUpdateWatcher: WatchStopHandle | undefined let stopUpdateWatcher: WatchStopHandle | undefined
const builtinLibraryHeadHTML = ` const builtinLibraryHeadHTML = `
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ant-design-vue@latest/dist/reset.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ant-design-vue@4.2.6/dist/reset.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@latest/dist/index.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@latest/dist/index.css">
` `