nuxtjs-drupal-ce
Advanced tools
Comparing version 2.0.0 to 2.1.0
@@ -12,3 +12,3 @@ import * as _nuxt_schema from '@nuxt/schema'; | ||
customErrorPages: boolean; | ||
fetchOptions: Object; | ||
fetchOptions: object; | ||
fetchProxyHeaders: string[]; | ||
@@ -21,4 +21,4 @@ useLocalizedMenuEndpoint: boolean; | ||
} | ||
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>; | ||
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>; | ||
export { type ModuleOptions, _default as default }; |
@@ -5,9 +5,9 @@ { | ||
"compatibility": { | ||
"nuxt": "^3.7.0" | ||
"nuxt": ">=3.7.0" | ||
}, | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"builder": { | ||
"@nuxt/module-builder": "0.7.0", | ||
"@nuxt/module-builder": "0.8.3", | ||
"unbuild": "2.0.0" | ||
} | ||
} |
import type { $Fetch, NitroFetchRequest } from 'nitropack'; | ||
import type { UseFetchOptions } from '#app'; | ||
export declare const useDrupalCe: () => { | ||
$ceApi: (fetchOptions?: UseFetchOptions<any>) => $Fetch<unknown, NitroFetchRequest>; | ||
useCeApi: (path: string | Ref<string>, fetchOptions?: UseFetchOptions<any>, doPassThroughHeaders?: boolean) => Promise<any>; | ||
fetchPage: (path: string, useFetchOptions?: UseFetchOptions<any>, overrideErrorHandler?: ((error?: any) => void) | undefined) => Promise<any>; | ||
fetchMenu: (name: string, useFetchOptions?: UseFetchOptions<any>, overrideErrorHandler?: ((error?: any) => void) | undefined) => Promise<any>; | ||
fetchPage: (path: string, useFetchOptions?: UseFetchOptions<any>, overrideErrorHandler?: (error?: any) => void) => Promise<any>; | ||
fetchMenu: (name: string, useFetchOptions?: UseFetchOptions<any>, overrideErrorHandler?: (error?: any) => void) => Promise<any>; | ||
getMessages: () => Ref; | ||
getPage: () => Ref; | ||
renderCustomElements: (customElements: Record<string, any> | Array<Object>) => any; | ||
renderCustomElements: (customElements: Record<string, any> | Array<object>) => any; | ||
passThroughHeaders: (nuxtApp: any, pageHeaders: any) => void; | ||
@@ -14,2 +15,3 @@ getCeApiEndpoint: (localize?: boolean) => any; | ||
getMenuBaseUrl: () => any; | ||
getPageLayout: (page: Ref<any>) => ComputedRef<string>; | ||
}; |
@@ -1,6 +0,6 @@ | ||
import { callWithNuxt } from "#app"; | ||
import { defu } from "defu"; | ||
import { appendResponseHeader } from "h3"; | ||
import { getDrupalBaseUrl, getMenuBaseUrl } from "./server.js"; | ||
import { useRuntimeConfig, useState, useFetch, navigateTo, createError, h, resolveComponent, setResponseStatus, useNuxtApp, useRequestHeaders, ref, watch } from "#imports"; | ||
import { callWithNuxt } from "#app"; | ||
import { useRuntimeConfig, useState, useFetch, navigateTo, createError, h, resolveComponent, setResponseStatus, useNuxtApp, useRequestHeaders, ref, watch, useRequestEvent, computed } from "#imports"; | ||
export const useDrupalCe = () => { | ||
@@ -75,4 +75,27 @@ const config = useRuntimeConfig().public.drupalCe; | ||
})); | ||
const serverResponse = useState("server-response", () => null); | ||
useFetchOptions.key = `page-${path}`; | ||
const { data: page, error } = await useCeApi(path, useFetchOptions, true); | ||
const page = ref(null); | ||
const pageError = ref(null); | ||
if (import.meta.server) { | ||
serverResponse.value = useRequestEvent(nuxtApp).context.drupalCeCustomPageResponse; | ||
} | ||
if (serverResponse.value) { | ||
if (serverResponse.value._data) { | ||
page.value = serverResponse.value._data; | ||
passThroughHeaders(nuxtApp, serverResponse.value.headers); | ||
} else if (serverResponse.value.error) { | ||
pageError.value = serverResponse.value.error; | ||
} | ||
if (import.meta.client) { | ||
serverResponse.value = null; | ||
} | ||
} else { | ||
const { data, error } = await useCeApi(path, useFetchOptions, true); | ||
page.value = data.value; | ||
pageError.value = error.value; | ||
} | ||
if (page.value?.messages) { | ||
pushMessagesToState(page.value.messages); | ||
} | ||
if (page?.value?.redirect) { | ||
@@ -85,7 +108,6 @@ await callWithNuxt(nuxtApp, navigateTo, [ | ||
} | ||
if (error.value) { | ||
overrideErrorHandler ? overrideErrorHandler(error) : pageErrorHandler(error, { config, nuxtApp }); | ||
page.value = error.value?.data; | ||
if (pageError.value) { | ||
overrideErrorHandler ? overrideErrorHandler(pageError) : pageErrorHandler(pageError, { config, nuxtApp }); | ||
page.value = pageError.value?.data; | ||
} | ||
page.value?.messages && pushMessagesToState(page.value.messages); | ||
pageState.value = page; | ||
@@ -129,2 +151,20 @@ return page; | ||
const getPage = () => useState("drupal-ce-page-data", () => ({})); | ||
const resolveCustomElement = (element) => { | ||
const nuxtApp = useNuxtApp(); | ||
const formatName = (name) => name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(""); | ||
const component = nuxtApp.vueApp.component(formatName(element)); | ||
if (typeof component === "object" && component.name) { | ||
return component; | ||
} | ||
const regex = /-?[a-z]+$/; | ||
let componentName = element; | ||
while (componentName) { | ||
const fallbackComponent = nuxtApp.vueApp.component(formatName(componentName) + "Default"); | ||
if (typeof fallbackComponent === "object" && fallbackComponent.name) { | ||
return fallbackComponent; | ||
} | ||
componentName = componentName.replace(regex, ""); | ||
} | ||
return typeof resolveComponent(element) === "object" ? resolveComponent(element) : null; | ||
}; | ||
const renderCustomElements = (customElements) => { | ||
@@ -134,3 +174,10 @@ if (Object.keys(customElements).length === 0) { | ||
} | ||
return Array.isArray(customElements) ? h("div", customElements.map((customElement) => h(resolveComponent(customElement.element), customElement))) : h(resolveComponent(customElements.element), customElements); | ||
if (Array.isArray(customElements)) { | ||
return customElements.map((customElement) => { | ||
const resolvedElement2 = resolveCustomElement(customElement.element); | ||
return resolvedElement2 ? h(resolvedElement2, customElement) : null; | ||
}); | ||
} | ||
const resolvedElement = resolveCustomElement(customElements.element); | ||
return resolvedElement ? h(resolvedElement, customElements) : null; | ||
}; | ||
@@ -150,2 +197,5 @@ const passThroughHeaders = (nuxtApp, pageHeaders) => { | ||
}; | ||
const getPageLayout = (page) => { | ||
return computed(() => page.value.page_layout || "default"); | ||
}; | ||
return { | ||
@@ -162,3 +212,4 @@ $ceApi, | ||
getDrupalBaseUrl, | ||
getMenuBaseUrl | ||
getMenuBaseUrl, | ||
getPageLayout | ||
}; | ||
@@ -165,0 +216,0 @@ }; |
@@ -5,3 +5,3 @@ /** | ||
* | ||
* @returns {string} | ||
* @returns {string} Returns the Drupal base URL. | ||
*/ | ||
@@ -12,4 +12,4 @@ export declare const getDrupalBaseUrl: () => any; | ||
* | ||
* @returns {string} | ||
* @returns {string} Returns the menu base URL. | ||
*/ | ||
export declare const getMenuBaseUrl: () => any; |
import { getRequestURL } from "h3"; | ||
import { useRuntimeConfig, defineNitroPlugin } from "#imports"; | ||
export default defineNitroPlugin((nitro) => { | ||
const { ceApiEndpoint } = useRuntimeConfig().public.drupalCe; | ||
const { serverLogLevel } = useRuntimeConfig().drupalCe; | ||
@@ -6,0 +5,0 @@ if (serverLogLevel === "error" || serverLogLevel === "info") { |
@@ -1,16 +0,1 @@ | ||
import type { ModuleOptions } from './module' | ||
declare module '@nuxt/schema' { | ||
interface NuxtConfig { ['drupalCe']?: Partial<ModuleOptions> } | ||
interface NuxtOptions { ['drupalCe']?: ModuleOptions } | ||
} | ||
declare module 'nuxt/schema' { | ||
interface NuxtConfig { ['drupalCe']?: Partial<ModuleOptions> } | ||
interface NuxtOptions { ['drupalCe']?: ModuleOptions } | ||
} | ||
export type { ModuleOptions, default } from './module' | ||
export { type ModuleOptions, default } from './module' |
{ | ||
"name": "nuxtjs-drupal-ce", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"license": "MIT", | ||
@@ -29,19 +29,20 @@ "bin": { | ||
"test": "vitest run", | ||
"lint": "eslint . --ext .js,.vue,.ts", | ||
"lint-fix": "eslint . --ext .js,.vue,.ts --fix" | ||
"lint": "eslint .", | ||
"lint-fix": "eslint . --fix" | ||
}, | ||
"dependencies": { | ||
"@nuxt/kit": "^3.11.2", | ||
"@nuxt/kit": "^3.13.1", | ||
"defu": "^6.1.4" | ||
}, | ||
"devDependencies": { | ||
"@nuxt/module-builder": "^0.7.0", | ||
"@nuxt/schema": "^3.11.2", | ||
"@nuxt/test-utils": "^3.13.1", | ||
"@nuxtjs/eslint-config-typescript": "^12.1.0", | ||
"@nuxtjs/i18n": "^8.3.1", | ||
"eslint": "^8.57.0", | ||
"nuxt": "^3.11.2", | ||
"@nuxt/eslint-config": "^0.5.6", | ||
"@nuxt/module-builder": "^0.8.3", | ||
"@nuxt/schema": "^3.13.1", | ||
"@nuxt/test-utils": "^3.14.1", | ||
"@nuxtjs/i18n": "^8.5.2", | ||
"eslint": "^9.9.1", | ||
"nuxt": "^3.13.1", | ||
"typescript": "^5.5.4", | ||
"vitest": "^1.6.0" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
# nuxtjs-drupal-ce - Nuxt.js Drupal Custom Elements Connector | ||
# nuxtjs-drupal-ce - Nuxt Drupal Custom Elements Connector | ||
@@ -24,10 +24,16 @@ [![npm version][npm-version-src]][npm-version-href] | ||
1. Add `nuxtjs-drupal-ce` dependency to your Nuxt project | ||
1. Go to your Nuxt project. If necessary, start a new one: | ||
```bash | ||
yarn add nuxtjs-drupal-ce@beta # or npm install nuxtjs-drupal-ce@beta | ||
npx nuxi@latest init <project-name> | ||
``` | ||
2. Add `nuxtjs-drupal-ce` to the `modules` section of `nuxt.config.js` | ||
2. Add the `nuxtjs-drupal-ce` module to your Nuxt project | ||
```bash | ||
npx nuxi@latest module add drupal-ce | ||
``` | ||
3. Configure `nuxtjs-drupal-ce` in your `nuxt.config.js` | ||
```js | ||
@@ -44,7 +50,6 @@ export default defineNuxtConfig({ | ||
``` | ||
The module defaults work well with [Lupus Decoupled Drupal](https://www.drupal.org/project/lupus_decoupled) - in that case setting the | ||
The module defaults work well with [Lupus Decoupled Drupal](https://drupal.org/project/lupus_decoupled) - in that case setting the | ||
`drupalBaseUrl` is enough to get started. | ||
3. Get started quickly by scaffolding initial files: | ||
4. Scaffold initial files. After scaffolding, edit them as suiting. | ||
```bash | ||
@@ -116,2 +121,40 @@ rm -f app.vue && npx nuxt-drupal-ce-init | ||
## Rendering custom elements | ||
Generally, custom elements are rendered as [dynamic components](https://nuxt.com/docs/guide/directory-structure/components#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 | ||
@@ -118,0 +161,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
43353
36
510
253
1
0
9
Updated@nuxt/kit@^3.13.1