diff --git a/README.md b/README.md index 3d085986..805640e7 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,23 @@ export default defineNuxtConfig({ }) ``` +You can also use your own custom component instead of the built-in `nuxt-icon` component using the `customComponent` option. +This custom component must have `icon` property, just like the `nuxt-icon` component [provided by nuxt-svgo](https://github.com/cpsoinos/nuxt-svgo/blob/main/src/runtime/components/nuxt-icon.vue). + +Example: + +```typescript +// nuxt.config.ts +import { defineNuxtConfig } from 'nuxt' + +export default defineNuxtConfig({ + modules: ['nuxt-svgo'], + svgo: { + customComponent: 'YourComponent' + } +}) +``` + By default module registers all icons inside `autoImportPath` globally. This may be unwanted behavior as it generates chunks for each icon to be used globally, which will result in huge amount of files if you have many icons. If you want to disable global registration simply use `global: false` in module options: ```typescript diff --git a/package.json b/package.json index bcb00f33..384ea4e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nuxt-svgo", - "version": "3.3.0", + "version": "3.4.0", "packageManager": "pnpm@8.6.8", "description": "Nuxt module to load optimized SVG files as Vue components", "keywords": [ diff --git a/playground/tsconfig.json b/playground/tsconfig.json new file mode 100644 index 00000000..a746f2a7 --- /dev/null +++ b/playground/tsconfig.json @@ -0,0 +1,4 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "extends": "./.nuxt/tsconfig.json" +} diff --git a/src/loaders/vite.ts b/src/loaders/vite.ts index 767c462e..b421f49c 100644 --- a/src/loaders/vite.ts +++ b/src/loaders/vite.ts @@ -8,6 +8,8 @@ import urlEncodeSvg from 'mini-svg-data-uri' export interface SvgLoaderOptions { autoImportPath?: string + /** The name of component in CapitalCase that will be used in `componentext` import type. defaults to `NuxtIcon` */ + customComponent: string defaultImport?: | 'url' | 'url_encode' @@ -28,9 +30,17 @@ export function svgLoader(options?: SvgLoaderOptions) { svgo, defaultImport, explicitImportsOnly, - autoImportPath + autoImportPath, + customComponent } = options || {} + const normalizedCustomComponent = customComponent.includes('-') + ? customComponent + .split('-') + .map((c) => c[0].toUpperCase() + c.substring(1).toLowerCase()) + .join('') + : customComponent + const autoImportPathNormalized = autoImportPath && autoImportPath.replaceAll(/^\.*(?=[/\\])/g, '') @@ -109,10 +119,10 @@ export function svgLoader(options?: SvgLoaderOptions) { if (importType === 'componentext') { code = - `import {NuxtIcon} from "#components";\nimport {h} from "vue";\n` + + `import {${normalizedCustomComponent}} from "#components";\nimport {h} from "vue";\n` + code - code += `\nexport default { render() { return h(NuxtIcon, {icon: {render}}) } }` + code += `\nexport default { render() { return h(${normalizedCustomComponent}, {icon: {render}}) } }` return code } else { return `${code}\nexport default { render: render }` diff --git a/src/module.ts b/src/module.ts index 110ef35e..7248fd60 100644 --- a/src/module.ts +++ b/src/module.ts @@ -64,7 +64,8 @@ const nuxtSvgo: NuxtModule = defineNuxtModule({ defaultImport: 'componentext', autoImportPath: './assets/icons/', svgoConfig: undefined, - global: true + global: true, + customComponent: 'NuxtIcon' }, async setup(options) { const { resolvePath, resolve } = createResolver(import.meta.url) diff --git a/test/componentext.options.custom.test.ts b/test/componentext.options.custom.test.ts new file mode 100644 index 00000000..1d8bca09 --- /dev/null +++ b/test/componentext.options.custom.test.ts @@ -0,0 +1,35 @@ +import { fileURLToPath } from 'node:url' +import { describe, it, expect } from 'vitest' +import { setup, $fetch } from '@nuxt/test-utils' +import type { NuxtConfig } from 'nuxt/schema' +import type { ModuleOptions } from '../src/module' + +describe('defaultImport: componentext', async () => { + await setup({ + rootDir: fileURLToPath(new URL('./fixtures/component', import.meta.url)), + nuxtConfig: { + svgo: { + defaultImport: 'componentext', + customComponent: 'TestWrapper' + } as ModuleOptions + } as NuxtConfig + }) + + it('renders the svg as TestWrapper component', async () => { + const html = await $fetch('/') + expect(html).toContain(`test-icon`) + expect(html).toContain(`test--fill`) + }) + + it('renders the svg from assets/icons folder', async () => { + // Get response to a server-rendered page with `$fetch`. + const html = await $fetch('/') + + expect(html).toContain( + '>' + ) + expect(html).toContain( + '>' + ) + }) +}) diff --git a/test/fixtures/component/components/TestWrapper.vue b/test/fixtures/component/components/TestWrapper.vue new file mode 100644 index 00000000..46d4dec3 --- /dev/null +++ b/test/fixtures/component/components/TestWrapper.vue @@ -0,0 +1,46 @@ + + + + +