Skip to content

Commit a680389

Browse files
committed
(feat) initial commit
0 parents  commit a680389

File tree

15 files changed

+5225
-0
lines changed

15 files changed

+5225
-0
lines changed

.editorconfig

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Editor configuration, see http://editorconfig.org
2+
root = true
3+
4+
[*]
5+
charset = utf-8
6+
indent_style = space
7+
indent_size = 2
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
max_line_length = 120
11+
12+
[*.md]
13+
max_line_length = off
14+
trim_trailing_whitespace = false
15+
16+
[*.ts]
17+
ij_typescript_force_semicolon_style = true
18+
ij_typescript_use_semicolon_after_statement = true
19+
ij_typescript_spaces_within_imports = true
20+
21+
[*.json]
22+
ij_json_array_wrapping = off
23+
ij_json_keep_blank_lines_in_code = 0
24+
ij_json_keep_indents_on_empty_lines = false
25+
ij_json_keep_line_breaks = true
26+
ij_json_keep_trailing_comma = true
27+
ij_json_object_wrapping = off
28+
ij_json_property_alignment = do_not_align
29+
ij_json_space_after_colon = true
30+
ij_json_space_after_comma = true
31+
ij_json_space_before_colon = false
32+
ij_json_space_before_comma = false
33+
ij_json_spaces_within_braces = false
34+
ij_json_spaces_within_brackets = false
35+
ij_json_wrap_long_lines = false

.github/actions/setup/action.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
name: Setup
3+
description: Setup the environment for the project
4+
5+
inputs:
6+
node-version:
7+
description: Node.js version
8+
default: '24'
9+
required: false
10+
node-registry:
11+
description: Node.js package registry to set up for auth
12+
required: false
13+
14+
runs:
15+
using: composite
16+
steps:
17+
- name: Install Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: ${{ inputs.node-version }}
21+
registry-url: ${{ inputs.node-registry }}
22+
23+
- name: Install pnpm
24+
uses: pnpm/action-setup@v4
25+
26+
- name: Get pnpm store directory
27+
id: pnpm-cache-dir
28+
shell: bash
29+
run: echo "dir=$(pnpm store path)" >> $GITHUB_OUTPUT
30+
31+
- name: Setup pnpm cache
32+
uses: actions/cache@v4
33+
with:
34+
path: ${{ steps.pnpm-cache-dir.outputs.dir }}
35+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
36+
restore-keys: |
37+
${{ runner.os }}-pnpm-store-
38+
39+
- name: Install dependencies
40+
shell: bash
41+
run: pnpm install --prefer-frozen-lockfile

.github/workflows/release.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
name: Release
3+
4+
on:
5+
push:
6+
tags:
7+
- 'v*'
8+
9+
jobs:
10+
gh-release:
11+
name: Create GitHub Release
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: write
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v5
18+
19+
- name: Create release
20+
env:
21+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22+
run: gh release create "$GITHUB_REF_NAME" --generate-notes
23+
24+
publish-npm:
25+
name: Publish to NPM
26+
runs-on: ubuntu-latest
27+
permissions:
28+
contents: read
29+
id-token: write
30+
steps:
31+
- name: Checkout repository
32+
uses: actions/checkout@v5
33+
34+
- name: Setup
35+
uses: ./.github/actions/setup
36+
with:
37+
node-registry: https://registry.npmjs.org
38+
39+
- name: Publish to NPM
40+
env:
41+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
42+
NPM_CONFIG_PROVENANCE: true
43+
run: pnpm publish --no-git-checks --access public

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.idea/
2+
node_modules/
3+
dist/
4+
.DS_Store

.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea/
2+
eslint.config.ts
3+
sample/

.prettierignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Add files and folders here to ignore them from prettier formatting
2+
3+
# Prettier default
4+
**/.git
5+
**/.svn
6+
**/.hg
7+
**/node_modules
8+
9+
# Dirs
10+
dist
11+
.idea
12+
13+
# Files
14+
README.md
15+
**/*.json
16+
**/*.yaml

.prettierrc.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
arrowParens: always
3+
bracketSpacing: true
4+
embeddedLanguageFormatting: auto
5+
htmlWhitespaceSensitivity: css
6+
insertPragma: false
7+
jsxSingleQuote: true
8+
printWidth: 120
9+
proseWrap: preserve
10+
quoteProps: as-needed
11+
requirePragma: false
12+
semi: true
13+
singleQuote: true
14+
tabWidth: 2
15+
trailingComma: none
16+
useTabs: false
17+
overrides:
18+
- files: '*.ts'
19+
options:
20+
parser: typescript

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025-present Ryan Bosher
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# @bosh-code/tsdown-plugin-inject-css
2+
3+
[![npm version](https://img.shields.io/npm/v/@bosh-code/tsdown-plugin-inject-css)](https://npmjs.com/package/@bosh-code/tsdown-plugin-inject-css)
4+
![license](https://img.shields.io/npm/l/@bosh-code/tsdown-plugin-inject-css)
5+
6+
Inject CSS imports at the top of each chunk file in tsdown builds.
7+
8+
During the build process, tsdown strips CSS imports from your source files. This plugin tracks those imports and
9+
re-injects them into output chunks.
10+
11+
```js
12+
// Input: foo.ts
13+
import './foo.css';
14+
15+
export const Foo = () => <div>Foo</div>;
16+
17+
// Output: foo.js (with plugin)
18+
import './foo.css';
19+
20+
export const Foo = () => <div>Foo</div>;
21+
```
22+
23+
## Features
24+
25+
- 💡 Automatically tracks CSS imports before they're stripped
26+
- 🎯 Injects imports into the correct output chunks
27+
- ⚡️ Sourcemap support
28+
- 🛠 Out-of-box, minimal configuration
29+
- 🔄 Works with tsdown's code splitting and chunking
30+
31+
## Installation
32+
33+
```bash
34+
npm install @bosh-code/tsdown-plugin-inject-css -D
35+
# or
36+
pnpm add @bosh-code/tsdown-plugin-inject-css -D
37+
# or
38+
yarn add @bosh-code/tsdown-plugin-inject-css -D
39+
```
40+
41+
## Usage
42+
43+
```ts
44+
// tsdown.config.ts
45+
import { defineConfig } from 'tsdown';
46+
import { libInjectCss } from '@bosh-code/tsdown-plugin-inject-css';
47+
48+
export default defineConfig({
49+
entry: ['./src/index.ts'],
50+
format: ['esm'],
51+
plugins: [
52+
libInjectCss({
53+
sourcemap: true, // default: true
54+
}),
55+
],
56+
});
57+
```
58+
59+
## How It Works
60+
61+
The plugin operates in three phases:
62+
63+
1. **Transform Phase**: Scans source files for CSS imports (e.g., `import './style.css'`) before they're stripped
64+
2. **Render Phase**: Tracks which source modules end up in which output chunks
65+
3. **Generate Phase**: Re-injects the CSS imports at the top of the appropriate chunks
66+
67+
### Example
68+
69+
Given this structure:
70+
71+
```ts
72+
// src/foo.ts
73+
import './foo.css';
74+
75+
export const Foo = () => <div>Foo < /div>;
76+
77+
// src/bar.ts
78+
import './bar.css';
79+
80+
export const Bar = () => <div>Bar < /div>;
81+
82+
// src/index.ts
83+
export { Foo } from './foo';
84+
export { Bar } from './bar';
85+
```
86+
87+
The plugin ensures:
88+
89+
- `foo.js` includes `import './foo.css';`
90+
- `bar.js` includes `import './bar.css';`
91+
- `index.js` imports from `foo.js` and `bar.js` (CSS already handled)
92+
93+
## Options
94+
95+
### `sourcemap`
96+
97+
- Type: `boolean`
98+
- Default: `true`
99+
100+
Whether to generate sourcemaps for the modified chunks.
101+
102+
```ts
103+
libInjectCss({
104+
sourcemap: false, // Disable sourcemap generation
105+
})
106+
```
107+
108+
## Why This Plugin?
109+
110+
When building component libraries with tsdown, CSS imports are typically stripped during the transpilation process. This
111+
plugin solves the problem by:
112+
113+
1. **Preserving CSS imports**: Ensures styles are loaded when components are used
114+
2. **Proper chunking**: Each chunk only imports its required CSS files
115+
3. **Tree-shaking friendly**: Works seamlessly with tsdown's code splitting
116+
4. **Zero configuration**: Works out of the box with sensible defaults
117+
118+
## Compatibility
119+
120+
This plugin is designed for:
121+
122+
- ✅ tsdown (primary target)
123+
- ✅ Rolldown (direct compatibility)
124+
- ⚠️ Rollup (may work with limitations)
125+
126+
## Configuration Tips
127+
128+
### For Component Libraries
129+
130+
When building a component library, you typically want:
131+
132+
```ts
133+
export default defineConfig({
134+
entry: ['./src/index.ts'],
135+
format: ['esm'],
136+
dts: true,
137+
sourcemap: true,
138+
plugins: [
139+
libInjectCss(),
140+
],
141+
});
142+
```
143+
144+
### With Multiple Entry Points
145+
146+
The plugin works seamlessly with multiple entries:
147+
148+
```ts
149+
export default defineConfig({
150+
entry: {
151+
index: './src/index.ts',
152+
button: './src/button/index.ts',
153+
card: './src/card/index.ts',
154+
},
155+
format: ['esm'],
156+
plugins: [
157+
libInjectCss(),
158+
],
159+
});
160+
```
161+
162+
Each entry point will have its CSS imports properly injected.
163+
164+
## Inspired By
165+
166+
This plugin is inspired by [vite-plugin-lib-inject-css](https://github.com/emosheeep/vite-plugin-lib-inject-css) but
167+
adapted specifically for tsdown's architecture and build process.
168+
169+
## License
170+
171+
MIT © bosh-code

commitlint.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default {
2+
extends: ['@commitlint/config-conventional'],
3+
}

0 commit comments

Comments
 (0)