ochrons / scalajs-spa-tutorial

Tutorial for creating a simple Single Page Application in ScalaJS
Apache License 2.0
672 stars 228 forks source link

Using Static (and Versioned) Assets in the Client #65

Open michaelahlers opened 7 years ago

michaelahlers commented 7 years ago

Is it possible to include static assets (namely images), served from Play and referenced from Scala.js code? Tricky because—when, for example, using sbt-digest to fingerprint assets—the final asset name isn't known and reverse Assets routes and AssetsFinder can't be used. Soliciting ideas or guidance here since my searches haven't turned up anything.

michaelahlers commented 7 years ago

Applying broadly to any Play project (not specific to Scala.js), the only way I've found to provide versioned assets to stylesheets and inline images involves adding a plugin which rewrites paths.

  1. Server and client projects as illustrated by this project.
  2. Play's configured with:
    1. The usual sbt-less and sbt-digest plugins
    2. Versioned asset routes.
    3. Also, now, with sbt-simple-url-update.
  3. Stylesheet, owned by Play, defining classes with the content property referencing a static image in the server project à la:
    img.my-logo {
      /* Not widely compatible; most common case is likely to provide a background. */
      content: url("path/to/my-logo.png");
    }
  4. Client project assigning that class to img tags à la (VDOM in this case):
    // Again, probably an uncommon usage.
    img(className := "my-logo")
  5. When staging, sbt-simple-url-update will notice the url data type in CSS file (which is itself fingerprinted) and rewrite it with the fingerprinted asset yielding:
    img.my-logo {
      content: url("path/to/ba35502b60181156f7e9d6c7341b64f8-my-logo.png");
    }
  6. Image appears as expected in the browser—even in production mode.

This isn't great. Have I missed anything obvious? I can't find any documentation offering a better way to reference versioned assets from CSS in a Play project.

And, while functional, this removes images from the client project (which runs afoul of locality, unless, of course, you consider it a handy way to share assets across multiple client apps. hosted by the same Play instance). I'd rather the client app. project own all its static assets (and kept close to the components referencing or styled with them).