Server side rendering with Laravel + Inertia.js + Vue.js
Tags: laravel, vue, tailwindcss, inertiajs
Published: 2022-02-15 05:45:03

**Notice:** This is a guide for Laravel with Laravel Mix which is using Webpack under the hood. Soon I'll be writing a new one for Vite.

SEO is really important so you should have SSR (server side rendering) whenever you are building a SPA (single page application). This is not an issue if you are using Laravel's default templating system, which is Blade, because everything is rendered on the server and the result gets directly shipped into the browser.

In our case the rendering is done on the client side so our DOM is pretty empty. To solve this problem and make our website work even without Javascript enabled we'll need to somehow render everything on and the server side and serve all the resulted HTML on page-load.

Luckily Inertia ships with some tools to help us tackle this issue.

Let's add the following two packages to our project:
```
npm install @vue/server-renderer
npm install @inertiajs/server
```
We are not using `-D` or `--save-dev` flag on these 2 packages because we also need to run them on our production sever. As a general rule for `composer.json` and `package.json`, the packages that are installed inside `require-dev` respectively `devDependencies` should be used only in a development environment.

Next we need to create a server configuration file called `ssr.js` inside the same folder as our `app.js`, meaning `resources/js`. This file will look very similar to our `app.js` file, but instead  of being compiled and handled by the browser, it will be handled by Node.js.

Our `ssr.js` file should look like this:
```
import { createSSRApp, h } from "vue";
import { renderToString } from "@vue/server-renderer";
import { createInertiaApp, Link, Head } from "@inertiajs/inertia-vue3";
import createServer from "@inertiajs/server";

import { ZiggyVue } from "ziggy";
import { Ziggy } from "./ziggy";

createServer((page) =>
    createInertiaApp({
        page,
        render: renderToString,
        resolve: (name) => require(`./Pages/${name}`),
        setup({ app, props, plugin }) {
            return createSSRApp({
                render: () => h(app, props),
            })
                .use(plugin)
                .use(ZiggyVue, Ziggy)
                .component("Link", Link)
                .component("Head", Head);
        },
    })
);
```
Notice that instead of `createApp` we import `createSSRApp` from Vue and we're also wrapping our `createInertiaApp` method inside `createServer` method. We also no longer import Inertia's progress bar because that won't be ever used on server-side.

Next we'll need one more package to fully support our Node server:
```
npm install webpack-node-externals
```
Now we'll create a separate Webpack file called `webpack.ssr.mix.js` which will be used by our Node.js server to compile the resources.
```
const path = require("path");
const mix = require("laravel-mix");
const webpackNodeExternals = require("webpack-node-externals");

// Rezolve Ziggy
mix.alias({
    ziggy: path.resolve("vendor/tightenco/ziggy/dist/vue"),
});

// Build files
mix.options({ manifest: false })
    .js("resources/js/ssr.js", "public/js")
    .vue({ version: 3, options: { optimizeSSR: true } })
    .alias({ "@": path.resolve("resources/js") })
    .webpackConfig({
        target: "node",
        externals: [webpackNodeExternals()],
    })
    .version();
```
As you can see our `webpack.ssr.mix.js` file is really similar to `webpack.mix.js`. You'll need to always remember to also update your SSR webpack file everytime you update your default webpack file with something that can be used on the server-side. Now eveything that's gonna be used by our Node.js server will be bundled to `public/js/ssr.js`.

Now let's publish the Inertia's SSR config file...
```
php artisan vendor:publish --provider="Inertia\ServiceProvider"
```
...and enable the SSR in `config/inertia.php` by changing the `enabled` flag to `true`.

The only thing that's left to be done now is to compile and to spin up our Node.js server:
```
npx mix --mix-config=webpack.ssr.mix.js
node public/js/ssr.js
```
If everything's fine you should get a similar output:
```
Starting SSR server on port 13714...
Inertia SSR server started.
```

Now you can even disable the browser's Javascript and you'll still be able to navigate through the site because everything will be rendered on the server side by the Node.js server and served to your browser on page load.

That's pretty much it.

You can find everything we've talk about in Part 1 & 2 in this [repo](https://github.com/geowrgetudor/laravel-inertia-vue-ssr).

#### Support & follow me
| [![Buy me a coffee](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/geowrgetudor) | [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/geowrgetudor) | [![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/geowrgetudor) | [![Linkedin](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://linkedin.com/in/geowrgetudor) |
| ------------- | ------------- | ------------- | ------------- |