unplugin-tailwindcss-mangle 0.0.0 → 0.0.1

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.
package/README.md CHANGED
@@ -1 +1,96 @@
1
- # unplugin-tailwindcss-mangle (WIP)
1
+ # unplugin-tailwindcss-mangle
2
+
3
+ mangle tailwindcss utilities plugin
4
+
5
+ > Now Support `vite` and `webpack`
6
+
7
+ - [unplugin-tailwindcss-mangle](#unplugin-tailwindcss-mangle)
8
+ - [Features](#features)
9
+ - [Usage](#usage)
10
+ - [1. Install Package](#1-install-package)
11
+ - [2. Run patch script](#2-run-patch-script)
12
+ - [3. add `prepare` script in your `package.json`](#3-add-prepare-script-in-your-packagejson)
13
+ - [4. register this plugin](#4-register-this-plugin)
14
+ - [vite](#vite)
15
+ - [webpack](#webpack)
16
+ - [Notice](#notice)
17
+
18
+ ## Features
19
+
20
+ ```html
21
+ <!-- before -->
22
+ <div class="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex"></div>
23
+ <!-- after -->
24
+ <div class="tw-g tw-h tw-i tw-d tw-e tw-j tw-k tw-l"></div>
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### 1. Install Package
30
+
31
+ ```sh
32
+ <npm|yarn|pnpm> i -D unplugin-tailwindcss-mangle tailwindcss-patch
33
+ ```
34
+
35
+ ### 2. Run patch script
36
+
37
+ ```sh
38
+ npx tw-patch
39
+ ```
40
+
41
+ ### 3. add `prepare` script in your `package.json`
42
+
43
+ ```json
44
+ "scripts": {
45
+ "prepare": "tw-patch"
46
+ },
47
+ ```
48
+
49
+ ### 4. register this plugin
50
+
51
+ #### vite
52
+
53
+ ```js
54
+ // for example: vue vite project
55
+ import { defineConfig } from 'vite'
56
+ import vue from '@vitejs/plugin-vue'
57
+ import utwm from 'unplugin-tailwindcss-mangle'
58
+ // https://vitejs.dev/config/
59
+ export default defineConfig({
60
+ plugins: [vue(), utwm.vite()]
61
+ })
62
+ ```
63
+
64
+ then run script:
65
+
66
+ ```sh
67
+ # generate bundle
68
+ yarn build
69
+ # preview
70
+ yarn preview
71
+ ```
72
+
73
+ You will see all class was renamed to `tw-*`
74
+
75
+ #### webpack
76
+
77
+ ```js
78
+ import utwm from 'unplugin-tailwindcss-mangle'
79
+ // use this webpack plugin
80
+ utwm.webpack()
81
+ ```
82
+
83
+ ## Notice
84
+
85
+ This plugin only transform those classes which name with `-` or `:`, like `w-32`, `before:h-[300px]`,`after:dark:via-[#0141ff]/40`. some classes like `flex`,`relative` will not be mangled.
86
+
87
+ because plugin will **traverse** all `html class attr` and `js StringLiteral` to find `utilities` generated by `tailwindcss`.
88
+
89
+ it's dangerous to mangle some `js StringLiteral` like:
90
+
91
+ ```js
92
+ const innerHTML = "i'm flex and relative and grid"
93
+ document.body.innerHTML = innerHTML
94
+ ```
95
+
96
+ so only strings with `-` or `:` will be transformed.
@@ -0,0 +1,17 @@
1
+ import type { IMangleOptions, IMangleContextClass, IClassGenerator } from './types';
2
+ declare class ClassGenerator implements IClassGenerator {
3
+ newClassMap: Record<string, IMangleContextClass>;
4
+ newClassSize: number;
5
+ context: Record<string, any>;
6
+ opts: IMangleOptions;
7
+ classPrefix: string;
8
+ constructor(opts?: IMangleOptions);
9
+ defaultClassGenerator(): string;
10
+ ignoreClassName(className: string): boolean;
11
+ includeFilePath(filePath: string): boolean;
12
+ excludeFilePath(filePath: string): boolean;
13
+ isFileIncluded(filePath: string): boolean;
14
+ transformCssClass(className: string): string;
15
+ generateClassName(original: string): IMangleContextClass;
16
+ }
17
+ export default ClassGenerator;
@@ -0,0 +1 @@
1
+ export declare const pluginName = "unplugin-tailwindcss-mangle";
@@ -0,0 +1,2 @@
1
+ import { IHandlerOptions } from '@/types';
2
+ export declare function cssHandler(rawSource: string, options: IHandlerOptions): string;
@@ -0,0 +1,7 @@
1
+ import { IMangleContextClass } from '@/types';
2
+ import type { PluginCreator } from 'postcss';
3
+ export type PostcssMangleTailwindcssPlugin = PluginCreator<{
4
+ newClassMap: Record<string, IMangleContextClass>;
5
+ }>;
6
+ declare const postcssMangleTailwindcssPlugin: PostcssMangleTailwindcssPlugin;
7
+ export { postcssMangleTailwindcssPlugin };
@@ -0,0 +1,2 @@
1
+ declare const _default: (options?: import("./types").Options | undefined) => import("unplugin").EsbuildPlugin;
2
+ export default _default;
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index.js');
4
+ require('unplugin');
5
+ require('tailwindcss-patch');
6
+ require('parse5');
7
+ require('@babel/generator');
8
+ require('@babel/parser');
9
+ require('@babel/traverse');
10
+ require('postcss');
11
+ require('postcss-selector-parser');
12
+
13
+ var esbuild = index.esbuild;
14
+
15
+ module.exports = esbuild;
@@ -0,0 +1,13 @@
1
+ import unplugin from './index.mjs';
2
+ import 'unplugin';
3
+ import 'tailwindcss-patch';
4
+ import 'parse5';
5
+ import '@babel/generator';
6
+ import '@babel/parser';
7
+ import '@babel/traverse';
8
+ import 'postcss';
9
+ import 'postcss-selector-parser';
10
+
11
+ var esbuild = unplugin.esbuild;
12
+
13
+ export { esbuild as default };
@@ -0,0 +1,2 @@
1
+ import { IHandlerOptions } from '@/types';
2
+ export declare function htmlHandler(rawSource: string, options: IHandlerOptions): string;
@@ -0,0 +1,3 @@
1
+ import type { Options } from './types';
2
+ declare const unplugin: import("unplugin").UnpluginInstance<Options | undefined, boolean>;
3
+ export default unplugin;
package/dist/index.js ADDED
@@ -0,0 +1,491 @@
1
+ 'use strict';
2
+
3
+ var unplugin$1 = require('unplugin');
4
+ var tailwindcssPatch = require('tailwindcss-patch');
5
+ var parse5 = require('parse5');
6
+ var _generate = require('@babel/generator');
7
+ var parser = require('@babel/parser');
8
+ var _traverse = require('@babel/traverse');
9
+ var postcss = require('postcss');
10
+ var parser$1 = require('postcss-selector-parser');
11
+
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
13
+
14
+ var _generate__default = /*#__PURE__*/_interopDefault(_generate);
15
+ var _traverse__default = /*#__PURE__*/_interopDefault(_traverse);
16
+ var postcss__default = /*#__PURE__*/_interopDefault(postcss);
17
+ var parser__default = /*#__PURE__*/_interopDefault(parser$1);
18
+
19
+ const pluginName = 'unplugin-tailwindcss-mangle';
20
+
21
+ function groupBy(arr, cb) {
22
+ if (!Array.isArray(arr)) {
23
+ throw new Error('expected an array for first argument');
24
+ }
25
+ if (typeof cb !== 'function') {
26
+ throw new Error('expected a function for second argument');
27
+ }
28
+ const result = {};
29
+ for (let i = 0; i < arr.length; i++) {
30
+ const item = arr[i];
31
+ const bucketCategory = cb(item);
32
+ const bucket = result[bucketCategory];
33
+ if (!Array.isArray(bucket)) {
34
+ result[bucketCategory] = [item];
35
+ }
36
+ else {
37
+ result[bucketCategory].push(item);
38
+ }
39
+ }
40
+ return result;
41
+ }
42
+ function getGroupedEntries(entries, options = {
43
+ cssMatcher(file) {
44
+ return /\.css$/.test(file);
45
+ },
46
+ htmlMatcher(file) {
47
+ return /\.html?$/.test(file);
48
+ },
49
+ jsMatcher(file) {
50
+ return /\.js$/.test(file);
51
+ }
52
+ }) {
53
+ const { cssMatcher, htmlMatcher, jsMatcher } = options;
54
+ const groupedEntries = groupBy(entries, ([file]) => {
55
+ if (cssMatcher(file)) {
56
+ return 'css';
57
+ }
58
+ else if (htmlMatcher(file)) {
59
+ return 'html';
60
+ }
61
+ else if (jsMatcher(file)) {
62
+ return 'js';
63
+ }
64
+ else {
65
+ return 'other';
66
+ }
67
+ });
68
+ return groupedEntries;
69
+ }
70
+ const acceptChars = 'abcdefghijklmnopqrstuvwxyz'.split('');
71
+ function stripEscapeSequence(words) {
72
+ return words.replace(/\\/g, '');
73
+ }
74
+ function isRegexp(value) {
75
+ return Object.prototype.toString.call(value) === '[object RegExp]';
76
+ }
77
+ function regExpTest(arr = [], str) {
78
+ if (Array.isArray(arr)) {
79
+ for (let i = 0; i < arr.length; i++) {
80
+ const item = arr[i];
81
+ if (typeof item === 'string') {
82
+ if (item === str) {
83
+ return true;
84
+ }
85
+ }
86
+ else if (isRegexp(item)) {
87
+ item.lastIndex = 0;
88
+ if (item.test(str)) {
89
+ return true;
90
+ }
91
+ }
92
+ }
93
+ return false;
94
+ }
95
+ throw new TypeError("paramater 'arr' should be a Array of Regexp | String !");
96
+ }
97
+ function escapeStringRegexp(str) {
98
+ if (typeof str !== 'string') {
99
+ throw new TypeError('Expected a string');
100
+ }
101
+ return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d');
102
+ }
103
+
104
+ class ClassGenerator {
105
+ constructor(opts = {}) {
106
+ var _a;
107
+ this.newClassMap = {};
108
+ this.newClassSize = 0;
109
+ this.context = {};
110
+ this.opts = opts;
111
+ this.classPrefix = (_a = opts.classPrefix) !== null && _a !== void 0 ? _a : 'tw-';
112
+ }
113
+ defaultClassGenerator() {
114
+ const chars = [];
115
+ let rest = (this.newClassSize - (this.newClassSize % acceptChars.length)) / acceptChars.length;
116
+ if (rest > 0) {
117
+ while (true) {
118
+ rest -= 1;
119
+ const m = rest % acceptChars.length;
120
+ const c = acceptChars[m];
121
+ chars.push(c);
122
+ rest -= m;
123
+ if (rest === 0) {
124
+ break;
125
+ }
126
+ rest /= acceptChars.length;
127
+ }
128
+ }
129
+ const prefixIndex = this.newClassSize % acceptChars.length;
130
+ const newClassName = `${this.classPrefix}${acceptChars[prefixIndex]}${chars.join('')}`;
131
+ return newClassName;
132
+ }
133
+ ignoreClassName(className) {
134
+ return regExpTest(this.opts.ignoreClass, className);
135
+ }
136
+ includeFilePath(filePath) {
137
+ const { include } = this.opts;
138
+ if (Array.isArray(include)) {
139
+ return regExpTest(include, filePath);
140
+ }
141
+ else {
142
+ return true;
143
+ }
144
+ }
145
+ excludeFilePath(filePath) {
146
+ const { exclude } = this.opts;
147
+ if (Array.isArray(exclude)) {
148
+ return regExpTest(exclude, filePath);
149
+ }
150
+ else {
151
+ return false;
152
+ }
153
+ }
154
+ isFileIncluded(filePath) {
155
+ return this.includeFilePath(filePath) && !this.excludeFilePath(filePath);
156
+ }
157
+ transformCssClass(className) {
158
+ const key = stripEscapeSequence(className);
159
+ const cn = this.newClassMap[key];
160
+ if (cn)
161
+ return cn.name;
162
+ return className;
163
+ }
164
+ generateClassName(original) {
165
+ const opts = this.opts;
166
+ original = stripEscapeSequence(original);
167
+ const cn = this.newClassMap[original];
168
+ if (cn)
169
+ return cn;
170
+ let newClassName;
171
+ if (opts.classGenerator) {
172
+ newClassName = opts.classGenerator(original, opts, this.context);
173
+ }
174
+ if (!newClassName) {
175
+ newClassName = this.defaultClassGenerator();
176
+ }
177
+ if (opts.reserveClassName && regExpTest(opts.reserveClassName, newClassName)) {
178
+ if (opts.log) {
179
+ console.log(`The class name has been reserved. ${newClassName}`);
180
+ }
181
+ this.newClassSize++;
182
+ return this.generateClassName(original);
183
+ }
184
+ if (opts.log) {
185
+ console.log(`Minify class name from ${original} to ${newClassName}`);
186
+ }
187
+ const newClass = {
188
+ name: newClassName,
189
+ usedBy: []
190
+ };
191
+ this.newClassMap[original] = newClass;
192
+ this.newClassSize++;
193
+ return newClass;
194
+ }
195
+ }
196
+
197
+ ({
198
+ HTML: parse5.html.NS.HTML,
199
+ XML: parse5.html.NS.XML,
200
+ MATHML: parse5.html.NS.MATHML,
201
+ SVG: parse5.html.NS.SVG,
202
+ XLINK: parse5.html.NS.XLINK,
203
+ XMLNS: parse5.html.NS.XMLNS
204
+ });
205
+
206
+ /**
207
+ * Determines if a given node is a document or not
208
+ * @param {Node} node Node to test
209
+ * @return {boolean}
210
+ */
211
+ function isDocument(node) {
212
+ return node.nodeName === '#document';
213
+ }
214
+ /**
215
+ * Determines if a given node is a document fragment or not
216
+ * @param {Node} node Node to test
217
+ * @return {boolean}
218
+ */
219
+ function isDocumentFragment(node) {
220
+ return node.nodeName === '#document-fragment';
221
+ }
222
+ /**
223
+ * Determines if a given node is a template node or not
224
+ * @param {Node} node Node to test
225
+ * @return {boolean}
226
+ */
227
+ function isTemplateNode(node) {
228
+ return node.nodeName === 'template';
229
+ }
230
+ const isElementNode = parse5.defaultTreeAdapter.isElementNode;
231
+ const isCommentNode = parse5.defaultTreeAdapter.isCommentNode;
232
+ const isDocumentTypeNode = parse5.defaultTreeAdapter.isDocumentTypeNode;
233
+ const isTextNode = parse5.defaultTreeAdapter.isTextNode;
234
+ /**
235
+ * Determines if a given node is a parent or not
236
+ * @param {Node} node Node to test
237
+ * @return {boolean}
238
+ */
239
+ function isParentNode(node) {
240
+ return (isDocument(node) ||
241
+ isDocumentFragment(node) ||
242
+ isElementNode(node) ||
243
+ isTemplateNode(node));
244
+ }
245
+
246
+ parse5.defaultTreeAdapter.appendChild;
247
+
248
+ /**
249
+ * Traverses the tree of a given node
250
+ * @param {Node} node Node to traverse
251
+ * @param {Visitor} visitor Visitor to apply
252
+ * @param {ParentNode=} parent Parent node of the current node
253
+ * @return {void}
254
+ */
255
+ function traverse$1(node, visitor, parent) {
256
+ const shouldVisitChildren = typeof visitor['pre:node'] !== 'function' ||
257
+ visitor['pre:node'](node, parent) !== false;
258
+ if (shouldVisitChildren && isParentNode(node)) {
259
+ for (const child of node.childNodes) {
260
+ traverse$1(child, visitor, node);
261
+ }
262
+ }
263
+ if (typeof visitor.node === 'function') {
264
+ visitor.node(node, parent);
265
+ }
266
+ if (typeof visitor.document === 'function' && isDocument(node)) {
267
+ visitor.document(node);
268
+ }
269
+ if (typeof visitor.documentFragment === 'function' &&
270
+ isDocumentFragment(node)) {
271
+ visitor.documentFragment(node, parent);
272
+ }
273
+ if (typeof visitor.element === 'function' && isElementNode(node)) {
274
+ visitor.element(node, parent);
275
+ }
276
+ if (typeof visitor.template === 'function' && isTemplateNode(node)) {
277
+ visitor.template(node, parent);
278
+ }
279
+ if (typeof visitor.comment === 'function' && isCommentNode(node)) {
280
+ visitor.comment(node, parent);
281
+ }
282
+ if (typeof visitor.text === 'function' && isTextNode(node)) {
283
+ visitor.text(node, parent);
284
+ }
285
+ if (typeof visitor.documentType === 'function' && isDocumentTypeNode(node)) {
286
+ visitor.documentType(node, parent);
287
+ }
288
+ }
289
+
290
+ function htmlHandler(rawSource, options) {
291
+ const { runtimeSet, classGenerator } = options;
292
+ const fragment = parse5.parse(rawSource);
293
+ traverse$1(fragment, {
294
+ element(node, parent) {
295
+ const attr = node.attrs.find((x) => x.name === 'class');
296
+ if (attr) {
297
+ const arr = attr.value.split(/\s/).filter((x) => x);
298
+ attr.value = arr
299
+ .map((x) => {
300
+ if (runtimeSet.has(x)) {
301
+ return classGenerator.generateClassName(x).name;
302
+ }
303
+ return x;
304
+ })
305
+ .join(' ');
306
+ }
307
+ }
308
+ });
309
+ return parse5.serialize(fragment);
310
+ }
311
+
312
+ const validateFilterRE = /[\w\u00A0-\uFFFF-_:%-?]/;
313
+ function isValidSelector(selector = '') {
314
+ return validateFilterRE.test(selector);
315
+ }
316
+ const splitCode = (code) => code.split(/[\s"]+/).filter(isValidSelector);
317
+
318
+ function getDefaultExportFromNamespaceIfPresent(n) {
319
+ return n && Object.prototype.hasOwnProperty.call(n, 'default') ? n.default : n;
320
+ }
321
+ const generate = getDefaultExportFromNamespaceIfPresent(_generate__default["default"]);
322
+ const traverse = getDefaultExportFromNamespaceIfPresent(_traverse__default["default"]);
323
+ function jsHandler(rawSource, options) {
324
+ const ast = parser.parse(rawSource);
325
+ const set = options.runtimeSet;
326
+ const clsGen = options.classGenerator;
327
+ const topt = {
328
+ StringLiteral: {
329
+ enter(p) {
330
+ const n = p.node;
331
+ const arr = splitCode(n.value);
332
+ let rawStr = n.value;
333
+ for (let i = 0; i < arr.length; i++) {
334
+ const v = arr[i];
335
+ if (set.has(v)) {
336
+ let ignoreFlag = false;
337
+ if (Array.isArray(n.leadingComments)) {
338
+ ignoreFlag = n.leadingComments.findIndex((x) => x.value.includes('tw-mangle') && x.value.includes('ignore')) > -1;
339
+ }
340
+ if (!ignoreFlag) {
341
+ rawStr = rawStr.replace(new RegExp(escapeStringRegexp(v), 'g'), clsGen.generateClassName(v).name);
342
+ }
343
+ }
344
+ }
345
+ n.value = rawStr;
346
+ }
347
+ },
348
+ noScope: true
349
+ };
350
+ traverse(ast, topt);
351
+ return generate(ast);
352
+ }
353
+
354
+ const postcssPlugin = 'postcss-mangle-tailwindcss-plugin';
355
+ const postcssMangleTailwindcssPlugin = (options) => {
356
+ let newClassMap = {};
357
+ if (options) {
358
+ if (options.newClassMap) {
359
+ newClassMap = options.newClassMap;
360
+ }
361
+ }
362
+ return {
363
+ postcssPlugin,
364
+ Rule(rule, helper) {
365
+ rule.selector = parser__default["default"]((selectors) => {
366
+ selectors.walk((s) => {
367
+ if (s.value) {
368
+ const hit = newClassMap[s.value];
369
+ if (hit) {
370
+ s.value = hit.name;
371
+ }
372
+ }
373
+ });
374
+ }).processSync(rule.selector);
375
+ }
376
+ };
377
+ };
378
+ postcssMangleTailwindcssPlugin.postcss = true;
379
+
380
+ function cssHandler(rawSource, options) {
381
+ return postcss__default["default"]([
382
+ postcssMangleTailwindcssPlugin({
383
+ newClassMap: options.classGenerator.newClassMap
384
+ })
385
+ ]).process(rawSource).css;
386
+ }
387
+
388
+ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
389
+ const mangleClass = (className) => {
390
+ return /[-:]/.test(className);
391
+ };
392
+ let classSet;
393
+ const classGenerator = new ClassGenerator();
394
+ function getCachedClassSet() {
395
+ const set = tailwindcssPatch.getClassCacheSet();
396
+ set.forEach((c) => {
397
+ if (!mangleClass(c)) {
398
+ set.delete(c);
399
+ }
400
+ });
401
+ classSet = set;
402
+ return classSet;
403
+ }
404
+ return {
405
+ name: pluginName,
406
+ enforce: 'post',
407
+ vite: {
408
+ generateBundle: {
409
+ handler(options, bundle, isWrite) {
410
+ const runtimeSet = getCachedClassSet();
411
+ const groupedEntries = getGroupedEntries(Object.entries(bundle));
412
+ if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
413
+ for (let i = 0; i < groupedEntries.html.length; i++) {
414
+ const [, asset] = groupedEntries.html[i];
415
+ asset.source = htmlHandler(asset.source.toString(), {
416
+ classGenerator,
417
+ runtimeSet
418
+ });
419
+ }
420
+ }
421
+ if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
422
+ for (let i = 0; i < groupedEntries.js.length; i++) {
423
+ const [, chunk] = groupedEntries.js[i];
424
+ chunk.code = jsHandler(chunk.code, {
425
+ runtimeSet,
426
+ classGenerator
427
+ }).code;
428
+ }
429
+ }
430
+ if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
431
+ for (let i = 0; i < groupedEntries.css.length; i++) {
432
+ const [, css] = groupedEntries.css[i];
433
+ css.source = cssHandler(css.source.toString(), {
434
+ classGenerator,
435
+ runtimeSet
436
+ });
437
+ }
438
+ }
439
+ }
440
+ }
441
+ },
442
+ webpack(compiler) {
443
+ const Compilation = compiler.webpack.Compilation;
444
+ const { ConcatSource } = compiler.webpack.sources;
445
+ compiler.hooks.compilation.tap(pluginName, (compilation) => {
446
+ compilation.hooks.processAssets.tap({
447
+ name: pluginName,
448
+ stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
449
+ }, (assets) => {
450
+ const runtimeSet = getCachedClassSet();
451
+ const groupedEntries = getGroupedEntries(Object.entries(assets));
452
+ if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
453
+ for (let i = 0; i < groupedEntries.html.length; i++) {
454
+ const [file, asset] = groupedEntries.html[i];
455
+ const html = htmlHandler(asset.source().toString(), {
456
+ classGenerator,
457
+ runtimeSet
458
+ });
459
+ const source = new ConcatSource(html);
460
+ compilation.updateAsset(file, source);
461
+ }
462
+ }
463
+ if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
464
+ for (let i = 0; i < groupedEntries.js.length; i++) {
465
+ const [file, chunk] = groupedEntries.js[i];
466
+ const code = jsHandler(chunk.source().toString(), {
467
+ runtimeSet,
468
+ classGenerator
469
+ }).code;
470
+ const source = new ConcatSource(code);
471
+ compilation.updateAsset(file, source);
472
+ }
473
+ }
474
+ if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
475
+ for (let i = 0; i < groupedEntries.css.length; i++) {
476
+ const [file, css] = groupedEntries.css[i];
477
+ const newCss = cssHandler(css.source().toString(), {
478
+ classGenerator,
479
+ runtimeSet
480
+ });
481
+ const source = new ConcatSource(newCss);
482
+ compilation.updateAsset(file, source);
483
+ }
484
+ }
485
+ });
486
+ });
487
+ }
488
+ };
489
+ });
490
+
491
+ module.exports = unplugin;