Files
api/web/scripts/validate-custom-elements-css.js
Eli Bosley af5ca11860 Feat/vue (#1655)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- New Features
- Introduced Docker management UI components: Overview, Logs, Console,
Preview, and Edit.
- Added responsive Card/Detail layouts with grouping, bulk actions, and
tabs.
  - New UnraidToaster component and global toaster configuration.
- Component auto-mounting improved with async loading and multi-selector
support.
- UI/UX
- Overhauled theme system (light/dark tokens, primary/orange accents)
and added theme variants.
  - Header OS version now includes integrated changelog modal.
- Registration displays warning states; multiple visual polish updates.
- API
  - CPU load now includes percentGuest and percentSteal metrics.
- Chores
  - Migrated web app to Vite; updated artifacts and manifests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
Co-authored-by: Michael Datelle <mdatelle@icloud.com>
2025-09-08 10:04:49 -04:00

170 lines
5.3 KiB
JavaScript

#!/usr/bin/env node
import fs from 'fs';
import path from 'path';
/**
* Recursively find JS files in a directory
*/
function findJSFiles(dir, jsFiles = []) {
if (!fs.existsSync(dir)) {
return jsFiles;
}
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
findJSFiles(fullPath, jsFiles);
} else if (item.endsWith('.js')) {
jsFiles.push(fullPath);
}
}
return jsFiles;
}
/**
* Validates that Tailwind CSS styles are properly inlined in the JavaScript bundle
*/
function validateCustomElementsCSS() {
console.log('🔍 Validating JS bundle includes inlined Tailwind styles...');
try {
// Check standalone apps first (new approach)
const standaloneDir = '.nuxt/standalone-apps';
let jsFiles = findJSFiles(standaloneDir);
let usingStandalone = true;
// Fallback to custom elements if standalone doesn't exist
if (jsFiles.length === 0) {
const customElementsDir = '.nuxt/nuxt-custom-elements/dist';
jsFiles = findJSFiles(customElementsDir);
usingStandalone = false;
if (jsFiles.length === 0) {
throw new Error('No JS files found in standalone apps or custom elements dist');
}
}
console.log(`📦 Using ${usingStandalone ? 'standalone apps' : 'custom elements'} bundle`);
// Find the largest JS file (likely the main bundle with inlined CSS)
const jsFile = jsFiles.reduce((largest, current) => {
const currentSize = fs.statSync(current).size;
const largestSize = fs.statSync(largest).size;
return currentSize > largestSize ? current : largest;
});
console.log(`📁 Checking JS bundle: ${jsFile}`);
// Read the JS content
const jsContent = fs.readFileSync(jsFile, 'utf8');
// Define required Tailwind indicators (looking for inlined CSS in JS)
// Updated patterns to work with minified CSS (no spaces)
const requiredIndicators = [
{
name: 'Tailwind utility classes (inline)',
pattern: /\.flex\s*\{[^}]*display:\s*flex|\.flex{display:flex/,
description: 'Basic Tailwind utility classes inlined',
},
{
name: 'Tailwind margin utilities (inline)',
pattern: /\.m-\d+\s*\{[^}]*margin:|\.m-\d+{[^}]*margin:/,
description: 'Tailwind margin utilities inlined',
},
{
name: 'Tailwind padding utilities (inline)',
pattern: /\.p-\d+\s*\{[^}]*padding:|\.p-\d+{[^}]*padding:/,
description: 'Tailwind padding utilities inlined',
},
{
name: 'Tailwind color utilities (inline)',
pattern: /\.text-\w+\s*\{[^}]*color:|\.text-\w+{[^}]*color:/,
description: 'Tailwind text color utilities inlined',
},
{
name: 'Tailwind background utilities (inline)',
pattern: /\.bg-\w+\s*\{[^}]*background|\.bg-\w+{[^}]*background/,
description: 'Tailwind background utilities inlined',
},
{
name: 'CSS custom properties',
pattern: /--[\w-]+:\s*[^;]+;|--[\w-]+:[^;]+;/,
description: 'CSS custom properties (variables)',
},
{
name: 'Responsive breakpoints',
pattern: /@media\s*\([^)]*min-width|@media\([^)]*min-width/,
description: 'Responsive media queries',
},
{
name: 'CSS reset styles',
pattern: /\*[^}]*box-sizing|box-sizing[^}]*border-box/,
description: 'Tailwind CSS reset/normalize styles',
},
];
// Validate each indicator
const results = [];
let allPassed = true;
for (const indicator of requiredIndicators) {
const found = indicator.pattern.test(jsContent);
results.push({
name: indicator.name,
description: indicator.description,
passed: found,
});
if (!found) {
allPassed = false;
}
}
// Report results
console.log('\n📊 Validation Results:');
console.log('====================');
for (const result of results) {
const status = result.passed ? '✅' : '❌';
console.log(`${status} ${result.name}`);
if (!result.passed) {
console.log(` └─ Missing: ${result.description}`);
}
}
// File size check
const fileSizeKB = Math.round(fs.statSync(jsFile).size / 1024);
console.log(`\n📏 JS bundle size: ${fileSizeKB} KB`);
if (fileSizeKB < 1000) {
console.log(
'⚠️ WARNING: JS bundle seems too small, inlined Tailwind styles might not be included'
);
allPassed = false;
} else {
console.log('✅ JS bundle size looks good');
}
// Final result
if (allPassed) {
console.log('\n🎉 SUCCESS: All Tailwind styles are properly inlined in the JS bundle!');
process.exit(0);
} else {
console.log('\n❌ FAILURE: Some Tailwind styles are missing from the JS bundle!');
console.log('\n💡 This might indicate:');
console.log(' - The CSS inline import in viteExtend is not working properly');
console.log(' - Tailwind configuration is not being processed');
console.log(' - CSS is not being injected into shadow DOM components');
process.exit(1);
}
} catch (error) {
console.error('\n❌ ERROR during validation:', error.message);
process.exit(1);
}
}
// Run the validation
validateCustomElementsCSS();