css is now string | CSSStyleSheet. A sheet is adopted as-is: into its own
shadow root, an enclosing shadow root, or document.adoptedStyleSheets for
light DOM at the document level. Strings behave as before.
The examples import their styles with `with { type: 'css' }` and their
static templates with `with { type: 'text' }`. Safari doesn't support those
yet, so vite.config.ts rewrites them into modules Vite builds: a constructed
CSSStyleSheet, or the file's text. npm run examples now just runs vite,
with root set in the config.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
43 lines
1.6 KiB
TypeScript
43 lines
1.6 KiB
TypeScript
import { readFile } from 'node:fs/promises';
|
|
import { defineConfig, type Plugin } from 'vite';
|
|
|
|
const ATTRIBUTE_IMPORT =
|
|
/(from\s*)(['"])([^'"]+)\2\s*with\s*\{\s*type\s*:\s*(['"])(css|text)\4\s*\}/g;
|
|
|
|
/**
|
|
* Standard import attributes, built for browsers that don't support them yet (Safari):
|
|
*
|
|
* - `import sheet from './x.css' with { type: 'css' }` → a `CSSStyleSheet`
|
|
* - `import text from './x.html' with { type: 'text' }` → the file's contents as a string
|
|
*
|
|
* The attribute is rewritten to a query before Vite sees the import. `?raw` makes Vite's own CSS
|
|
* handling leave the file alone; `&sheet` is loaded here as a module that builds the stylesheet.
|
|
*/
|
|
function importAttributes(): Plugin {
|
|
return {
|
|
name: 'import-attributes',
|
|
enforce: 'pre',
|
|
transform(code, id) {
|
|
if (!/\.[cm]?[jt]s$/.test(id) || !code.includes('with')) return null;
|
|
const out = code.replace(
|
|
ATTRIBUTE_IMPORT,
|
|
(_, from: string, quote: string, path: string, _q: string, type: string) =>
|
|
`${from}${quote}${path}?raw${type === 'css' ? '&sheet' : ''}${quote}`,
|
|
);
|
|
return out === code ? null : { code: out, map: null };
|
|
},
|
|
async load(id) {
|
|
if (!id.endsWith('?raw&sheet')) return null;
|
|
const file = id.slice(0, -'?raw&sheet'.length);
|
|
this.addWatchFile(file);
|
|
const css = await readFile(file, 'utf8');
|
|
return `const sheet = new CSSStyleSheet();\nsheet.replaceSync(${JSON.stringify(css)});\nexport default sheet;\n`;
|
|
},
|
|
};
|
|
}
|
|
|
|
export default defineConfig({
|
|
root: 'examples',
|
|
plugins: [importAttributes()],
|
|
});
|