Skip to content

Commit

Permalink
Fixed bug (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
hkbertoson authored Nov 23, 2024
1 parent 531db17 commit 4690189
Showing 1 changed file with 116 additions and 100 deletions.
216 changes: 116 additions & 100 deletions packages/core/src/vite-plugin-astro-icon.ts
Original file line number Diff line number Diff line change
@@ -1,130 +1,146 @@
import type { AstroConfig, AstroIntegrationLogger } from "astro";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import type { Plugin } from "vite";
import type {AstroConfig, AstroIntegrationLogger} from 'astro';
import {mkdir, readFile, writeFile} from 'node:fs/promises';
import type {Plugin} from 'vite';
import type {
AstroIconCollectionMap,
IconCollection,
IntegrationOptions,
} from "../typings/integration";
import loadLocalCollection from "./loaders/loadLocalCollection.js";
import loadIconifyCollections from "./loaders/loadIconifyCollections.js";
import { createHash } from "node:crypto";
AstroIconCollectionMap,
IconCollection,
IntegrationOptions,
} from '../typings/integration';
import loadLocalCollection from './loaders/loadLocalCollection.js';
import loadIconifyCollections from './loaders/loadIconifyCollections.js';
import {createHash} from 'node:crypto';

interface PluginContext extends Pick<AstroConfig, "root" | "output"> {
logger: AstroIntegrationLogger;
interface PluginContext extends Pick<AstroConfig, 'root' | 'output'> {
logger: AstroIntegrationLogger;
}

export function createPlugin(
{ include = {}, iconDir = "src/icons", svgoOptions }: IntegrationOptions,
ctx: PluginContext,
{include = {}, iconDir = 'src/icons', svgoOptions}: IntegrationOptions,
ctx: PluginContext
): Plugin {
let collections: AstroIconCollectionMap | undefined;
const { root } = ctx;
const virtualModuleId = "virtual:astro-icon";
const resolvedVirtualModuleId = "\0" + virtualModuleId;
let collections: AstroIconCollectionMap | undefined;
const {root} = ctx;
const virtualModuleId = 'virtual:astro-icon';
const resolvedVirtualModuleId = '\0' + virtualModuleId;

return {
name: "astro-icon",
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
async load(id) {
if (id === resolvedVirtualModuleId) {
if (!collections) {
collections = await loadIconifyCollections({ root, include });
}
try {
// Attempt to create local collection
const local = await loadLocalCollection(iconDir, svgoOptions);
collections["local"] = local;
} catch (ex) {
// Failed to load the local collection
}
logCollections(collections, { ...ctx, iconDir });
await generateIconTypeDefinitions(Object.values(collections), root);
return {
name: 'astro-icon',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},

return `export default ${JSON.stringify(
collections,
)};\nexport const config = ${JSON.stringify({ include })}`;
}
},
};
async load(id) {
if (id === resolvedVirtualModuleId) {
try {
if (!collections) {
collections = await loadIconifyCollections({root, include});
}
const local = await loadLocalCollection(iconDir, svgoOptions);
collections['local'] = local;
logCollections(collections, {...ctx, iconDir});
await generateIconTypeDefinitions(Object.values(collections), root);
} catch (ex) {
// Failed to load the local collection
}
return `export default ${JSON.stringify(collections)};\nexport const config = ${JSON.stringify({include})}`;
}
},
configureServer({watcher, moduleGraph}) {
watcher.add(`${iconDir}/**/*.svg`);
watcher.on('change', async () => {
console.log(`Local icons changed, reloading`);
try {
if (!collections) {
collections = await loadIconifyCollections({root, include});
}
const local = await loadLocalCollection(iconDir, svgoOptions);
collections['local'] = local;
logCollections(collections, {...ctx, iconDir});
await generateIconTypeDefinitions(Object.values(collections), root);
moduleGraph.invalidateAll();
} catch (ex) {
// Failed to load the local collection
}
return `export default ${JSON.stringify(collections)};\nexport const config = ${JSON.stringify({include})}`;
});
},
};
}

function logCollections(
collections: AstroIconCollectionMap,
{ logger, iconDir }: PluginContext & { iconDir: string },
collections: AstroIconCollectionMap,
{logger, iconDir}: PluginContext & {iconDir: string}
) {
if (Object.keys(collections).length === 0) {
logger.warn("No icons detected!");
return;
}
const names: string[] = Object.keys(collections).filter((v) => v !== "local");
if (collections["local"]) {
names.unshift(iconDir);
}
logger.info(`Loaded icons from ${names.join(", ")}`);
if (Object.keys(collections).length === 0) {
logger.warn('No icons detected!');
return;
}
const names: string[] = Object.keys(collections).filter((v) => v !== 'local');
if (collections['local']) {
names.unshift(iconDir);
}
logger.info(`Loaded icons from ${names.join(', ')}`);
}

async function generateIconTypeDefinitions(
collections: IconCollection[],
rootDir: URL,
defaultPack = "local",
collections: IconCollection[],
rootDir: URL,
defaultPack = 'local'
): Promise<void> {
const typeFile = new URL("./.astro/icon.d.ts", rootDir);
await ensureDir(new URL("./", typeFile));
const oldHash = await tryGetHash(typeFile);
const currentHash = collectionsHash(collections);
if (currentHash === oldHash) {
return;
}
await writeFile(
typeFile,
`// Automatically generated by astro-icon
const typeFile = new URL('./.astro/icon.d.ts', rootDir);
await ensureDir(new URL('./', typeFile));
const oldHash = await tryGetHash(typeFile);
const currentHash = collectionsHash(collections);
if (currentHash === oldHash) {
return;
}
await writeFile(
typeFile,
`// Automatically generated by astro-icon
// ${currentHash}
declare module 'virtual:astro-icon' {
\texport type Icon = ${
collections.length > 0
? collections
.map((collection) =>
Object.keys(collection.icons).map(
(icon) =>
`\n\t\t| "${
collection.prefix === defaultPack
? ""
: `${collection.prefix}:`
}${icon}"`,
),
)
.flat(1)
.join("")
: "never"
};
}`,
);
collections.length > 0
? collections
.map((collection) =>
Object.keys(collection.icons).map(
(icon) =>
`\n\t\t| "${
collection.prefix === defaultPack
? ''
: `${collection.prefix}:`
}${icon}"`
)
)
.flat(1)
.join('')
: 'never'
};
}`
);
}

function collectionsHash(collections: IconCollection[]): string {
const hash = createHash("sha256");
for (const collection of collections) {
hash.update(collection.prefix);
hash.update(Object.keys(collection.icons).sort().join(","));
}
return hash.digest("hex");
const hash = createHash('sha256');
for (const collection of collections) {
hash.update(collection.prefix);
hash.update(Object.keys(collection.icons).sort().join(','));
}
return hash.digest('hex');
}

async function tryGetHash(path: URL): Promise<string | void> {
try {
const text = await readFile(path, { encoding: "utf-8" });
return text.split("\n", 3)[1].replace("// ", "");
} catch {}
try {
const text = await readFile(path, {encoding: 'utf-8'});
return text.split('\n', 3)[1].replace('// ', '');
} catch {}
}

async function ensureDir(path: URL): Promise<void> {
try {
await mkdir(path, { recursive: true });
} catch {}
try {
await mkdir(path, {recursive: true});
} catch {}
}

0 comments on commit 4690189

Please sign in to comment.