FORGEBOX Enterprise 🚀 - Take your ColdFusion (CFML) Development to Modern Times! Learn More...

cbInertia

v3.0.0 Modules

cbInertia

Master Branch Build Status

The ColdBox adapter for Inertia.js

What is Inertia.js?

Inertia.js lets you, in its own words, "quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers." Using Inertia.js is like using your favorite MVC server-side framework (ColdBox, of course) with Vue as the templating language - no need to build a separate API. You can learn all about Inertia.js on their website.

What is this module for?

This module provides the needed lifecycle and ajax responses to integrate Inertia.js into a ColdBox app on the server. It will let you render Inertia responses, both for the initial page visit and subsequent client-side transitions, as well as share data on every Inertia request.

Requirements, Installation, and Configuration

cbInertia requires ColdFusion 2016+ or Lucee 5+ and ColdBox 5.6.0+.

Install cbInertia into your ColdBox project using CommandBox.

box install cbInertia

By default, no configuration is needed. However, you can disable the automatic registering of the InertiaLifecycle interceptor, the cbInertia application helper, or the Controller decorator if you wish. You can also customize the view arguments for Inertia events.

The one setting you will likely modify is the version setting. You can read more about it below.

// config/ColdBox.cfc
moduleSettings = {
    "cbInertia": {
        "autoRegisterInterceptor": true,
        "autoRegisterHelpers": true,
        "autoRegisterControllerDecorator": true,
        "defaultViewArgs": {
            "view": "main/index",
            "module": "cbInertia"
        },
        "version": function() {
            return "";
        }
    }
}

Usage

You use cbInertia from your handlers/controllers. You can either inject the Inertia model using the Inertia@cbInertia dsl or you can use the automatically loaded (by default) helper: inertia(). We'll cover both use cases, but the choice is just a matter of style preference.

Once available in your handler, you render an Inertia route using the render method.

render

NameTypeRequiredDefaultDescription
componentstringtrue The component name to render.
propsstructfalse{}Any props to inject in to the component. Any props passed will be serialized to json.
// handlers/Users.cfc
component {

    property name="inertia" inject="@cbInertia";

    function index( event, rc, prc ) {
        inertia.render( "Users/Index", {
            "users" = [ /* ... */ ]
        } );
    }

}

You can get an instance of Inertia by calling the inertia() helper function.

// handlers/Users.cfc
component {

    function index( event, rc, prc ) {
        inertia().render( "Users/Index", {
            "users" = [ /* ... */ ]
        } );
    }

}

Since render is the most common method called, you can pass the arguments to render directly to the inertia() helper function.

// handlers/Users.cfc
component {

    function index( event, rc, prc ) {
        inertia( "Users/Index", {
            "users" = [ /* ... */ ]
        } );
    }

}

The other Inertia method you will use is the share method:

share

NameTypeRequiredDefaultDescription
keystringtrue The key name for the shared property.
valueanytrue The shared property value. This can also accept a closure. Closures will be evaluated just prior to rendering.

The share method is used for values that should be available on every Inertia render. A common example of this is the authenticated user (or null if there is none). You can set up an interceptor to share your global values, and they will be available on every Inertia render as a prop.

inertia.share( "user", function() {
    return auth.check() ? // auth == cbauth
        auth.user().loadRelationship( "account" ).getMemento() :
        javacast( "null", "" );
} );

You can call share as many times as you need.

Customizing the Inertia View

The default view that ships with cbInertia suits most use cases. If you need to use a different view for any reason, you can customize the view arguments sent to the setView function using the defaultViewArgs setting.

moduleSettings = {
    "cbInertia": {
        "defaultViewArgs": {
            "view": "custom/view/page"
        }
    }
};

Controller Decorator

Inertia automatically registers a Controller decorator by default. This decorator is used to automate setting the status code for redirects for PUT, PATCH, and DELETE verbs to 303. (See here.)

If you choose not to use the controller decorator, you will need to ensure that redirects from PUT, PATCH, and DELETE actions return a 303 status code.

relocate( event = "home.index", statusCode = 303 );

Code Splitting and ColdBox Elixir Integration

Using Pages creates a natural code splitting point. You can reduce the javascript your users have to initially download and speed up your site by only delivering the javascript for the page they are requesting. You can do this with ColdBox Elixir.

Here is an example client-side boilerplate for Vue.js

import Vue from "vue";
import VueMeta from "vue-meta";
import PortalVue from "portal-vue";
import { InertiaApp } from "@inertiajs/inertia-vue";

Vue.config.productionTip = false;
Vue.use(InertiaApp);
Vue.use(PortalVue);
Vue.use(VueMeta);

let app = document.getElementById("app");

new Vue({
  metaInfo: {
    title: "Loading...",
    titleTemplate: "%s | My Inertia.js App"
  },
  render: h =>
    h(InertiaApp, {
      props: {
        initialPage: JSON.parse(app.dataset.page),
        resolveComponent: name =>
          import(
            /* webpackChunkName: "includes/js/pages/[request]" */ `@/Pages/${name}`
          ).then(module => module.default)
      }
    })
}).$mount(app);

The webpackChunkName will create each of the pages in a includes/js/pages directory and use the current chunk name in place of [request].

Additionally, you need to add a bit of Webpack config to combine the shared parts of your pages together. For instance, if two pages each import a Button component you have, you want a shared module for those components.

The configuration sample here will pull out all shared components from your Pages directory into one file. You can tweak the configuration if your needs are different:

const elixir = require("coldbox-elixir");

elixir.config.mergeConfig({
  optimization: {
    splitChunks: {
      cacheGroups: {
        shared: {
          chunks: "async",
          minChunks: 2,
          name: "includes/js/pages/shared"
        }
      }
    }
  }
});

module.exports = elixir(mix => {
  mix.css("app.css");
  mix.vue("app.js");
});

versioning

cbInertia follows the Inertia.js spec for versioning. If you are using ColdBox Elixir, use the following function as the value for version in your config/ColdBox.cfc:

moduleSettings = {
    "cbInertia": {
        "version": function() {
            return hash( fileRead( "/includes/rev-manifest.json" ) );
        }
    }
};

If you are using versioning with ColdBox Elixir (which is the default for a production build), this will return a unique version string for cbInertia to compare.

v3.0.0

24 Aug 2023 — 02:32: 35 UTC

BREAKING

  • CI: Drop support for adobe@2016 (dd52dc3)

chore

  • CI: Update testing matrix (f52e1ca)
  • CI: Migrate from Travis to GitHub Actions (a595523)
  • Tests: Re-enable getFullUrl expectations (474ce0b)

feat

  • testing: Add TestBox Matchers (a3c7579)
  • ModuleConfig: Move defaultViewArgs to a module setting (f55f374)
  • InertiaLifecycle: Allow for partial reloading (7df586e)
  • Versioning: Follow Inertia.js spec on versioning (c4ae40f)
  • ModuleConfig: Add toggles for automatic registering of interceptors and helpers (7ccb0f9)
  • Props: Resolve closures in props before rendering (7ed313e)

fix

  • InertiaLifecycle: Allow null values as props (ee04d75)

other

  • *: chore: Pin commandbox-semantic-release to ^3.0.0 (6b66c69)
  • *: chore: Pin commandbox-semantic-release to ^3.0.0 (d1a597c)
  • *: chore: Update repository links to coldbox-modules org (fe79e22)
  • *: fix: Update arguments in controller decorator (dae38b9)
  • *: Merge branch 'coldbox_6' (b5d7394)
  • *: fix: Updates for coldbox@6 (a28dd96)
  • *: Merge pull request #3 from shreddtech/master (91f2a39)
  • *: update readme (2b99edb)
  • *: chore: Use forgeboxStorage (19cec2b)
  • *: chore: Format to 80 column max width (a43c6c8)
  • *: fix: Better resolveClosures handling of arrays (7a7b7ca)
  • *: chore: Add automatic formatting with cfformat (686d830)
  • *: feat: Automatically use a 303 status code where required (62bbb31)
  • *: docs: Document cbInertia (384c287)
  • *: feat: Initial commit (24feb4e)
  • *: build: Enable commandbox-semantic-release (b9cb566)
  • *: Initial commit (1ca8877)

v1.5.0

27 May 2020 — 05:31: 03 UTC

chore

  • Tests: Re-enable getFullUrl expectations (474ce0b)

feat

  • ModuleConfig: Move defaultViewArgs to a module setting (f55f374)
  • InertiaLifecycle: Allow for partial reloading (7df586e)
  • Versioning: Follow Inertia.js spec on versioning (c4ae40f)
  • ModuleConfig: Add toggles for automatic registering of interceptors and helpers (7ccb0f9)
  • Props: Resolve closures in props before rendering (7ed313e)

other

  • *: Merge branch 'coldbox_6' (b5d7394)
  • *: fix: Updates for coldbox@6 (a28dd96)
  • *: Merge pull request #3 from shreddtech/master (91f2a39)
  • *: update readme (2b99edb)
  • *: chore: Use forgeboxStorage (19cec2b)
  • *: chore: Format to 80 column max width (a43c6c8)
  • *: fix: Better resolveClosures handling of arrays (7a7b7ca)
  • *: chore: Add automatic formatting with cfformat (686d830)
  • *: feat: Automatically use a 303 status code where required (62bbb31)
  • *: docs: Document cbInertia (384c287)
  • *: feat: Initial commit (24feb4e)
  • *: build: Enable commandbox-semantic-release (b9cb566)
  • *: Initial commit (1ca8877)

v1.4.2

13 Feb 2020 — 17:33: 35 UTC

other

  • *: chore: Use forgeboxStorage (19cec2b)

v1.4.1

31 Jan 2020 — 18:54: 01 UTC

other

  • *: chore: Format to 80 column max width (a43c6c8)
  • *: fix: Better resolveClosures handling of arrays (7a7b7ca)

v1.4.0

29 Jan 2020 — 06:26: 43 UTC

feat

  • ModuleConfig: Move defaultViewArgs to a module setting (f55f374)

v1.3.0

28 Jan 2020 — 07:30: 07 UTC

feat

  • InertiaLifecycle: Allow for partial reloading (7df586e)
  • Versioning: Follow Inertia.js spec on versioning (c4ae40f)

other

  • *: chore: Add automatic formatting with cfformat (686d830)

v1.2.1

22 Jan 2020 — 21:04: 19 UTC

other

  • *: feat: Automatically use a 303 status code where required (62bbb31)

v1.2.0

31 Dec 2019 — 17:03: 59 UTC

chore

  • Tests: Re-enable getFullUrl expectations (474ce0b)

feat

  • ModuleConfig: Add toggles for automatic registering of interceptors and helpers (7ccb0f9)

other

  • *: docs: Document cbInertia (384c287)

v1.1.0

24 Dec 2019 — 05:38: 10 UTC

feat

  • Props: Resolve closures in props before rendering (7ed313e)

v1.0.0

16 Aug 2019 — 20:28: 55 UTC

other

  • *: feat: Initial commit (24feb4e)
  • *: build: Enable commandbox-semantic-release (b9cb566)
  • *: Initial commit (1ca8877)

$ box install cbInertia

No collaborators yet.
     
  • {{ getFullDate("2019-08-16T15:28:56Z") }}
  • {{ getFullDate("2023-08-24T02:32:37Z") }}
  • 4,543
  • 4,739