unplugin-tailwindcss-mangle 0.0.0 → 0.0.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.
- package/README.md +96 -1
- package/dist/classGenerator.d.ts +17 -0
- package/dist/constants.d.ts +1 -0
- package/dist/css/index.d.ts +2 -0
- package/dist/css/plugins.d.ts +7 -0
- package/dist/esbuild.d.ts +2 -0
- package/dist/esbuild.js +15 -0
- package/dist/esbuild.mjs +13 -0
- package/dist/html/index.d.ts +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +497 -0
- package/dist/index.mjs +488 -0
- package/dist/js/index.d.ts +2 -0
- package/dist/js/split.d.ts +3 -0
- package/dist/nuxt.d.ts +2 -0
- package/dist/nuxt.js +49 -0
- package/dist/nuxt.mjs +47 -0
- package/dist/rollup.d.ts +2 -0
- package/dist/rollup.js +15 -0
- package/dist/rollup.mjs +13 -0
- package/dist/types.d.ts +26 -0
- package/dist/utils.d.ts +14 -0
- package/dist/vite.d.ts +2 -0
- package/dist/vite.js +15 -0
- package/dist/vite.mjs +13 -0
- package/dist/webpack.d.ts +2 -0
- package/dist/webpack.js +15 -0
- package/dist/webpack.mjs +13 -0
- package/package.json +83 -8
package/README.md
CHANGED
|
@@ -1 +1,96 @@
|
|
|
1
|
-
# unplugin-tailwindcss-mangle
|
|
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 contain `-` 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,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 };
|
package/dist/esbuild.js
ADDED
|
@@ -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;
|
package/dist/esbuild.mjs
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,497 @@
|
|
|
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 isMangleClass = (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 (!isMangleClass(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
|
+
if (!runtimeSet.size) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const groupedEntries = getGroupedEntries(Object.entries(bundle));
|
|
415
|
+
if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
|
|
416
|
+
for (let i = 0; i < groupedEntries.html.length; i++) {
|
|
417
|
+
const [, asset] = groupedEntries.html[i];
|
|
418
|
+
asset.source = htmlHandler(asset.source.toString(), {
|
|
419
|
+
classGenerator,
|
|
420
|
+
runtimeSet
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
|
|
425
|
+
for (let i = 0; i < groupedEntries.js.length; i++) {
|
|
426
|
+
const [, chunk] = groupedEntries.js[i];
|
|
427
|
+
chunk.code = jsHandler(chunk.code, {
|
|
428
|
+
runtimeSet,
|
|
429
|
+
classGenerator
|
|
430
|
+
}).code;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
|
|
434
|
+
for (let i = 0; i < groupedEntries.css.length; i++) {
|
|
435
|
+
const [, css] = groupedEntries.css[i];
|
|
436
|
+
css.source = cssHandler(css.source.toString(), {
|
|
437
|
+
classGenerator,
|
|
438
|
+
runtimeSet
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
webpack(compiler) {
|
|
446
|
+
const Compilation = compiler.webpack.Compilation;
|
|
447
|
+
const { ConcatSource } = compiler.webpack.sources;
|
|
448
|
+
compiler.hooks.compilation.tap(pluginName, (compilation) => {
|
|
449
|
+
compilation.hooks.processAssets.tap({
|
|
450
|
+
name: pluginName,
|
|
451
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
|
|
452
|
+
}, (assets) => {
|
|
453
|
+
const runtimeSet = getCachedClassSet();
|
|
454
|
+
if (!runtimeSet.size) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
const groupedEntries = getGroupedEntries(Object.entries(assets));
|
|
458
|
+
if (Array.isArray(groupedEntries.html) && groupedEntries.html.length) {
|
|
459
|
+
for (let i = 0; i < groupedEntries.html.length; i++) {
|
|
460
|
+
const [file, asset] = groupedEntries.html[i];
|
|
461
|
+
const html = htmlHandler(asset.source().toString(), {
|
|
462
|
+
classGenerator,
|
|
463
|
+
runtimeSet
|
|
464
|
+
});
|
|
465
|
+
const source = new ConcatSource(html);
|
|
466
|
+
compilation.updateAsset(file, source);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (Array.isArray(groupedEntries.js) && groupedEntries.js.length) {
|
|
470
|
+
for (let i = 0; i < groupedEntries.js.length; i++) {
|
|
471
|
+
const [file, chunk] = groupedEntries.js[i];
|
|
472
|
+
const code = jsHandler(chunk.source().toString(), {
|
|
473
|
+
runtimeSet,
|
|
474
|
+
classGenerator
|
|
475
|
+
}).code;
|
|
476
|
+
const source = new ConcatSource(code);
|
|
477
|
+
compilation.updateAsset(file, source);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (Array.isArray(groupedEntries.css) && groupedEntries.css.length) {
|
|
481
|
+
for (let i = 0; i < groupedEntries.css.length; i++) {
|
|
482
|
+
const [file, css] = groupedEntries.css[i];
|
|
483
|
+
const newCss = cssHandler(css.source().toString(), {
|
|
484
|
+
classGenerator,
|
|
485
|
+
runtimeSet
|
|
486
|
+
});
|
|
487
|
+
const source = new ConcatSource(newCss);
|
|
488
|
+
compilation.updateAsset(file, source);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
module.exports = unplugin;
|