Skip to content

Commit 0006dd3

Browse files
authored
[Refactor] Split custom vite plugins to files under build/plugins (#3531)
1 parent 7355209 commit 0006dd3

File tree

5 files changed

+257
-240
lines changed

5 files changed

+257
-240
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Plugin } from 'vite'
2+
3+
/**
4+
* Vite plugin that adds an alias export for Vue's createBaseVNode as createElementVNode.
5+
*
6+
* This plugin addresses compatibility issues where some components or libraries
7+
* might be using the older createElementVNode function name instead of createBaseVNode.
8+
* It modifies the Vue vendor chunk during build to add the alias export.
9+
*
10+
* @returns {Plugin} A Vite plugin that modifies the Vue vendor chunk exports
11+
*/
12+
export function addElementVnodeExportPlugin(): Plugin {
13+
return {
14+
name: 'add-element-vnode-export-plugin',
15+
16+
renderChunk(code, chunk, _options) {
17+
if (chunk.name.startsWith('vendor-vue')) {
18+
const exportRegex = /(export\s*\{)([^}]*)(\}\s*;?\s*)$/
19+
const match = code.match(exportRegex)
20+
21+
if (match) {
22+
const existingExports = match[2].trim()
23+
const exportsArray = existingExports
24+
.split(',')
25+
.map((e) => e.trim())
26+
.filter(Boolean)
27+
28+
const hasCreateBaseVNode = exportsArray.some((e) =>
29+
e.startsWith('createBaseVNode')
30+
)
31+
const hasCreateElementVNode = exportsArray.some((e) =>
32+
e.includes('createElementVNode')
33+
)
34+
35+
if (hasCreateBaseVNode && !hasCreateElementVNode) {
36+
const newExportStatement = `${match[1]} ${existingExports ? existingExports + ',' : ''} createBaseVNode as createElementVNode ${match[3]}`
37+
const newCode = code.replace(exportRegex, newExportStatement)
38+
39+
console.log(
40+
`[add-element-vnode-export-plugin] Added 'createBaseVNode as createElementVNode' export to vendor-vue chunk.`
41+
)
42+
43+
return { code: newCode, map: null }
44+
} else if (!hasCreateBaseVNode) {
45+
console.warn(
46+
`[add-element-vnode-export-plugin] Warning: 'createBaseVNode' not found in exports of vendor-vue chunk. Cannot add alias.`
47+
)
48+
}
49+
} else {
50+
console.warn(
51+
`[add-element-vnode-export-plugin] Warning: Could not find expected export block format in vendor-vue chunk.`
52+
)
53+
}
54+
}
55+
56+
return null
57+
}
58+
}
59+
}

build/plugins/comfyAPIPlugin.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import path from 'path'
2+
import { Plugin } from 'vite'
3+
4+
interface ShimResult {
5+
code: string
6+
exports: string[]
7+
}
8+
9+
function isLegacyFile(id: string): boolean {
10+
return (
11+
id.endsWith('.ts') &&
12+
(id.includes('src/extensions/core') || id.includes('src/scripts'))
13+
)
14+
}
15+
16+
function transformExports(code: string, id: string): ShimResult {
17+
const moduleName = getModuleName(id)
18+
const exports: string[] = []
19+
let newCode = code
20+
21+
// Regex to match different types of exports
22+
const regex =
23+
/export\s+(const|let|var|function|class|async function)\s+([a-zA-Z$_][a-zA-Z\d$_]*)(\s|\()/g
24+
let match
25+
26+
while ((match = regex.exec(code)) !== null) {
27+
const name = match[2]
28+
// All exports should be bind to the window object as new API endpoint.
29+
if (exports.length == 0) {
30+
newCode += `\nwindow.comfyAPI = window.comfyAPI || {};`
31+
newCode += `\nwindow.comfyAPI.${moduleName} = window.comfyAPI.${moduleName} || {};`
32+
}
33+
newCode += `\nwindow.comfyAPI.${moduleName}.${name} = ${name};`
34+
exports.push(
35+
`export const ${name} = window.comfyAPI.${moduleName}.${name};\n`
36+
)
37+
}
38+
39+
return {
40+
code: newCode,
41+
exports
42+
}
43+
}
44+
45+
function getModuleName(id: string): string {
46+
// Simple example to derive a module name from the file path
47+
const parts = id.split('/')
48+
const fileName = parts[parts.length - 1]
49+
return fileName.replace(/\.\w+$/, '') // Remove file extension
50+
}
51+
52+
export function comfyAPIPlugin(isDev: boolean): Plugin {
53+
return {
54+
name: 'comfy-api-plugin',
55+
transform(code: string, id: string) {
56+
if (isDev) return null
57+
58+
if (isLegacyFile(id)) {
59+
const result = transformExports(code, id)
60+
61+
if (result.exports.length > 0) {
62+
const projectRoot = process.cwd()
63+
const relativePath = path.relative(path.join(projectRoot, 'src'), id)
64+
const shimFileName = relativePath.replace(/\.ts$/, '.js')
65+
66+
const shimComment = `// Shim for ${relativePath}\n`
67+
68+
this.emitFile({
69+
type: 'asset',
70+
fileName: shimFileName,
71+
source: shimComment + result.exports.join('')
72+
})
73+
}
74+
75+
return {
76+
code: result.code,
77+
map: null // If you're not modifying the source map, return null
78+
}
79+
}
80+
}
81+
}
82+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import type { OutputOptions } from 'rollup'
2+
import { HtmlTagDescriptor, Plugin } from 'vite'
3+
4+
interface VendorLibrary {
5+
name: string
6+
pattern: RegExp
7+
}
8+
9+
/**
10+
* Vite plugin that generates an import map for vendor chunks.
11+
*
12+
* This plugin creates a browser-compatible import map that maps module specifiers
13+
* (like 'vue' or 'primevue') to their actual file locations in the build output.
14+
* This improves module loading in modern browsers and enables better caching.
15+
*
16+
* The plugin:
17+
* 1. Tracks vendor chunks during bundle generation
18+
* 2. Creates mappings between module names and their file paths
19+
* 3. Injects an import map script tag into the HTML head
20+
* 4. Configures manual chunk splitting for vendor libraries
21+
*
22+
* @param vendorLibraries - An array of vendor libraries to split into separate chunks
23+
* @returns {Plugin} A Vite plugin that generates and injects an import map
24+
*/
25+
export function generateImportMapPlugin(
26+
vendorLibraries: VendorLibrary[]
27+
): Plugin {
28+
const importMapEntries: Record<string, string> = {}
29+
30+
return {
31+
name: 'generate-import-map-plugin',
32+
33+
// Configure manual chunks during the build process
34+
configResolved(config) {
35+
if (config.build) {
36+
// Ensure rollupOptions exists
37+
if (!config.build.rollupOptions) {
38+
config.build.rollupOptions = {}
39+
}
40+
41+
const outputOptions: OutputOptions = {
42+
manualChunks: (id: string) => {
43+
for (const lib of vendorLibraries) {
44+
if (lib.pattern.test(id)) {
45+
return `vendor-${lib.name}`
46+
}
47+
}
48+
return null
49+
},
50+
// Disable minification of internal exports to preserve function names
51+
minifyInternalExports: false
52+
}
53+
config.build.rollupOptions.output = outputOptions
54+
}
55+
},
56+
57+
generateBundle(_options, bundle) {
58+
for (const fileName in bundle) {
59+
const chunk = bundle[fileName]
60+
if (chunk.type === 'chunk' && !chunk.isEntry) {
61+
// Find matching vendor library by chunk name
62+
const vendorLib = vendorLibraries.find(
63+
(lib) => chunk.name === `vendor-${lib.name}`
64+
)
65+
66+
if (vendorLib) {
67+
const relativePath = `./${chunk.fileName.replace(/\\/g, '/')}`
68+
importMapEntries[vendorLib.name] = relativePath
69+
70+
console.log(
71+
`[ImportMap Plugin] Found chunk: ${chunk.name} -> Mapped '${vendorLib.name}' to '${relativePath}'`
72+
)
73+
}
74+
}
75+
}
76+
},
77+
78+
transformIndexHtml(html) {
79+
if (Object.keys(importMapEntries).length === 0) {
80+
console.warn(
81+
'[ImportMap Plugin] No vendor chunks found to create import map.'
82+
)
83+
return html
84+
}
85+
86+
const importMap = {
87+
imports: importMapEntries
88+
}
89+
90+
const importMapTag: HtmlTagDescriptor = {
91+
tag: 'script',
92+
attrs: { type: 'importmap' },
93+
children: JSON.stringify(importMap, null, 2),
94+
injectTo: 'head'
95+
}
96+
97+
return {
98+
html,
99+
tags: [importMapTag]
100+
}
101+
}
102+
}
103+
}

build/plugins/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { addElementVnodeExportPlugin } from './addElementVnodeExportPlugin'
2+
export { comfyAPIPlugin } from './comfyAPIPlugin'
3+
export { generateImportMapPlugin } from './generateImportMapPlugin'

0 commit comments

Comments
 (0)