Skip to content

Latest commit

 

History

History
432 lines (325 loc) · 12.7 KB

README.md

File metadata and controls

432 lines (325 loc) · 12.7 KB

Sidecar SSR for InertiaJS

🚨 This is currently very much in beta!

You can see a fully working Jetstream + Inertia + Sidecar demo repo at hammerstonedev/sidecar-inertia-demo.

Overview

This package provides a Sidecar function to run Inertia server-side rendering on AWS Lambda.

Sidecar packages, deploys, and executes AWS Lambda functions from your Laravel application.

It works with any Laravel 7 or 8 application, hosted anywhere including your local machine, Vapor, Heroku, a shared virtual server, or any other kind of hosting environment.

Both Webpack (Laravel Mix) and Vite are supported.

Installation

To require this package, run the following:

composer require hammerstone/sidecar-inertia

This will install Sidecar as well.

Using the Sidecar Gateway

Update your AppServiceProvider to use the SidecarGateway as the default Inertia SSR Gateway

namespace App\Providers;

use Hammerstone\Sidecar\Inertia\SidecarGateway;
use Illuminate\Support\ServiceProvider;
use Inertia\Ssr\Gateway;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // Use Sidecar to run Inertia SSR.
        $this->app->instance(Gateway::class, new SidecarGateway);
    }
}

Vite Instructions

If your app uses Webpack (Laravel Mix), skip to the Webpack Instructions.

Enabling SSR

If you just installed a fresh Laravel Jetstream app with the --ssr flag, you can skip this step.

Make sure that inertia/laravel-inertia is at least version 0.5.1.

Add @inertiaHead to the end of the <head> section of your app.blade.php file:

<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    ...
    @inertiaHead
  </head>
  <body>
    @inertia
  </body>
</html>

Publish the inertia.php config to your config folder if it doesn't exist: php artisan vendor:publish --provider="Inertia\ServiceProvider"

Updating Configuration

Update your config/inertia.php to include the Sidecar settings

<?php

return [
    'ssr' => [
        'enabled' => true,

        'sidecar' => [
            // The Sidecar function that handles the SSR for Vite builds.
            'handler' => \Hammerstone\Sidecar\Inertia\ViteSSR::class,
            
            // Log some stats on how long each Lambda request takes.
            'timings' => false,
            
            // Throw exceptions, should they occur.
            'debug' => env('APP_DEBUG', false),
            
            // Compile Ziggy routes with the Lambda function.
            'ziggy' => false
        ],
    ],

    // ...
];

Configuring Sidecar

If you haven't already, you'll need to configure Sidecar.

Publish the sidecar.php configuration file by running

php artisan sidecar:install

To configure your Sidecar AWS credentials interactively, you can run

php artisan sidecar:configure

The official Sidecar docs go into much further detail.

Now update your config/sidecar.php to include the function shipped with this package.

<?php

return [
    'functions' => [
        \Hammerstone\Sidecar\Inertia\ViteSSR::class
    ],
    
    // ...
];

Updating Your JavaScript

This only covers Vue3, please follow the Inertia docs for Vue2 or React, and please open any issues.

Update your vite.config.js to include the following. If you're using Ziggy, you'll want to uncomment the Ziggy stuff:

import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
    plugins: [
        laravel({
            input: "resources/js/app.js",
            ssr: "resources/js/ssr.js",
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
    // Uncomment the following if using Ziggy:
    // build: {
    //     rollupOptions: {
    //         external: ["./compiledZiggy.mjs"],
    //     },
    // },
    ssr: {
        noExternal: ["@inertiajs/server"],
    },
});

And update your resources/js/ssr.js to look something like this. The specifics may vary based on your application.

import { createSSRApp, h } from "vue";
import { renderToString } from "@vue/server-renderer";
import { createInertiaApp } from "@inertiajs/inertia-vue3";
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers";
// import { ZiggyVue } from "../../vendor/tightenco/ziggy/dist/vue.m";

const appName = "Laravel";

export async function handler(event) {
    // This is the file that Sidecar has compiled for us if
    // this application uses Ziggy. We import it using
    // this syntax since it may not exist at all.
    // const compiledZiggy = await import("./compiledZiggy.mjs");

    return await createInertiaApp({
        page: event,
        render: renderToString,
        resolve: (name) =>
            resolvePageComponent(
                `./Pages/${name}.vue`,
                import.meta.glob("./Pages/**/*.vue")
            ),
        setup({ app, props, plugin }) {
            // const Ziggy = {
            //     // Start with the stuff that may be baked into this Lambda.
            //     ...(compiledZiggy?.default || {}),

            //     // Then if they passed anything to us via the event,
            //     // overwrite everything that was baked in.
            //     ...event?.props?.ziggy,
            // };

            // // Construct a new location, since window.location is not available.
            // Ziggy.location = new URL(Ziggy.location);

            return createSSRApp({
                render: () => h(app, props),
            })
                .use(plugin)
                // .use(ZiggyVue, Ziggy);
        },
    });
}

Now, continue to Deploying Your SSR Function

Webpack Instructions

Enabling SSR

Following the official Inertia docs on enabling SSR is a good place to start, but there are a few things you can skip:

  • You do not need to npm install @inertiajs/server
  • You do not need to npm install webpack-node-externals
  • Come back here when you get to the "Building your application" section

Make sure that inertia/laravel-inertia is at least version 0.5.1.

Updating Configuration

Update your config/inertia.php to include the Sidecar settings

<?php

return [
    'ssr' => [
        'enabled' => true,

        'sidecar' => [
            // The Sidecar function that handles the SSR.
            'handler' => \Hammerstone\Sidecar\Inertia\SSR::class,
            
            // Log some stats on how long each Lambda request takes.
            'timings' => false,
            
            // Throw exceptions, should they occur.
            'debug' => env('APP_DEBUG', false),
            
            // Compile Ziggy routes with the Lambda function.
            'ziggy' => false
        ],
    ],

    // ...
];

Configuring Sidecar

If you haven't already, you'll need to configure Sidecar.

Publish the sidecar.php configuration file by running

php artisan sidecar:install

To configure your Sidecar AWS credentials interactively, you can run

php artisan sidecar:configure

The official Sidecar docs go into much further detail.

Now update your config/sidecar.php to include the function shipped with this package.

<?php

return [
    'functions' => [
        \Hammerstone\Sidecar\Inertia\SSR::class
    ],
    
    // ...
];

Updating Your JavaScript

This only covers Vue3, please follow the Inertia docs for Vue2 or React, and please open any issues.

You'll need to update your webpack.ssr.mix.js file. This should work for most cases, but please open any issues for errors you run into. (This is based on the Inertia docs, with slight modifications.)

const path = require('path')
const mix = require('laravel-mix')

mix
    .js('resources/js/ssr.js', 'public/js')
    .options({
        manifest: false
    })
    .vue({
        version: 3,
        useVueStyleLoader: true,
        options: {
            optimizeSSR: true
        }
    })
    .alias({
        '@': path.resolve('resources/js')
    })
    .webpackConfig({
        target: 'node',
        externals: {
            node: true,
            // Sidecar will ship a file called compiledZiggy as a part of
            // the package. We don't want webpack to try to inline it
            // because it doesn't exist at the time webpack runs.
            // './compiledZiggy': 'require("./compiledZiggy")'
        },
        resolve: {
            alias: {
                // Uncomment if you're using Ziggy.
                // ziggy: path.resolve('vendor/tightenco/ziggy/src/js'),
            },
        },
    })

And update your resources/js/ssr.js to look something like this. The specifics may vary based on your application. If you're using Ziggy, you'll want to uncomment the Ziggy stuff. (This is based on the Inertia docs, with slight modifications.)

import {createSSRApp, h} from 'vue'
import {renderToString} from '@vue/server-renderer'
import {createInertiaApp} from '@inertiajs/inertia-vue3'
// import route from 'ziggy';

exports.handler = async function (event) {
    // This is the file that Sidecar has compiled for us if
    // this application uses Ziggy. We import it using
    // this syntax since it may not exist at all.
    // const compiledZiggy = await import('./compiledZiggy');

    return await createInertiaApp({
        page: event,
        render: renderToString,
        resolve: (name) => require(`./Pages/${name}`),
        setup({app, props, plugin}) {
            // const Ziggy = {
            //     // Start with the stuff that may be baked into this Lambda.
            //     ...(compiledZiggy || {}),
            // 
            //     // Then if they passed anything to us via the event,
            //     // overwrite everything that was baked in.
            //     ...event?.props?.ziggy,
            // }

            // Construct a new location, since window.location is not available.
            // Ziggy.location = new URL(Ziggy.url)

            return createSSRApp({
                render: () => h(app, props),
            }).use(plugin).mixin({
                methods: {
                    // Use our custom Ziggy object as the config.
                    // route: (name, params, absolute, config = Ziggy) => route(name, params, absolute, config),
                },
            })
        },
    });
}

Deploying Your SSR Function

After you have added the SSR function to your sidecar.php, you should run php artisan sidecar:deploy --activate to deploy your function.

This will compile your JavaScript for you as a beforeDeployment hook, so you don't have to worry about remembering to do that first.

Debugging SSR

It's recommended that you deploy your Sidecar function locally so that you can test SSR more quickly. You can run php artisan sidecar:deploy --activate from your local machine and your SSR function will be deployed to Lambda.

You can also set ssr.sidecar.debug to true in your config/inertia.php file, so that Sidecar will throw exceptions when SSR fails instead of falling back to client-side rendering. This will help you diagnose issues quickly.

Ziggy (Optional)

If you are using Ziggy, you'll need to pass some Ziggy information along to your Lambda. You can do that by adding the following to your HandleInertiaRequests middleware.

class HandleInertiaRequests extends Middleware
{
    public function share(Request $request)
    {
        $ziggy = (new Ziggy())->toArray();

        // During development, send over the entire Ziggy object, so that
        // when routes change we don't have to redeploy.  In production,
        // only send the current URL, as we will bake the Ziggy config
        // into the Lambda SSR package.
        $ziggy = app()->environment('production') ? Arr::only($ziggy, 'url') : $ziggy;

        $ziggy = array_merge($ziggy, [
            'location' => $request->url()
        ]);
        
        return array_merge(parent::share($request), [
            'ziggy' => $ziggy
        ]);
    }
}