Skip to content

Commit

Permalink
feat(#693): update druxt-router for @nuxt/kit
Browse files Browse the repository at this point in the history
  • Loading branch information
Decipher committed Aug 30, 2024
1 parent 0b075d7 commit 758ccff
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 126 deletions.
1 change: 1 addition & 0 deletions packages/router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"templates"
],
"dependencies": {
"@nuxt/kit": "^3.12.2",
"druxt": "^0.24.0",
"url-parse": "^1.5.10"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/router/src/components/DruxtRouter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
},
Expand Down
9 changes: 9 additions & 0 deletions packages/router/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,12 @@ export { DruxtRouterStore } from './stores/router'
* </script>
*/
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'")
}
190 changes: 103 additions & 87 deletions packages/router/src/nuxt/index.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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
4 changes: 2 additions & 2 deletions packages/router/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
71 changes: 35 additions & 36 deletions packages/router/test/nuxt/index.test.js
Original file line number Diff line number Diff line change
@@ -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()
})

0 comments on commit 758ccff

Please sign in to comment.