Skip to content

Commit 1a6178f

Browse files
JodiWarrenJodi Warren
andauthored
v3.1.5: Fix #75 (#76)
Add feature scoping Co-authored-by: Jodi Warren <jodi@jodwarren.com>
1 parent 59b60e7 commit 1a6178f

File tree

8 files changed

+134
-12
lines changed

8 files changed

+134
-12
lines changed

changelog.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
## V3.1.2
1+
## V3.1.5
2+
- fix [issue#75](https://github.com/indooorsman/esbuild-css-modules-plugin/issues/75)
3+
4+
- ## V3.1.2
25
- fix [issue#74](https://github.com/indooorsman/esbuild-css-modules-plugin/issues/74)
36

47
## V3.1.1

index.d.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { Plugin, PluginBuild } from 'esbuild';
22
import type {
33
BundleOptions,
44
CustomAtRules,
5-
TransformOptions,
65
} from 'lightningcss';
76

87
declare type EmitDtsConfig = Partial<
@@ -138,6 +137,36 @@ declare interface BuildOptions
138137
module?: string;
139138
version: string;
140139
};
140+
/**
141+
* Enforces usage of one or more id or class selectors for each rule.
142+
*
143+
* If you enable this option, Lightning CSS will throw an error for CSS rules
144+
* that don't have at least one id or class selector, like div. This is useful
145+
* because selectors like div are not scoped and affects all elements on the
146+
* page.
147+
*
148+
* https://lightningcss.dev/css-modules.html#pure-mode
149+
*/
150+
pure?: boolean;
151+
/**
152+
* Turn off feature scoping for animations;
153+
*
154+
* https://lightningcss.dev/css-modules.html#turning-off-feature-scoping
155+
*/
156+
animation?: boolean;
157+
/**
158+
* Turn off feature scoping for custom idents:
159+
* https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident;
160+
*
161+
* https://lightningcss.dev/css-modules.html#turning-off-feature-scoping
162+
*/
163+
customIdents?: boolean;
164+
/**
165+
* Turn off feature scoping for grid areas;
166+
*
167+
* https://lightningcss.dev/css-modules.html#turning-off-feature-scoping
168+
*/
169+
grid?: boolean;
141170
}
142171

143172
declare function CssModulesPlugin(options?: BuildOptions): Plugin;

index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export const setup = (build, _options) => {
112112
const rpath = relative(buildRoot, path);
113113
const prefix = basename(rpath, extname(path))
114114
.replace(/[^a-zA-Z0-9]/g, '-')
115-
.replace(/^\-*/, '');
115+
.replace(/^-*/, '');
116116
const suffix = patchedBuild.context.packageVersion?.replace(/[^a-zA-Z0-9]/g, '') ?? '';
117117

118118
const buildResult = CSSTransformer.getInstance(patchedBuild).bundle(path, {
@@ -320,7 +320,9 @@ export const setup = (build, _options) => {
320320
/** @type {[string, string][]} */
321321
const filesToBuild = [];
322322
warnMetafile();
323-
const cssOutputsMap = Object.entries(r.metafile?.outputs ?? {}).reduce((m, [o, { inputs }]) => {
323+
324+
const cssOutputsMap = Object.entries(r.metafile?.outputs ?? {})
325+
.reduce(/** @type {(m: Record<string, string>, o: any) => Record<string, string>} */(m, [o, {inputs}]) => {
324326
const keys = Object.keys(inputs);
325327
if (keys.length === 1 && new RegExp(`^${pluginCssNamespace}:.+\.css$`).test(keys[0])) {
326328
m[keys[0].replace(`${pluginCssNamespace}:`, '')] = o;

lib/css.helper.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,11 @@ ${uniqNames.map(([o, l]) => ` "${o}": ${l}`).join(',\n')}
271271
filename: fullpath,
272272
cssModules: {
273273
dashedIdents: options?.dashedIndents,
274-
pattern: options?.pattern ?? `${opt?.prefix ?? ''}__[local]_[hash]__${opt?.suffix ?? ''}`
274+
pattern: options?.pattern ?? `${opt?.prefix ?? ''}__[local]_[hash]__${opt?.suffix ?? ''}`,
275+
pure: options?.pure ?? false,
276+
animation: options?.animation ?? true,
277+
customIdents: options?.customIdents ?? true,
278+
grid: options?.grid ?? true,
275279
},
276280
drafts: {
277281
customMedia: true,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "esbuild-css-modules-plugin",
3-
"version": "3.1.4",
3+
"version": "3.1.5",
44
"description": "A esbuild plugin to bundle css modules into js(x)/ts(x), based on extremely fast [Lightning CSS](https://lightningcss.dev/)",
55
"main": "./index.cjs",
66
"module": "./index.js",

test/styles/app.modules.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
.hello_world {
44
color: red;
55
background: url("../components/world.jpg");
6+
7+
animation: 3s linear slide-in;
8+
display: grid;
9+
grid-template: "image text";
610
}
711

812
.hello-world img {
913
display: inline-block;
14+
grid-area: image;
1015
}
1116

1217
.hello-world:hover {
@@ -16,3 +21,17 @@
1621
.some-other-selector {
1722
background-image: url('../components/world.jpg');
1823
}
24+
25+
/* Should throw an error when `pure: true` */
26+
div {
27+
border-radius: 20px;
28+
}
29+
30+
@keyframes slide-in {
31+
from {
32+
margin-left: -20%;
33+
}
34+
to {
35+
margin-left: 100%;
36+
}
37+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.hello-text {
22
composes: bg-red from "../../base.modules.css";
33
color: grey;
4+
grid-area: text;
45
}

test/test.js

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import cssModulesPlugin from '../index.js';
1919
plugins: [
2020
cssModulesPlugin({
2121
inject: '#my-custom-element-with-shadow-dom',
22-
emitDeclarationFile: true
22+
emitDeclarationFile: true,
23+
pattern: "__[hash]_[local]"
2324
})
2425
],
2526
metafile: true,
@@ -56,7 +57,8 @@ import cssModulesPlugin from '../index.js';
5657
document.head.appendChild(styleEle);
5758
}
5859
`;
59-
}
60+
},
61+
pattern: "__[hash]_[local]"
6062
})
6163
],
6264
logLevel: 'debug'
@@ -85,7 +87,9 @@ import cssModulesPlugin from '../index.js';
8587
cssModulesPlugin({
8688
inject: false,
8789
namedExports: true,
88-
filter: /\.css$/i
90+
filter: /\.css$/i,
91+
pattern: "__[hash]_[local]"
92+
8993
})
9094
],
9195
logLevel: 'debug',
@@ -112,7 +116,8 @@ import cssModulesPlugin from '../index.js';
112116
cssModulesPlugin({
113117
inject: false,
114118
namedExports: true,
115-
emitDeclarationFile: true
119+
emitDeclarationFile: true,
120+
pattern: "__[hash]_[local]"
116121
})
117122
],
118123
logLevel: 'debug',
@@ -144,7 +149,8 @@ import cssModulesPlugin from '../index.js';
144149
},
145150
force: true,
146151
forceInlineImages: true,
147-
inject: '#my-styles-container'
152+
inject: '#my-styles-container',
153+
pattern: "__[hash]_[local]"
148154
})
149155
],
150156
logLevel: 'debug',
@@ -169,14 +175,72 @@ import cssModulesPlugin from '../index.js';
169175
},
170176
plugins: [
171177
cssModulesPlugin({
172-
inject: true
178+
inject: true,
179+
pattern: "__[hash]_[local]"
173180
})
174181
],
175182
logLevel: 'debug',
176183
metafile: true
177184
});
178185
console.log('[test][esbuild:bundle:splitting] done, please check `test/dist/bundle-splitting`', '\n');
179186

187+
try {
188+
// testing pure: true
189+
await esbuild.build({
190+
entryPoints: ['app.jsx'],
191+
entryNames: '[name]-[hash]',
192+
format: 'esm',
193+
target: ['esnext'],
194+
bundle: true,
195+
minify: false,
196+
publicPath: 'https://my.domain/static/',
197+
external: ['react', 'react-dom'],
198+
outdir: './dist/pure',
199+
write: true,
200+
loader: {
201+
'.jpg': 'file'
202+
},
203+
plugins: [
204+
cssModulesPlugin({
205+
pure: true,
206+
pattern: "__[hash]_[local]"
207+
})
208+
],
209+
metafile: true,
210+
logLevel: 'debug'
211+
});
212+
} catch (error) {
213+
console.log('Should result in " [ERROR] A selector in CSS modules should contain at least one class or ID selector [plugin esbuild-css-modules-plugin]"`', '\n');
214+
}
215+
216+
// testing feature scoping
217+
await esbuild.build({
218+
entryPoints: ['app.jsx'],
219+
entryNames: '[name]-[hash]',
220+
format: 'esm',
221+
target: ['esnext'],
222+
bundle: true,
223+
minify: false,
224+
publicPath: 'https://my.domain/static/',
225+
external: ['react', 'react-dom'],
226+
outdir: './dist/feature-scoping',
227+
write: true,
228+
loader: {
229+
'.jpg': 'file'
230+
},
231+
plugins: [
232+
cssModulesPlugin({
233+
animation: false,
234+
customIdents: false,
235+
grid: false,
236+
pattern: "__[hash]_[local]"
237+
})
238+
],
239+
metafile: true,
240+
logLevel: 'debug'
241+
});
242+
console.log('Should result in " [ERROR] A selector in CSS modules should contain at least one class or ID selector [plugin esbuild-css-modules-plugin]"`', '\n');
243+
180244
// testing no metafile & write false
181245
const r = await esbuild.build({
182246
...buildOptions,

0 commit comments

Comments
 (0)