-
-
Notifications
You must be signed in to change notification settings - Fork 126
fix: prevent CSS entry from generating empty JS files that overwrite ... #674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ Deploy Preview for tsdown ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
npm i https://pkg.pr.new/tsdown@674
npm i https://pkg.pr.new/create-tsdown@674
npm i https://pkg.pr.new/tsdown-migrate@674
commit: ce84ed1
jinghaihan
commented
Dec 27, 2025
Thank you for your contribution, but I've found some issues.
Source
- tsdown.config.ts
import { defineConfig } from 'tsdown' export default defineConfig({ entry: ['./src/index.ts', './src/index.css'], dts: { vue: true, }, })
- src/index.ts
// import { defineAsyncComponent } from 'vue' // import './index.css' export { default as Foo } from './foo.vue' // export const Foo = defineAsyncComponent(() => import('./foo.vue')) export const foo = 1
- src/index.css
a { color: red; }
- src/foo.vue
<template> <div class="foo" /> </template> <style> .bar { color: blue; } </style>
Output
- index.mjs ✓
- index.d.mts ✓
- index.css(only have
foo.vuestyle, the CSS of the index.css entry is missing) ✗
.bar { color: blue; }
liwenka1
commented
Dec 28, 2025
Thanks for the feedback! I've fixed the issue where CSS entry content was missing when used with Vue components.
Now the CSS entry (src/index.css) is properly merged with Vue component styles (<style> in .vue files) when they output to the same filename.
Could you please review again? @jinghaihan
jinghaihan
commented
Dec 28, 2025
Thanks for the feedback! I've fixed the issue where CSS entry content was missing when used with Vue components.
Now the CSS entry (src/index.css) is properly merged with Vue component styles (<style> in .vue files) when they output to the same filename.
Could you please review again? @jinghaihan
This has indeed been fixed. Thanks for the contribution!
sxzz
commented
Dec 30, 2025
Before submitting a large PR, it is better to first communicate with the team in the issue and explain your proposed solution. This will help us review your work more effectively.
@sxzz
sxzz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will try to rework on your PR later. It's really hard to review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lightningcss is not a dep, or peer dep, so it's impossible to import on the userland.
I think we can make this feature as optional and experimental.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
really sorry for my oversight! I totally didn’t think through the lightningcss dependency handling properly and took it way too lightly.
Problem
Closes #627
When using CSS files as entries alongside JS files with the same base name (e.g.,
index.jsandindex.css), Rolldown generates an empty JS file (0 bytes) for the CSS entry, which overwrites the legitimate JS output.Example:
Before this fix:
dist/index.js- 0 bytes (empty, generated from CSS entry)dist/index.css- correct CSS outputindex.jsoutput was overwrittenSolution
I attempted to fix this issue by separating CSS entries from JS entries and processing them independently using LightningCSS. I'm not deeply familiar with this codebase, so please let me know if there are any issues with this approach or if there's a better way to handle this.
Key Changes
Separate CSS and JS entries (
src/features/entry.ts).cssextension in entry names to avoid name conflictsseparateCssEntries()function to split entries by typeDirect CSS processing (
src/features/css-bundle.ts)transform()API@importstatements (not inlined)Watch mode support (
src/index.ts)fs.watch()Enhanced reporting (
src/features/report.ts)ReportPluginto accept extra chunks (CSS chunks)Behavior Changes
After this fix:
dist/index.js- correct JS output ✅dist/index.css- correct CSS output ✅Build output:
Watch mode output:
Testing
.mjsfiles)Implementation Details
Why use
transform()instead ofbundleAsync()?I chose to use LightningCSS's
transform()API instead ofbundleAsync()to preserve the original behavior where each CSS file is output separately. This means:@importstatements are preserved in the output (not inlined)Watch Mode Implementation
In watch mode, there was a challenge where Rolldown's watcher would clear all chunks (including CSS chunks) on each rebuild. The solution:
STARTevent)Reporting Integration
The
ReportPluginwas enhanced to accept a callback that provides extra chunks (CSS chunks). This allows:Notes
@importstatements are preserved in the output (not inlined)lightningcsspeer dependencyfs.watch()(no additional dependencies)I'm not deeply familiar with this codebase, so this is my attempt to fix the issue. Please let me know if there are any problems with this approach or if there's a better way to handle it. Thank you for reviewing! 🙏