-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature: add support for a resolver for unplugin-auto-import #364
Comments
I think it's possible but I am too busy to work on it. |
I was going to submit a PR, however the repo structure is a bit confusing to me, so I'll just add the items that I was able to get working, here. This would add the // icon-resolver.ts
import { readdirSync } from 'fs'
import { dirname } from 'path'
import { resolveModule } from 'local-pkg'
import type { ImportsMap } from 'unplugin-auto-import/types'
let _cache: ImportsMap | undefined
export default (pkg: string): ImportsMap => {
if (!_cache) {
let packages: Array<string>
try {
const icon_path = resolveModule(pkg) as string
packages = readdirSync(dirname(icon_path), { withFileTypes: true })
.filter(item => !item.isDirectory() && item.name.match(/^[A-Z][A-Za-z0-9]+\.js$/))
.map(item => item.name.replace(/\.js$/, ''))
}
catch (error) {
console.error(error)
throw new Error(`[auto-import] failed to load "${pkg}", have you installed it?`)
}
if (packages) {
_cache = {
[pkg]: packages,
}
}
}
return _cache || {}
} And this would be how it can be used: // vite.config.js
import { defineConfig } from "vite"
import AutoImport from "unplugin-auto-import/vite"
import IconResolver from "./icon-resolver.ts"
export default defineConfig({
// [...]
plugins: [
// [...]
AutoImport({
imports: [
// [...]
// replacing @vicons/ionicons5 with whatever package the user is using.
// if it's not installed, it will throw an exception, suggesting to install it.
// can also be specified multiple times to load multiple packages.
IconResolver("@vicons/ionicons5"),
],
}),
],
}) Then, you can just use |
Also going to work on a That would allow referencing the icons as components dynamically, as well. Not just JS/TS. |
And here is the vue auto-component-import resolver: // icon-component-resolver.ts
import { readdirSync } from 'fs'
import { dirname } from 'path'
import { resolveModule } from 'local-pkg'
import type { ComponentResolver } from 'unplugin-vue-components/types'
let _cache: Array<string>
export interface IconResolverOptions {
pkg: string
prefix?: string
}
export function IconComponentResolver(options: IconResolverOptions): ComponentResolver {
if (!_cache) {
try {
const icon_path = resolveModule(options.pkg) as string
_cache = readdirSync(dirname(icon_path), { withFileTypes: true })
.filter(item => !item.isDirectory() && item.name.match(/^[A-Z][A-Za-z0-9]+\.js$/))
.map(item => item.name.replace(/\.js$/, ''))
} catch (error) {
console.error(error)
throw new Error(`[unplugin-vue-components] failed to load "${options.pkg}", have you installed it?`)
}
}
return {
type: 'component',
resolve: (name: string) => {
if (name.startsWith(options.prefix)) {
name = name.substring(options.prefix.length)
}
if (_cache.includes(name)) {
return {
name: name,
from: options.pkg,
}
}
},
}
} And usage example: // vite.config.js
import { defineConfig } from "vite"
import Components from "unplugin-vue-components/vite"
import { IconComponentResolver } from "./icon-component-resolver.ts"
export default defineConfig({
// [...]
plugins: [
// [...]
Components({
directoryAsNamespace: true,
resolvers: [IconComponentResolver({ pkg: "@vicons/ionicons5", prefix: "X" })],
}),
],
}) As shown above, you can supply an optional prefix, primarily as a way of ensuring that the components can follow the standard of requiring a dash (e.g. With the above, a user just dropping in two lines into their |
I think this a good example. I'll try to add it later. |
Also I've a question. Is there any performance issue? since there may be more than 5k icon files in a single package (fluent icons, meterial icons). |
I haven't tried fluent or material yet, but I did try ionicons5 with aliased import names, which would have been near that amount, and it was still very fast, adding virtually no overhead. With that being said, I also do have a Ryzen 9 5900x and 32GB ram, so I'm not sure on a slower device, what it'd look like. It should still be very fast I'd think though, as both of the above approaches gather the list of importable names and returns those, and that array is cached until you restart Vite (or update any of the resolver/vite files). It would only be iterating through a relatively lightweight array, and if you use one of the matching names, only then does it actually import it (so still tree shakeable, like normal). Vites internal cache I believe also means that it's not going to re-import each HMR, similar to any other module import. |
great catch, this worked perfect with Vite + Vue 3 and Antdv 3 |
Given the current nature of how many icons exist within each sub-package, it'd be nice to have support to auto-import icons using antfu/unplugin-auto-import.
Normally it'd be pretty easy to add a custom resolver, however due to the icons not having naming prefixes, my guess is the best bet is generating a resolver for each package, that includes the list of importable icons.
The benefit in doing so, if folks use
unplugin-auto-import
, is that they no longer need to import any icons, and only the referenced icons are actually bundled.Thoughts?
The text was updated successfully, but these errors were encountered: