Skip to main content

Card Asset Dependencies

A console card can need scripts and stylesheets beyond the views toolkit. A datatables card needs jQuery, DataTables and Juneau's glue script. The card declares that need, and <@page> loads each asset once, in dependency order, after the body has rendered.

Toolkit packs​

A toolkit pack is a named list of CSS and JS assets. A pack can depend on other packs, and it has a kind:

  • VENDOR packs are libraries and their glue. Their CSS comes before the page css=, and their JS comes before every runtime script.
  • RUNTIME packs are Juneau UI runtimes. They keep the position the views pack always had.
PackKindLoadsDepends on
jqueryVENDORjquery.min.js (WebJar org.webjars:jquery)
datatablesVENDORdataTables.min.js, dataTables.dataTables.min.css (npm WebJars datatables.net, datatables.net-dt)jquery
datatables-glueVENDORjuneau-datatables.js (served by DataTablesMixin)datatables
datatables-buttonsVENDORdataTables.buttons.min.js, buttons.html5.min.js, buttons.dataTables.min.cssdatatables
viewsRUNTIMEthe views runtime
calendarRUNTIMEjuneau-calendar.js, juneau-calendar.css
xtermVENDORxterm.js, xterm.css (npm WebJar @xterm/xterm)
terminalRUNTIMEjuneau-terminal.js, juneau-terminal.css (served by TerminalMixin)views, xterm
chartsRUNTIMEjuneau-charts.js (served by ConsoleChromeMixin)
joblogRUNTIMEjuneau-joblog.js (served by ConsoleChromeMixin)

datatables-buttons gives copy and CSV export. Excel and PDF export need JSZip and pdfmake, which aren't included; register your own pack for them (below).

What a page loads​

<@page> loads the packs in toolkit=, plus the packs its cards require:

CardRequires
type="datatables"datatables-glue, plus joblog when its detail.region is a job-log region
type="html"nothing
type="terminal-view"nothing extra (its runtime ships in the views pack)
type="terminal"terminal (which pulls in views and xterm)
type="chart"charts
type="job-log"joblog

A card adds more with requires=:

<@card type="datatables" id="rel" requires="datatables-buttons">{ ... }</@card>

A card type can also require packs from the card's body: a CardTypeHandler overrides requiredPacks(JsonMap body) (empty by default), and the page unions what it returns with the type's packs and requires=. That is how a datatables card with a job-log detail region gets joblog without a requires=.

requires= takes a comma-separated string or a sequence. An unknown pack name fails the render with a 500 that names the card.

Each pack loads after the packs it depends on, and each asset loads once, however many cards need it. Markup outside a card records nothing. jcHasToolkit reports only toolkit=.

Serving the WebJars​

Compose WebJarsMixin (from juneau-rest-server) into the resource that serves the page. It serves /webjars/* from the classpath with a one-year immutable Cache-Control, and the URLs carry the WebJar version. juneau-console-datatables brings the WebJars in as dependencies.

@Rest(mixins={FreemarkerMixin.class, ViewsMixin.class, DataTablesMixin.class, WebJarsMixin.class})
public class PetConsole extends BasicRestServlet { ... }

If the host doesn't compose WebJarsMixin, the library URLs 404 and the table doesn't start.

Customizing​

All of this is on ConsoleFreemarkerMixin.Builder, and build() checks it: an unknown pack name, a cycle, or a VENDOR pack that depends on a RUNTIME pack fails the build.

ConsoleFreemarkerMixin.create()
.registerToolkitPack(ToolkitPack.create("datatables-export")
.js("/app/jszip.min.js", "/app/pdfmake.min.js", "/app/vfs_fonts.js")
.dependsOn("datatables-buttons")
.kind(ToolkitPack.Kind.VENDOR)
.resolver((req, path) -> req.getUriResolver().resolve("servlet:" + path))
.build())
.cardRequires("datatables", "datatables-export") // every datatables card
.providedPacks("jquery") // the chrome already loads jQuery
.build();
  • registerToolkitPack(ToolkitPack) adds a pack. A pack with a built-in name replaces it, including its dependencies, so registerToolkitPack(ToolkitPack.create("datatables")...) swaps in your own DataTables build. The (name, css, js) form registers a RUNTIME pack with no dependencies.
  • cardRequires(type, packs...) adds packs to every card of a type.
  • providedPacks(names...) names packs your chrome already loads. A provided pack loads nothing; its dependencies still load unless they're provided too.

If a page already loads a file through init= or css=, a pack asset with the same file name is skipped, and the log gets a WARN naming the template. A copy loaded through init= is not a bridge: it is skipped only when the file name matches, and the pack's other assets still load. An app that has its own copies of the libraries names the packs in providedPacks(...), or mounts WebJarsMixin and lets the packs load them.

Load order​

  1. <@head phase="before-page-css">, then VENDOR CSS, then the page css=, then RUNTIME CSS.
  2. juneau-console.js, then VENDOR JS (for a datatables card: jQuery, DataTables, juneau-datatables.js), then RUNTIME JS, then <@scripts phase="after-toolkit">, then init=.

See also​