diff --git a/README.md b/README.md index f796f3ba..28838fcd 100644 --- a/README.md +++ b/README.md @@ -226,7 +226,8 @@ export default defineConfig({ ] }) ``` - + +
Vue CLI
@@ -243,6 +244,7 @@ module.exports = { ``` You can also rename the Vue configuration file to `vue.config.mjs` and use static import syntax (you should use latest `@vue/cli-service ^5.0.8`): + ```ts // vue.config.mjs import Icons from 'unplugin-icons/webpack' @@ -274,6 +276,7 @@ export default defineConfig({ sveltekit(), Icons({ compiler: 'svelte', + // compiler: 'svelte-snippet', For snippet support }) ] }) @@ -283,12 +286,15 @@ Check instructions in the `Frameworks -> Svelte` section below if you faced modu See [the SvelteKit example](examples/sveltekit) for a working example project. +See [the SvelteKit + Snippet example](examples/sveltekit-snippet) for a working example project. +
Svelte + Vite
Svelte support requires the `@sveltejs/vite-plugin-svelte` plugin: + ```shell npm i -D @sveltejs/vite-plugin-svelte ``` @@ -306,6 +312,7 @@ export default defineConfig({ svelte(), Icons({ compiler: 'svelte', + // compiler: 'svelte-snippet', For snippet support }), ], }) @@ -315,12 +322,15 @@ Check instructions in the `Frameworks -> Svelte` section below if you faced modu See [the Svelte + Vite example](examples/vite-svelte) for a working example project. +See [the Svelte + Snippet + Vite example](examples/vite-svelte-snippet) for a working example project. +
Next.js
The `unplugin-icons` plugin should be configured on `next.config.js` configuration file: + ```ts // next.config.js /** @type {import('next').NextConfig} */ @@ -340,6 +350,7 @@ module.exports = { ``` You can also rename the Next configuration file to `next.config.mjs` and use static import syntax: + ```ts // next.config.mjs import Icons from 'unplugin-icons/webpack' @@ -615,6 +626,12 @@ See [the Solid example](examples/vite-solid) for a working example project. Icons({ compiler: 'svelte' }) ``` +If you want to use [snippet](https://svelte.dev/docs/svelte/snippet) + +```ts +Icons({ compiler: 'svelte-snippet' }) +``` + Type Declarations For SvelteKit, in the `src/app.d.ts` file: @@ -623,6 +640,20 @@ For SvelteKit, in the `src/app.d.ts` file: import 'unplugin-icons/types/svelte' ``` +For SvelteKit + Snippet + +```ts +import 'unplugin-icons/types/svelte-snippet' +``` + +For Svelte + Snippet + Vite, in the `src/vite-env.d.ts` file: + +```js +/// +/// +/// +``` + For Svelte + Vite, in the `src/vite-env.d.ts` file: ```js @@ -632,6 +663,7 @@ For Svelte + Vite, in the `src/vite-env.d.ts` file: ``` If you're still using Svelte 4, replace the reference to use Svelte 4: + ```js /// /// @@ -639,6 +671,7 @@ If you're still using Svelte 4, replace the reference to use Svelte 4: ``` If you're still using Svelte 3, replace the reference to use Svelte 3: + ```js /// /// @@ -647,6 +680,8 @@ If you're still using Svelte 3, replace the reference to use Svelte 3: See [the Svelte example](examples/vite-svelte) for a working example project. +See [the Svelte + Snippet example](examples/vite-svelte-snippet) for a working example project. +
@@ -705,6 +740,7 @@ Icons({ compiler: 'qwik' }) ``` Alternatively, you can use `jsx` compiler, requires peer dependency `@svgr/core` and its plugin `@svgr/plugin-jsx`: + ```bash npm i -D @svgr/core @svgr/plugin-jsx ``` @@ -804,6 +840,7 @@ import IconBar from '~icons/my-yet-other-icons/bar' ``` > 💡 SVG Authoring Tips: +> > - To make your icons color adaptable, set `fill="currentColor"` or `stroke="currentColor"` in your SVG. > - Leave the `height` and `width` unspecified, we will set them for you. @@ -830,6 +867,7 @@ From version `v0.18.3` you can use other packages to load icons from others auth **WARNING**: external packages must include `icons.json` file with the `icons` data in `IconifyJSON` format, which can be exported with Iconify Tools. Check [Exporting icon set as JSON package](https://iconify.design/docs/libraries/tools/export/json-package.html) for more details. For example, you can use `an-awesome-collection` or `@my-awesome-collections/some-collection` to load your custom or third party icons: + ```ts // loader helpers import { ExternalPackageIconLoader } from 'unplugin-icons/loaders' @@ -838,6 +876,7 @@ Icons({ customCollections: ExternalPackageIconLoader('my-awesome-collection') }) ``` When using with resolvers for auto-importing, remember you will need to tell it your custom collection names: + ```ts IconResolver({ customCollections: [ @@ -847,6 +886,7 @@ IconResolver({ ``` You can also combine it with `FileSystemIconLoader` or with other custom icon loaders: + ```ts // loader helpers import { ExternalPackageIconLoader, FileSystemIconLoader } from 'unplugin-icons/loaders' @@ -949,6 +989,7 @@ See `src/App.vue` component and `vite.config.ts` configuration on `vite-vue3` ex ## Global Custom Icon Transformation From version `0.14.2`, when loading your custom icons, you can transform them, for example adding `fill` attribute with `currentColor`: + ```ts Icons({ customCollections: { @@ -972,7 +1013,7 @@ Icons({ When using this plugin with your custom icons, consider using a cleanup process similar to that done by [Iconify](https://iconify.design/) for any icons sets. All the tools you need are available in [Iconify Tools](https://docs.iconify.design/tools/tools2/). -You can check this repo, using `unplugin-icons` on a `SvelteKit` project: https://github.com/iconify/tools/tree/main/%40iconify-demo/unplugin-svelte. +You can check this repo, using `unplugin-icons` on a `SvelteKit` project: . Read [Cleaning up icons](https://docs.iconify.design/articles/cleaning-up-icons/) article from [Iconify](https://iconify.design/) for more details. diff --git a/examples/sveltekit-snippet/.stackblitz.js b/examples/sveltekit-snippet/.stackblitz.js new file mode 100644 index 00000000..4c0b28b7 --- /dev/null +++ b/examples/sveltekit-snippet/.stackblitz.js @@ -0,0 +1,15 @@ +import { promises as fsPromises } from 'node:fs' + +updatePackageJson() + +async function updatePackageJson() { + const filename = './package.json' + try { + const contents = await fsPromises.readFile(filename, 'utf-8') + const updatedContent = contents.replace('workspace:*', 'latest') + await fsPromises.writeFile(filename, updatedContent) + } + catch (err) { + console.error(err) + } +} diff --git a/examples/sveltekit-snippet/package.json b/examples/sveltekit-snippet/package.json new file mode 100644 index 00000000..8383e872 --- /dev/null +++ b/examples/sveltekit-snippet/package.json @@ -0,0 +1,29 @@ +{ + "name": "sveltekit-snippet-example", + "type": "module", + "private": true, + "description": "unplugin-icons + SvelteKit + Snippet", + "scripts": { + "build": "vite build", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@iconify-json/icon-park": "^1.2.2", + "@iconify-json/logos": "^1.2.4", + "@iconify-json/mdi": "^1.2.3", + "@sveltejs/kit": "^2.17.2", + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "svelte": "^5.20.1", + "svelte-check": "^4.1.4", + "tslib": "^2.8.1", + "typescript": "^5.7.3", + "unplugin-icons": "workspace:*" + }, + "stackblitz": { + "installDependencies": false, + "startCommand": "node .stackblitz.js && npm install && npm run dev" + } +} diff --git a/examples/sveltekit-snippet/src/app.d.ts b/examples/sveltekit-snippet/src/app.d.ts new file mode 100644 index 00000000..52804557 --- /dev/null +++ b/examples/sveltekit-snippet/src/app.d.ts @@ -0,0 +1,12 @@ +import 'unplugin-icons/types/svelte-snippet' + +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface Platform {} + } +} + +export {} diff --git a/examples/sveltekit-snippet/src/app.html b/examples/sveltekit-snippet/src/app.html new file mode 100644 index 00000000..8c6240db --- /dev/null +++ b/examples/sveltekit-snippet/src/app.html @@ -0,0 +1,10 @@ + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/examples/sveltekit-snippet/src/routes/+page.svelte b/examples/sveltekit-snippet/src/routes/+page.svelte new file mode 100644 index 00000000..07775330 --- /dev/null +++ b/examples/sveltekit-snippet/src/routes/+page.svelte @@ -0,0 +1,37 @@ + + +
+ + {@render svelteLogoSnippet({ + style: "font-size:2em" + })} + +
+
+ + + {@render mdiStore24HourSnippet()} + + + {@render mdiAlarmOffSnippet()} + + + {@render iconParkAbnormalSnippet()} + + {@html RawMdiAlarmOff} + {@html RawMdiAlarmOff2} +
+ + + diff --git a/examples/sveltekit-snippet/static/favicon.ico b/examples/sveltekit-snippet/static/favicon.ico new file mode 100644 index 00000000..d75d248e Binary files /dev/null and b/examples/sveltekit-snippet/static/favicon.ico differ diff --git a/examples/sveltekit-snippet/svelte.config.js b/examples/sveltekit-snippet/svelte.config.js new file mode 100644 index 00000000..7d19b264 --- /dev/null +++ b/examples/sveltekit-snippet/svelte.config.js @@ -0,0 +1,10 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + // Consult https://github.com/sveltejs/svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} + +export default config diff --git a/examples/sveltekit-snippet/tsconfig.json b/examples/sveltekit-snippet/tsconfig.json new file mode 100644 index 00000000..d1deb760 --- /dev/null +++ b/examples/sveltekit-snippet/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.svelte-kit/tsconfig.json" +} diff --git a/examples/sveltekit-snippet/vite.config.ts b/examples/sveltekit-snippet/vite.config.ts new file mode 100644 index 00000000..9e2c4c47 --- /dev/null +++ b/examples/sveltekit-snippet/vite.config.ts @@ -0,0 +1,12 @@ +import { sveltekit } from '@sveltejs/kit/vite' +import Icons from 'unplugin-icons/vite' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [ + sveltekit(), + Icons({ + compiler: 'svelte-snippet', + }), + ], +}) diff --git a/examples/vite-svelte-snippet/.stackblitz.js b/examples/vite-svelte-snippet/.stackblitz.js new file mode 100644 index 00000000..4c0b28b7 --- /dev/null +++ b/examples/vite-svelte-snippet/.stackblitz.js @@ -0,0 +1,15 @@ +import { promises as fsPromises } from 'node:fs' + +updatePackageJson() + +async function updatePackageJson() { + const filename = './package.json' + try { + const contents = await fsPromises.readFile(filename, 'utf-8') + const updatedContent = contents.replace('workspace:*', 'latest') + await fsPromises.writeFile(filename, updatedContent) + } + catch (err) { + console.error(err) + } +} diff --git a/examples/vite-svelte-snippet/index.html b/examples/vite-svelte-snippet/index.html new file mode 100644 index 00000000..222c291c --- /dev/null +++ b/examples/vite-svelte-snippet/index.html @@ -0,0 +1,11 @@ + + + + + Vite App + + +
+ + + diff --git a/examples/vite-svelte-snippet/package.json b/examples/vite-svelte-snippet/package.json new file mode 100644 index 00000000..3b777402 --- /dev/null +++ b/examples/vite-svelte-snippet/package.json @@ -0,0 +1,31 @@ +{ + "name": "vite-svelte-snippet", + "type": "module", + "private": true, + "description": "unplugin-icons + Svelte + Snippet (Vite)", + "scripts": { + "build": "DEBUG='unplugin-icons:*' vite build", + "dev": "DEBUG='unplugin-icons:*' vite", + "serve": "npm run build && DEBUG='unplugin-icons:*' vite preview", + "build-custom": "DEBUG='unplugin-icons:*' CUSTOM_COMPILER=true vite build", + "dev-custom": "DEBUG='unplugin-icons:*' CUSTOM_COMPILER=true vite", + "serve-custom": "npm run build-custom && DEBUG='unplugin-icons:*' CUSTOM_COMPILER=true vite preview" + }, + "devDependencies": { + "@iconify-json/icon-park": "^1.2.2", + "@iconify-json/logos": "^1.2.4", + "@iconify-json/mdi": "^1.2.3", + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "@tsconfig/svelte": "^5.0.4", + "svelte": "^5.20.1", + "svelte-check": "^4.1.4", + "svelte-preprocess": "^6.0.3", + "typescript": "^5.7.3", + "unplugin-icons": "workspace:*", + "vite": "^6.1.0" + }, + "stackblitz": { + "installDependencies": false, + "startCommand": "node .stackblitz.js && npm install && npm run dev" + } +} diff --git a/examples/vite-svelte-snippet/src/App.svelte b/examples/vite-svelte-snippet/src/App.svelte new file mode 100644 index 00000000..455dce49 --- /dev/null +++ b/examples/vite-svelte-snippet/src/App.svelte @@ -0,0 +1,38 @@ + + +
+ + {@render svelteLogoSnippet({ + style: "font-size:2em" + })} + +
+
+ + + {@render mdiStore24HourSnippet()} + + + {@render mdiAlarmOffSnippet()} + + + {@render iconParkAbnormalSnippet()} + + {@html RawMdiAlarmOff} + {@html RawMdiAlarmOff2} +
+ + + + \ No newline at end of file diff --git a/examples/vite-svelte-snippet/src/CustomSvg.svelte b/examples/vite-svelte-snippet/src/CustomSvg.svelte new file mode 100644 index 00000000..38b0aa1f --- /dev/null +++ b/examples/vite-svelte-snippet/src/CustomSvg.svelte @@ -0,0 +1,4 @@ + +{@html content} diff --git a/examples/vite-svelte-snippet/src/main.ts b/examples/vite-svelte-snippet/src/main.ts new file mode 100644 index 00000000..928b6c52 --- /dev/null +++ b/examples/vite-svelte-snippet/src/main.ts @@ -0,0 +1,8 @@ +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { + target: document.getElementById('app')!, +}) + +export default app diff --git a/examples/vite-svelte-snippet/src/vite-env.d.ts b/examples/vite-svelte-snippet/src/vite-env.d.ts new file mode 100644 index 00000000..545ba206 --- /dev/null +++ b/examples/vite-svelte-snippet/src/vite-env.d.ts @@ -0,0 +1,3 @@ +/// +/// +/// diff --git a/examples/vite-svelte-snippet/svelte.config.js b/examples/vite-svelte-snippet/svelte.config.js new file mode 100644 index 00000000..aa911a70 --- /dev/null +++ b/examples/vite-svelte-snippet/svelte.config.js @@ -0,0 +1,7 @@ +import sveltePreprocess from 'svelte-preprocess' + +export default { + // Consult https://github.com/sveltejs/svelte-preprocess + // for more information about preprocessors + preprocess: sveltePreprocess(), +} diff --git a/examples/vite-svelte-snippet/tsconfig.json b/examples/vite-svelte-snippet/tsconfig.json new file mode 100644 index 00000000..1d1132bb --- /dev/null +++ b/examples/vite-svelte-snippet/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "esnext", + "baseUrl": ".", + "module": "esnext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true + }, + "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] +} diff --git a/examples/vite-svelte-snippet/vite.config.js b/examples/vite-svelte-snippet/vite.config.js new file mode 100644 index 00000000..d025610d --- /dev/null +++ b/examples/vite-svelte-snippet/vite.config.js @@ -0,0 +1,39 @@ +import process from 'node:process' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import Icons from 'unplugin-icons/vite' +import { defineConfig } from 'vite' + +const options = process.env.CUSTOM_COMPILER === 'true' + ? { + compiler: { + extension: 'svelte-snippet', + compiler: compilerFactory(), + }, + } + : { compiler: 'svelte-snippet' } + +export default defineConfig({ + plugins: [ + svelte(), + Icons(options), + ], +}) + +function customSvelteCompiler(svg) { + const openTagStart = svg.indexOf('', openTagStart) + const closeTagStart = svg.lastIndexOf(' + import CustomSvg from "/src/CustomSvg.svelte"; + const content=\`${content.replace(/`/g, '`')}\`; + + +` +} + +// to show how to use async +async function compilerFactory() { + return Promise.resolve(customSvelteCompiler) +} diff --git a/package.json b/package.json index d5930fe3..fcddac8f 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,9 @@ "./types/svelte5": { "types": "./types/svelte5.d.ts" }, + "./types/svelte-snippet": { + "types": "./types/svelte-snippet.d.ts" + }, "./types/vue": { "types": "./types/vue.d.ts" }, diff --git a/src/core/compilers/index.ts b/src/core/compilers/index.ts index 0335c66a..2095db5c 100644 --- a/src/core/compilers/index.ts +++ b/src/core/compilers/index.ts @@ -8,6 +8,7 @@ import { QwikCompiler } from './qwik' import { RawCompiler } from './raw' import { SolidCompiler } from './solid' import { SvelteCompiler } from './svelte' +import { SvelteSnippetCompiler } from './svelte-snippet' import { Vue2Compiler } from './vue2' import { Vue3Compiler } from './vue3' import { WebComponentsCompiler } from './web-components' @@ -20,6 +21,7 @@ export const compilers: Record { + const openTagEnd = svg.indexOf('>', svg.indexOf('` + + sfc += svg.slice(openTagEnd + 1, closeTagStart) + + sfc += svg.slice(closeTagStart) + + return `{#snippet snippet(p)}${sfc}{/snippet}{@render snippet(p)}` +}) as Compiler diff --git a/src/index.ts b/src/index.ts index b930d9a8..4f15210b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,6 +35,7 @@ const unplugin = createUnplugin((options = {}) => { return `${res}.jsx` case 'marko': return `${res}.marko` + case 'svelte-snippet': case 'svelte': return `${res}.svelte` case 'solid': diff --git a/src/types.ts b/src/types.ts index cc2ecd6f..f9d5abc3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -70,7 +70,7 @@ export interface Options { * * @default (detect automatically, fallback to 'vue3') */ - compiler?: 'astro' | 'jsx' | 'marko' | 'none' | 'solid' | 'svelte' | 'raw' | 'vue2' | 'vue3' | 'web-components' | 'qwik' | CustomCompiler + compiler?: 'astro' | 'jsx' | 'marko' | 'none' | 'solid' | 'svelte' | 'svelte-snippet' | 'raw' | 'vue2' | 'vue3' | 'web-components' | 'qwik' | CustomCompiler /** * JSX style, works only when compiler set to `jsx` diff --git a/types/svelte-snippet.d.ts b/types/svelte-snippet.d.ts new file mode 100644 index 00000000..2d211973 --- /dev/null +++ b/types/svelte-snippet.d.ts @@ -0,0 +1,21 @@ +declare module 'virtual:icons/*' { + import type { Component, Snippet } from 'svelte' + import type { SvelteHTMLElements } from 'svelte/elements' + + const component: Component + const snippet: Snippet<[SvelteHTMLElements['svg']?]> + + export default component + export { snippet } +} + +declare module '~icons/*' { + import type { Component, Snippet } from 'svelte' + import type { SvelteHTMLElements } from 'svelte/elements' + + const component: Component + const snippet: Snippet<[SvelteHTMLElements['svg']?]> + + export default component + export { snippet } +} diff --git a/types/svelte5.d.ts b/types/svelte5.d.ts index 41680d49..78c8030e 100644 --- a/types/svelte5.d.ts +++ b/types/svelte5.d.ts @@ -1,6 +1,5 @@ declare module 'virtual:icons/*' { import type { Component } from 'svelte' - import type { SvelteHTMLElements } from 'svelte/elements' const component: Component @@ -9,7 +8,6 @@ declare module 'virtual:icons/*' { declare module '~icons/*' { import type { Component } from 'svelte' - import type { SvelteHTMLElements } from 'svelte/elements' const component: Component