@elenajs/plugin-rollup-css 0.6.0 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +184 -0
  2. package/package.json +12 -4
  3. package/src/index.js +71 -7
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ <div align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://elenajs.com/img/elena-dark.png" alt="Elena" width="558" height="220">
4
+ </source>
5
+ <source media="(prefers-color-scheme: light)" srcset="https://elenajs.com/img/elena-light.png" alt="Elena" width="558" height="220">
6
+ </source>
7
+ <img src="https://elenajs.com/img/elena-light.png" alt="Elena" width="558" height="220">
8
+ </picture>
9
+
10
+ ### Rollup plugin that minifies and bundles individual Elena CSS files.
11
+
12
+ <br/>
13
+
14
+ <a href="https://arielsalminen.com"><img src="https://img.shields.io/badge/creator-@arielle-F95B1F" alt="Creator @arielle"/></a>
15
+ <a href="https://www.npmjs.com/package/@elenajs/plugin-rollup-css"><img src="https://img.shields.io/npm/v/@elenajs/plugin-rollup-css.svg" alt="Latest version on npm" /></a>
16
+ <a href="https://github.com/getelena/elena/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-yellow.svg" alt="Elena is released under the MIT license." /></a>
17
+ <a href="https://github.com/getelena/elena/actions/workflows/tests.yml"><img src="https://github.com/getelena/elena/actions/workflows/tests.yml/badge.svg" alt="Tests status" /></a>
18
+
19
+ </div>
20
+
21
+ <br/>
22
+
23
+ <p align="center"><strong>@elenajs/plugin-rollup-css</strong> is a <a href="https://rollupjs.org">Rollup</a> plugin that minifies individual Elena CSS files and optionally concatenates them into a single bundle. Built for <a href="https://elenajs.com">Elena</a> Progressive Web Component libraries, but works with any Rollup project.</p>
24
+
25
+ <br/>
26
+
27
+ ## Table of contents
28
+
29
+ - **[Install](#install)**
30
+ - **[Usage](#usage)**
31
+ - **[Individual CSS files](#individual-css-files)**
32
+ - **[CSS bundle](#css-bundle)**
33
+ - **[CSS Module Scripts](#css-module-scripts)**
34
+ - **[Static styles](#static-styles)**
35
+ - **[All together](#all-together)**
36
+ - **[API](#api)**
37
+ - **[`cssPlugin(srcDir)`](#csspluginsrcdir)**
38
+ - **[`cssBundlePlugin(srcDir, fileName)`](#cssbundlepluginsrcdir-filename)**
39
+ - **[`cssModuleScriptPlugin()`](#cssmodulescriptplugin)**
40
+ - **[`cssStaticStylesPlugin()`](#cssstaticstylesplugin)**
41
+ - **[`minifyCss(css, filename?)`](#minifycsscss-filename)**
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ npm install --save-dev @elenajs/plugin-rollup-css
47
+ ```
48
+
49
+ **Peer dependency:** `rollup >= 4.0.0`
50
+
51
+ ## Usage
52
+
53
+ ### Individual CSS files
54
+
55
+ Emit minified copies of each CSS file from your source directory:
56
+
57
+ ```js
58
+ // rollup.config.js
59
+ import { cssPlugin } from "@elenajs/plugin-rollup-css";
60
+
61
+ export default {
62
+ input: "src/index.js",
63
+ output: { dir: "dist", format: "esm" },
64
+ plugins: [cssPlugin("src")],
65
+ };
66
+ ```
67
+
68
+ This scans `src/` for `.css` files and emits each one (minified) into the output directory, preserving the original file name.
69
+
70
+ ### CSS bundle
71
+
72
+ Concatenate all CSS files into a single minified bundle:
73
+
74
+ ```js
75
+ // rollup.config.js
76
+ import { cssBundlePlugin } from "@elenajs/plugin-rollup-css";
77
+
78
+ export default {
79
+ input: "src/index.js",
80
+ output: { dir: "dist", format: "esm" },
81
+ plugins: [cssBundlePlugin("src", "bundle.css")],
82
+ };
83
+ ```
84
+
85
+ ### CSS Module Scripts
86
+
87
+ Handle `import styles from "./component.css" with { type: "css" }` imports. The plugin intercepts these imports, minifies the CSS, and returns a JS module that constructs a `CSSStyleSheet` for Shadow DOM adoption. CSS files handled this way are automatically excluded from `cssBundlePlugin`:
88
+
89
+ ```js
90
+ // rollup.config.js
91
+ import { cssModuleScriptPlugin } from "@elenajs/plugin-rollup-css";
92
+
93
+ export default {
94
+ input: "src/index.js",
95
+ output: { dir: "dist", format: "esm" },
96
+ plugins: [cssModuleScriptPlugin()],
97
+ };
98
+ ```
99
+
100
+ ### Static styles
101
+
102
+ Minify CSS strings assigned to `static styles` template literal class fields:
103
+
104
+ ```js
105
+ // rollup.config.js
106
+ import { cssStaticStylesPlugin } from "@elenajs/plugin-rollup-css";
107
+
108
+ export default {
109
+ input: "src/index.js",
110
+ output: { dir: "dist", format: "esm" },
111
+ plugins: [cssStaticStylesPlugin()],
112
+ };
113
+ ```
114
+
115
+ ### All together
116
+
117
+ Use all plugins together for a complete CSS build pipeline:
118
+
119
+ ```js
120
+ // rollup.config.js
121
+ import {
122
+ cssPlugin,
123
+ cssBundlePlugin,
124
+ cssModuleScriptPlugin,
125
+ cssStaticStylesPlugin,
126
+ } from "@elenajs/plugin-rollup-css";
127
+
128
+ export default {
129
+ input: "src/index.js",
130
+ output: { dir: "dist", format: "esm" },
131
+ plugins: [
132
+ cssModuleScriptPlugin(),
133
+ cssStaticStylesPlugin(),
134
+ cssPlugin("src"),
135
+ cssBundlePlugin("src", "bundle.css"),
136
+ ],
137
+ };
138
+ ```
139
+
140
+ ## API
141
+
142
+ ### `cssPlugin(srcDir)`
143
+
144
+ Returns a Rollup plugin that finds all `.css` files in `srcDir` and emits each one as a minified asset.
145
+
146
+ | Parameter | Type | Description |
147
+ | --------- | -------- | ------------------------------------------ |
148
+ | `srcDir` | `string` | Source directory to scan for `.css` files. |
149
+
150
+ ### `cssBundlePlugin(srcDir, fileName)`
151
+
152
+ Returns a Rollup plugin that concatenates all `.css` files in `srcDir`, minifies the result, and emits it as a single asset. CSS files resolved by `cssModuleScriptPlugin` are automatically excluded from the bundle.
153
+
154
+ | Parameter | Type | Description |
155
+ | ---------- | -------- | ----------------------------------------------------- |
156
+ | `srcDir` | `string` | Source directory to scan for `.css` files. |
157
+ | `fileName` | `string` | Output filename for the bundle (e.g. `"bundle.css"`). |
158
+
159
+ ### `cssModuleScriptPlugin()`
160
+
161
+ Returns a Rollup plugin that handles CSS Module Script imports (`with { type: "css" }`). Reads the CSS file, minifies it, and returns a JS module that constructs and exports a `CSSStyleSheet` for Shadow DOM adoption. Must be listed before `@rollup/plugin-node-resolve` in the plugins array.
162
+
163
+ ### `cssStaticStylesPlugin()`
164
+
165
+ Returns a Rollup plugin that finds `static styles` class fields with template literal values and minifies the CSS inside them.
166
+
167
+ ### `minifyCss(css, filename?)`
168
+
169
+ Minifies a CSS string using [Lightning CSS](https://lightningcss.dev/).
170
+
171
+ | Parameter | Type | Description |
172
+ | ----------- | -------- | -------------------------------------- |
173
+ | `css` | `string` | The CSS source to minify. |
174
+ | `filename?` | `string` | Optional filename for error reporting. |
175
+
176
+ **Returns:** `string`, the minified CSS.
177
+
178
+ ## License
179
+
180
+ MIT
181
+
182
+ ## Copyright
183
+
184
+ Copyright © 2026 [Ariel Salminen](https://arielsalminen.com)
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "@elenajs/plugin-rollup-css",
3
- "version": "0.6.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "Rollup plugin that minifies individual CSS files and optionally concatenates them into a single bundle.",
5
5
  "author": "Elena <hi@elenajs.com>",
6
6
  "homepage": "https://elenajs.com/",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/getelena/elena.git",
10
+ "directory": "packages/plugin-rollup-css"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/getelena/elena/issues"
14
+ },
7
15
  "license": "MIT",
8
16
  "publishConfig": {
9
17
  "access": "public"
@@ -25,10 +33,10 @@
25
33
  "rollup": ">=4.0.0"
26
34
  },
27
35
  "dependencies": {
28
- "lightningcss": "^1.31.1"
36
+ "lightningcss": "1.32.0"
29
37
  },
30
38
  "devDependencies": {
31
- "vitest": "4.0.18"
39
+ "vitest": "4.1.0"
32
40
  },
33
- "gitHead": "b4c41483e5196b542a1b87361f7d37222737fccc"
41
+ "gitHead": "18e13f305c8823f7633c739f2ec61cec2420267b"
34
42
  }
package/src/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * ██████████ ████
3
3
  * ░░███░░░░░█░░███
4
- * ░███ █ ░ ███ ██████ ████████ ██████
5
- * ░██████ ███ ███░░███░░███░░███ ░░░░░███
6
- * ░███░░█ ███ ░███████ ░███ ░███ ███████
7
- * ░███ ░ █ ███ ░███░░░ ░███ ░███ ███░░███
4
+ * ░███ █ ░ ░███ ██████ ████████ ██████
5
+ * ░██████ ░███ ███░░███░░███░░███ ░░░░░███
6
+ * ░███░░█ ░███ ░███████ ░███ ░███ ███████
7
+ * ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
8
8
  * ██████████ █████░░██████ ████ █████░░████████
9
9
  * ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
10
10
  *
@@ -12,7 +12,7 @@
12
12
  * https://elenajs.com
13
13
  */
14
14
 
15
- import { basename } from "path";
15
+ import { basename, resolve, dirname } from "path";
16
16
  import { readFileSync, readdirSync } from "fs";
17
17
  import { transform } from "lightningcss";
18
18
 
@@ -23,7 +23,7 @@ import { transform } from "lightningcss";
23
23
  * @param {string} [filename]
24
24
  * @returns {string}
25
25
  */
26
- function minifyCss(css, filename = "style.css") {
26
+ export function minifyCss(css, filename = "style.css") {
27
27
  const { code } = transform({
28
28
  filename,
29
29
  code: Buffer.from(css),
@@ -32,6 +32,59 @@ function minifyCss(css, filename = "style.css") {
32
32
  return code.toString();
33
33
  }
34
34
 
35
+ /**
36
+ * Rollup plugin that handles CSS Module Script imports (`with { type: "css" }`).
37
+ * Loads the CSS file content, minifies it, and returns a JS module that
38
+ * constructs and exports a CSSStyleSheet for Shadow DOM adoption. This prevents
39
+ * Rollup from attempting to parse CSS files as JavaScript.
40
+ *
41
+ * @returns {import("rollup").Plugin}
42
+ */
43
+ export function cssModuleScriptPlugin() {
44
+ const PREFIX = "\0css-module:";
45
+
46
+ return {
47
+ name: "css-module-script",
48
+ resolveId(source, importer, options) {
49
+ if (!source.endsWith(".css") || options?.attributes?.type !== "css") {
50
+ return null;
51
+ }
52
+ return { id: PREFIX + resolve(dirname(importer), source) };
53
+ },
54
+ load(id) {
55
+ if (!id.startsWith(PREFIX)) {
56
+ return null;
57
+ }
58
+ const filePath = id.slice(PREFIX.length);
59
+ const css = minifyCss(readFileSync(filePath, "utf8"), basename(filePath));
60
+ return `const sheet = new CSSStyleSheet();\nsheet.replaceSync(${JSON.stringify(css)});\nexport default sheet;`;
61
+ },
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Rollup plugin that minifies CSS strings assigned to `static styles` class fields.
67
+ *
68
+ * @returns {import("rollup").Plugin}
69
+ */
70
+ export function cssStaticStylesPlugin() {
71
+ return {
72
+ name: "css-static-styles",
73
+ transform(code, id) {
74
+ if (!id.endsWith(".js") && !id.endsWith(".ts")) {
75
+ return null;
76
+ }
77
+ if (!code.includes("static styles")) {
78
+ return null;
79
+ }
80
+ const newCode = code.replace(/static\s+styles\s*=\s*`([\s\S]*?)`/g, (_match, css) => {
81
+ return `static styles = \`${minifyCss(css)}\``;
82
+ });
83
+ return newCode !== code ? { code: newCode } : null;
84
+ },
85
+ };
86
+ }
87
+
35
88
  /**
36
89
  * Rollup plugin that copies and minifies individual CSS files from `srcDir`
37
90
  * into the output directory.
@@ -48,6 +101,9 @@ export function cssPlugin(srcDir) {
48
101
  .map(f => `${srcDir}/${f}`);
49
102
 
50
103
  for (const file of cssFiles) {
104
+ if (this.addWatchFile) {
105
+ this.addWatchFile(resolve(file));
106
+ }
51
107
  const source = minifyCss(readFileSync(file, "utf8"), basename(file));
52
108
  this.emitFile({ type: "asset", fileName: basename(file), source });
53
109
  }
@@ -67,9 +123,17 @@ export function cssBundlePlugin(srcDir, fileName) {
67
123
  return {
68
124
  name: "css-bundle",
69
125
  generateBundle() {
126
+ const shadowDomCssFiles = new Set();
127
+ for (const id of this.getModuleIds()) {
128
+ if (id.startsWith("\0css-module:")) {
129
+ shadowDomCssFiles.add(id.slice("\0css-module:".length));
130
+ }
131
+ }
132
+
70
133
  const cssFiles = readdirSync(srcDir, { recursive: true })
71
134
  .filter(f => f.endsWith(".css"))
72
- .map(f => `${srcDir}/${f}`);
135
+ .map(f => resolve(`${srcDir}/${f}`))
136
+ .filter(f => !shadowDomCssFiles.has(f));
73
137
 
74
138
  const source = minifyCss(cssFiles.map(f => readFileSync(f, "utf8")).join("\n"), fileName);
75
139