Skip to content

Instantly share code, notes, and snippets.

@jpzwarte
Last active November 5, 2025 12:48
Show Gist options
  • Select an option

  • Save jpzwarte/184ff7680c245496fd12358aa8473ef6 to your computer and use it in GitHub Desktop.

Select an option

Save jpzwarte/184ff7680c245496fd12358aa8473ef6 to your computer and use it in GitHub Desktop.
This shows how you can use CSS imports in your code when using vite and tsdown. This code is extracted from an NPM package that uses it.
const styles = new CSSStyleSheet();
styles.replaceSync(":host {\n align-items: center;\n border-block-start: var(--sl-size-borderWidth-default) solid var(--sl-color-border-plain);\n display: flex;\n padding: var(--sl-size-100);\n}\n\n:host([collapsed]) {\n sl-button sl-icon {\n display: none;\n }\n}\n\nsl-button {\n flex: 1;\n\n sl-icon {\n margin-inline-start: auto;\n }\n\n sl-avatar::part(name) {\n font-weight: var(--sl-text-typeset-fontWeight-demibold);\n }\n}\n\nsl-menu {\n min-inline-size: 250px;\n\n sl-avatar {\n justify-content: center;\n }\n}\n\nsl-menu-item sl-icon + sl-icon {\n margin-inline-start: auto;\n}\n");
let CurrentUser = class CurrentUser$1 extends ScopedElementsMixin(LitElement) {
// Rest of output removed for brevity
static {
this.styles = styles;
}
}
import styles from './current-user.css' with { type: 'css' };
export class CurrentUser extends ScopedElementsMixin(LitElement) {
// Rest of code removed for brevity
static override styles: CSSResultGroup = styles;
}
import { readFileSync } from 'node:fs';
import { URL } from 'node:url';
import { compile } from 'sass-embedded';
import { defineConfig } from 'tsdown/config';
// This plugin handles CSS imports with { type: 'css' } and converts them to CSSStyleSheet
const cssPlugin = {
name: 'css-stylesheet',
transform(code, id) {
// Check if this is a CSS import with type: 'css' attribute
const cssImportRegex = /import\s+(\w+)\s+from\s+['"]([^'"]+\.css)['"]\s+with\s+\{\s*type:\s*['"]css['"]\s*\}/g;
let transformedCode = code;
let hasTransformations = false;
transformedCode = transformedCode.replace(cssImportRegex, (match, varName, cssPath) => {
hasTransformations = true;
// Resolve the CSS file path relative to the current file
const resolvedPath = new URL(cssPath, `file://${id}`).pathname;
try {
const cssContent = readFileSync(resolvedPath, 'utf-8');
// Create a CSSStyleSheet with the CSS content
return `
const ${varName} = new CSSStyleSheet();
${varName}.replaceSync(${JSON.stringify(cssContent)});
`;
} catch (error) {
this.error(`Failed to read CSS file ${resolvedPath}: ${error.message}`);
}
});
return hasTransformations ? { code: transformedCode, map: null } : null;
}
};
export default defineConfig({
dts: true,
entry: ['index.ts', 'src/service-worker/sw.ts'],
exports: true,
inputOptions: {
transform: {
assumptions: {
setPublicClassFields: true
},
typescript: {
removeClassFieldsWithoutInitializer: true
},
decorator: {
legacy: true
}
}
},
platform: 'browser',
plugins: [cssPlugin],
target: 'es2022',
unbundle: true
});
declare module '*.css' {
const css: CSSStyleSheet;
export default css;
}
import { importCSSSheet } from '@roenlie/vite-plugin-import-css-sheet';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [importCSSSheet()],
// etc
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment