Skip to content

v1.2.0

Choose a tag to compare

@DominusKelvin DominusKelvin released this 22 Feb 03:45

inertia-sails v1.2.0

Locals — Sails-idiomatic view data

This release replaces the viewData API with locals, aligning inertia-sails with how Sails.js natively handles view data. In Sails, the second argument to res.view() is an object of locals — each key becomes a top-level variable in your EJS template. inertia-sails now works the same way.

What changed

The viewData key in action returns is now locals:

// Before
return {
  page: 'courses/show',
  props: { course },
  viewData: {
    title: course.title,
    description: course.description,
    ogImage: course.thumbnailUrl
  }
}

// After
return {
  page: 'courses/show',
  props: { course },
  locals: {
    title: course.title,
    description: course.description,
    ogImage: course.thumbnailUrl
  }
}

The API methods on sails.inertia have been renamed:

Before After
sails.inertia.viewData(key, value) sails.inertia.local(key, value)
sails.inertia.viewDataGlobally(key, value) sails.inertia.localGlobally(key, value)
sails.inertia.getViewData(key) sails.inertia.getLocals(key)

Locals are now spread directly into res.view()

Previously, all view data was nested under a viewData key, requiring awkward access patterns in EJS:

<!-- Before: nested, requires typeof guard -->
<title><%= typeof viewData !== 'undefined' && viewData.title ? viewData.title : 'My App' %></title>

Now locals are spread directly, so each one is a first-class EJS variable. Use the built-in locals object for safe access with fallbacks:

<!-- After: clean, idiomatic EJS -->
<title><%= locals.title || 'My App' %></title>

Three ways to set locals

From actions — the most common pattern:

return {
  page: 'blog/show',
  props: { post },
  locals: {
    title: `${post.title} | My Blog`,
    description: post.excerpt,
    ogImage: post.coverImageUrl
  }
}

From hooks/middleware — for request-scoped values (concurrency-safe via AsyncLocalStorage):

sails.inertia.local('canonicalUrl', `https://myapp.com${req.path}`)

Globally — for app-wide defaults set once at boot:

sails.inertia.localGlobally('title', 'My App')
sails.inertia.localGlobally('ogImage', '/images/default-og.png')

Locals merge in precedence order: global → request-scoped → action (last wins).

Migration guide

  1. Update inertia-sails

    npm install inertia-sails@1.2.0
  2. Rename viewData to locals in action returns

    Find and replace viewData: with locals: in your controllers.

  3. Rename API calls

    Find Replace with
    sails.inertia.viewData( sails.inertia.local(
    sails.inertia.viewDataGlobally( sails.inertia.localGlobally(
    sails.inertia.getViewData( sails.inertia.getLocals(
  4. Update views/app.ejs

    Replace viewData.x references with locals.x:

    <!-- Before -->
    <title><%= typeof viewData !== 'undefined' && viewData.title ? viewData.title : 'My App' %></title>
    <meta name="description" content="<%= typeof viewData !== 'undefined' && viewData.description ? viewData.description : '' %>" />
    
    <!-- After -->
    <title><%= locals.title || 'My App' %></title>
    <meta name="description" content="<%= locals.description || '' %>" />

Breaking changes

  • viewData key in action returns no longer recognized — use locals
  • sails.inertia.viewData() removed — use sails.inertia.local()
  • sails.inertia.viewDataGlobally() removed — use sails.inertia.localGlobally()
  • sails.inertia.getViewData() removed — use sails.inertia.getLocals()
  • viewData is no longer passed as a nested object to res.view() — locals are spread directly

Documentation

Full Changelog: v1.1.0...v1.2.0