Display schemas
Druxt turns Drupal's display modes into field schemas, so each component renders the right fields and asks JSON:API for only those.
After routing resolves which entity to render, the next question is which fields, in what order, with what settings. Druxt's answer is unusual: it doesn't invent a frontend field configuration, it reads Drupal's display modes. A display mode is Drupal's saved, per-view configuration of which fields appear, in what order, with which formatter and settings, managed by site builders in the admin UI.
The druxt-schema package turns view modes and form modes into
schemas: plain objects describing the fields to render and the
components to render them with.
An example schema
A schema for an article's teaser view mode looks conceptually like:
{
id: 'node--article--teaser--view',
resourceType: 'node--article',
config: { mode: 'teaser', schemaType: 'view' },
fields: {
field_image: {
id: 'field_image',
type: 'image', // the Drupal field formatter id
weight: 0,
label: { text: 'Image', position: 'hidden' },
settings: { /* formatter settings */ },
},
// ...
},
}Each field entry has the formatter and its settings from Drupal, in
weight order. Entity components turn each field's formatter type into a
DruxtField* component (an image formatter becomes DruxtFieldImage),
so the field order and configuration in the schema is what renders on the
page.
Where schemas come from
DruxtSchema reads Drupal's entity_view_display and
entity_form_display config entities over JSON:API: the same entities
that power Drupal's own Manage display screens. A schema is assembled
per combination of entity type, bundle, display mode, and (where relevant)
form or view variant, then cached in its own Vuex store.
A site builder rearranging fields in Drupal changes the decoupled frontend too, since both read the same source of truth.
When schemas are generated
druxt-schema builds every schema during Nuxt's builder:prepared hook,
once, when nuxt dev or nuxt build starts, and writes each one to a
static schemas/<id>.json file. At runtime, $druxtSchema.import(id) reads
that file.
By default that is the only time Drupal is asked. Rearranging fields,
changing a formatter, or adding a view mode in Drupal does not reach the
frontend until you restart nuxt dev or rebuild. This surprises people because content
changes update live but display-mode changes don't: they run through
entirely different paths.
druxt.schema.refresh, off by default, removes the restart on a Nuxt
server. The server regenerates a schema after each cache clear, the first time a
page needs it, and holds it until the next clear. Under nuxt dev every
request regenerates, as there is no cache to clear. The browser fetches
the schema from the server at /_druxt/schema/<id>, and the schema from
the build is used whenever regeneration fails. A generated static site
still needs a rebuild, unless its own Node server serves the schema route
with createSchemaRefresh from druxt-schema. Cache Drupal responses on
the Nuxt server covers the clear that triggers it. In
nuxt.config.js:
// nuxt.config.js
export default {
druxt: {
schema: { refresh: true },
},
}Schemas shape the queries, not just the rendering
A less visible role: schemas narrow the JSON:API query. Rendering only
needs the fields the display includes, so the fetch can add a
fields[node--article]=... filter derived from the schema. Less data
crosses the wire, and because the store distinguishes
partial from full resources, those slim
fetches cache as partial, not as complete resources.
The entity module enables this with:
// nuxt.config.js
export default {
druxt: {
entity: {
query: { schema: true },
},
},
}Field components
Rendering a field means choosing a component for its formatter. The schema
system maps Drupal field formatters to DruxtField* components: an image
field with an image formatter becomes DruxtFieldImage, a text field with
the default formatter becomes DruxtFieldTextDefault, and so on. As with
everything Druxt, the chosen component is then themeable via the
suggestion system: you override the
rendering, not the mapping.
Why display modes?
Display modes are where Druxt starts, not a rule it enforces. They come with a UI, per-bundle and per-mode overrides, third-party settings from contrib, and a decade of Drupal muscle memory. A site that follows them gets a frontend that changes when site builders change Drupal, with no second field configuration to keep in step.
Each entity's wrapper component decides how much of that to use. The
default slot renders every field in the display mode's order. Each field
also has a slot of its own, so a wrapper can pick fields and place them
where it wants. A wrapper can also render the entity's data directly and
leave the schema out, with query.fields setting which fields Druxt
fetches. Component resolution
explains how a wrapper is picked for an entity type, bundle and mode.
Following display modes depends on their config being present and correct on the backend. A wrapper that replaces them makes its own field choices instead.