From 7d7a575ecc45ed3e5ebf30953612539f8d31d1c4 Mon Sep 17 00:00:00 2001 From: Stuart Clark Date: Tue, 27 Aug 2024 14:07:28 +1000 Subject: [PATCH] feat(#693): update druxt-blocks for @nuxt/kit --- packages/blocks/README.md | 2 +- packages/blocks/package.json | 5 +- packages/blocks/src/components/DruxtBlock.vue | 10 +-- .../src/components/DruxtBlockRegion.vue | 6 +- packages/blocks/src/index.js | 33 +++------ packages/blocks/src/nuxt/index.js | 73 +++++++++++++++++++ .../{nuxtStorybook.js => nuxt/storybook.js} | 3 +- packages/blocks/src/nuxtModule.js | 55 -------------- packages/blocks/test/nuxt/index.test.js | 25 +++++++ .../storybook.test.js} | 7 +- packages/blocks/test/nuxtModule.test.js | 24 ------ 11 files changed, 128 insertions(+), 115 deletions(-) create mode 100644 packages/blocks/src/nuxt/index.js rename packages/blocks/src/{nuxtStorybook.js => nuxt/storybook.js} (97%) delete mode 100644 packages/blocks/src/nuxtModule.js create mode 100644 packages/blocks/test/nuxt/index.test.js rename packages/blocks/test/{nuxtStorybook.test.js => nuxt/storybook.test.js} (65%) delete mode 100644 packages/blocks/test/nuxtModule.test.js diff --git a/packages/blocks/README.md b/packages/blocks/README.md index 76ed85685..4d1704163 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -25,7 +25,7 @@ Add module to `nuxt.config.js` ```js module.exports = { - modules: ['druxt-blocks'], + modules: ['druxt-blocks/nuxt'], druxt: { baseUrl: 'https://demo-api.druxtjs.org', blocks: { diff --git a/packages/blocks/package.json b/packages/blocks/package.json index 5da0f335d..044a11217 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -33,15 +33,18 @@ "require": "./dist/druxt-blocks.ssr.js", "import": "./dist/druxt-blocks.esm.js" }, - "./components/*": "./dist/components/*" + "./components/*": "./dist/components/*", + "./nuxt/*": "./nuxt/*" }, "main": "dist/druxt-blocks.ssr.js", "module": "dist/druxt-blocks.esm.js", "files": [ "dist", + "nuxt", "templates" ], "dependencies": { + "@nuxt/kit": "^3.12.4", "axios": "0.28.0", "drupal-jsonapi-params": "^2.3.1", "druxt": "^0.24.0", diff --git a/packages/blocks/src/components/DruxtBlock.vue b/packages/blocks/src/components/DruxtBlock.vue index 7eb55279a..a182204b8 100644 --- a/packages/blocks/src/components/DruxtBlock.vue +++ b/packages/blocks/src/components/DruxtBlock.vue @@ -93,7 +93,7 @@ export default { * * @return {object} */ - block: ({ resource }) => (resource || {}).data, + block: ({ resource }) => resource?.data, }, watch: { @@ -156,7 +156,7 @@ export default { const type = 'block--block' const query = new DrupalJsonApiParams() - const fields = ((this.$druxt.settings.blocks || {}).query || {}).fields + const fields = this.$druxt?.settings.blocks?.query?.fields if (Array.isArray(fields)) { query.addFields(type, [ ...fields, @@ -214,10 +214,10 @@ export default { scopedSlots.default = () => { let summary, description - if ((this.block || {}).attributes) { + if (this.block?.attributes) { summary = `Missing Vue template for the '${this.block.attributes.drupal_internal__id}' block` description = [ - h('p', `Create a Druxt theme component to render the "${this.block.attributes.settings.label}" block.`), + h('p', `Create a Druxt theme component to render the "${this.block.attributes?.settings?.label}" block.`), ] // Ensure an ID or UUID. } else if (!this.id && !this.uuid) { @@ -229,7 +229,7 @@ export default { { props: { summary } }, [ h('div', description), - !!this.component.options.length && h('DruxtDevelTemplate', { props: { options: this.component.options }}), + !!this.component.options?.length && h('DruxtDevelTemplate', { props: { options: this.component.options }}), !!this.block && h('details', [h('summary', 'JSON:API resource'), h('pre', [h('code', [JSON.stringify(this.block, null, ' ')])])]) ] ) diff --git a/packages/blocks/src/components/DruxtBlockRegion.vue b/packages/blocks/src/components/DruxtBlockRegion.vue index e70d78349..3d8629b41 100644 --- a/packages/blocks/src/components/DruxtBlockRegion.vue +++ b/packages/blocks/src/components/DruxtBlockRegion.vue @@ -172,7 +172,7 @@ export default { type, query }) - this.blocks = collection.data + this.blocks = collection?.data }, /** @@ -207,7 +207,7 @@ export default { slots(h) { // Build scoped slots for each block. const scopedSlots = {} - this.blocks.map((block) => { + this.blocks?.map((block) => { scopedSlots[block.attributes.drupal_internal__id] = (attrs) => { delete (attrs || {})['data-fetch-key'] return h('DruxtBlock', { @@ -223,7 +223,7 @@ export default { }) // Build default slot. - scopedSlots.default = (attrs) => h('div', this.blocks.map((block) => + scopedSlots.default = (attrs) => h('div', this.blocks?.map((block) => this.isVisible(block) ? scopedSlots[block.attributes.drupal_internal__id](attrs) : false diff --git a/packages/blocks/src/index.js b/packages/blocks/src/index.js index 09f76b1eb..f895716f5 100644 --- a/packages/blocks/src/index.js +++ b/packages/blocks/src/index.js @@ -1,27 +1,3 @@ -import { DruxtBlocksNuxtModule } from './nuxtModule' - -/** - * The Nuxt.js module function. - * - * Installs the module functionality in a Nuxt application. - * - * @type {Function} - * @exports default - * @name DruxtBlocksModule - * @see {@link /api/packages/blocks/nuxtModule|DruxtBlocksModule} - * - * @example nuxt.config.js @lang js - * module.exports = { - * modules: [ - * 'druxt-blocks' - * ], - * druxt: { - * baseUrl: 'https://demo-api.druxtjs.org' - * } - * } - */ -export default DruxtBlocksNuxtModule - /** * The DruxtBlocksBlockMixin adds props and computed props to your DruxtBlock * wrapper component. @@ -52,3 +28,12 @@ export default DruxtBlocksNuxtModule * } */ export { DruxtBlocksRegionMixin } from './mixins/region' + +/** + * 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("DruxtBlocks Nuxt module must be installed as 'druxt-blocks/nuxt'") +} diff --git a/packages/blocks/src/nuxt/index.js b/packages/blocks/src/nuxt/index.js new file mode 100644 index 000000000..7b0de2789 --- /dev/null +++ b/packages/blocks/src/nuxt/index.js @@ -0,0 +1,73 @@ +import { defineNuxtModule, installModule } from '@nuxt/kit' +import { join } from 'path' +// import DruxtBlocksStorybook from './storybook' + +/** + * The Nuxt.js module function. + * + * - Adds the Vue.js components to the Nuxt.js frontend. + * + * The module function should not be used directly, but rather installed via yout Nuxt.js configuration file. + * + * Options are set on the root level `druxt` Nuxt.js config object. + * + * @example @lang js + * // `nuxt.config.js` + * module.exports = { + * modules: [ + * 'druxt-blocks' + * ], + * druxt: { + * baseUrl: 'https://demo-api.druxtjs.org' + * } + * } + * + * @param {object} moduleOptions - Nuxt.js module options object. + */ +const DruxtBlocksNuxtModule = defineNuxtModule({ + meta: { + name: 'druxt-blocks' + }, + defaults: { + baseUrl: '', + endpoint: '/jsonapi', + }, + + async setup(moduleOptions, nuxt) { + // Prevent issue "FATAL: Cannot determine nuxt version! Is current + // instance passed?". + nuxt._version = nuxt._version || '2.' + // This is required to prevent "FATAL: nuxt.options._layers is not iterable" + // error when using `installModule()`. + nuxt.options._layers = nuxt.options._layers || [] + + // Set default options. + const options = { + baseUrl: moduleOptions.baseUrl, + ...nuxt.options?.druxt || {}, + blocks: { + query: {}, + ...nuxt.options?.druxt?.blocks, + ...moduleOptions, + } + } + + // Add Druxt module. + await installModule('druxt/nuxt', options, nuxt) + + // Register components directories. + nuxt.hook('components:dirs', dirs => { + dirs.push({ path: join(__dirname, '../dist/components') }) + dirs.push({ path: join(__dirname, '../dist/components/blocks') }) + }) + + // Nuxt Storybook. + // @TODO - @nuxt/kit and @nuxt/storybook aren't compatible. + // nuxt.hook('storybook:config', async ({ stories }) => { + // await DruxtBlocksStorybook.call(nuxt, { stories }) + // }) + } +}) + +export default DruxtBlocksNuxtModule + diff --git a/packages/blocks/src/nuxtStorybook.js b/packages/blocks/src/nuxt/storybook.js similarity index 97% rename from packages/blocks/src/nuxtStorybook.js rename to packages/blocks/src/nuxt/storybook.js index 4b0e1a23b..2cfd94e2f 100644 --- a/packages/blocks/src/nuxtStorybook.js +++ b/packages/blocks/src/nuxt/storybook.js @@ -1,3 +1,4 @@ +import { addTemplate } from '@nuxt/kit' import { resolve } from 'path' import { DrupalJsonApiParams } from 'drupal-jsonapi-params' import { DruxtClient } from 'druxt' @@ -8,7 +9,7 @@ const titleFn = (parts) => ).join('/') export default async function ({ stories }) { - const { addTemplate, options } = this + const { options } = this // Setup DruxtClient instance. const druxt = new DruxtClient(options.druxt.baseUrl, { ...options.druxt, proxy: { api: false } }) diff --git a/packages/blocks/src/nuxtModule.js b/packages/blocks/src/nuxtModule.js deleted file mode 100644 index f39000923..000000000 --- a/packages/blocks/src/nuxtModule.js +++ /dev/null @@ -1,55 +0,0 @@ -import { join } from 'path' -import DruxtBlocksStorybook from './nuxtStorybook' - -/** - * The Nuxt.js module function. - * - * - Adds the Vue.js components to the Nuxt.js frontend. - * - * The module function should not be used directly, but rather installed via yout Nuxt.js configuration file. - * - * Options are set on the root level `druxt` Nuxt.js config object. - * - * @example @lang js - * // `nuxt.config.js` - * module.exports = { - * modules: [ - * 'druxt-blocks' - * ], - * druxt: { - * baseUrl: 'https://demo-api.druxtjs.org' - * } - * } - * - * @param {object} moduleOptions - Nuxt.js module options object. - */ -const DruxtBlocksNuxtModule = async function (moduleOptions = {}) { - // Set default options. - const options = { - baseUrl: moduleOptions.baseUrl, - ...(this.options || {}).druxt || {}, - blocks: { - query: {}, - ...((this.options || {}).druxt || {}).site, - ...moduleOptions, - } - } - - // Add Druxt module. - await this.addModule(['druxt', options]) - - // Register components directories. - this.nuxt.hook('components:dirs', dirs => { - dirs.push({ path: join(__dirname, 'components') }) - dirs.push({ path: join(__dirname, 'components/blocks') }) - }) - - // Nuxt Storybook. - this.nuxt.hook('storybook:config', async ({ stories }) => { - await DruxtBlocksStorybook.call(this, { stories }) - }) -} - -DruxtBlocksNuxtModule.meta = require('../package.json') - -export { DruxtBlocksNuxtModule } diff --git a/packages/blocks/test/nuxt/index.test.js b/packages/blocks/test/nuxt/index.test.js new file mode 100644 index 000000000..c4d8e37a7 --- /dev/null +++ b/packages/blocks/test/nuxt/index.test.js @@ -0,0 +1,25 @@ +import DruxtBlocksNuxtModule from '../../src/nuxt' + +// jest.mock('../src/nuxt/storybook') + +jest.mock('@nuxt/kit', () => ({ + defineNuxtModule: (module) => module, + installModule: jest.fn(), +})) + +const nuxtMock = { + hook: jest.fn((hook, fn) => { + const arg = { + 'components:dirs': [], + // 'storybook:config': { stories: [] } + } + return fn(arg[hook]) + }), +} + +test('Nuxt module', async () => { + nuxtMock.options = { + druxt: {} + } + await DruxtBlocksNuxtModule.setup({}, nuxtMock) +}) diff --git a/packages/blocks/test/nuxtStorybook.test.js b/packages/blocks/test/nuxt/storybook.test.js similarity index 65% rename from packages/blocks/test/nuxtStorybook.test.js rename to packages/blocks/test/nuxt/storybook.test.js index 593638cca..37ec0e57e 100644 --- a/packages/blocks/test/nuxtStorybook.test.js +++ b/packages/blocks/test/nuxt/storybook.test.js @@ -1,7 +1,12 @@ -import DruxtBlocksStorybook from '../src/nuxtStorybook' +import DruxtBlocksStorybook from '../../src/nuxt/storybook' jest.mock('axios') +jest.mock('@nuxt/kit', () => ({ + addTemplate: jest.fn(), + defineNuxtModule: (module) => module, +})) + const mock = { addTemplate: jest.fn(), options: { diff --git a/packages/blocks/test/nuxtModule.test.js b/packages/blocks/test/nuxtModule.test.js deleted file mode 100644 index 47e04540a..000000000 --- a/packages/blocks/test/nuxtModule.test.js +++ /dev/null @@ -1,24 +0,0 @@ -import { DruxtBlocksNuxtModule } from '../src/nuxtModule' - -jest.mock('../src/nuxtStorybook') - -const mock = { - addModule: jest.fn(), - nuxt: { - hook: jest.fn((hook, fn) => { - const arg = { - 'components:dirs': [], - 'storybook:config': { stories: [] } - } - return fn(arg[hook]) - }), - }, - DruxtBlocksNuxtModule -} - -test('Nuxt module', () => { - mock.options = { - druxt: {} - } - mock.DruxtBlocksNuxtModule() -})