Skip to content

A Nuxt module to easily connect Drupal via custom elements.

License

Notifications You must be signed in to change notification settings

drunomics/nuxtjs-drupal-ce

Repository files navigation

nuxtjs-drupal-ce - Nuxt Drupal Custom Elements Connector

npm version npm downloads ci codecov License

Connects Nuxt v3 with Drupal via the Lupus Custom Elements Renderer

Please refer to https://www.drupal.org/project/lupus_decoupled for more info.

The 2.x version of the module is compatible with Nuxt 3. For a Nuxt 2 compatible version, please checkout the 1.x version

Pre-requisites

Setup

  1. Go to your Nuxt project. If necessary, start a new one:
npx nuxi@latest init <project-name>
  1. Add the nuxtjs-drupal-ce module to your Nuxt project
npx nuxi@latest module add drupal-ce
  1. Configure nuxtjs-drupal-ce in your nuxt.config.js
export default defineNuxtConfig({
  modules: [
    'nuxtjs-drupal-ce',
  ],
  drupalCe: {
    drupalBaseUrl: 'https://your-drupal.example.com',
    // more options...
  }
})

The module defaults work well with Lupus Decoupled Drupal - in that case setting the drupalBaseUrl is enough to get started.

  1. Scaffold initial files. After scaffolding, edit them as suiting.
rm -f app.vue && npx nuxt-drupal-ce-init

Features

  • Fetches pages via the custom elements API provided by the Lupus Custom Elements Renderer
  • Provides a Nuxt-wildcard route, so all Drupal pages can be rendered via Nuxt.js and vue-router.
  • Integrates page metadata and the page title with Nuxt.
  • Supports breadcrumbs and local tasks ("Tabs")
  • Supports authenticated requests. Cookies are passed through to Drupal by default.
  • Supports display of Drupal messages in the frontend.
  • Provides unstyled skeleton components for getting started quickly.
  • Supports fetching and display of Drupal menus via the Rest menu items module.

Options

  • drupalBaseUrl: The Drupal base URL, e.g. https://example.com:8080. Required.

  • serverDrupalBaseUrl: Optionally, an alternative drupal base URL to apply in server context.

  • ceApiEndpoint: The custom elements API endpoint. Defaults to /ce-api.

  • fetchOptions: The default fetchOptions to apply when fetching from the Drupal. Defaults to { credentials: 'include' }.

  • fetchProxyHeaders: The HTTP request headers to pass through to Drupal, via useRequestHeaders. Defaults to ['cookie'].

  • menuEndpoint: The menu endpoint pattern used for fetching menus. Defaults to 'api/menu_items/$$$NAME$$$' as fitting to the API provided by the Rest menu items Drupal module. $$$NAME$$$ is replaced by the menu name being fetched.

  • menuBaseUrl: The menu base URL. Defaults to drupalBaseUrl + ceApiEndpoint.

  • addRequestContentFormat: If specified, the given value is added as _content_format URL parameter to requests. Disabled by default.

  • addRequestFormat: If set to true, the _format=custom_elements URL parameter is added automatically to requests. Defaults to false.

  • customErrorPages: By default, error pages provided by Drupal (e.g. 403, 404 page) are shown, while keeping the right status code. By enabling customErrorPages, the regular Nuxt error pages are shown instead, such that the pages can be customized with Nuxt. Defaults to false.

  • useLocalizedMenuEndpoint: If enabled, the menu endpoint will use a language prefix as configured by nuxtjs/i18n module. Defaults to true.

  • serverApiProxy: If enabled, the module will create a Nitro server handler that proxies API requests to Drupal backend. Defaults to true for SSR (it's disabled for SSG).

  • passThroughHeaders: Response headers to pass through from Drupal to the client. Defaults to ['cache-control', 'content-language', 'set-cookie', 'x-drupal-cache', 'x-drupal-dynamic-cache']. Note: This is only available in SSR mode.

  • serverLogLevel: The log level to use for server-side logging. Defaults to 'info'. Options:

    • false: The server plugin will not be loaded, keeps the default Nuxt error logging.
    • 'info': Log all server requests and errors.
    • 'error': Log only errors.
  • disableFormHandler: If set to true, the form handler middleware will be disabled. Defaults to false.

Overriding options with environment variables

Runtime config values can be overridden with environment variables via NUXT_PUBLIC_ prefix. Supported runtime overrides:

  • drupalBaseUrl -> NUXT_PUBLIC_DRUPAL_CE_DRUPAL_BASE_URL
  • serverDrupalBaseUrl -> NUXT_PUBLIC_DRUPAL_CE_SERVER_DRUPAL_BASE_URL
  • menuBaseUrl -> NUXT_PUBLIC_DRUPAL_CE_MENU_BASE_URL
  • ceApiEndpoint -> NUXT_PUBLIC_DRUPAL_CE_CE_API_ENDPOINT

Rendering custom elements

Generally, custom elements are rendered as dynamic components and simply need to be registered as global components.

The components should be placed in ~/components/global, refer to the /playground directory for an example. For example, for the custom element node-article-teaser a global component node-article-teaser.vue would be picked up for rendering.

Naming recommendation

We recommend to name the components lowercase using kebap-case, such that there is a clear 1:1 mapping between custom element names used in the API response and the frontend components. For example use custom-element-name.vue instead of CustomElementName.vue. Both variants work though.

Default components (JSON only)

When using JSON-based rendering of custom elements, the module offers fallback component support. If a custom element lacks a corresponding Vue component, the module attempts to find a suitable default component.

How it works:

  1. The module removes the last --separated prefix from the element name.
  2. It then appends a --default suffix.
  3. If this modified component exists, it's used for rendering.
  4. If the component is not exiting, the process is repeated.

This approach allows for generic default components like drupal-form--default.vue to be used for specific elements such as drupal-form-user-login-form.vue. For customization, developers can simply copy and modify the default component as needed.

Example lookup process

When a specific component isn't found, the module searches for a default component by progressively removing segments from the custom element name. For example when rendering the custom element node-custom-view it looks for components in the following order:

x node-custom-view.vue
x node-custom-view--default.vue
x node-custom--default.vue
✓ node--default.vue

Deprecated options

The following options are deprecated and only there for improved backwards compatibility.

  • baseURL: The base URL of the Drupal /ce-api endpoint, e.g. http://localhost:8888/ce-api. If set, drupalBaseUrl is set with the origin of the provided URL.

Error handling

The module provides a default error handler for the fetchPage and fetchMenu methods:

  • fetchPage: Throws an error with the status code and message provided by Drupal.
  • fetchMenu: Logs an error message to the console and displays a message in the frontend.

Customizing error handling

You have the option to override the default error handlers by using a parameter when calling the fetch methods.

  • fetchPage:

    <script lang="ts" setup>
      const { fetchPage } = useDrupalCe()
    
      function customPageError (error: Record<string, any>) {
        throw createError({ statusCode: error.value.statusCode, statusMessage: 'No access.', data: {}, fatal: true })
      }
      const page = await fetchPage(useRoute().path, { query: useRoute().query }, customPageError)
    </script>
  • fetchMenu:

    <script lang="ts" setup>
      const { fetchMenu } = useDrupalCe()
      const { getMessages } = useDrupalCe()
      const messages = getMessages()
    
      function customMenuError (error: Record<string, any>) {
        messages.value.push({
          type: 'error',
          message: `Menu error: Unavailable. ${error.value.statusCode}`
        })
      }
      const mainMenu = await fetchMenu('main', {}, customMenuError)
    </script>

Note: The error parameter is optional and can be omitted.

Previous options not supported in 2.x version

The following options were support in 1.x but got dropped:

  • addVueCompiler: This is necessary if you want to render custom elements markup on runtime; i.e. use the 'markup' content format. Instead, the vue runtime compiler can be enabled in via Nuxt config, see here.

  • axios: Options to pass-through to the drupal-ce axios instance. Use fetchOptions instead.

Development

  1. Clone this repository.
  2. Install dependencies using npm install.
  3. Run npm run dev:prepare to generate type stubs.
  4. Use npm run dev to start playground in development mode.
  5. Update baseURL setting in Nuxt config with Lupus Decoupled Drupal instance URL and append the API-prefix /ce-api, e.g. https://8080-shaal-drupalpod-8m3z0ms7mb6.ws-eu67.gitpod.io/ce-api

Run on StackBlitz

  1. Launch it on StackBlitz
  2. Update baseURL setting in Nuxt config with Lupus Decoupled Drupal instance URL and append the API-prefix /ce-api, e.g. https://8080-shaal-drupalpod-8m3z0ms7mb6.ws-eu67.gitpod.io/ce-api

License

MIT License

Credits

Development sponsored by drunomics hello@drunomics.com