From 758ccffba0982e291b110279f656bb9d22a967c8 Mon Sep 17 00:00:00 2001 From: Stuart Clark Date: Tue, 27 Aug 2024 14:09:36 +1000 Subject: [PATCH] feat(#693): update druxt-router for @nuxt/kit --- packages/router/package.json | 1 + .../router/src/components/DruxtRouter.vue | 2 +- packages/router/src/index.js | 9 + packages/router/src/nuxt/index.js | 190 ++++++++++-------- packages/router/src/router.js | 4 +- packages/router/test/nuxt/index.test.js | 71 ++++--- 6 files changed, 151 insertions(+), 126 deletions(-) diff --git a/packages/router/package.json b/packages/router/package.json index 49fbc38aa..ae57feeaa 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -42,6 +42,7 @@ "templates" ], "dependencies": { + "@nuxt/kit": "^3.12.2", "druxt": "^0.24.0", "url-parse": "^1.5.10" }, diff --git a/packages/router/src/components/DruxtRouter.vue b/packages/router/src/components/DruxtRouter.vue index 69bc18189..035469460 100644 --- a/packages/router/src/components/DruxtRouter.vue +++ b/packages/router/src/components/DruxtRouter.vue @@ -67,7 +67,7 @@ export default { const result = await store.dispatch('druxtRouter/get', route.fullPath) // Process redirect. - if (result.redirect) { + if (result?.redirect) { redirect(result.redirect) } }, diff --git a/packages/router/src/index.js b/packages/router/src/index.js index 625ebd6c2..715842930 100644 --- a/packages/router/src/index.js +++ b/packages/router/src/index.js @@ -57,3 +57,12 @@ export { DruxtRouterStore } from './stores/router' * */ export { DruxtRouterMixin } from './mixins/router' + +/** + * Default function to alert user to incorrectly installed module. + * + * This was added as part of the @nuxt/kit update due to breaking changes. + */ +export default () => { + throw new Error("DruxtRouter Nuxt module must be installed as 'druxt-router/nuxt'") +} diff --git a/packages/router/src/nuxt/index.js b/packages/router/src/nuxt/index.js index f2cbbe2e3..8d21b03d7 100644 --- a/packages/router/src/nuxt/index.js +++ b/packages/router/src/nuxt/index.js @@ -1,3 +1,4 @@ +import { addPluginTemplate, addTemplate, defineNuxtModule, extendPages, installModule } from '@nuxt/kit' import { existsSync } from 'fs' import { join, resolve } from 'path' import { DrupalJsonApiParams } from 'drupal-jsonapi-params' @@ -27,107 +28,122 @@ import { DruxtClient } from 'druxt' * @property {string} options.druxt.baseUrl - Base URL of Drupal JSON:API backend. * @property {string} options.druxt.router.component - File to custom Router component. */ -const DruxtRouterNuxtModule = async function (moduleOptions = {}) { - // Set default options. - const options = { - baseUrl: moduleOptions.baseUrl, - ...(this.options || {}).druxt || {}, - router: { - pages: (await existsSync(resolve(this.options.srcDir, this.options.dir.pages))), - wildcard: true, - ...((this.options || {}).druxt || {}).router, - ...moduleOptions, +const DruxtRouterNuxtModule = defineNuxtModule({ + meta: { + name: 'druxt-router', + }, + defaults: { + baseUrl: '', + endpoint: '/jsonapi', + }, + + async setup(moduleOptions, nuxt) { + // Set default options. + const options = { + baseUrl: moduleOptions.baseUrl, + ...nuxt.options?.druxt || {}, + router: { + pages: (await existsSync(resolve(nuxt.options.srcDir, nuxt.options.dir.pages))), + wildcard: true, + ...nuxt.options?.druxt?.router, + ...moduleOptions, + } } - } - // Add dependant modules. - await this.addModule(['druxt', options]) + // Add dependant modules. + await installModule('druxt/nuxt', options, nuxt) - // Register components directories. - this.nuxt.hook('components:dirs', dirs => { - dirs.push({ path: join(__dirname, '../dist/components') }) - }) + // Register components directories. + nuxt.hook('components:dirs', dirs => { + dirs.push({ path: join(__dirname, '../dist/components') }) + }) - // Add Druxt router custom wildcard route. - if (options.router.wildcard) { - // Ignore page routes. - if (!options.router.pages) { - this.nuxt.hook('build:before', () => - this.nuxt.options.build.createRoutes = () => [] - ) - } + // Add Druxt router custom wildcard route. + if (options.router.wildcard) { + // Ignore page routes. + if (!options.router.pages) { + nuxt.hook('build:before', () => + nuxt.options.build.createRoutes = () => [] + ) + } - // Add route template. - this.addTemplate({ - src: resolve(__dirname, '../templates/component.js'), - fileName: 'components/druxt-router.js', - options - }) + // Add route template. + addTemplate({ + src: resolve(__dirname, '../templates/component.js'), + fileName: 'components/druxt-router.js', + options, + write: true + }) - // Fetch languages. - let languages = [] - const druxt = new DruxtClient(options.baseUrl, { - ...options, - // Disable API Proxy, as Proxies aren't available at build. - proxy: { ...options.proxy || {}, api: false }, - }) - const languageResourceType = 'configurable_language--configurable_language' - if (((await druxt.getIndex(languageResourceType)) || {}).href) { - const query = new DrupalJsonApiParams().addFields(languageResourceType, ['drupal_internal__id']) - languages = (await druxt.getCollectionAll(languageResourceType, query) || []) - .map((o) => o.data) - .flat() - .filter((o) => !['und', 'zxx'].includes(((o || {}).attributes || {}).drupal_internal__id)) - } + // Fetch languages. + let languages = [] + const druxt = new DruxtClient(options.baseUrl, { + ...options, + // Disable API Proxy, as Proxies aren't available at build. + proxy: { ...options.proxy || {}, api: false }, + }) + const languageResourceType = 'configurable_language--configurable_language' + if (((await druxt.getIndex(languageResourceType)) || {}).href) { + const query = new DrupalJsonApiParams().addFields(languageResourceType, ['drupal_internal__id']) + languages = (await druxt.getCollectionAll(languageResourceType, query) || []) + .map((o) => o.data) + .flat() + .filter((o) => !['und', 'zxx'].includes(o?.attributes?.drupal_internal__id)) + } - // Extend routes. - this.extendRoutes((routes) => { - // Add route per language. - languages.filter((o) => o).forEach((o) => { + // Extend pages. + extendPages((routes) => { + // Add route per language. + languages.filter((o) => o).forEach((o) => { + routes.push({ + name: `druxt-router__${o.attributes.drupal_internal__id}`, + path: `/${o.attributes.drupal_internal__id}$/*`, + component: resolve(nuxt.options.buildDir, 'components/druxt-router.js'), + chunkName: 'druxt-router', + meta: { langcode: o.attributes.drupal_internal__id } + }) + }) + + // Add wildcard route. routes.push({ - name: `druxt-router__${o.attributes.drupal_internal__id}`, - path: `/${o.attributes.drupal_internal__id}*`, - component: resolve(this.options.buildDir, 'components/druxt-router.js'), - chunkName: 'druxt-router', - meta: { langcode: o.attributes.drupal_internal__id } + name: 'druxt-router', + path: '/*', + component: resolve(nuxt.options.buildDir, 'components/druxt-router.js'), + chunkName: 'druxt-router' }) }) + } - // Add wildcard route. - routes.push({ - name: 'druxt-router', - path: '*', - component: resolve(this.options.buildDir, 'components/druxt-router.js'), - chunkName: 'druxt-router' - }) + // Add plugin. + addPluginTemplate({ + src: resolve(__dirname, '../templates/plugin.js'), + fileName: 'druxt-router.js', + options }) - } - - // Add plugin. - this.addPlugin({ - src: resolve(__dirname, '../templates/plugin.js'), - fileName: 'druxt-router.js', - options - }) - - // Add Vuex plugin. - this.addPlugin({ - src: resolve(__dirname, '../templates/store.js'), - fileName: 'store/druxt-router.js', - options - }) - // Nuxt Storybook. - this.nuxt.hook('storybook:config', async ({ stories }) => { - this.addTemplate({ - src: resolve(__dirname, '../templates/druxt-router.stories.js'), - fileName: 'stories/druxt-router.stories.js', - options: {} + // Add store. + addPluginTemplate({ + src: resolve(__dirname, '../templates/store.js'), + fileName: 'store/druxt-router.js', + options: { + ...options + } }) - stories.push(resolve(this.options.buildDir, './stories/druxt-router.stories.js')) - }) -} -DruxtRouterNuxtModule.meta = require('../package.json') + // Enable Vuex Store. + nuxt.options.store = true + + // Nuxt Storybook. + // @TODO - @nuxt/kit and @nuxt/storybook aren't compatible. + // nuxt.hook('storybook:config', async ({ stories }) => { + // addTemplate({ + // src: resolve(__dirname, '../templates/druxt-router.stories.js'), + // fileName: 'stories/druxt-router.stories.js', + // options: {} + // }) + // stories.push(resolve(options.buildDir, './stories/druxt-router.stories.js')) + // }) + } +}) export default DruxtRouterNuxtModule diff --git a/packages/router/src/router.js b/packages/router/src/router.js index 7bafad20c..94cbbf16c 100644 --- a/packages/router/src/router.js +++ b/packages/router/src/router.js @@ -186,10 +186,10 @@ class DruxtRouter { * @returns {boolean|string} The redirect path or false. */ getRedirect (path, route = {}) { - const prefix = (route.props || {}).langcode || '' + const prefix = route.props?.langcode || '' // Redirect to route provided redirect. - if (((route.redirect || [])[0] || {}).to) { + if (route.redirect?.[0]?.to) { return route.redirect[0].to } const url = Url(path) diff --git a/packages/router/test/nuxt/index.test.js b/packages/router/test/nuxt/index.test.js index 58559174d..6faaa2c03 100644 --- a/packages/router/test/nuxt/index.test.js +++ b/packages/router/test/nuxt/index.test.js @@ -1,55 +1,54 @@ -import DruxtRouterNuxtModule from '../../nuxt' +import DruxtRouterNuxtModule from '../../src/nuxt' -const mock = { - addModule: jest.fn(), - addPlugin: jest.fn(), +jest.mock('@nuxt/kit', () => ({ + addPluginTemplate: jest.fn(), addTemplate: jest.fn(), - extendRoutes: jest.fn((func) => { - const routes = [] - const resolve = jest.fn() + defineNuxtModule: (module) => module, + extendPages: jest.fn(), + installModule: jest.fn(), +})) - func(routes, resolve) +import { addPluginTemplate, addTemplate, extendPages, installModule } from '@nuxt/kit' + +const nuxtMock = { + hook: jest.fn((hook, fn) => { + const arg = { + 'components:dirs': [], + 'storybook:config': { stories: [] } + } + return fn(arg[hook]) }), - nuxt: { - hook: jest.fn((hook, fn) => { - const arg = { - 'components:dirs': [], - 'storybook:config': { stories: [] } - } - return fn(arg[hook]) - }), - options: { build: {} } - }, - DruxtRouterNuxtModule } + test('Nuxt module', async () => { - mock.options = { + nuxtMock.options = { + build: {}, buildDir: '', dir: { pages: 'pages' }, druxt: { baseUrl: 'https://demo-api.druxtjs.org' }, srcDir: __dirname, } - mock.options.druxt.router = { pages: true } - await mock.DruxtRouterNuxtModule() - expect(mock.addPlugin).toHaveBeenCalledTimes(2) - expect(mock.addTemplate).toHaveBeenCalledTimes(2) - expect(mock.nuxt.hook).toHaveBeenCalledTimes(2) + nuxtMock.options.druxt.router = { pages: true } + await DruxtRouterNuxtModule.setup({}, nuxtMock) + expect(addPluginTemplate).toHaveBeenCalledTimes(2) + expect(addTemplate).toHaveBeenCalledTimes(1) + expect(nuxtMock.hook).toHaveBeenCalledTimes(1) jest.clearAllMocks() - mock.options.druxt.router = { wildcard: false } - await mock.DruxtRouterNuxtModule() - expect(mock.addPlugin).toHaveBeenCalledTimes(2) - expect(mock.addTemplate).toHaveBeenCalledTimes(1) - expect(mock.nuxt.hook).toHaveBeenCalledTimes(2) + nuxtMock.options.druxt.router = { wildcard: false } + await DruxtRouterNuxtModule.setup({}, nuxtMock) + expect(addPluginTemplate).toHaveBeenCalledTimes(2) + expect(addTemplate).toHaveBeenCalledTimes(0) + expect(nuxtMock.hook).toHaveBeenCalledTimes(1) jest.clearAllMocks() - mock.options.druxt.router = { pages: false } - await mock.DruxtRouterNuxtModule() - expect(mock.addPlugin).toHaveBeenCalledTimes(2) - expect(mock.addTemplate).toHaveBeenCalledTimes(2) - expect(mock.nuxt.hook).toHaveBeenCalledTimes(3) - expect(mock.nuxt.options.build.createRoutes()).toStrictEqual([]) + nuxtMock.options.druxt.router = { pages: false } + await DruxtRouterNuxtModule.setup({}, nuxtMock) + expect(addPluginTemplate).toHaveBeenCalledTimes(2) + expect(addTemplate).toHaveBeenCalledTimes(1) + expect(nuxtMock.hook).toHaveBeenCalledTimes(2) + expect(nuxtMock.options.build.createRoutes()).toStrictEqual([]) jest.clearAllMocks() })