diff --git a/packages/site/README.md b/packages/site/README.md index e26264af2..c4be3e362 100644 --- a/packages/site/README.md +++ b/packages/site/README.md @@ -25,7 +25,7 @@ ```js module.exports = { modules: [ - 'druxt-site' + 'druxt-site/nuxt' ], druxt: { baseUrl: 'https://demo-api.druxtjs.org' diff --git a/packages/site/package.json b/packages/site/package.json index 4c7b0ae90..4aaf16a96 100644 --- a/packages/site/package.json +++ b/packages/site/package.json @@ -33,18 +33,21 @@ "import": "./dist/druxt-site.esm.js" }, "./components/*": "./dist/components/*", - "./layouts/*": "./dist/layouts/*" + "./layouts/*": "./dist/layouts/*", + "./nuxt": "./nuxt/index.js" }, "main": "dist/druxt-site.ssr.js", "module": "dist/druxt-site.esm.js", "files": [ "dist", + "nuxt", "templates" ], "dependencies": { + "@nuxt/kit": "^3.11.2", "drupal-jsonapi-params": "^2.3.1", "druxt": "^0.24.0", - "druxt-blocks": "^0.17.1", + "druxt-blocks": "^0.17.2", "druxt-breadcrumb": "^0.17.1", "druxt-entity": "^0.28.0", "druxt-menu": "^0.21.0", diff --git a/packages/site/src/index.js b/packages/site/src/index.js index 8d7a33050..e848ebd8e 100644 --- a/packages/site/src/index.js +++ b/packages/site/src/index.js @@ -1,5 +1,3 @@ -import { DruxtSiteNuxtModule } from './nuxtModule' - /** * Vue.js Mixin. * @@ -26,23 +24,10 @@ import { DruxtSiteNuxtModule } from './nuxtModule' export { DruxtSiteMixin } from './mixins/site' /** - * The Nuxt.js module functions. - * - * Installs and configures all DruxtJS Site modules. + * Default function to alert user to incorrectly installed module. * - * @type {Function} - * @exports default - * @name DruxtSiteNuxtModule - * @see {@link ./nuxtModule|DruxtSiteNuxtModule} - * - * @example nuxt.config.js @lang js - * module.exports = { - * modules: [ - * 'druxt-site' - * ], - * druxt: { - * baseUrl: 'https://demo-api.druxtjs.org' - * } - * } + * This was added as part of the @nuxt/kit update due to breaking changes. */ -export default DruxtSiteNuxtModule +export default () => { + throw new Error("DruxtSite Nuxt module must be installed as 'druxt-site/nuxt'") +} diff --git a/packages/site/src/nuxt/index.js b/packages/site/src/nuxt/index.js new file mode 100644 index 000000000..7ad60dcc9 --- /dev/null +++ b/packages/site/src/nuxt/index.js @@ -0,0 +1,90 @@ +import { addLayout, defineNuxtModule, installModule } from '@nuxt/kit' +import { existsSync } from 'fs' +import { resolve } from 'path' +// import DruxtSiteStorybook from '../nuxtStorybook' + +/** + * Nuxt module function to install Druxt Site. + * + * - Adds the DruxtSite component. + * - Adds the core modules for DruxtJS Site. + * - Adds default configuration for @nuxtjs/proxy. + * - Enables Vuex store. + * + * @param {ModuleOptions} moduleOptions - The Nuxt.js module options. + */ +const DruxtSiteNuxtModule = defineNuxtModule({ + meta: { + name: 'druxt-site', + }, + 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, + proxy: { + api: false, + files: true, + ...nuxt.options?.druxt?.proxy, + }, + site: { + layout: true, + ...nuxt.options?.druxt?.site, + ...moduleOptions, + }, + } + nuxt.options.druxt = options + + // Register components directories. + nuxt.hook('components:dirs', dirs => { + dirs.push({ path: resolve(__dirname, '../dist/components') }) + }) + + // Add Druxt modules. + const druxtModules = [ + 'druxt/nuxt', + 'druxt-blocks/nuxt', + 'druxt-breadcrumb/nuxt', + 'druxt-entity/nuxt', + 'druxt-menu/nuxt', + 'druxt-router/nuxt', + 'druxt-schema/nuxt', + 'druxt-views/nuxt' + ] + for (const module of druxtModules) { + await installModule(module, {}, nuxt) + } + + // Add default layout. + if (!(await existsSync(resolve(nuxt.options.srcDir, nuxt.options.dir.layouts))) && options.site.layout) { + addLayout(resolve(__dirname, '../dist/layouts/default.vue'), 'default') + } + + // Nuxt Storybook. + // @TODO - @nuxt/kit and @nuxt/storybook aren't compatible. + // this.nuxt.hook('storybook:config', async ({ stories }) => { + // await DruxtSiteStorybook.call(this, { options, stories }) + // }) + } +}) + +export default DruxtSiteNuxtModule + +/** + * Module options object. + * + * @typedef {object} ModuleOptions + * @see {@link ./typedefs/moduleOptions|ModuleOptions} + */ diff --git a/packages/site/src/nuxtStorybook.js b/packages/site/src/nuxt/storybook.js similarity index 100% rename from packages/site/src/nuxtStorybook.js rename to packages/site/src/nuxt/storybook.js diff --git a/packages/site/src/nuxtModule.js b/packages/site/src/nuxtModule.js deleted file mode 100644 index c5e6dcc35..000000000 --- a/packages/site/src/nuxtModule.js +++ /dev/null @@ -1,73 +0,0 @@ -import { existsSync } from 'fs' -import { join, resolve } from 'path' -import DruxtSiteStorybook from './nuxtStorybook' - -/** - * Nuxt module function to install Druxt Site. - * - * - Adds the DruxtSite component. - * - Adds the core modules for DruxtJS Site. - * - Adds default configuration for @nuxtjs/proxy. - * - Enables Vuex store. - * - * @param {ModuleOptions} moduleOptions - The Nuxt.js module options. - */ -const DruxtSiteNuxtModule = async function (moduleOptions = {}) { - // Set default options. - const options = { - baseUrl: moduleOptions.baseUrl, - ...(this.options || {}).druxt || {}, - proxy: { - api: false, - files: true, - ...((this.options || {}).druxt || {}).proxy, - }, - site: { - layout: true, - ...((this.options || {}).druxt || {}).site, - ...moduleOptions, - }, - } - this.options.druxt = options - - // Register components directories. - this.nuxt.hook('components:dirs', dirs => { - dirs.push({ path: join(__dirname, 'components') }) - }) - - // Add Druxt modules. - const druxtModules = [ - 'druxt', - 'druxt-blocks', - 'druxt-breadcrumb', - 'druxt-entity', - 'druxt-menu', - 'druxt-router/nuxt', - 'druxt-schema', - 'druxt-views' - ] - for (const module of druxtModules) { - await this.addModule(module) - } - - // Add default layout. - if (!(await existsSync(resolve(this.options.srcDir, this.options.dir.layouts))) && options.site.layout) { - this.addLayout(resolve(__dirname, './layouts/default.vue'), 'default') - } - - // Nuxt Storybook. - this.nuxt.hook('storybook:config', async ({ stories }) => { - await DruxtSiteStorybook.call(this, { options, stories }) - }) -} - -DruxtSiteNuxtModule.meta = require('../package.json') - -export { DruxtSiteNuxtModule } - -/** - * Module options object. - * - * @typedef {object} ModuleOptions - * @see {@link ./typedefs/moduleOptions|ModuleOptions} - */ diff --git a/packages/site/test/__snapshots__/nuxtStorybook.test.js.snap b/packages/site/test/nuxt/__snapshots__/storybook.test.js.snap similarity index 100% rename from packages/site/test/__snapshots__/nuxtStorybook.test.js.snap rename to packages/site/test/nuxt/__snapshots__/storybook.test.js.snap diff --git a/packages/site/test/nuxt/index.test.js b/packages/site/test/nuxt/index.test.js new file mode 100644 index 000000000..f77c8ce7c --- /dev/null +++ b/packages/site/test/nuxt/index.test.js @@ -0,0 +1,39 @@ +import DruxtSiteNuxtModule from '../../src/nuxt' + +jest.mock('../../src/nuxt/storybook') + +jest.mock('@nuxt/kit', () => ({ + addLayout: jest.fn(), + defineNuxtModule: (module) => module, + installModule: jest.fn(), +})) + +import { installModule } from '@nuxt/kit' + +const nuxtMock = { + hook: jest.fn((hook, fn) => { + const arg = { + 'components:dirs': [], + 'storybook:config': { stories: [] } + } + return fn(arg[hook]) + }), +} + +jest.mock('druxt-schema') + +describe('DruxtJS Site module', () => { + test('Nuxt module', async () => { + nuxtMock.options = { + dir: { layouts: 'layouts' }, + druxt: {}, + srcDir: __dirname, + } + + // Call DruxtSite module. + await await DruxtSiteNuxtModule.setup({}, nuxtMock) + + // Expect 9 modules to be added. + expect(installModule).toHaveBeenCalledTimes(8) + }) +}) diff --git a/packages/site/test/nuxtStorybook.test.js b/packages/site/test/nuxt/storybook.test.js similarity index 88% rename from packages/site/test/nuxtStorybook.test.js rename to packages/site/test/nuxt/storybook.test.js index 837b1d7c2..9665cf035 100644 --- a/packages/site/test/nuxtStorybook.test.js +++ b/packages/site/test/nuxt/storybook.test.js @@ -1,5 +1,5 @@ import { resolve } from 'path' -import DruxtEntityStorybook from '../src/nuxtStorybook' +import DruxtEntityStorybook from '../../src/nuxt/storybook' jest.mock('axios') diff --git a/packages/site/test/nuxtModule.test.js b/packages/site/test/nuxtModule.test.js deleted file mode 100644 index f36ec3b64..000000000 --- a/packages/site/test/nuxtModule.test.js +++ /dev/null @@ -1,38 +0,0 @@ -import { DruxtSiteNuxtModule } from '../src/nuxtModule' - -jest.mock('../src/nuxtStorybook') - -const mock = { - addLayout: jest.fn(), - addModule: jest.fn(), - addPlugin: jest.fn(), - addTemplate: jest.fn(), - nuxt: { - hook: jest.fn((hook, fn) => { - const arg = { - 'components:dirs': [], - 'storybook:config': { stories: [] } - } - return fn(arg[hook]) - }), - }, - DruxtSiteNuxtModule -} - -jest.mock('druxt-schema') - -describe('DruxtJS Site module', () => { - test('Nuxt module', async () => { - mock.options = { - dir: { layouts: 'layouts' }, - druxt: {}, - srcDir: __dirname, - } - - // Call DruxtSite module. - await mock.DruxtSiteNuxtModule() - - // Expect 9 modules to be added. - expect(mock.addModule).toHaveBeenCalledTimes(8) - }) -})