react-static-plugin-favicons
Version:
Favicons plugin for React-Static
90 lines (80 loc) • 2.64 kB
text/typescript
import * as React from 'react';
import ReactStaticFavicons from '@kuroku/react-static-favicons';
import { Configuration as FaviconsConfiguration } from 'favicons';
interface Options {
/**
* The source image
*/
inputFile: string;
/**
* Directory where the image files will be written
*/
outputDir?: string;
/**
* Configuration for `favicons`, see https://www.npmjs.com/package/favicons#nodejs
*/
configuration?: FaviconsConfiguration;
};
interface HookOptions {
meta: {
faviconsElements?: JSX.Element[];
};
};
interface ReactStaticConfig {
paths: {
ASSETS: string;
};
};
interface ReactStaticConfigData {
config: ReactStaticConfig;
};
export default (options: Options) => {
if (typeof options.inputFile === 'undefined') {
console.error('[react-static-plugin-favicons] Please specify a source image for your favicon through the `inputFile` parameter.');
return;
}
let reactStaticFavicons: ReactStaticFavicons;
return {
afterGetConfig: (configData: ReactStaticConfigData) => {
if (typeof reactStaticFavicons === 'undefined') {
reactStaticFavicons = new ReactStaticFavicons({
inputFile: options.inputFile,
outputDir: options.outputDir || configData.config.paths.ASSETS,
configuration: options.configuration || {},
});
}
return configData;
},
beforeRenderToHtml: async (element: JSX.Element, { meta }: HookOptions) => {
meta.faviconsElements = await renderFaviconsOnce(reactStaticFavicons);
return element;
},
headElements: async (elements: JSX.Element[], { meta }: HookOptions) => {
return [
...elements,
meta.faviconsElements
]
}
};
};
let renderPromise: Promise<JSX.Element[]>;
/**
* Singleton process to render favicons
*
* Because the Node hooks (e.g. `beforeRenderToHtml`) of React Static get called a lot, simply
* calling ReactStaticFavicons.render() would spawn a lot of process rendering favicons.
* Hence, this function only calls that once, and returns that promise again if called again.
*
* @param rsf Configured instance of React Static Favicons
* @returns Promise that completes once all icons have been generated, returning the elements that
* should be added to a page's `<head>`.
*/
function renderFaviconsOnce(rsf: ReactStaticFavicons) {
// We cannot test this due to storing `renderPromise` in the module scope, and thus preserving it
// in different tests:
/* istanbul ignore else */
if (typeof renderPromise === 'undefined') {
renderPromise = rsf.render();
}
return renderPromise;
}