Skip to content

Commit a89aade

Browse files
authored
fix: enable HMR for vite-plugin-lit-css (#80)
The plugin creates virtual modules for CSS imports but wasn't watching the underlying CSS files or invalidating the virtual modules on change. - Add `addWatchFile` in the `load` hook so Vite watches the CSS files - Add `handleHotUpdate` hook to invalidate virtual modules when their source CSS files change - Add integration test verifying HMR invalidation and re-transform Closes #79 Assisted-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d602875 commit a89aade

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { createServer } from 'vite';
2+
import { writeFileSync, readFileSync } from 'node:fs';
3+
import { resolve } from 'node:path';
4+
5+
const cssFile = resolve('src/styles.css');
6+
const originalCSS = readFileSync(cssFile, 'utf8');
7+
8+
async function test() {
9+
const server = await createServer({
10+
configFile: resolve('vite.config.js'),
11+
server: { port: 0 },
12+
});
13+
14+
await server.listen();
15+
16+
try {
17+
// Transform the entry to populate the module graph
18+
const entryModule = await server.transformRequest('src/my-element.js');
19+
if (!entryModule) throw new Error('Could not transform entry module');
20+
21+
// Verify the virtual module exists in the module graph
22+
const resolvedCssPath = resolve(cssFile);
23+
const virtualId = `\0${resolvedCssPath}.lit-css.js`;
24+
const mod = server.moduleGraph.getModuleById(virtualId);
25+
if (!mod) throw new Error('Virtual module not found in module graph');
26+
console.log('OK: Virtual module found in module graph');
27+
28+
// Wait for watcher to settle, then modify the CSS
29+
await new Promise(r => setTimeout(r, 500));
30+
writeFileSync(cssFile, ':host { display: block; outline: 4px solid red; }\n');
31+
32+
// Wait for the module to be invalidated (transformResult nulled out)
33+
await new Promise((resolve, reject) => {
34+
const timeout = setTimeout(
35+
() => reject(new Error('HMR timeout - virtual module was not invalidated')),
36+
5000,
37+
);
38+
const interval = setInterval(() => {
39+
const currentMod = server.moduleGraph.getModuleById(virtualId);
40+
if (currentMod && currentMod.transformResult === null) {
41+
clearTimeout(timeout);
42+
clearInterval(interval);
43+
resolve();
44+
}
45+
}, 100);
46+
});
47+
console.log('OK: HMR invalidated the virtual module after CSS change');
48+
49+
// Verify updated content is served
50+
const updated = await server.transformRequest(mod.url, { forceTransform: true });
51+
if (!updated?.code.includes('solid red'))
52+
throw new Error('Transformed module does not contain updated CSS');
53+
console.log('OK: Transformed module contains updated CSS');
54+
55+
console.log('\nAll HMR tests passed!');
56+
} finally {
57+
writeFileSync(cssFile, originalCSS);
58+
await server.close();
59+
}
60+
}
61+
62+
test().catch(e => {
63+
console.error(`FAIL: ${e.message}`);
64+
process.exit(1);
65+
});

packages/vite-plugin-lit-css/vite-plugin-lit-css.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ export function litCSS(options?: LitCSSOptions): Plugin {
7676
// Extract the original CSS file path (remove \0 prefix and .lit-css.js suffix)
7777
const cleanId = id.replace(/^\0/, '').replace(/\.lit-css\.js$/, '');
7878

79+
// Watch the original CSS file so changes trigger rebuilds
80+
this.addWatchFile(cleanId);
81+
7982
try {
8083
const css = await readFile(cleanId, 'utf8');
8184
const code = await transform({ css, specifier, tag, filePath: cleanId, ...rest });
@@ -87,6 +90,13 @@ export function litCSS(options?: LitCSSOptions): Plugin {
8790
this.error(error?.message ?? String(error));
8891
}
8992
},
93+
94+
handleHotUpdate({ file, server, modules }) {
95+
if (!filter(file)) return;
96+
const virtualId = `\0${file}.lit-css.js`;
97+
const module = server.moduleGraph.getModuleById(virtualId);
98+
if (module) return [...modules, module];
99+
},
90100
};
91101
}
92102

0 commit comments

Comments
 (0)