Assets

app/js Modules

Keep application browser modules in app/js and load them through the generated importmap.

By Guillermo Alvarez - Published - Updated

Keep source outside public files

Application JavaScript source lives under app/js:

app/js/app.js
app/js/controllers/hello_controller.js

Generated browser assets live under public files:

app/public/assets/importmap.json
app/public/assets/lazyshaft/

lazy js reads the source files, writes content-hashed public outputs, and maps stable browser specifiers to those outputs.

Load the app entry

The layout inlines the importmap before importing the app module:

{{importmap "/assets/importmap.json"}}
<script type="module">import "/js/app.js"</script>

The generated importmap can map /js/app.js to a hashed lazyshaft file:

{
  "imports": {
    "/js/app.js": "/assets/lazyshaft/app/app-ZWUSRUPQ.js"
  }
}

Templates keep using the stable /js/app.js specifier while browsers receive the fingerprinted asset.

Import Turbo and Stimulus

The app entry may use GoLazy source directives:

// golazy:turbo
// golazy:stimulus

// golazy:turbo expands to:

import "@hotwired/turbo"

// golazy:stimulus imports Stimulus, starts the application, scans app/js/controllers/**/*_controller.js, and registers each controller.

Add a Stimulus controller

Create a controller source file:

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    this.element.dataset.ready = "true"
  }
}

For this file:

app/js/controllers/hello_controller.js

GoLazy registers the identifier:

hello

Nested directories use --, and underscores in filenames become dashes.

Use lazy js for the manifest, library bundles, workers, copied assets, and generated outputs.