mirror of
https://github.com/unraid/api.git
synced 2026-01-07 17:19:52 -06:00
refactor: enhance manifest validation and Vue app mounting logic
- Improved validation in `WebComponentsExtractor` to log errors for missing standalone apps entries and file keys, ensuring better error handling during manifest processing. - Updated CSS content retrieval in `vite.standalone.config.ts` to include a fallback mechanism for missing Nuxt CSS files, enhancing robustness. - Simplified modal component mounting in `standalone-mount.ts` by utilizing a dedicated function for better readability and maintainability. - Refined `mountVueApp` logic in `vue-mount-app.ts` to differentiate between the main app and clones, optimizing the mounting process for multiple targets.
This commit is contained in:
@@ -113,14 +113,18 @@ class WebComponentsExtractor
|
||||
$manifest = $this->getManifestContents($manifestPath);
|
||||
$subfolder = $this->getRelativePath($manifestPath);
|
||||
|
||||
// Check if STANDALONE_APPS_ENTRY exists and has a valid 'file' key
|
||||
// Check if STANDALONE_APPS_ENTRY exists
|
||||
if (!isset($manifest[self::STANDALONE_APPS_ENTRY])) {
|
||||
continue; // Skip this manifest if entry doesn't exist
|
||||
error_log("Standalone apps manifest at '{$manifestPath}' is missing the '" . self::STANDALONE_APPS_ENTRY . "' entry key");
|
||||
return '';
|
||||
}
|
||||
|
||||
$entry = $manifest[self::STANDALONE_APPS_ENTRY];
|
||||
|
||||
// Check if 'file' key exists
|
||||
if (!isset($entry['file']) || empty($entry['file'])) {
|
||||
continue; // Skip if 'file' key is missing or empty
|
||||
error_log("Standalone apps manifest at '{$manifestPath}' has entry '" . self::STANDALONE_APPS_ENTRY . "' but is missing the 'file' field");
|
||||
return '';
|
||||
}
|
||||
|
||||
// Build the JS file path
|
||||
|
||||
@@ -164,7 +164,7 @@ export function mountVueApp(options: MountOptions): VueApp | null {
|
||||
// Mount to all targets
|
||||
const clones: VueApp[] = [];
|
||||
const containers: HTMLElement[] = [];
|
||||
targets.forEach((target) => {
|
||||
targets.forEach((target, index) => {
|
||||
const mountTarget = target as HTMLElement;
|
||||
|
||||
// Add unraid-reset class to ensure webgui styles don't leak in
|
||||
@@ -186,20 +186,25 @@ export function mountVueApp(options: MountOptions): VueApp | null {
|
||||
// Inject styles into shadow root
|
||||
injectStyles(mountTarget.shadowRoot!);
|
||||
|
||||
// Clone and mount the app to this container
|
||||
const clonedApp = createApp(component, props);
|
||||
clonedApp.use(i18n);
|
||||
clonedApp.use(globalPinia);
|
||||
clonedApp.provide(DefaultApolloClient, client);
|
||||
clonedApp.mount(container);
|
||||
clones.push(clonedApp);
|
||||
// For the first target, use the main app, otherwise create clones
|
||||
if (index === 0) {
|
||||
app.mount(container);
|
||||
} else {
|
||||
const targetProps = { ...parsePropsFromElement(mountTarget), ...props };
|
||||
const clonedApp = createApp(component, targetProps);
|
||||
clonedApp.use(i18n);
|
||||
clonedApp.use(globalPinia);
|
||||
clonedApp.provide(DefaultApolloClient, client);
|
||||
clonedApp.mount(container);
|
||||
clones.push(clonedApp);
|
||||
}
|
||||
} else {
|
||||
// Direct mount without shadow root
|
||||
injectStyles(document);
|
||||
|
||||
// For multiple targets, we need to create separate app instances
|
||||
// but they'll share the same Pinia store
|
||||
if (Array.from(targets).indexOf(mountTarget) === 0) {
|
||||
if (index === 0) {
|
||||
// First target, use the main app
|
||||
app.mount(mountTarget);
|
||||
} else {
|
||||
|
||||
@@ -60,15 +60,11 @@ componentMappings.forEach(({ component, selector, appId }) => {
|
||||
});
|
||||
});
|
||||
|
||||
// Special handling for Modals - also mount to #modals if it exists
|
||||
if (document.querySelector('#modals')) {
|
||||
mountVueApp({
|
||||
component: Modals,
|
||||
selector: '#modals',
|
||||
appId: 'modals-direct',
|
||||
useShadowRoot: false,
|
||||
});
|
||||
}
|
||||
// Special handling for Modals - also mount to #modals
|
||||
autoMountComponent(Modals, '#modals', {
|
||||
appId: 'modals-direct',
|
||||
useShadowRoot: false,
|
||||
});
|
||||
|
||||
// Expose functions globally for testing and dynamic mounting
|
||||
declare global {
|
||||
|
||||
@@ -25,6 +25,13 @@ const getCssContent = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to source asset
|
||||
const fallback = path.resolve(__dirname, 'assets/main.css');
|
||||
if (fs.existsSync(fallback)) {
|
||||
console.warn('Nuxt CSS not found; falling back to assets/main.css');
|
||||
return fs.readFileSync(fallback, 'utf-8');
|
||||
}
|
||||
|
||||
console.warn('No CSS file found, using empty string');
|
||||
return '';
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user