Files
sk-react-toolkit/vite/index.ts
T

82 lines
3.3 KiB
TypeScript

import type { Plugin } from 'vite'
/** The choices of VITE_FONT. */
export const FONTS = ['cdn', 'bundled', 'none'] as const
export type Font = (typeof FONTS)[number]
const FONT_MODULE = 'virtual:font'
/**
* Provides the fonts of the toolkit's fonts.ts as VITE_FONT selects: cdn adds the Google Fonts links for Roboto and
* Roboto Mono to index.html, bundled imports @fontsource/roboto through the virtual:font module, none adds nothing; a
* font not provided falls back to the system fonts of its stack. The toolkit's renderApp imports virtual:font.
*/
export function font(choice: Font): Plugin {
const resolved = `\0${FONT_MODULE}`
return {
name: 'font',
resolveId(id) {
return id === FONT_MODULE ? resolved : undefined
},
load(id) {
if (id !== resolved) {
return undefined
}
return choice === 'bundled' ? ['300', '400', '500', '700'].map((weight) => `import '@fontsource/roboto/${weight}.css'`).join('\n') : ''
},
transformIndexHtml() {
if (choice !== 'cdn') {
return []
}
return [
{ tag: 'link', attrs: { rel: 'preconnect', href: 'https://fonts.googleapis.com' } },
{ tag: 'link', attrs: { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: true } },
{ tag: 'link', attrs: { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Roboto+Mono:wght@300;400;500;700&display=swap' } },
]
},
}
}
/**
* Sets the color scheme of appTheme on the page before its first paint, so a dark page, and a page in an iframe of a
* dark page, is not white until the application renders: adds to index.html a script that sets the class dark or
* light on <html>, from MUI's mui-mode in localStorage or, for system, from prefers-color-scheme, and a style that
* gives those classes their color-scheme and the dark scheme MUI's dark background.
*/
export function colorScheme(): Plugin {
const script = `(function () {
try {
var mode = localStorage.getItem('mui-mode') || 'system';
var dark = mode === 'dark' || (mode === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.add(dark ? 'dark' : 'light');
} catch (e) {}
})();`
return {
name: 'color-scheme',
transformIndexHtml() {
return [
{ tag: 'style', children: 'html.light { color-scheme: light; }\nhtml.dark { color-scheme: dark; background-color: #121212; }', injectTo: 'head' },
{ tag: 'script', children: script, injectTo: 'head' },
]
},
}
}
/** VITE_FONT of env, the variables Vite's loadEnv answers, cdn when it is not set; another value throws. */
export function fontChoice(env: Record<string, string>): Font {
const choice = env.VITE_FONT ?? 'cdn'
if (!FONTS.includes(choice as Font)) {
throw new Error(`VITE_FONT=${choice} is not one of ${FONTS.join(', ')}.`)
}
return choice as Font
}
/**
* The resolve options of an application that uses the toolkit's web code through a link: the toolkit's imports of
* React, MUI and Emotion are resolved from the application's own node_modules, so the page has one copy of each.
*/
export const TOOLKIT_RESOLVE = {
dedupe: ['react', 'react-dom', '@mui/material', '@mui/icons-material', '@mui/system', '@emotion/react', '@emotion/styled'],
}