Files
AppFlowy-Web/vite-plugin-strip-testid.ts
2025-09-05 23:12:30 +08:00

88 lines
2.9 KiB
TypeScript

import { Plugin } from 'vite';
/**
* Vite plugin to strip data-testid attributes from production builds
* This reduces bundle size and removes test-specific attributes from production code
*/
export function stripTestIdPlugin(): Plugin {
return {
name: 'strip-test-id',
apply: 'build', // Only apply during build, not dev
transform(code: string, id: string) {
// Skip node_modules to avoid transforming external libraries
if (id.includes('node_modules')) {
return null;
}
// Only process .tsx and .jsx files from our source
if (!id.match(/src.*\.(tsx|jsx)$/)) {
return null;
}
// Only strip in production builds
if (process.env.NODE_ENV !== 'production') {
return null;
}
let transformedCode = code;
let hasChanges = false;
try {
// Pattern 1: Simple string attributes: data-testid="value" or data-testid='value'
// This is the safest pattern to remove
const simpleStringPattern = /\s+data-testid\s*=\s*["'][^"']*["']/g;
const matches = transformedCode.match(simpleStringPattern);
if (matches && matches.length > 0) {
console.log(`Stripping ${matches.length} data-testid attributes from ${id}`);
transformedCode = transformedCode.replace(simpleStringPattern, '');
hasChanges = true;
}
// Pattern 2: Simple expressions without nested braces: data-testid={variable}
const simpleExpressionPattern = /\s+data-testid\s*=\s*\{[^{}]+\}/g;
const exprMatches = transformedCode.match(simpleExpressionPattern);
if (exprMatches && exprMatches.length > 0) {
console.log(`Stripping ${exprMatches.length} data-testid expressions from ${id}`);
transformedCode = transformedCode.replace(simpleExpressionPattern, '');
hasChanges = true;
}
// Pattern 3: Template literals: data-testid={`value-${id}`}
const templatePattern = /\s+data-testid\s*=\s*\{`[^`]*`\}/g;
if (templatePattern.test(transformedCode)) {
transformedCode = transformedCode.replace(templatePattern, '');
hasChanges = true;
}
if (hasChanges) {
// Quick validation: check for obvious syntax errors
// Count opening and closing braces to ensure we didn't break anything
const openBraces = (transformedCode.match(/\{/g) || []).length;
const closeBraces = (transformedCode.match(/\}/g) || []).length;
if (openBraces !== closeBraces) {
console.warn(`Warning: Brace mismatch after transformation in ${id}. Skipping transformation.`);
return null;
}
return {
code: transformedCode,
map: null,
};
}
} catch (error) {
console.error(`Error processing ${id}:`, error);
// Return null to skip transformation on error
return null;
}
return null;
},
};
}