From 3ac8aa248c4b4ad74401a1106be0322d18e2b26a Mon Sep 17 00:00:00 2001 From: filtered <176114999+webfiltered@users.noreply.github.com> Date: Mon, 2 Jun 2025 09:57:47 +1000 Subject: [PATCH] Revert "Export vue new (#3966)" (#4050) --- build/plugins/addElementVnodeExportPlugin.ts | 59 ++++++++++ build/plugins/generateImportMapPlugin.ts | 111 +++++-------------- build/plugins/index.ts | 1 + vite.config.mts | 43 ++----- 4 files changed, 99 insertions(+), 115 deletions(-) create mode 100644 build/plugins/addElementVnodeExportPlugin.ts diff --git a/build/plugins/addElementVnodeExportPlugin.ts b/build/plugins/addElementVnodeExportPlugin.ts new file mode 100644 index 000000000..1266d13e2 --- /dev/null +++ b/build/plugins/addElementVnodeExportPlugin.ts @@ -0,0 +1,59 @@ +import { Plugin } from 'vite' + +/** + * Vite plugin that adds an alias export for Vue's createBaseVNode as createElementVNode. + * + * This plugin addresses compatibility issues where some components or libraries + * might be using the older createElementVNode function name instead of createBaseVNode. + * It modifies the Vue vendor chunk during build to add the alias export. + * + * @returns {Plugin} A Vite plugin that modifies the Vue vendor chunk exports + */ +export function addElementVnodeExportPlugin(): Plugin { + return { + name: 'add-element-vnode-export-plugin', + + renderChunk(code, chunk, _options) { + if (chunk.name.startsWith('vendor-vue')) { + const exportRegex = /(export\s*\{)([^}]*)(\}\s*;?\s*)$/ + const match = code.match(exportRegex) + + if (match) { + const existingExports = match[2].trim() + const exportsArray = existingExports + .split(',') + .map((e) => e.trim()) + .filter(Boolean) + + const hasCreateBaseVNode = exportsArray.some((e) => + e.startsWith('createBaseVNode') + ) + const hasCreateElementVNode = exportsArray.some((e) => + e.includes('createElementVNode') + ) + + if (hasCreateBaseVNode && !hasCreateElementVNode) { + const newExportStatement = `${match[1]} ${existingExports ? existingExports + ',' : ''} createBaseVNode as createElementVNode ${match[3]}` + const newCode = code.replace(exportRegex, newExportStatement) + + console.log( + `[add-element-vnode-export-plugin] Added 'createBaseVNode as createElementVNode' export to vendor-vue chunk.` + ) + + return { code: newCode, map: null } + } else if (!hasCreateBaseVNode) { + console.warn( + `[add-element-vnode-export-plugin] Warning: 'createBaseVNode' not found in exports of vendor-vue chunk. Cannot add alias.` + ) + } + } else { + console.warn( + `[add-element-vnode-export-plugin] Warning: Could not find expected export block format in vendor-vue chunk.` + ) + } + } + + return null + } + } +} diff --git a/build/plugins/generateImportMapPlugin.ts b/build/plugins/generateImportMapPlugin.ts index 80ccb6c9f..c6661a811 100644 --- a/build/plugins/generateImportMapPlugin.ts +++ b/build/plugins/generateImportMapPlugin.ts @@ -1,24 +1,9 @@ -import glob from 'fast-glob' -import fs from 'fs-extra' -import { dirname, join } from 'node:path' -import { HtmlTagDescriptor, Plugin, normalizePath } from 'vite' +import type { OutputOptions } from 'rollup' +import { HtmlTagDescriptor, Plugin } from 'vite' -interface ImportMapSource { +interface VendorLibrary { name: string - pattern: string | RegExp - entry: string - recursiveDependence?: boolean - override?: Record> -} - -const parseDeps = (root: string, pkg: string) => { - const pkgPath = join(root, 'node_modules', pkg, 'package.json') - if (fs.existsSync(pkgPath)) { - const content = fs.readFileSync(pkgPath, 'utf-8') - const pkg = JSON.parse(content) - return Object.keys(pkg.dependencies || {}) - } - return [] + pattern: RegExp } /** @@ -38,89 +23,53 @@ const parseDeps = (root: string, pkg: string) => { * @returns {Plugin} A Vite plugin that generates and injects an import map */ export function generateImportMapPlugin( - importMapSources: ImportMapSource[] + vendorLibraries: VendorLibrary[] ): Plugin { const importMapEntries: Record = {} - const resolvedImportMapSources: Map = new Map() - const assetDir = 'assets/lib' - let root: string return { name: 'generate-import-map-plugin', // Configure manual chunks during the build process configResolved(config) { - root = config.root - if (config.build) { // Ensure rollupOptions exists if (!config.build.rollupOptions) { config.build.rollupOptions = {} } - for (const source of importMapSources) { - resolvedImportMapSources.set(source.name, source) - if (source.recursiveDependence) { - const deps = parseDeps(root, source.name) - - while (deps.length) { - const dep = deps.shift()! - const depSource = Object.assign({}, source, { - name: dep, - pattern: dep, - ...source.override?.[dep] - }) - resolvedImportMapSources.set(depSource.name, depSource) - - const _deps = parseDeps(root, depSource.name) - deps.unshift(..._deps) + const outputOptions: OutputOptions = { + manualChunks: (id: string) => { + for (const lib of vendorLibraries) { + if (lib.pattern.test(id)) { + return `vendor-${lib.name}` + } } - } + return null + }, + // Disable minification of internal exports to preserve function names + minifyInternalExports: false } - - const external: (string | RegExp)[] = [] - for (const [, source] of resolvedImportMapSources) { - external.push(source.pattern) - } - config.build.rollupOptions.external = external + config.build.rollupOptions.output = outputOptions } }, - generateBundle(_options) { - for (const [, source] of resolvedImportMapSources) { - if (source.entry) { - const moduleFile = join(source.name, source.entry) - const sourceFile = join(root, 'node_modules', moduleFile) - const targetFile = join(root, 'dist', assetDir, moduleFile) + generateBundle(_options, bundle) { + for (const fileName in bundle) { + const chunk = bundle[fileName] + if (chunk.type === 'chunk' && !chunk.isEntry) { + // Find matching vendor library by chunk name + const vendorLib = vendorLibraries.find( + (lib) => chunk.name === `vendor-${lib.name}` + ) - importMapEntries[source.name] = - './' + normalizePath(join(assetDir, moduleFile)) + if (vendorLib) { + const relativePath = `./${chunk.fileName.replace(/\\/g, '/')}` + importMapEntries[vendorLib.name] = relativePath - const targetDir = dirname(targetFile) - if (!fs.existsSync(targetDir)) { - fs.mkdirSync(targetDir, { recursive: true }) - } - fs.copyFileSync(sourceFile, targetFile) - } - - if (source.recursiveDependence) { - const files = glob.sync(['**/*.{js,mjs}'], { - cwd: join(root, 'node_modules', source.name) - }) - - for (const file of files) { - const moduleFile = join(source.name, file) - const sourceFile = join(root, 'node_modules', moduleFile) - const targetFile = join(root, 'dist', assetDir, moduleFile) - - importMapEntries[normalizePath(join(source.name, dirname(file)))] = - './' + normalizePath(join(assetDir, moduleFile)) - - const targetDir = dirname(targetFile) - if (!fs.existsSync(targetDir)) { - fs.mkdirSync(targetDir, { recursive: true }) - } - fs.copyFileSync(sourceFile, targetFile) + console.log( + `[ImportMap Plugin] Found chunk: ${chunk.name} -> Mapped '${vendorLib.name}' to '${relativePath}'` + ) } } } diff --git a/build/plugins/index.ts b/build/plugins/index.ts index f8c2d695c..c67473f7a 100644 --- a/build/plugins/index.ts +++ b/build/plugins/index.ts @@ -1,2 +1,3 @@ +export { addElementVnodeExportPlugin } from './addElementVnodeExportPlugin' export { comfyAPIPlugin } from './comfyAPIPlugin' export { generateImportMapPlugin } from './generateImportMapPlugin' diff --git a/vite.config.mts b/vite.config.mts index d134e936c..eda339517 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -8,7 +8,11 @@ import { createHtmlPlugin } from 'vite-plugin-html' import vueDevTools from 'vite-plugin-vue-devtools' import type { UserConfigExport } from 'vitest/config' -import { comfyAPIPlugin, generateImportMapPlugin } from './build/plugins' +import { + addElementVnodeExportPlugin, + comfyAPIPlugin, + generateImportMapPlugin +} from './build/plugins' dotenv.config() @@ -85,40 +89,11 @@ export default defineConfig({ : [vue()]), comfyAPIPlugin(IS_DEV), generateImportMapPlugin([ - { - name: 'vue', - pattern: 'vue', - entry: './dist/vue.esm-browser.prod.js' - }, - { - name: 'vue-i18n', - pattern: 'vue-i18n', - entry: './dist/vue-i18n.esm-browser.prod.js' - }, - { - name: 'primevue', - pattern: /^primevue\/?.*/, - entry: './index.mjs', - recursiveDependence: true - }, - { - name: '@primevue/themes', - pattern: /^@primevue\/themes\/?.*/, - entry: './index.mjs', - recursiveDependence: true - }, - { - name: '@primevue/forms', - pattern: /^@primevue\/forms\/?.*/, - entry: './index.mjs', - recursiveDependence: true, - override: { - '@primeuix/forms': { - entry: '' - } - } - } + { name: 'vue', pattern: /[\\/]node_modules[\\/]vue[\\/]/ }, + { name: 'primevue', pattern: /[\\/]node_modules[\\/]primevue[\\/]/ }, + { name: 'vue-i18n', pattern: /[\\/]node_modules[\\/]vue-i18n[\\/]/ } ]), + addElementVnodeExportPlugin(), Icons({ compiler: 'vue3'