unplugin-tailwindcss-mangle 0.0.5 → 0.1.0

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  mangle tailwindcss utilities plugin
4
4
 
5
- > Now Support `vite` and `webpack`(Experiment!)
5
+ > Now Support `vite` and `webpack`
6
6
 
7
7
  - [unplugin-tailwindcss-mangle](#unplugin-tailwindcss-mangle)
8
8
  - [Features](#features)
@@ -15,6 +15,7 @@ mangle tailwindcss utilities plugin
15
15
  - [webpack](#webpack)
16
16
  - [Options](#options)
17
17
  - [classGenerator](#classgenerator)
18
+ - [include / exclude](#include--exclude)
18
19
  - [Notice](#notice)
19
20
 
20
21
  ## Features
@@ -76,15 +77,23 @@ You will see all class was renamed to `tw-*`
76
77
 
77
78
  #### webpack
78
79
 
79
- > Experiment, not work right now
80
-
81
80
  ```js
82
81
  // esm
83
82
  import { webpackPlugin as utwm } from 'unplugin-tailwindcss-mangle'
84
83
  // or cjs
85
84
  const { webpackPlugin: utwm } = require('unplugin-tailwindcss-mangle')
86
85
  // use this webpack plugin
87
- utwm()
86
+ // for example next.config.js
87
+ /** @type {import('next').NextConfig} */
88
+ const nextConfig = {
89
+ reactStrictMode: true,
90
+ webpack: (config) => {
91
+ config.plugins.push(utwm())
92
+ return config
93
+ }
94
+ }
95
+
96
+ module.exports = nextConfig
88
97
  ```
89
98
 
90
99
  ## Options
@@ -105,6 +114,12 @@ export interface IClassGeneratorOptions {
105
114
  }
106
115
  ```
107
116
 
117
+ ### include / exclude
118
+
119
+ type: glob string
120
+
121
+ allow you to control the mangle range of bundles.
122
+
108
123
  ## Notice
109
124
 
110
125
  This plugin only transform those classes which name contain `-` or `:`, like `w-32`, `before:h-[300px]`,`after:dark:via-[#0141ff]/40`. some classes like `flex`,`relative` will not be mangled.
@@ -1 +1,2 @@
1
1
  export declare const pluginName = "unplugin-tailwindcss-mangle";
2
+ export declare const webpackCacheKey: string;
package/dist/esbuild.js CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  var index = require('./index.js');
4
4
  require('unplugin');
5
- require('tailwindcss-patch');
5
+ require('micromatch');
6
6
  require('parse5');
7
7
  require('@babel/generator');
8
8
  require('@babel/parser');
9
9
  require('@babel/traverse');
10
10
  require('postcss');
11
11
  require('postcss-selector-parser');
12
+ require('path');
13
+ require('fs');
14
+ require('tailwindcss-patch');
12
15
 
13
16
  var esbuild = index.unplugin.esbuild;
14
17
 
package/dist/esbuild.mjs CHANGED
@@ -1,12 +1,15 @@
1
1
  import { unplugin } from './index.mjs';
2
2
  import 'unplugin';
3
- import 'tailwindcss-patch';
3
+ import 'micromatch';
4
4
  import 'parse5';
5
5
  import '@babel/generator';
6
6
  import '@babel/parser';
7
7
  import '@babel/traverse';
8
8
  import 'postcss';
9
9
  import 'postcss-selector-parser';
10
+ import 'path';
11
+ import 'fs';
12
+ import 'tailwindcss-patch';
10
13
 
11
14
  var esbuild = unplugin.esbuild;
12
15
 
package/dist/index.js CHANGED
@@ -3,13 +3,16 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var unplugin$1 = require('unplugin');
6
- var tailwindcssPatch = require('tailwindcss-patch');
6
+ var micromatch = require('micromatch');
7
7
  var parse5 = require('parse5');
8
8
  var _generate = require('@babel/generator');
9
9
  var parser = require('@babel/parser');
10
10
  var _traverse = require('@babel/traverse');
11
11
  var postcss = require('postcss');
12
12
  var parser$1 = require('postcss-selector-parser');
13
+ var path = require('path');
14
+ var fs = require('fs');
15
+ var tailwindcssPatch = require('tailwindcss-patch');
13
16
 
14
17
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
15
18
 
@@ -17,6 +20,8 @@ var _generate__default = /*#__PURE__*/_interopDefault(_generate);
17
20
  var _traverse__default = /*#__PURE__*/_interopDefault(_traverse);
18
21
  var postcss__default = /*#__PURE__*/_interopDefault(postcss);
19
22
  var parser__default = /*#__PURE__*/_interopDefault(parser$1);
23
+ var path__default = /*#__PURE__*/_interopDefault(path);
24
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
20
25
 
21
26
  const pluginName = 'unplugin-tailwindcss-mangle';
22
27
 
@@ -67,6 +72,18 @@ function getGroupedEntries(entries, options = {
67
72
  return 'other';
68
73
  }
69
74
  });
75
+ if (!groupedEntries.css) {
76
+ groupedEntries.css = [];
77
+ }
78
+ if (!groupedEntries.html) {
79
+ groupedEntries.html = [];
80
+ }
81
+ if (!groupedEntries.js) {
82
+ groupedEntries.js = [];
83
+ }
84
+ if (!groupedEntries.other) {
85
+ groupedEntries.other = [];
86
+ }
70
87
  return groupedEntries;
71
88
  }
72
89
  const acceptChars = 'abcdefghijklmnopqrstuvwxyz'.split('');
@@ -102,98 +119,15 @@ function escapeStringRegexp(str) {
102
119
  }
103
120
  return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d');
104
121
  }
105
-
106
- class ClassGenerator {
107
- constructor(opts = {}) {
108
- var _a;
109
- this.newClassMap = {};
110
- this.newClassSize = 0;
111
- this.context = {};
112
- this.opts = opts;
113
- this.classPrefix = (_a = opts.classPrefix) !== null && _a !== void 0 ? _a : 'tw-';
114
- }
115
- defaultClassGenerate() {
116
- const chars = [];
117
- let rest = (this.newClassSize - (this.newClassSize % acceptChars.length)) / acceptChars.length;
118
- if (rest > 0) {
119
- while (true) {
120
- rest -= 1;
121
- const m = rest % acceptChars.length;
122
- const c = acceptChars[m];
123
- chars.push(c);
124
- rest -= m;
125
- if (rest === 0) {
126
- break;
127
- }
128
- rest /= acceptChars.length;
129
- }
130
- }
131
- const prefixIndex = this.newClassSize % acceptChars.length;
132
- const newClassName = `${this.classPrefix}${acceptChars[prefixIndex]}${chars.join('')}`;
133
- return newClassName;
134
- }
135
- ignoreClassName(className) {
136
- return regExpTest(this.opts.ignoreClass, className);
137
- }
138
- includeFilePath(filePath) {
139
- const { include } = this.opts;
140
- if (Array.isArray(include)) {
141
- return regExpTest(include, filePath);
142
- }
143
- else {
144
- return true;
145
- }
146
- }
147
- excludeFilePath(filePath) {
148
- const { exclude } = this.opts;
149
- if (Array.isArray(exclude)) {
150
- return regExpTest(exclude, filePath);
151
- }
152
- else {
153
- return false;
154
- }
155
- }
156
- isFileIncluded(filePath) {
157
- return this.includeFilePath(filePath) && !this.excludeFilePath(filePath);
158
- }
159
- transformCssClass(className) {
160
- const key = stripEscapeSequence(className);
161
- const cn = this.newClassMap[key];
162
- if (cn)
163
- return cn.name;
164
- return className;
165
- }
166
- generateClassName(original) {
167
- const opts = this.opts;
168
- original = stripEscapeSequence(original);
169
- const cn = this.newClassMap[original];
170
- if (cn)
171
- return cn;
172
- let newClassName;
173
- if (opts.customGenerate && typeof opts.customGenerate === 'function') {
174
- newClassName = opts.customGenerate(original, opts, this.context);
175
- }
176
- if (!newClassName) {
177
- newClassName = this.defaultClassGenerate();
178
- }
179
- if (opts.reserveClassName && regExpTest(opts.reserveClassName, newClassName)) {
180
- if (opts.log) {
181
- console.log(`The class name has been reserved. ${newClassName}`);
182
- }
183
- this.newClassSize++;
184
- return this.generateClassName(original);
185
- }
186
- if (opts.log) {
187
- console.log(`Minify class name from ${original} to ${newClassName}`);
188
- }
189
- const newClass = {
190
- name: newClassName,
191
- usedBy: []
122
+ function createGlobMatcher(pattern, fallbackValue = false) {
123
+ if (typeof pattern === 'undefined') {
124
+ return function (file) {
125
+ return fallbackValue;
192
126
  };
193
- this.newClassMap[original] = newClass;
194
- this.newClassSize++;
195
- return newClass;
196
127
  }
128
+ return function (file) {
129
+ return micromatch.isMatch(file, pattern);
130
+ };
197
131
  }
198
132
 
199
133
  ({
@@ -399,7 +333,105 @@ function cssHandler(rawSource, options) {
399
333
  ]).process(rawSource).css;
400
334
  }
401
335
 
402
- const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
336
+ class ClassGenerator {
337
+ constructor(opts = {}) {
338
+ var _a;
339
+ this.newClassMap = {};
340
+ this.newClassSize = 0;
341
+ this.context = {};
342
+ this.opts = opts;
343
+ this.classPrefix = (_a = opts.classPrefix) !== null && _a !== void 0 ? _a : 'tw-';
344
+ }
345
+ defaultClassGenerate() {
346
+ const chars = [];
347
+ let rest = (this.newClassSize - (this.newClassSize % acceptChars.length)) / acceptChars.length;
348
+ if (rest > 0) {
349
+ while (true) {
350
+ rest -= 1;
351
+ const m = rest % acceptChars.length;
352
+ const c = acceptChars[m];
353
+ chars.push(c);
354
+ rest -= m;
355
+ if (rest === 0) {
356
+ break;
357
+ }
358
+ rest /= acceptChars.length;
359
+ }
360
+ }
361
+ const prefixIndex = this.newClassSize % acceptChars.length;
362
+ const newClassName = `${this.classPrefix}${acceptChars[prefixIndex]}${chars.join('')}`;
363
+ return newClassName;
364
+ }
365
+ ignoreClassName(className) {
366
+ return regExpTest(this.opts.ignoreClass, className);
367
+ }
368
+ includeFilePath(filePath) {
369
+ const { include } = this.opts;
370
+ if (Array.isArray(include)) {
371
+ return regExpTest(include, filePath);
372
+ }
373
+ else {
374
+ return true;
375
+ }
376
+ }
377
+ excludeFilePath(filePath) {
378
+ const { exclude } = this.opts;
379
+ if (Array.isArray(exclude)) {
380
+ return regExpTest(exclude, filePath);
381
+ }
382
+ else {
383
+ return false;
384
+ }
385
+ }
386
+ isFileIncluded(filePath) {
387
+ return this.includeFilePath(filePath) && !this.excludeFilePath(filePath);
388
+ }
389
+ transformCssClass(className) {
390
+ const key = stripEscapeSequence(className);
391
+ const cn = this.newClassMap[key];
392
+ if (cn)
393
+ return cn.name;
394
+ return className;
395
+ }
396
+ generateClassName(original) {
397
+ const opts = this.opts;
398
+ original = stripEscapeSequence(original);
399
+ const cn = this.newClassMap[original];
400
+ if (cn)
401
+ return cn;
402
+ let newClassName;
403
+ if (opts.customGenerate && typeof opts.customGenerate === 'function') {
404
+ newClassName = opts.customGenerate(original, opts, this.context);
405
+ }
406
+ if (!newClassName) {
407
+ newClassName = this.defaultClassGenerate();
408
+ }
409
+ if (opts.reserveClassName && regExpTest(opts.reserveClassName, newClassName)) {
410
+ if (opts.log) {
411
+ console.log(`The class name has been reserved. ${newClassName}`);
412
+ }
413
+ this.newClassSize++;
414
+ return this.generateClassName(original);
415
+ }
416
+ if (opts.log) {
417
+ console.log(`Minify class name from ${original} to ${newClassName}`);
418
+ }
419
+ const newClass = {
420
+ name: newClassName,
421
+ usedBy: []
422
+ };
423
+ this.newClassMap[original] = newClass;
424
+ this.newClassSize++;
425
+ return newClass;
426
+ }
427
+ }
428
+
429
+ function getOptions(options = {}) {
430
+ const includeMatcher = createGlobMatcher(options.include, true);
431
+ const excludeMatcher = createGlobMatcher(options.exclude, false);
432
+ function isInclude(file) {
433
+ return includeMatcher(file) && !excludeMatcher(file);
434
+ }
403
435
  const isMangleClass = (className) => {
404
436
  return /[-:]/.test(className);
405
437
  };
@@ -415,6 +447,18 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
415
447
  classSet = set;
416
448
  return classSet;
417
449
  }
450
+ return {
451
+ getCachedClassSet,
452
+ classGenerator,
453
+ includeMatcher,
454
+ excludeMatcher,
455
+ isInclude
456
+ };
457
+ }
458
+
459
+ const outputCachedMap = new Map();
460
+ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
461
+ const { classGenerator, getCachedClassSet, isInclude } = getOptions(options);
418
462
  return {
419
463
  name: pluginName,
420
464
  enforce: 'post',
@@ -428,29 +472,35 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
428
472
  const groupedEntries = getGroupedEntries(Object.entries(bundle));
429
473
  if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
430
474
  for (let i = 0; i < groupedEntries.html.length; i++) {
431
- const [, asset] = groupedEntries.html[i];
432
- asset.source = htmlHandler(asset.source.toString(), {
433
- classGenerator,
434
- runtimeSet
435
- });
475
+ const [file, asset] = groupedEntries.html[i];
476
+ if (isInclude(file)) {
477
+ asset.source = htmlHandler(asset.source.toString(), {
478
+ classGenerator,
479
+ runtimeSet
480
+ });
481
+ }
436
482
  }
437
483
  }
438
484
  if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
439
485
  for (let i = 0; i < groupedEntries.js.length; i++) {
440
- const [, chunk] = groupedEntries.js[i];
441
- chunk.code = jsHandler(chunk.code, {
442
- runtimeSet,
443
- classGenerator
444
- }).code;
486
+ const [file, chunk] = groupedEntries.js[i];
487
+ if (isInclude(file)) {
488
+ chunk.code = jsHandler(chunk.code, {
489
+ runtimeSet,
490
+ classGenerator
491
+ }).code;
492
+ }
445
493
  }
446
494
  }
447
495
  if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
448
496
  for (let i = 0; i < groupedEntries.css.length; i++) {
449
- const [, css] = groupedEntries.css[i];
450
- css.source = cssHandler(css.source.toString(), {
451
- classGenerator,
452
- runtimeSet
453
- });
497
+ const [file, css] = groupedEntries.css[i];
498
+ if (isInclude(file)) {
499
+ css.source = cssHandler(css.source.toString(), {
500
+ classGenerator,
501
+ runtimeSet
502
+ });
503
+ }
454
504
  }
455
505
  }
456
506
  }
@@ -459,49 +509,129 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
459
509
  webpack(compiler) {
460
510
  const Compilation = compiler.webpack.Compilation;
461
511
  const { ConcatSource } = compiler.webpack.sources;
512
+ function getAssetPath(outputPath, file, abs = true) {
513
+ const fn = abs ? path__default["default"].resolve : path__default["default"].relative;
514
+ return fn(compiler.context, path__default["default"].resolve(outputPath, file));
515
+ }
516
+ function overwriteServerSideAsset(outputPath, file, data) {
517
+ const abs = getAssetPath(outputPath, file);
518
+ const rel = getAssetPath(outputPath, file, false);
519
+ try {
520
+ fs__default["default"].writeFileSync(abs, data, 'utf-8');
521
+ console.log('[tailwindcss-mangle]: ' + rel + ' overwrited successfully');
522
+ }
523
+ catch (error) {
524
+ console.log('[tailwindcss-mangle]: ' + rel + ' overwrited fail!');
525
+ console.log(error);
526
+ }
527
+ }
462
528
  compiler.hooks.compilation.tap(pluginName, (compilation) => {
463
529
  compilation.hooks.processAssets.tap({
464
530
  name: pluginName,
465
531
  stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
466
532
  }, (assets) => {
467
533
  const runtimeSet = getCachedClassSet();
534
+ const groupedEntries = getGroupedEntries(Object.entries(assets));
468
535
  if (!runtimeSet.size) {
536
+ const css = new Map();
537
+ const html = new Map();
538
+ const js = new Map();
539
+ groupedEntries.css.forEach(([file, source]) => {
540
+ css.set(file, source);
541
+ });
542
+ groupedEntries.html.forEach(([file, source]) => {
543
+ html.set(file, source);
544
+ });
545
+ groupedEntries.js.forEach(([file, source]) => {
546
+ js.set(file, source);
547
+ });
548
+ if (js.size || css.size || html.size) {
549
+ outputCachedMap.set(compiler.outputPath, {
550
+ css,
551
+ html,
552
+ js
553
+ });
554
+ }
469
555
  return;
470
556
  }
471
- const groupedEntries = getGroupedEntries(Object.entries(assets));
472
- if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
557
+ if (groupedEntries.html.length) {
473
558
  for (let i = 0; i < groupedEntries.html.length; i++) {
474
559
  const [file, asset] = groupedEntries.html[i];
475
- const html = htmlHandler(asset.source().toString(), {
476
- classGenerator,
477
- runtimeSet
478
- });
479
- const source = new ConcatSource(html);
480
- compilation.updateAsset(file, source);
560
+ if (isInclude(file)) {
561
+ const html = htmlHandler(asset.source().toString(), {
562
+ classGenerator,
563
+ runtimeSet
564
+ });
565
+ const source = new ConcatSource(html);
566
+ compilation.updateAsset(file, source);
567
+ }
481
568
  }
482
569
  }
483
- if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
570
+ if (groupedEntries.js.length) {
484
571
  for (let i = 0; i < groupedEntries.js.length; i++) {
485
572
  const [file, chunk] = groupedEntries.js[i];
486
- const code = jsHandler(chunk.source().toString(), {
487
- runtimeSet,
488
- classGenerator
489
- }).code;
490
- const source = new ConcatSource(code);
491
- compilation.updateAsset(file, source);
573
+ if (isInclude(file)) {
574
+ const code = jsHandler(chunk.source().toString(), {
575
+ runtimeSet,
576
+ classGenerator
577
+ }).code;
578
+ const source = new ConcatSource(code);
579
+ compilation.updateAsset(file, source);
580
+ }
492
581
  }
493
582
  }
494
- if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
583
+ if (groupedEntries.css.length) {
495
584
  for (let i = 0; i < groupedEntries.css.length; i++) {
496
585
  const [file, css] = groupedEntries.css[i];
497
- const newCss = cssHandler(css.source().toString(), {
498
- classGenerator,
499
- runtimeSet
500
- });
501
- const source = new ConcatSource(newCss);
502
- compilation.updateAsset(file, source);
586
+ if (isInclude(file)) {
587
+ const newCss = cssHandler(css.source().toString(), {
588
+ classGenerator,
589
+ runtimeSet
590
+ });
591
+ const source = new ConcatSource(newCss);
592
+ compilation.updateAsset(file, source);
593
+ }
503
594
  }
504
595
  }
596
+ outputCachedMap.forEach(({ js, html, css }, key) => {
597
+ if (html.size) {
598
+ html.forEach((asset, file) => {
599
+ if (isInclude(file)) {
600
+ const html = htmlHandler(asset.source().toString(), {
601
+ classGenerator,
602
+ runtimeSet
603
+ });
604
+ overwriteServerSideAsset(key, file, html);
605
+ }
606
+ });
607
+ html.clear();
608
+ }
609
+ if (js.size) {
610
+ js.forEach((chunk, file) => {
611
+ if (isInclude(file)) {
612
+ const rawCode = chunk.source().toString();
613
+ const code = jsHandler(rawCode, {
614
+ runtimeSet,
615
+ classGenerator
616
+ }).code;
617
+ overwriteServerSideAsset(key, file, code);
618
+ }
619
+ });
620
+ js.clear();
621
+ }
622
+ if (css.size) {
623
+ css.forEach((style, file) => {
624
+ if (isInclude(file)) {
625
+ const newCss = cssHandler(style.source().toString(), {
626
+ classGenerator,
627
+ runtimeSet
628
+ });
629
+ overwriteServerSideAsset(key, file, newCss);
630
+ }
631
+ });
632
+ css.clear();
633
+ }
634
+ });
505
635
  });
506
636
  });
507
637
  }
package/dist/index.mjs CHANGED
@@ -1,11 +1,14 @@
1
1
  import { createUnplugin } from 'unplugin';
2
- import { getClassCacheSet } from 'tailwindcss-patch';
2
+ import { isMatch } from 'micromatch';
3
3
  import { html, defaultTreeAdapter, parse, serialize } from 'parse5';
4
4
  import _generate from '@babel/generator';
5
5
  import { parse as parse$1 } from '@babel/parser';
6
6
  import _traverse from '@babel/traverse';
7
7
  import postcss from 'postcss';
8
8
  import parser from 'postcss-selector-parser';
9
+ import path from 'path';
10
+ import fs from 'fs';
11
+ import { getClassCacheSet } from 'tailwindcss-patch';
9
12
 
10
13
  const pluginName = 'unplugin-tailwindcss-mangle';
11
14
 
@@ -56,6 +59,18 @@ function getGroupedEntries(entries, options = {
56
59
  return 'other';
57
60
  }
58
61
  });
62
+ if (!groupedEntries.css) {
63
+ groupedEntries.css = [];
64
+ }
65
+ if (!groupedEntries.html) {
66
+ groupedEntries.html = [];
67
+ }
68
+ if (!groupedEntries.js) {
69
+ groupedEntries.js = [];
70
+ }
71
+ if (!groupedEntries.other) {
72
+ groupedEntries.other = [];
73
+ }
59
74
  return groupedEntries;
60
75
  }
61
76
  const acceptChars = 'abcdefghijklmnopqrstuvwxyz'.split('');
@@ -91,98 +106,15 @@ function escapeStringRegexp(str) {
91
106
  }
92
107
  return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d');
93
108
  }
94
-
95
- class ClassGenerator {
96
- constructor(opts = {}) {
97
- var _a;
98
- this.newClassMap = {};
99
- this.newClassSize = 0;
100
- this.context = {};
101
- this.opts = opts;
102
- this.classPrefix = (_a = opts.classPrefix) !== null && _a !== void 0 ? _a : 'tw-';
103
- }
104
- defaultClassGenerate() {
105
- const chars = [];
106
- let rest = (this.newClassSize - (this.newClassSize % acceptChars.length)) / acceptChars.length;
107
- if (rest > 0) {
108
- while (true) {
109
- rest -= 1;
110
- const m = rest % acceptChars.length;
111
- const c = acceptChars[m];
112
- chars.push(c);
113
- rest -= m;
114
- if (rest === 0) {
115
- break;
116
- }
117
- rest /= acceptChars.length;
118
- }
119
- }
120
- const prefixIndex = this.newClassSize % acceptChars.length;
121
- const newClassName = `${this.classPrefix}${acceptChars[prefixIndex]}${chars.join('')}`;
122
- return newClassName;
123
- }
124
- ignoreClassName(className) {
125
- return regExpTest(this.opts.ignoreClass, className);
126
- }
127
- includeFilePath(filePath) {
128
- const { include } = this.opts;
129
- if (Array.isArray(include)) {
130
- return regExpTest(include, filePath);
131
- }
132
- else {
133
- return true;
134
- }
135
- }
136
- excludeFilePath(filePath) {
137
- const { exclude } = this.opts;
138
- if (Array.isArray(exclude)) {
139
- return regExpTest(exclude, filePath);
140
- }
141
- else {
142
- return false;
143
- }
144
- }
145
- isFileIncluded(filePath) {
146
- return this.includeFilePath(filePath) && !this.excludeFilePath(filePath);
147
- }
148
- transformCssClass(className) {
149
- const key = stripEscapeSequence(className);
150
- const cn = this.newClassMap[key];
151
- if (cn)
152
- return cn.name;
153
- return className;
154
- }
155
- generateClassName(original) {
156
- const opts = this.opts;
157
- original = stripEscapeSequence(original);
158
- const cn = this.newClassMap[original];
159
- if (cn)
160
- return cn;
161
- let newClassName;
162
- if (opts.customGenerate && typeof opts.customGenerate === 'function') {
163
- newClassName = opts.customGenerate(original, opts, this.context);
164
- }
165
- if (!newClassName) {
166
- newClassName = this.defaultClassGenerate();
167
- }
168
- if (opts.reserveClassName && regExpTest(opts.reserveClassName, newClassName)) {
169
- if (opts.log) {
170
- console.log(`The class name has been reserved. ${newClassName}`);
171
- }
172
- this.newClassSize++;
173
- return this.generateClassName(original);
174
- }
175
- if (opts.log) {
176
- console.log(`Minify class name from ${original} to ${newClassName}`);
177
- }
178
- const newClass = {
179
- name: newClassName,
180
- usedBy: []
109
+ function createGlobMatcher(pattern, fallbackValue = false) {
110
+ if (typeof pattern === 'undefined') {
111
+ return function (file) {
112
+ return fallbackValue;
181
113
  };
182
- this.newClassMap[original] = newClass;
183
- this.newClassSize++;
184
- return newClass;
185
114
  }
115
+ return function (file) {
116
+ return isMatch(file, pattern);
117
+ };
186
118
  }
187
119
 
188
120
  ({
@@ -388,7 +320,105 @@ function cssHandler(rawSource, options) {
388
320
  ]).process(rawSource).css;
389
321
  }
390
322
 
391
- const unplugin = createUnplugin((options = {}, meta) => {
323
+ class ClassGenerator {
324
+ constructor(opts = {}) {
325
+ var _a;
326
+ this.newClassMap = {};
327
+ this.newClassSize = 0;
328
+ this.context = {};
329
+ this.opts = opts;
330
+ this.classPrefix = (_a = opts.classPrefix) !== null && _a !== void 0 ? _a : 'tw-';
331
+ }
332
+ defaultClassGenerate() {
333
+ const chars = [];
334
+ let rest = (this.newClassSize - (this.newClassSize % acceptChars.length)) / acceptChars.length;
335
+ if (rest > 0) {
336
+ while (true) {
337
+ rest -= 1;
338
+ const m = rest % acceptChars.length;
339
+ const c = acceptChars[m];
340
+ chars.push(c);
341
+ rest -= m;
342
+ if (rest === 0) {
343
+ break;
344
+ }
345
+ rest /= acceptChars.length;
346
+ }
347
+ }
348
+ const prefixIndex = this.newClassSize % acceptChars.length;
349
+ const newClassName = `${this.classPrefix}${acceptChars[prefixIndex]}${chars.join('')}`;
350
+ return newClassName;
351
+ }
352
+ ignoreClassName(className) {
353
+ return regExpTest(this.opts.ignoreClass, className);
354
+ }
355
+ includeFilePath(filePath) {
356
+ const { include } = this.opts;
357
+ if (Array.isArray(include)) {
358
+ return regExpTest(include, filePath);
359
+ }
360
+ else {
361
+ return true;
362
+ }
363
+ }
364
+ excludeFilePath(filePath) {
365
+ const { exclude } = this.opts;
366
+ if (Array.isArray(exclude)) {
367
+ return regExpTest(exclude, filePath);
368
+ }
369
+ else {
370
+ return false;
371
+ }
372
+ }
373
+ isFileIncluded(filePath) {
374
+ return this.includeFilePath(filePath) && !this.excludeFilePath(filePath);
375
+ }
376
+ transformCssClass(className) {
377
+ const key = stripEscapeSequence(className);
378
+ const cn = this.newClassMap[key];
379
+ if (cn)
380
+ return cn.name;
381
+ return className;
382
+ }
383
+ generateClassName(original) {
384
+ const opts = this.opts;
385
+ original = stripEscapeSequence(original);
386
+ const cn = this.newClassMap[original];
387
+ if (cn)
388
+ return cn;
389
+ let newClassName;
390
+ if (opts.customGenerate && typeof opts.customGenerate === 'function') {
391
+ newClassName = opts.customGenerate(original, opts, this.context);
392
+ }
393
+ if (!newClassName) {
394
+ newClassName = this.defaultClassGenerate();
395
+ }
396
+ if (opts.reserveClassName && regExpTest(opts.reserveClassName, newClassName)) {
397
+ if (opts.log) {
398
+ console.log(`The class name has been reserved. ${newClassName}`);
399
+ }
400
+ this.newClassSize++;
401
+ return this.generateClassName(original);
402
+ }
403
+ if (opts.log) {
404
+ console.log(`Minify class name from ${original} to ${newClassName}`);
405
+ }
406
+ const newClass = {
407
+ name: newClassName,
408
+ usedBy: []
409
+ };
410
+ this.newClassMap[original] = newClass;
411
+ this.newClassSize++;
412
+ return newClass;
413
+ }
414
+ }
415
+
416
+ function getOptions(options = {}) {
417
+ const includeMatcher = createGlobMatcher(options.include, true);
418
+ const excludeMatcher = createGlobMatcher(options.exclude, false);
419
+ function isInclude(file) {
420
+ return includeMatcher(file) && !excludeMatcher(file);
421
+ }
392
422
  const isMangleClass = (className) => {
393
423
  return /[-:]/.test(className);
394
424
  };
@@ -404,6 +434,18 @@ const unplugin = createUnplugin((options = {}, meta) => {
404
434
  classSet = set;
405
435
  return classSet;
406
436
  }
437
+ return {
438
+ getCachedClassSet,
439
+ classGenerator,
440
+ includeMatcher,
441
+ excludeMatcher,
442
+ isInclude
443
+ };
444
+ }
445
+
446
+ const outputCachedMap = new Map();
447
+ const unplugin = createUnplugin((options = {}, meta) => {
448
+ const { classGenerator, getCachedClassSet, isInclude } = getOptions(options);
407
449
  return {
408
450
  name: pluginName,
409
451
  enforce: 'post',
@@ -417,29 +459,35 @@ const unplugin = createUnplugin((options = {}, meta) => {
417
459
  const groupedEntries = getGroupedEntries(Object.entries(bundle));
418
460
  if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
419
461
  for (let i = 0; i < groupedEntries.html.length; i++) {
420
- const [, asset] = groupedEntries.html[i];
421
- asset.source = htmlHandler(asset.source.toString(), {
422
- classGenerator,
423
- runtimeSet
424
- });
462
+ const [file, asset] = groupedEntries.html[i];
463
+ if (isInclude(file)) {
464
+ asset.source = htmlHandler(asset.source.toString(), {
465
+ classGenerator,
466
+ runtimeSet
467
+ });
468
+ }
425
469
  }
426
470
  }
427
471
  if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
428
472
  for (let i = 0; i < groupedEntries.js.length; i++) {
429
- const [, chunk] = groupedEntries.js[i];
430
- chunk.code = jsHandler(chunk.code, {
431
- runtimeSet,
432
- classGenerator
433
- }).code;
473
+ const [file, chunk] = groupedEntries.js[i];
474
+ if (isInclude(file)) {
475
+ chunk.code = jsHandler(chunk.code, {
476
+ runtimeSet,
477
+ classGenerator
478
+ }).code;
479
+ }
434
480
  }
435
481
  }
436
482
  if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
437
483
  for (let i = 0; i < groupedEntries.css.length; i++) {
438
- const [, css] = groupedEntries.css[i];
439
- css.source = cssHandler(css.source.toString(), {
440
- classGenerator,
441
- runtimeSet
442
- });
484
+ const [file, css] = groupedEntries.css[i];
485
+ if (isInclude(file)) {
486
+ css.source = cssHandler(css.source.toString(), {
487
+ classGenerator,
488
+ runtimeSet
489
+ });
490
+ }
443
491
  }
444
492
  }
445
493
  }
@@ -448,49 +496,129 @@ const unplugin = createUnplugin((options = {}, meta) => {
448
496
  webpack(compiler) {
449
497
  const Compilation = compiler.webpack.Compilation;
450
498
  const { ConcatSource } = compiler.webpack.sources;
499
+ function getAssetPath(outputPath, file, abs = true) {
500
+ const fn = abs ? path.resolve : path.relative;
501
+ return fn(compiler.context, path.resolve(outputPath, file));
502
+ }
503
+ function overwriteServerSideAsset(outputPath, file, data) {
504
+ const abs = getAssetPath(outputPath, file);
505
+ const rel = getAssetPath(outputPath, file, false);
506
+ try {
507
+ fs.writeFileSync(abs, data, 'utf-8');
508
+ console.log('[tailwindcss-mangle]: ' + rel + ' overwrited successfully');
509
+ }
510
+ catch (error) {
511
+ console.log('[tailwindcss-mangle]: ' + rel + ' overwrited fail!');
512
+ console.log(error);
513
+ }
514
+ }
451
515
  compiler.hooks.compilation.tap(pluginName, (compilation) => {
452
516
  compilation.hooks.processAssets.tap({
453
517
  name: pluginName,
454
518
  stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
455
519
  }, (assets) => {
456
520
  const runtimeSet = getCachedClassSet();
521
+ const groupedEntries = getGroupedEntries(Object.entries(assets));
457
522
  if (!runtimeSet.size) {
523
+ const css = new Map();
524
+ const html = new Map();
525
+ const js = new Map();
526
+ groupedEntries.css.forEach(([file, source]) => {
527
+ css.set(file, source);
528
+ });
529
+ groupedEntries.html.forEach(([file, source]) => {
530
+ html.set(file, source);
531
+ });
532
+ groupedEntries.js.forEach(([file, source]) => {
533
+ js.set(file, source);
534
+ });
535
+ if (js.size || css.size || html.size) {
536
+ outputCachedMap.set(compiler.outputPath, {
537
+ css,
538
+ html,
539
+ js
540
+ });
541
+ }
458
542
  return;
459
543
  }
460
- const groupedEntries = getGroupedEntries(Object.entries(assets));
461
- if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
544
+ if (groupedEntries.html.length) {
462
545
  for (let i = 0; i < groupedEntries.html.length; i++) {
463
546
  const [file, asset] = groupedEntries.html[i];
464
- const html = htmlHandler(asset.source().toString(), {
465
- classGenerator,
466
- runtimeSet
467
- });
468
- const source = new ConcatSource(html);
469
- compilation.updateAsset(file, source);
547
+ if (isInclude(file)) {
548
+ const html = htmlHandler(asset.source().toString(), {
549
+ classGenerator,
550
+ runtimeSet
551
+ });
552
+ const source = new ConcatSource(html);
553
+ compilation.updateAsset(file, source);
554
+ }
470
555
  }
471
556
  }
472
- if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
557
+ if (groupedEntries.js.length) {
473
558
  for (let i = 0; i < groupedEntries.js.length; i++) {
474
559
  const [file, chunk] = groupedEntries.js[i];
475
- const code = jsHandler(chunk.source().toString(), {
476
- runtimeSet,
477
- classGenerator
478
- }).code;
479
- const source = new ConcatSource(code);
480
- compilation.updateAsset(file, source);
560
+ if (isInclude(file)) {
561
+ const code = jsHandler(chunk.source().toString(), {
562
+ runtimeSet,
563
+ classGenerator
564
+ }).code;
565
+ const source = new ConcatSource(code);
566
+ compilation.updateAsset(file, source);
567
+ }
481
568
  }
482
569
  }
483
- if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
570
+ if (groupedEntries.css.length) {
484
571
  for (let i = 0; i < groupedEntries.css.length; i++) {
485
572
  const [file, css] = groupedEntries.css[i];
486
- const newCss = cssHandler(css.source().toString(), {
487
- classGenerator,
488
- runtimeSet
489
- });
490
- const source = new ConcatSource(newCss);
491
- compilation.updateAsset(file, source);
573
+ if (isInclude(file)) {
574
+ const newCss = cssHandler(css.source().toString(), {
575
+ classGenerator,
576
+ runtimeSet
577
+ });
578
+ const source = new ConcatSource(newCss);
579
+ compilation.updateAsset(file, source);
580
+ }
492
581
  }
493
582
  }
583
+ outputCachedMap.forEach(({ js, html, css }, key) => {
584
+ if (html.size) {
585
+ html.forEach((asset, file) => {
586
+ if (isInclude(file)) {
587
+ const html = htmlHandler(asset.source().toString(), {
588
+ classGenerator,
589
+ runtimeSet
590
+ });
591
+ overwriteServerSideAsset(key, file, html);
592
+ }
593
+ });
594
+ html.clear();
595
+ }
596
+ if (js.size) {
597
+ js.forEach((chunk, file) => {
598
+ if (isInclude(file)) {
599
+ const rawCode = chunk.source().toString();
600
+ const code = jsHandler(rawCode, {
601
+ runtimeSet,
602
+ classGenerator
603
+ }).code;
604
+ overwriteServerSideAsset(key, file, code);
605
+ }
606
+ });
607
+ js.clear();
608
+ }
609
+ if (css.size) {
610
+ css.forEach((style, file) => {
611
+ if (isInclude(file)) {
612
+ const newCss = cssHandler(style.source().toString(), {
613
+ classGenerator,
614
+ runtimeSet
615
+ });
616
+ overwriteServerSideAsset(key, file, newCss);
617
+ }
618
+ });
619
+ css.clear();
620
+ }
621
+ });
494
622
  });
495
623
  });
496
624
  }
package/dist/nuxt.js CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  var index = require('./index.js');
4
4
  require('unplugin');
5
- require('tailwindcss-patch');
5
+ require('micromatch');
6
6
  require('parse5');
7
7
  require('@babel/generator');
8
8
  require('@babel/parser');
9
9
  require('@babel/traverse');
10
10
  require('postcss');
11
11
  require('postcss-selector-parser');
12
+ require('path');
13
+ require('fs');
14
+ require('tailwindcss-patch');
12
15
 
13
16
  /******************************************************************************
14
17
  Copyright (c) Microsoft Corporation.
package/dist/nuxt.mjs CHANGED
@@ -1,12 +1,15 @@
1
1
  import { unplugin } from './index.mjs';
2
2
  import 'unplugin';
3
- import 'tailwindcss-patch';
3
+ import 'micromatch';
4
4
  import 'parse5';
5
5
  import '@babel/generator';
6
6
  import '@babel/parser';
7
7
  import '@babel/traverse';
8
8
  import 'postcss';
9
9
  import 'postcss-selector-parser';
10
+ import 'path';
11
+ import 'fs';
12
+ import 'tailwindcss-patch';
10
13
 
11
14
  /******************************************************************************
12
15
  Copyright (c) Microsoft Corporation.
@@ -0,0 +1,9 @@
1
+ import type { Options } from './types';
2
+ import ClassGenerator from './classGenerator';
3
+ export declare function getOptions(options?: Options | undefined): {
4
+ getCachedClassSet: () => Set<string>;
5
+ classGenerator: ClassGenerator;
6
+ includeMatcher: (file: string) => boolean;
7
+ excludeMatcher: (file: string) => boolean;
8
+ isInclude: (file: string) => boolean;
9
+ };
package/dist/rollup.js CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  var index = require('./index.js');
4
4
  require('unplugin');
5
- require('tailwindcss-patch');
5
+ require('micromatch');
6
6
  require('parse5');
7
7
  require('@babel/generator');
8
8
  require('@babel/parser');
9
9
  require('@babel/traverse');
10
10
  require('postcss');
11
11
  require('postcss-selector-parser');
12
+ require('path');
13
+ require('fs');
14
+ require('tailwindcss-patch');
12
15
 
13
16
  var rollup = index.unplugin.rollup;
14
17
 
package/dist/rollup.mjs CHANGED
@@ -1,12 +1,15 @@
1
1
  import { unplugin } from './index.mjs';
2
2
  import 'unplugin';
3
- import 'tailwindcss-patch';
3
+ import 'micromatch';
4
4
  import 'parse5';
5
5
  import '@babel/generator';
6
6
  import '@babel/parser';
7
7
  import '@babel/traverse';
8
8
  import 'postcss';
9
9
  import 'postcss-selector-parser';
10
+ import 'path';
11
+ import 'fs';
12
+ import 'tailwindcss-patch';
10
13
 
11
14
  var rollup = unplugin.rollup;
12
15
 
package/dist/types.d.ts CHANGED
@@ -24,4 +24,6 @@ export interface IHandlerOptions {
24
24
  }
25
25
  export interface Options {
26
26
  classGenerator?: IClassGeneratorOptions;
27
+ exclude?: string[];
28
+ include?: string[];
27
29
  }
package/dist/utils.d.ts CHANGED
@@ -12,3 +12,4 @@ export declare function isRegexp(value: unknown): boolean;
12
12
  export declare function isMap(value: unknown): boolean;
13
13
  export declare function regExpTest(arr: (string | RegExp)[] | undefined, str: string): boolean;
14
14
  export declare function escapeStringRegexp(str: string): string;
15
+ export declare function createGlobMatcher(pattern: string | string[] | undefined, fallbackValue?: boolean): (file: string) => boolean;
package/dist/vite.js CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  var index = require('./index.js');
4
4
  require('unplugin');
5
- require('tailwindcss-patch');
5
+ require('micromatch');
6
6
  require('parse5');
7
7
  require('@babel/generator');
8
8
  require('@babel/parser');
9
9
  require('@babel/traverse');
10
10
  require('postcss');
11
11
  require('postcss-selector-parser');
12
+ require('path');
13
+ require('fs');
14
+ require('tailwindcss-patch');
12
15
 
13
16
  var vite = index.unplugin.vite;
14
17
 
package/dist/vite.mjs CHANGED
@@ -1,12 +1,15 @@
1
1
  import { unplugin } from './index.mjs';
2
2
  import 'unplugin';
3
- import 'tailwindcss-patch';
3
+ import 'micromatch';
4
4
  import 'parse5';
5
5
  import '@babel/generator';
6
6
  import '@babel/parser';
7
7
  import '@babel/traverse';
8
8
  import 'postcss';
9
9
  import 'postcss-selector-parser';
10
+ import 'path';
11
+ import 'fs';
12
+ import 'tailwindcss-patch';
10
13
 
11
14
  var vite = unplugin.vite;
12
15
 
package/dist/webpack.js CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  var index = require('./index.js');
4
4
  require('unplugin');
5
- require('tailwindcss-patch');
5
+ require('micromatch');
6
6
  require('parse5');
7
7
  require('@babel/generator');
8
8
  require('@babel/parser');
9
9
  require('@babel/traverse');
10
10
  require('postcss');
11
11
  require('postcss-selector-parser');
12
+ require('path');
13
+ require('fs');
14
+ require('tailwindcss-patch');
12
15
 
13
16
  var webpack = index.unplugin.webpack;
14
17
 
package/dist/webpack.mjs CHANGED
@@ -1,12 +1,15 @@
1
1
  import { unplugin } from './index.mjs';
2
2
  import 'unplugin';
3
- import 'tailwindcss-patch';
3
+ import 'micromatch';
4
4
  import 'parse5';
5
5
  import '@babel/generator';
6
6
  import '@babel/parser';
7
7
  import '@babel/traverse';
8
8
  import 'postcss';
9
9
  import 'postcss-selector-parser';
10
+ import 'path';
11
+ import 'fs';
12
+ import 'tailwindcss-patch';
10
13
 
11
14
  var webpack = unplugin.webpack;
12
15
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unplugin-tailwindcss-mangle",
3
- "version": "0.0.5",
4
- "description": "mangle tailwindcss utilities class",
3
+ "version": "0.1.0",
4
+ "description": "mangle tailwindcss utilities class plugin. support vite and webpack!",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
@@ -31,6 +31,11 @@
31
31
  "require": "./dist/esbuild.js",
32
32
  "import": "./dist/esbuild.mjs"
33
33
  },
34
+ "./nuxt": {
35
+ "types": "./dist/nuxt.d.ts",
36
+ "require": "./dist/nuxt.js",
37
+ "import": "./dist/nuxt.mjs"
38
+ },
34
39
  "./*": "./*"
35
40
  },
36
41
  "typesVersions": {
@@ -59,14 +64,13 @@
59
64
  "@babel/parser": "^7.21.4",
60
65
  "@babel/traverse": "^7.21.4",
61
66
  "@babel/types": "^7.21.4",
62
- "acorn-walk": "^8.2.0",
63
- "escodegen": "^2.0.0",
67
+ "micromatch": "^4.0.5",
64
68
  "parse5": "^7.1.2",
65
- "postcss": "^8.4.22",
69
+ "postcss": "^8.4.23",
66
70
  "postcss-selector-parser": "^6.0.11",
67
71
  "semver": "^7.5.0",
68
72
  "unplugin": "^1.3.1",
69
- "tailwindcss-patch": "1.0.2"
73
+ "tailwindcss-patch": "1.0.3"
70
74
  },
71
75
  "publishConfig": {
72
76
  "access": "public",
@@ -75,14 +79,15 @@
75
79
  "devDependencies": {
76
80
  "@parse5/tools": "^0.1.0",
77
81
  "@types/babel__generator": "^7.6.4",
78
- "@types/babel__traverse": "^7.18.3",
82
+ "@types/babel__traverse": "^7.18.4",
79
83
  "@types/escodegen": "^0.0.7",
84
+ "@types/micromatch": "^4.0.2",
80
85
  "@types/semver": "^7.3.13",
81
86
  "pkg-types": "^1.0.2",
82
- "tailwindcss": "^3.3.1",
87
+ "tailwindcss": "^3.3.2",
83
88
  "tslib": "^2.5.0",
84
- "vite": "^4.2.2",
85
- "webpack": "^5.79.0"
89
+ "vite": "^4.3.2",
90
+ "webpack": "^5.80.0"
86
91
  },
87
92
  "homepage": "https://github.com/sonofmagic/tailwindcss-mangle",
88
93
  "repository": {