Combining Adonis and Svelte using InertiaJS
Introduction
These days web apps are usually built with a separate backend and frontend. They communicate through REST API, GraphQL, etc. This is because a SPA framework/library like React, Svelte, or Vue provides a much better DX and UX compared to the old school templating languages like EJS, HBS, Blade, etc.
Now, what if, we combine the old school monolithic approach with those SPA frameworks/libraries? Thankfully, there’s InertiaJS!
In this post, I’ll try to explain how to get it up and running using Adonis and Svelte, but I won’t use Typescript for Svelte to keep it simple.
What is InertiaJS
Quoting from its website:
Inertia is a new approach to building classic server-driven web apps. We call it the modern monolith.
Basically, it lets you use a SPA framework/library as the template language for your backend framework of choice, whether it be Laravel, Ruby on Rails, Adonis, and many more.
You should check their website! It has a thorough explanation of what it does, who is it for, how it works, etc.
I’ll assume you already know Adonis/Svelte since the new hotness here is InertiaJS.
Installation
Installing Adonis
First thing first, we’ll need to create a new adonis app. Simply run
npm init adonis-ts-app@latest your-app-name
If you’re greeted with this prompt, choose web
.
CUSTOMIZE PROJECT
❯ Select the project structure … Press <ENTER> to select
api (Tailored for creating a REST API server)
▸ web (Traditional web application with server-rendered templates)
slim (A smallest possible AdonisJS application)
Pick whatever project name you like. Let’s leave it as the default.
CUSTOMIZE PROJECT
❯ Select the project structure · web
❯ Enter the project name · my-app-name
You’ll be prompted to set up eslint/prettier or not. Either way is fine, but I personally prefer to set it to true (press y
for true, n
for false)
CUSTOMIZE PROJECT
❯ Select the project structure · web
❯ Enter the project name · my-app-name
❯ Setup eslint? (y/N) · true
❯ Setup prettier? (y/N) · true
We’ll also say true to the Webpack Encore setup.
CUSTOMIZE PROJECT
❯ Select the project structure · web
❯ Enter the project name · perpus
❯ Setup eslint? (y/N) · true
❯ Setup prettier? (y/N) · true
❯ Configure webpack encore for compiling frontend assets? (y/N) ‣ true
After that, it will set up the project and you’ll just need to cd
to the project directory when it’s done. In this case, it’s my-app-name
.
Installing inertia-adonisjs Adapter
Inertia only supports Laravel and Ruby on Rails officially, but there are a lot of community adapters. One of them is inertia-adonisjs which we will use in our project. Simply install it like a regular package and configure it using ace.
# install the package using npm
npm i @eidellev/inertia-adonisjs
# configure the package using ace
node ace configure @eidellev/inertia-adonisjs
It will give you several questions. Make sure you choose Svelte, you can leave the rest of them as default.
❯ Select the view you would like to use · app
❯ Would you like to install Inertia.js? (Y/n) · true
❯ Which client-side adapter would you like to set up? … Press <ENTER> to select
Vue 2
Vue 3
React
▸ Svelte
Installing Svelte
We’ll need the svelte-loader and svelte-preprocess for our app. As usual, install it using npm.
npm i svelte-loader svelte-preprocess @babel/plugin-syntax-dynamic-import
We need @babel/plugin-syntax-dynamic-import
to be able to use the import syntax required for code splitting.
Configuration
Webpack configuration
We’ll add svelte-loader and svelte-preprocess to our webpack configuration. Open up webpack.config.js
in your favourite editor and add these lines.
const { join } = require("path");
const Encore = require("@symfony/webpack-encore");
// add this line
const sveltePreprocess = require("svelte-preprocess");
/****the rest of the config****/
// add this block
Encore.addLoader({
test: /\\.svelte$/,
loader: "svelte-loader",
options: {
emitCss: true,
preprocess: sveltePreprocess({}),
},
});
/****the rest of the config****/
const config = Encore.getWebpackConfig();
config.infrastructureLogging = {
level: "warn",
};
config.stats = "errors-warnings";
// add this line
config.output.chunkFilename = "js/[name].js?id=[chunkhash]";
Inertia configuration
To use Svelte, we need to initialise our app. To do that, go to resources/js/app.js
and add this snippet.
import { createInertiaApp } from "@inertiajs/inertia-svelte";
import { InertiaProgress } from "@inertiajs/progress";
InertiaProgress.init({
showSpinner: true,
});
createInertiaApp({
resolve: (name) => import(`./Pages/${name}.svelte`),
setup({ el, App, props }) {
new App({ target: el, props });
},
});
We also added @inertiajs/progress
for the loading progress because SPA app doesn’t trigger the browser’s loading progress and it can become annoying when your app navigation is slow. This is a bad UX.
Our Svelte files will live inside resources/js/Pages
directory. When we want to render our app, we’ll just reference its name and it will automatically get resolved by the resolve
function. For example, Foo
will resolve to ./Pages/Foo.svelte
.
We use import
instead of require
because we want to enable code splitting.
Adding assets
Don’t forget to link the javascript into our main entry point. Otherwise, there won’t be anything rendered on the page. Simply add this in resources/views/app.edge
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="/favicon.ico">
<title>App Title</title>
<!-- add this line -->
<script src="{{ asset('assets/app.js') }}" defer></script>
</head>
<body>
@inertia()
</body>
</html>
Usage
Finally, let’s see if it actually works. Create a new Svelte file in resources/js/Pages/Foo.svelte
with this content.
<script>
export let text
</script>
<h1>Your Text: {text}</h1>
Open start/routes.ts
and add a new route for our Svelte app.
Route.get("/foo", async ({ inertia }) => {
return inertia.render("Foo", { text: "Hello, World!" });
});
As you can see, passing props is as simple as passing our data to the second argument. This data can come from anywhere, whether it be hardcoded, from the database, etc.
Try running the server using npm run dev
or node ace serve --watch
.
If we open http://localhost:3333/foo
(3333 is the default port, you can change it in .env
), you should see a big text saying Your Text: Hello, World!
which means our app is working!
References
Of course, always refer to Adonis/Svelte/Inertia for more detailed API references, they all have extensive documentation (and a good website, too).
Here are some references I used when trying this out.
- eidellev/inertia-adonisjs - The adapter repository.
- Adonis, Inertia, and Svelte by Eidellev - This one is kinda outdated, that’s why I made this post.
- danangponorogo/adonisvelnertia
Closing Note
Inertia is an interesting library indeed. It might not be suitable for every use case but if you want to build an app where you want to use a SPA library but don’t bother with fetching the data from the API then this is perfect for you.
Hopefully this post helped you and have a nice day! :)