@auaust/inertia-adapter-solid
v0.4.2
Published
A better maintained fork of the SolidJS adapter for Inertia.js
Downloads
50
Readme
Inertia SolidJS Adapter
An adapter to bring SolidJS compatibility to systems using InertiaJS.
Installation
# Using NPM
npm install -D solid-js vite-plugin-solid inertia-adapter-solid
# Using Yarn
yarn add -D solid-js vite-plugin-solid inertia-adapter-solid
# Using PNPM
pnpm add -D solid-js vite-plugin-solid inertia-adapter-solid
Setup Vite
In your vite.config.js
file, you will need to add the SolidJS plugin if not done already.
import { defineConfig } from 'vite'
+ import solid from 'vite-plugin-solid'
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
+ solid(),
// ...
]
})
Initialize the Inertia app
Next, update your main JavaScript file to boot your Inertia app. To accomplish this, we'll initialize SolidJS with the base Inertia component.
import { createInertiaApp } from "inertia-adapter-solid";
import { render } from "solid-js/web";
createInertiaApp({
resolve(name) {
const pages = import.meta.glob("./Pages/**/*.jsx", { eager: true });
return pages[`./Pages/${name}.jsx`];
},
setup({ el, App, props }) {
render(() => <App {...props} />, el);
},
});
Defining a root element
By default, Inertia assumes that yoru application's root template has a root element
with an id
of app
. If your application's root element has a different id
, you
can provide it using the id
property.
createInertiaApp({
id: "my-app",
// ...
});
Code splitting
Vite enables code splitting (or lazy-loading as they call it) by default when using
their import.meta.glob()
function, so simply omit the { eager: true }
option,
or set it to false
, to disable eager loading.
- const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
- return pages[`./Pages/${name}.jsx`]
+ const pages = import.meta.glob('./Pages/**/*.jsx')
+ return pages[`./Pages/${name}.jsx`]()
Pages
Inertia pages are simply SolidJS components, you will feel right at home.
import Layout from './Layout'
import { Title } from '@solidjs/meta'
export default function Welcome(props) {
const user () => props.user
return (
<Layout>
<Title>Welcome</Title>
<h1>Welcome</h1>
<p>Hello {user().name}, welcome to your first Inertia app!</p>
</Layout>
)
}
Creating Layouts
While not required, for most projects it makes sense to create a site layout that all
of your pages can extend. You may have noticed in our example above that we're wrapping
the page content within a <Layout>
component. Here's an example of such component:
import { Link } from "inertia-adapter-solid";
export default function Layout(props) {
return (
<main>
<header>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/contact">Contact</Link>
</header>
<article>{props.children}</article>
</main>
);
}
As you can see, this is a typical Solid component.
Persistent Layouts
While it's simple to implement layouts as children of page components, it forces the layout instance to be destroyed and recreated between visits. This means that you cannot have persistent layout state when navigating between pages.
For example, maybe you have an audio player on a podcast website that you want to continue playinh as users navigate the site. Or, maybe, you simply want to maintain the scroll position in your sidebar navigation between page visits. In these situations, the solution is to leverage Inertia's persistent layouts.
import Layout from './Layout'
import { Title } from '@solidjs/meta'
export default function Welcome(props) {
const user () => props.user
return (
<>
<Title>Welcome</Title>
<h1>Welcome</h1>
<p>Hello {user().name}, welcome to your first Inertia app!</p>
</>
)
}
Welcome.layout = Layout
Alternatively, you can also stack multiple layouts on top of each other.
import SiteLayout from './SiteLayout'
import NestedLayout from './NestedLayout'
import { Title } from '@solidjs/meta'
export default function Welcome(props) {
const user () => props.user
return (
<>
<Title>Welcome</Title>
<h1>Welcome</h1>
<p>Hello {user().name}, welcome to your first Inertia app!</p>
</>
)
}
Welcome.layout = [SiteLayout, NestedLayout]
You can also create more complex layout arrangements using nested layouts.
import Layout from './Layout'
import { Title } from '@solidjs/meta'
export default function Welcome(props) {
const user () => props.user
return (
<Layout>
<Title>Welcome</Title>
<h1>Welcome</h1>
<p>Hello {user().name}, welcome to your first Inertia app!</p>
</Layout>
)
}
Welcome.layout = (props) => {
<SiteLayout title="Welcome">
<NestedLayout>
{props.children}
</NestedLayout>
</SiteLayout>
}
Props
Updating props
The page props are a Solid mutable. This means they are settable in a reactive way.
function Welcome(props) {
return (
<>
Hello, {props.user.name}
<button onClick={() => (props.user.name = "John Doe")}>
Change name
</button>
</>
);
}
It is best avoided to mutate the props directly from the frontend, but is sometimes useful when server endpoints are fetched to get additional data or update a specific part of the props, where using the only
option isn't enough.
Uses cases for this could be:
- When paginating through a list of items. You can make a get request, and manually append the new items to the existing props.
- Modifying a simple state, i.e. a wishlist/liked boolean on a product. Instead of returning the whole page again, the endpoint can return the new status of the product, and you can update the props directly.
Using a mutable rather than a store allows for direct assignment of the new value, instead of being forced to know the fully qualified path of the value you want to update along with the store setter function.
### Updated props persistence
Frontend updated props are persisted in the history only. This means you can update the props, move away and return to the same page and the state will be the same as when you left. However, it won't persist a page reload. This is mostly aimed to allow for optimistic updates, i.e. updating a prop knowing that the backend will persist the change or manually updating a specific part of the props based on the returned data from an endpoint.
Title & Metadata
This adapter brings compatibility to Meta-tags using @solidjs/meta
official package, working in both Client-side Rendering and Server-side Rendering.
import { Title, Meta } from '@solidjs/meta'
<>
<Title>Your page title</Title>
<Meta name="description" content="Your page description" />
</>
Server-side Rendering (SSR)
Server-side rendering pre-renders your JavaScript pages on the server, allowing your visitors to receive fully rendered HTML when they visit your application. Since fully rendered HTML is served by your application, it's also easier for search engines to index your site.
Warning Server-side rendering uses Node.js to render your pages in a background process; therefore, Node must be available on your server for server-side rendering to function properly.
Note For this adapter, no additional dependencies are required.
Add server entry-point
Create a resources/js/ssr.js
file whitin your Laravel project that will serve as the SSR
entry point.
touch resources/js/ssr.js
This file is going to look very similar to your resources/js/app.js
file, except it's not
going to run in the browser, but rather in Node.js. Here's a complete example.
import { createInertiaApp } from "inertia-adapter-solid";
import createServer from "inertia-adapter-solid/server";
createServer((page) =>
createInertiaApp({
page,
resolve(name) {
const pages = import.meta.glob("./Pages/**/*.jsx", { eager: true });
return pages[`./Pages/${name}.jsx`];
},
})
);
Client-side Hydration
Since your website will now be server-side rendered, you can instruct SolidJS to "hydrate" the static markup and make it interactive instead of re-rendering all the HTML that we just generated.
import { createInertiaApp } from 'inertia-adapter-solid'
- import { render } from 'solid-js/web'
+ import { hydrate } from 'solid-js/web'
createInertiaApp({
resolve(name) {
const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
return pages[`./Pages/${name}.jsx`]
},
setup({ el, App, props }) {
- render(() => <App {...props} />, el)
+ hydrate(() => <App {...props} />, el)
},
})
Setup Vite
Next, we need to update our Vite configuration to build our new ssr.js file. We can do this by adding a ssr property to Laravel's Vite plugin configuration in our vite.config.js file.
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
+ ssr: 'resources/js/ssr.js',
refresh: true,
}),
- solid(),
+ solid({ ssr: true }),
// ...
],
})
Update build script
Next, let's update the build
script in our pacakge.json
file to also build
our new ssr.js
file.
"scripts" {
"dev": "vite",
- "build": "vite build"
+ "build": "vite build && vite build --ssr"
}
Now you can build both your client-side and server-side bundles.
# Using NPM
npm run build
# Using Yarn
yarn build
# Using PNPM
pnpm build
Next steps
You can read the full documentation on Server-side Rendering on InertiaJS's Offial Guide.