Drupal JS libraries
Overview
Drupal emits the JavaScript libraries attached to a rendered form, block or component as <drupal-library-*> custom elements. See Drupal JavaScript for what the backend sends and why; this page covers loading them in Nuxt.
Rendering library elements
Add a global drupal-library--default.vue component - the default component lookup resolves it for every drupal-library-* element, whatever library the backend attached. A reference implementation is part of the playground: drupal-library--default.vue.
The component is renderless: it takes the library, js and drupalSettings props of the element, hands them to useDrupalCe().loadLibrary() on mount, and renders nothing.
<script setup>
const props = defineProps({ js: Array, drupalSettings: String })
const { loadLibrary } = useDrupalCe()
onMounted(() => loadLibrary({ js: props.js, drupalSettings: props.drupalSettings }))
</script>
loadLibrary()
useDrupalCe().loadLibrary(library) takes a resolved library ({ js, drupalSettings }) and returns a promise settling once its files have loaded. On the server it resolves immediately - loading is a client-side concern.
It lazy-loads the actual loader via a dynamic import, so the loader chunk - and the Drupal JavaScript it pulls in - is only fetched by pages that actually render a library element. The loader then:
- resolves the file URLs against the configured
drupalBaseUrl, - appends them as
<script>tags, preserving execution order across all calls, so libraries load in the dependency order the backend resolved, - loads each URL only once, even when several libraries share a file,
- merges
drupalSettingsintowindow.drupalSettingsbefore any script runs, - calls
Drupal.attachBehaviors()once the batch has loaded, so behaviours attach to the server-rendered markup, - skips a file that fails to load with a console warning, rather than aborting the batch.
The attributes a library declares for its <script> tags are currently not applied.
Overriding or skipping a library
To replace a library with a native implementation, add a component named after its element tag - drupal-library-core-drupal-states.vue for core/drupal.states. It takes precedence over the default component, so the library's JavaScript is never loaded. A component that renders nothing and does nothing skips the library entirely.
Trying it out
The playground has a form whose conditional field is driven by core/drupal.states at /form/states, served by a mock Custom Elements API response - a working example of the whole path, from the emitted elements to the attached behaviour.