Skip to content

Instantly share code, notes, and snippets.

@hakimzulkufli
Last active January 5, 2023 04:34
Show Gist options
  • Save hakimzulkufli/7f03908995794bc2335fe5c0a6b96c53 to your computer and use it in GitHub Desktop.
Save hakimzulkufli/7f03908995794bc2335fe5c0a6b96c53 to your computer and use it in GitHub Desktop.
Detect and Resolve layout files automatically like SvelteKit using Inertia.js (Laravel + Vite + Svelte)
import { createInertiaApp } from "@inertiajs/inertia-svelte";
import { InertiaProgress } from "@inertiajs/progress";
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers";
import DefaultLayout from "$/Pages/__layout.svelte";
const appName = window.document.getElementsByTagName("title")[0]?.innerText || "App Name";
const layouts = import.meta.glob('./Pages/**/__layout.svelte');
const pages = import.meta.glob('./Pages/**/*.svelte');
/**
* Resolve layout file recursively a la SvelteKit.
*
* @param { string } page Path to current page.
*/
async function resolveLayoutFile(page, loadedLayouts = [])
{
if (!page) {
return loadedLayouts;
}
const path = (page.substr(0, page.lastIndexOf('/')));
const layout = layouts[path + '/__layout.svelte'];
if (typeof layout === 'function') {
loadedLayouts.unshift(layout());
}
return resolveLayoutFile(path, loadedLayouts);
};
/**
* Smartly resolve page component by the following convention:
* 1. Treat as directory and find Index.svelte;
* 2. If fails, treat as path to a page component.
*
* @param { string } pageName Page name.
* @returns Page component.
*/
async function resolvePage(pageName)
{
var page, name = pageName;
try {
page = await resolvePageComponent(`./Pages/${pageName}/Index.svelte`, pages);
name = `${pageName}/Index.svelte`;
} catch (error) {
page = await resolvePageComponent(`./Pages/${pageName}.svelte`, pages);
}
return {
page: page,
name: name
};
}
/**
* Resolve page component and load layout file.
*
* @param { string } pageName Page name.
* @returns Page component.
*/
async function importPage(pageName)
{
return await resolvePage(pageName)
.then(async ({page, name}) => {
const module = page;
const layouts = (await resolveLayoutFile(`./Pages/${name}.svelte`));
/**
* Technically you won't need to specify a fallback DefaultLayout
* since we're looking for it recursively but just in case you there's none found
* and have a default layout stored somewhere, we can tell it to use that instead.
*/
const loadedLayouts = (await Promise.all(layouts)).map((layout) => layout.default) || DefaultLayout;
return Object.assign({ layout: loadedLayouts }, module);
});
}
/**
* Render Inertia.js app.
*/
createInertiaApp({
resolve: (pageName) => importPage(pageName),
setup({ el, App, props }) {
new App({ target: el, props });
}
});
/**
* Progress bar.
*/
InertiaProgress.init({ color: "#4B5563" });
@hakimzulkufli
Copy link
Author

This is my attempt to mimic SvelteKit's layout files loading by finding and nesting them recursively up the directories. I really liked how SvelteKit handled it. This is far more easier than having to define the layout on every file, especially when you have multiple layouts.

I don't know how performant this is. Never tried with an SSR. I've only just started using this method in a brand new project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment