Skip to content

Commit

Permalink
feat: provide auto imports for linkRel, richTextComponents, and `…
Browse files Browse the repository at this point in the history
…sliceZoneDefaultComponent`
  • Loading branch information
lihbr committed Jan 13, 2025
1 parent 0d940d7 commit 5b754e4
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 13 deletions.
13 changes: 11 additions & 2 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ export default defineNuxtModule<PrismicModuleOptions>({
clientConfig: {},
...prismicFiles,
injectComponents: true,
components: {},
components: {
linkRel: '~/prismic/linkRel',
richTextComponents: '~/prismic/richTextComponents',
sliceZoneDefaultComponent: '~/prismic/sliceZoneDefaultComponent',
},
preview: '/preview',
toolbar: true,
devtools: true,
Expand All @@ -88,7 +92,7 @@ export default defineNuxtModule<PrismicModuleOptions>({

// Add runtime user code
const proxyUserFileWithUndefinedFallback
= (filename: string, path: string, extensions = ['js', 'mjs', 'ts']): boolean => {
= (filename: string, path: string, extensions = ['js', 'mjs', 'ts', 'vue']): boolean => {
const resolvedFilename = `prismic/proxy/${filename}.ts`
const resolvedPath = path.replace(/^(~~|@@)/, nuxt.options.rootDir).replace(/^(~|@)/, nuxt.options.srcDir)
const maybeUserFile = fileExists(resolvedPath, extensions)
Expand Down Expand Up @@ -123,6 +127,11 @@ export default defineNuxtModule<PrismicModuleOptions>({
proxyUserFileWithUndefinedFallback('linkResolver', moduleOptions.linkResolver!)
proxyUserFileWithUndefinedFallback('richTextSerializer', moduleOptions.richTextSerializer!)

// Components
proxyUserFileWithUndefinedFallback('linkRel', moduleOptions.components!.linkRel!)
proxyUserFileWithUndefinedFallback('richTextComponents', moduleOptions.components!.richTextComponents!)
proxyUserFileWithUndefinedFallback('sliceZoneDefaultComponent', moduleOptions.components!.sliceZoneDefaultComponent!)

nuxt.options.build.transpile.push(resolver.resolve('runtime'), '@nuxtjs/prismic', '@prismicio/vue')
nuxt.options.vite.optimizeDeps ||= {}
nuxt.options.vite.optimizeDeps.exclude ||= []
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import _client from '#build/prismic/proxy/client'
import linkResolver from '#build/prismic/proxy/linkResolver'
// @ts-expect-error vfs cannot be resolved here
import richTextSerializer from '#build/prismic/proxy/richTextSerializer'
// @ts-expect-error vfs cannot be resolved here
import linkRel from '#build/prismic/proxy/linkRel'
// @ts-expect-error vfs cannot be resolved here
import richTextComponents from '#build/prismic/proxy/richTextComponents'
// @ts-expect-error vfs cannot be resolved here
import sliceZoneDefaultComponent from '#build/prismic/proxy/sliceZoneDefaultComponent'

export default defineNuxtPlugin({
name: 'prismic:setup',
Expand Down Expand Up @@ -51,6 +57,9 @@ export default defineNuxtPlugin({
linkInternalComponent: NuxtLink,
linkExternalComponent: NuxtLink,
...options.components,
linkRel,
richTextComponents,
sliceZoneDefaultComponent,
},
})

Expand Down
43 changes: 41 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import type { PrismicPluginOptions } from '@prismicio/vue'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { PrismicPluginOptions, SliceComponentProps, TODOSliceComponent } from '@prismicio/vue'

/**
* `@nuxtjs/prismic` module options.
*
* @see Module documentation: {@link https://prismic.nuxtjs.org}
* @see Prismic documentation: {@link https://prismic.io/docs/nuxt-3-setup}
*/
export type PrismicModuleOptions = Omit<PrismicPluginOptions, 'endpoint' | 'client' | 'linkResolver' | 'htmlSerializer' | 'richTextSerializer'> & {
export type PrismicModuleOptions = Omit<
PrismicPluginOptions,
'endpoint' | 'client' | 'linkResolver' | 'htmlSerializer' | 'richTextSerializer' | 'components'
> & {
/**
* A Prismic repository endpoint to init the module's `@prismicio/client`
* instance used to fetch content from a Prismic repository with.
Expand Down Expand Up @@ -93,4 +97,39 @@ export type PrismicModuleOptions = Omit<PrismicPluginOptions, 'endpoint' | 'clie
* @defaultValue `true`
*/
devtools?: boolean

/**
* Options used by Prismic Vue components.
*/
components?: Omit<
Required<PrismicPluginOptions>['components'],
'richTextComponents' | 'linkRel' | 'sliceZoneDefaultComponent' | 'linkInternalComponent' | 'linkExternalComponent'
> & {
/**
* An optional path to a file exporting the `rel` attribute to apply on links.
* It can export a function to use the link's metadata to determine the `rel` value.
*
* @defaultValue `"noreferrer"` for external links.
*/
linkRel?: string

/**
* An optional path to a file exporting a map of Rich Text block types to Vue Components.
* It is used to render Rich Text or title fields.
*
* @see Templating Rich Text and title fields from Prismic {@link https://prismic.io/docs/rich-text}
*/
richTextComponents?: string

/**
* An optional path to a file exporting a component or a functional component rendered
* if a component mapping from the `components` prop cannot be found.
*
* @remarks
* Components will be rendered using the {@link SliceComponentProps} interface.
*
* @defaultValue `null` when `process.env.NODE_ENV === "production"` else {@link TODOSliceComponent}
*/
sliceZoneDefaultComponent?: string
}
}
6 changes: 5 additions & 1 deletion test/module-options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ it('exposes options in runtime config', () => {
{
"client": "~/app/prismic/client",
"clientConfig": {},
"components": {},
"components": {
"linkRel": "~/prismic/linkRel",
"richTextComponents": "~/prismic/richTextComponents",
"sliceZoneDefaultComponent": "~/prismic/sliceZoneDefaultComponent",
},
"devtools": true,
"endpoint": "qwerty",
"environment": "",
Expand Down
70 changes: 66 additions & 4 deletions test/module-userFileProxy--nuxt4.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ afterEach(() => {
it('proxies nothing if user files are not available', () => {
mockedPrismicModule({ endpoint: 'qwerty' })

expect(addTemplate).toHaveBeenCalledTimes(3)
expect(addTemplate).toHaveBeenCalledTimes(6)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect(vi.mocked(addTemplate).mock.calls.flat().map((options: any) => [options.filename, options.getContents()])).toMatchInlineSnapshot(`
[
Expand All @@ -41,6 +41,18 @@ it('proxies nothing if user files are not available', () => {
"prismic/proxy/richTextSerializer.ts",
"export default undefined",
],
[
"prismic/proxy/linkRel.ts",
"export default undefined",
],
[
"prismic/proxy/richTextComponents.ts",
"export default undefined",
],
[
"prismic/proxy/sliceZoneDefaultComponent.ts",
"export default undefined",
],
]
`)
})
Expand All @@ -50,11 +62,14 @@ it('proxies user files from default location', () => {
'/tmp/nuxt/app/prismic/client.ts': '',
'/tmp/nuxt/app/prismic/linkResolver.ts': '',
'/tmp/nuxt/app/prismic/richTextSerializer.ts': '',
'/tmp/nuxt/app/prismic/linkRel.ts': '',
'/tmp/nuxt/app/prismic/richTextComponents.ts': '',
'/tmp/nuxt/app/prismic/sliceZoneDefaultComponent.vue': '',
})

mockedPrismicModule({ endpoint: 'qwerty' })

expect(addTemplate).toHaveBeenCalledTimes(3)
expect(addTemplate).toHaveBeenCalledTimes(6)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect(vi.mocked(addTemplate).mock.calls.flat().map((options: any) => [options.filename, options.getContents()])).toMatchInlineSnapshot(`
[
Expand All @@ -70,6 +85,18 @@ it('proxies user files from default location', () => {
"prismic/proxy/richTextSerializer.ts",
"export { default } from '~/prismic/richTextSerializer'",
],
[
"prismic/proxy/linkRel.ts",
"export { default } from '~/prismic/linkRel'",
],
[
"prismic/proxy/richTextComponents.ts",
"export { default } from '~/prismic/richTextComponents'",
],
[
"prismic/proxy/sliceZoneDefaultComponent.ts",
"export { default } from '~/prismic/sliceZoneDefaultComponent'",
],
]
`)
})
Expand All @@ -79,11 +106,14 @@ it('proxies user files from default location (Nuxt 4)', () => {
'/tmp/nuxt/app/prismic/client.ts': '',
'/tmp/nuxt/app/prismic/linkResolver.ts': '',
'/tmp/nuxt/app/prismic/richTextSerializer.ts': '',
'/tmp/nuxt/app/prismic/linkRel.ts': '',
'/tmp/nuxt/app/prismic/richTextComponents.ts': '',
'/tmp/nuxt/app/prismic/sliceZoneDefaultComponent.vue': '',
})

mockedPrismicModule({ endpoint: 'qwerty' })

expect(addTemplate).toHaveBeenCalledTimes(3)
expect(addTemplate).toHaveBeenCalledTimes(6)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect(vi.mocked(addTemplate).mock.calls.flat().map((options: any) => [options.filename, options.getContents()])).toMatchInlineSnapshot(`
[
Expand All @@ -99,6 +129,18 @@ it('proxies user files from default location (Nuxt 4)', () => {
"prismic/proxy/richTextSerializer.ts",
"export { default } from '~/prismic/richTextSerializer'",
],
[
"prismic/proxy/linkRel.ts",
"export { default } from '~/prismic/linkRel'",
],
[
"prismic/proxy/richTextComponents.ts",
"export { default } from '~/prismic/richTextComponents'",
],
[
"prismic/proxy/sliceZoneDefaultComponent.ts",
"export { default } from '~/prismic/sliceZoneDefaultComponent'",
],
]
`)
})
Expand All @@ -108,16 +150,24 @@ it('proxies user files from provided location', () => {
'/tmp/nuxt/app/custom/client.ts': '',
'/tmp/nuxt/app/custom/linkResolver.ts': '',
'/tmp/nuxt/app/custom/richTextSerializer.ts': '',
'/tmp/nuxt/app/custom/linkRel.ts': '',
'/tmp/nuxt/app/custom/richTextComponents.ts': '',
'/tmp/nuxt/app/custom/sliceZoneDefaultComponent.vue': '',
})

mockedPrismicModule({
endpoint: 'qwerty',
client: '~/custom/client',
linkResolver: '~/custom/linkResolver',
richTextSerializer: '~/custom/richTextSerializer',
components: {
linkRel: '~/custom/linkRel',
richTextComponents: '~/custom/richTextComponents',
sliceZoneDefaultComponent: '~/custom/sliceZoneDefaultComponent',
},
})

expect(addTemplate).toHaveBeenCalledTimes(3)
expect(addTemplate).toHaveBeenCalledTimes(6)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect(vi.mocked(addTemplate).mock.calls.flat().map((options: any) => [options.filename, options.getContents()])).toMatchInlineSnapshot(`
[
Expand All @@ -133,6 +183,18 @@ it('proxies user files from provided location', () => {
"prismic/proxy/richTextSerializer.ts",
"export { default } from '~/custom/richTextSerializer'",
],
[
"prismic/proxy/linkRel.ts",
"export { default } from '~/custom/linkRel'",
],
[
"prismic/proxy/richTextComponents.ts",
"export { default } from '~/custom/richTextComponents'",
],
[
"prismic/proxy/sliceZoneDefaultComponent.ts",
"export { default } from '~/custom/sliceZoneDefaultComponent'",
],
]
`)
})
Loading

0 comments on commit 5b754e4

Please sign in to comment.