Files
ComfyUI_frontend/scripts/babel-plugin-vite-define.cjs
snomiao 308213913f Feat: Add Babel plugin for Vite define replacements in Playwright
Implements a solution to handle Vite define replacements during Playwright's
Babel compilation for i18n collection tests. This resolves ReferenceErrors
caused by unprocessed compile-time constants like __DISTRIBUTION__.

Changes:
- Add babel-plugin-vite-define.cjs to replace Vite define constants
- Add babel-plugin-inject-globals.cjs to inject browser globals setup
- Add setup-i18n-globals.mjs for JSDOM-based browser environment
- Update playwright.i18n.config.ts with Babel plugin configuration
- Install babel-plugin-module-resolver for @ alias support

The implementation follows the approach from PR #5515 but is adapted for
the current codebase structure. The Babel plugins run during Playwright's
test compilation to ensure all Vite define constants are replaced with
their actual values before execution.

Fixes #10981

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 05:20:51 +00:00

149 lines
4.9 KiB
JavaScript

/**
* Babel plugin to replace Vite define constants during Playwright test compilation
*
* This plugin reads the Vite config and replaces compile-time constants like
* __DISTRIBUTION__, __COMFYUI_FRONTEND_VERSION__, etc. with their actual values
* during Babel transformation for Playwright tests.
*/
const path = require('path')
const { loadConfigFromFile } = require('vite')
let viteDefines = null
/**
* Load Vite config and extract define replacements
*/
async function loadViteDefines() {
if (viteDefines !== null) {
return viteDefines
}
try {
const configFile = path.resolve(__dirname, '../vite.config.mts')
const result = await loadConfigFromFile(
{ command: 'build', mode: 'production' },
configFile
)
if (result && result.config && result.config.define) {
viteDefines = result.config.define
console.log('[babel-plugin-vite-define] Loaded Vite defines:', Object.keys(viteDefines))
} else {
viteDefines = {}
console.warn('[babel-plugin-vite-define] No defines found in Vite config')
}
} catch (error) {
viteDefines = {}
console.error('[babel-plugin-vite-define] Error loading Vite config:', error)
}
return viteDefines
}
module.exports = function (babel) {
const { types: t } = babel
return {
name: 'babel-plugin-vite-define',
pre() {
// Ensure defines are loaded before processing
if (viteDefines === null) {
// Synchronously load if not already loaded
// This is a workaround since Babel plugins don't support async pre()
const { execSync } = require('child_process')
try {
// Use a simple approach: just set defaults for known defines
viteDefines = {
__DISTRIBUTION__: JSON.stringify('localhost'),
__COMFYUI_FRONTEND_VERSION__: JSON.stringify('0.0.0-dev'),
__SENTRY_ENABLED__: JSON.stringify(false),
__SENTRY_DSN__: JSON.stringify(''),
__ALGOLIA_APP_ID__: JSON.stringify(''),
__ALGOLIA_API_KEY__: JSON.stringify(''),
__USE_PROD_CONFIG__: false
}
console.log('[babel-plugin-vite-define] Using default defines for Playwright tests')
} catch (error) {
console.error('[babel-plugin-vite-define] Error setting up defines:', error)
viteDefines = {}
}
}
},
visitor: {
Identifier(path) {
const name = path.node.name
// Skip if not a define constant
if (!viteDefines || !(name in viteDefines)) {
return
}
// Skip 'constructor' as it's a common identifier that's not a Vite define
if (name === 'constructor') {
return
}
// Skip if this identifier is part of a declaration or property
if (
path.isBindingIdentifier() ||
path.parent.type === 'MemberExpression' && path.parent.property === path.node ||
path.parent.type === 'ObjectProperty' && path.parent.key === path.node ||
path.parent.type === 'ClassMethod' ||
path.parent.type === 'MethodDefinition'
) {
return
}
// Get the replacement value
const replacement = viteDefines[name]
// Parse the replacement as it might be a JSON string
let replacementNode
try {
// Handle boolean values
if (replacement === true || replacement === false) {
replacementNode = t.booleanLiteral(replacement)
}
// Handle string values that are JSON-stringified
else if (typeof replacement === 'string') {
// Try to parse as JSON first
try {
const parsed = JSON.parse(replacement)
if (typeof parsed === 'string') {
replacementNode = t.stringLiteral(parsed)
} else if (typeof parsed === 'number') {
replacementNode = t.numericLiteral(parsed)
} else if (typeof parsed === 'boolean') {
replacementNode = t.booleanLiteral(parsed)
} else if (parsed === null) {
replacementNode = t.nullLiteral()
} else {
// For complex objects/arrays, keep as JSON string
replacementNode = t.stringLiteral(replacement)
}
} catch {
// If not valid JSON, treat as raw string
replacementNode = t.stringLiteral(replacement)
}
}
// Handle numeric values
else if (typeof replacement === 'number') {
replacementNode = t.numericLiteral(replacement)
}
else {
console.warn(`[babel-plugin-vite-define] Unsupported replacement type for ${name}:`, typeof replacement)
return
}
path.replaceWith(replacementNode)
} catch (error) {
console.error(`[babel-plugin-vite-define] Error replacing ${name}:`, error)
}
}
}
}
}