unplugin-tailwindcss-mangle 1.2.7 → 2.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
@@ -8,14 +8,13 @@ mangle tailwindcss utilities plugin
8
8
  - [Features](#features)
9
9
  - [Usage](#usage)
10
10
  - [1. Install Package](#1-install-package)
11
- - [2. Run patch script](#2-run-patch-script)
11
+ - [2. Run install script](#2-run-install-script)
12
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)
13
+ - [4. Run extract command](#4-run-extract-command)
14
+ - [5. Register this plugin](#5-register-this-plugin)
14
15
  - [vite](#vite)
15
16
  - [webpack](#webpack)
16
17
  - [Options](#options)
17
- - [classGenerator](#classgenerator)
18
- - [include / exclude](#include--exclude)
19
18
  - [Notice](#notice)
20
19
 
21
20
  ## Features
@@ -35,21 +34,33 @@ mangle tailwindcss utilities plugin
35
34
  <npm|yarn|pnpm> i -D unplugin-tailwindcss-mangle tailwindcss-patch
36
35
  ```
37
36
 
38
- ### 2. Run patch script
37
+ ### 2. Run install script
39
38
 
40
39
  ```sh
41
- npx tw-patch
40
+ npx tw-patch install
42
41
  ```
43
42
 
44
43
  ### 3. add `prepare` script in your `package.json`
45
44
 
46
45
  ```json
47
46
  "scripts": {
48
- "prepare": "tw-patch"
47
+ "prepare": "tw-patch install"
49
48
  },
50
49
  ```
51
50
 
52
- ### 4. register this plugin
51
+ ### 4. Run extract command
52
+
53
+ cd to the same directory as `package.son` and `tailwind.config.js`, then run:
54
+
55
+ ```sh
56
+ npx tw-patch extract
57
+ ```
58
+
59
+ > See more options in [tailwindcss-patch](https://github.com/sonofmagic/tailwindcss-mangle/tree/main/packages/tailwindcss-patch)
60
+
61
+ Then there will generate a json file: `.tw-patch/tw-class-list.json`
62
+
63
+ ### 5. Register this plugin
53
64
 
54
65
  #### vite
55
66
 
@@ -57,7 +68,7 @@ npx tw-patch
57
68
  // for example: vue vite project
58
69
  import { defineConfig } from 'vite'
59
70
  import vue from '@vitejs/plugin-vue'
60
- import { vitePlugin as utwm } from 'unplugin-tailwindcss-mangle'
71
+ import utwm from 'unplugin-tailwindcss-mangle/vite'
61
72
  // https://vitejs.dev/config/
62
73
  export default defineConfig({
63
74
  plugins: [vue(), utwm()]
@@ -81,7 +92,7 @@ You will see all class was renamed to `tw-*`
81
92
  // esm
82
93
  import { webpackPlugin as utwm } from 'unplugin-tailwindcss-mangle'
83
94
  // or cjs
84
- const { webpackPlugin: utwm } = require('unplugin-tailwindcss-mangle')
95
+ const utwm = require('unplugin-tailwindcss-mangle/webpack')
85
96
  // use this webpack plugin
86
97
  // for example next.config.js
87
98
  const { defineConfig } = require('@vue/cli-service')
@@ -89,7 +100,9 @@ const { defineConfig } = require('@vue/cli-service')
89
100
  module.exports = defineConfig({
90
101
  transpileDependencies: true,
91
102
  configureWebpack: (config) => {
92
- config.plugins.push(utwm())
103
+ if (process.env.NODE_ENV === 'production') {
104
+ config.plugins.push(utwm())
105
+ }
93
106
  }
94
107
  })
95
108
 
@@ -97,34 +110,12 @@ module.exports = defineConfig({
97
110
 
98
111
  ## Options
99
112
 
100
- ### classGenerator
101
-
102
- custom class generator, if you want to custom class name (default 'tw-*'), use this options
103
-
104
- ```js
105
- export interface IClassGeneratorOptions {
106
- reserveClassName?: (string | RegExp)[]
107
- // custom generate class name
108
- customGenerate?: (original: string, opts: IClassGeneratorOptions, context: Record<string, any>) => string | undefined
109
- log?: boolean
110
- exclude?: (string | RegExp)[]
111
- include?: (string | RegExp)[]
112
- ignoreClass?: (string | RegExp)[]
113
- // default 'tw-',for example: tw-a,tw-b, you can set any you want, like '','ice-'
114
- classPrefix?: string
115
- }
116
- ```
117
-
118
- ### include / exclude
119
-
120
- Type: `string | string[]`
121
-
122
- Default: `undefined`
123
-
124
- `glob string` allow you to control the mangle range of bundles.
113
+ [types.ts]('./src/types.ts')
125
114
 
126
115
  ## Notice
127
116
 
117
+ By default, only the build will take effect. Due to some restrictions, it cannot take effect in the development mode.
118
+
128
119
  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.
129
120
 
130
121
  because plugin will **traverse** all `html class attr` and `js StringLiteral` to find `utilities` generated by `tailwindcss`.
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const index = require('./index.cjs');
4
+ require('node:fs');
5
+ require('node:path');
6
+ require('@tailwindcss-mangle/shared');
7
+ require('@tailwindcss-mangle/config');
8
+ require('fast-sort');
9
+ require('@tailwindcss-mangle/core');
10
+ require('micromatch');
11
+ require('unplugin');
12
+
13
+ const esbuild = index.esbuild;
14
+
15
+ module.exports = esbuild;
package/dist/esbuild.d.ts CHANGED
@@ -1,2 +1,7 @@
1
- declare const _default: (options?: import("./types").Options | undefined) => import("esbuild").Plugin;
2
- export default _default;
1
+ import * as esbuild from 'esbuild';
2
+ import { O as Options } from './types-3f814672.js';
3
+ import '@tailwindcss-mangle/shared';
4
+
5
+ declare const _default: (options?: Options | undefined) => esbuild.Plugin;
6
+
7
+ export { _default as default };
package/dist/esbuild.mjs CHANGED
@@ -1,12 +1,13 @@
1
- import { unplugin } from './index.mjs';
2
- import 'unplugin';
3
- import 'micromatch';
1
+ import unplugin from './index.mjs';
4
2
  import 'node:fs';
5
3
  import 'node:path';
6
- import 'tailwindcss-mangle-shared';
7
- import 'tailwindcss-mangle-core';
8
- import 'tailwindcss-patch';
4
+ import '@tailwindcss-mangle/shared';
5
+ import '@tailwindcss-mangle/config';
6
+ import 'fast-sort';
7
+ import '@tailwindcss-mangle/core';
8
+ import 'micromatch';
9
+ import 'unplugin';
9
10
 
10
- var esbuild = unplugin.esbuild;
11
+ const esbuild = unplugin.esbuild;
11
12
 
12
13
  export { esbuild as default };
package/dist/index.cjs ADDED
@@ -0,0 +1,343 @@
1
+ 'use strict';
2
+
3
+ const unplugin$1 = require('unplugin');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const shared = require('@tailwindcss-mangle/shared');
7
+ const config = require('@tailwindcss-mangle/config');
8
+ const fastSort = require('fast-sort');
9
+ const core = require('@tailwindcss-mangle/core');
10
+ const micromatch = require('micromatch');
11
+
12
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
13
+
14
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
15
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
16
+ const micromatch__default = /*#__PURE__*/_interopDefaultCompat(micromatch);
17
+
18
+ function isObject(value) {
19
+ return value !== null && typeof value === "object";
20
+ }
21
+ function _defu(baseObject, defaults, namespace = ".", merger) {
22
+ if (!isObject(defaults)) {
23
+ return _defu(baseObject, {}, namespace, merger);
24
+ }
25
+ const object = Object.assign({}, defaults);
26
+ for (const key in baseObject) {
27
+ if (key === "__proto__" || key === "constructor") {
28
+ continue;
29
+ }
30
+ const value = baseObject[key];
31
+ if (value === null || value === void 0) {
32
+ continue;
33
+ }
34
+ if (merger && merger(object, key, value, namespace)) {
35
+ continue;
36
+ }
37
+ if (Array.isArray(value) && Array.isArray(object[key])) {
38
+ object[key] = [...value, ...object[key]];
39
+ } else if (isObject(value) && isObject(object[key])) {
40
+ object[key] = _defu(
41
+ value,
42
+ object[key],
43
+ (namespace ? `${namespace}.` : "") + key.toString(),
44
+ merger
45
+ );
46
+ } else {
47
+ object[key] = value;
48
+ }
49
+ }
50
+ return object;
51
+ }
52
+ function createDefu(merger) {
53
+ return (...arguments_) => (
54
+ // eslint-disable-next-line unicorn/no-array-reduce
55
+ arguments_.reduce((p, c) => _defu(p, c, "", merger), {})
56
+ );
57
+ }
58
+ const defu = createDefu();
59
+
60
+ const pluginName = "unplugin-tailwindcss-mangle";
61
+
62
+ const { isMatch } = micromatch__default;
63
+ function getGroupedEntries(entries, options = {
64
+ cssMatcher(file) {
65
+ return /\.css$/.test(file);
66
+ },
67
+ htmlMatcher(file) {
68
+ return /\.html?$/.test(file);
69
+ },
70
+ jsMatcher(file) {
71
+ return /\.[cm]?js$/.test(file);
72
+ }
73
+ }) {
74
+ const { cssMatcher, htmlMatcher, jsMatcher } = options;
75
+ const groupedEntries = shared.groupBy(entries, ([file]) => {
76
+ if (cssMatcher(file)) {
77
+ return "css";
78
+ } else if (htmlMatcher(file)) {
79
+ return "html";
80
+ } else if (jsMatcher(file)) {
81
+ return "js";
82
+ } else {
83
+ return "other";
84
+ }
85
+ });
86
+ if (!groupedEntries.css) {
87
+ groupedEntries.css = [];
88
+ }
89
+ if (!groupedEntries.html) {
90
+ groupedEntries.html = [];
91
+ }
92
+ if (!groupedEntries.js) {
93
+ groupedEntries.js = [];
94
+ }
95
+ if (!groupedEntries.other) {
96
+ groupedEntries.other = [];
97
+ }
98
+ return groupedEntries;
99
+ }
100
+ function createGlobMatcher(pattern, fallbackValue = false) {
101
+ if (pattern === void 0) {
102
+ return function() {
103
+ return fallbackValue;
104
+ };
105
+ }
106
+ return function(file) {
107
+ return isMatch(file, pattern);
108
+ };
109
+ }
110
+ function getCacheDir(basedir = process.cwd()) {
111
+ return path__default.resolve(basedir, "node_modules/.cache", pluginName);
112
+ }
113
+ function mkCacheDirectory(cwd = process.cwd()) {
114
+ const cacheDirectory = getCacheDir(cwd);
115
+ const exists = fs__default.existsSync(cacheDirectory);
116
+ if (!exists) {
117
+ fs__default.mkdirSync(cacheDirectory, {
118
+ recursive: true
119
+ });
120
+ }
121
+ return cacheDirectory;
122
+ }
123
+ function cacheDump(filename, data, basedir) {
124
+ try {
125
+ const dir = mkCacheDirectory(basedir);
126
+ fs__default.writeFileSync(path__default.resolve(dir, filename), JSON.stringify([...data], void 0, 2), "utf8");
127
+ } catch (error) {
128
+ console.log(error);
129
+ }
130
+ }
131
+
132
+ function getOptions(opts = {}) {
133
+ const {
134
+ include,
135
+ exclude,
136
+ disabled,
137
+ mangleClassFilter,
138
+ classMapOutput,
139
+ classGenerator: classGeneratorOptions,
140
+ classListPath: _classListPath
141
+ } = defu(opts, {
142
+ include: ["**/*.{js,jsx,ts,tsx,svelte,vue}"],
143
+ exclude: ["**/*.{css,scss,less,sass,postcss,html,htm}"],
144
+ disabled: process.env.NODE_ENV === "development"
145
+ });
146
+ const includeMatcher = createGlobMatcher(include, true);
147
+ const excludeMatcher = createGlobMatcher(exclude, false);
148
+ const currentMangleClassFilter = mangleClassFilter ?? shared.defaultMangleClassFilter;
149
+ function isInclude(file) {
150
+ return includeMatcher(file) && !excludeMatcher(file);
151
+ }
152
+ const classSet = /* @__PURE__ */ new Set();
153
+ const replaceMap = /* @__PURE__ */ new Map();
154
+ let userConfig = config.getDefaultUserConfig();
155
+ const classMapOutputOptions = {
156
+ filename: "classMap.json"
157
+ };
158
+ if (typeof classMapOutput === "object") {
159
+ Object.assign(classMapOutputOptions, classMapOutput);
160
+ }
161
+ const classGenerator = new shared.ClassGenerator(classGeneratorOptions);
162
+ function getCachedClassSet() {
163
+ return classSet;
164
+ }
165
+ function getReplaceMap() {
166
+ return replaceMap;
167
+ }
168
+ async function initConfig() {
169
+ const { config: config$1 } = await config.getConfig();
170
+ userConfig = config$1;
171
+ let classListPath = "";
172
+ if (userConfig) {
173
+ classListPath = path.resolve(process.cwd(), userConfig.patch?.output?.filename);
174
+ }
175
+ if (_classListPath) {
176
+ classListPath = _classListPath;
177
+ }
178
+ if (classListPath && fs__default.existsSync(classListPath)) {
179
+ const rawClassList = fs__default.readFileSync(classListPath, "utf8");
180
+ const list = JSON.parse(rawClassList);
181
+ const classList = fastSort.sort(list).desc((c) => c.length);
182
+ for (const className of classList) {
183
+ if (currentMangleClassFilter(className)) {
184
+ classSet.add(className);
185
+ }
186
+ }
187
+ }
188
+ for (const cls of classSet) {
189
+ classGenerator.generateClassName(cls);
190
+ }
191
+ for (const x of Object.entries(classGenerator.newClassMap)) {
192
+ replaceMap.set(x[0], x[1].name);
193
+ }
194
+ return config$1;
195
+ }
196
+ function addToUsedBy(key, file) {
197
+ const hit = classGenerator.newClassMap[key];
198
+ if (hit) {
199
+ hit.usedBy.add(file);
200
+ }
201
+ }
202
+ return {
203
+ getCachedClassSet,
204
+ classGenerator,
205
+ includeMatcher,
206
+ excludeMatcher,
207
+ isInclude,
208
+ classMapOutputOptions,
209
+ initConfig,
210
+ getReplaceMap,
211
+ addToUsedBy,
212
+ disabled,
213
+ htmlHandler: core.htmlHandler,
214
+ cssHandler: core.cssHandler,
215
+ jsHandler: core.jsHandler,
216
+ preProcessJs: core.preProcessJs
217
+ };
218
+ }
219
+
220
+ const unplugin = unplugin$1.createUnplugin((options = {}) => {
221
+ const { isInclude, initConfig, getReplaceMap, classGenerator, addToUsedBy, classMapOutputOptions, disabled, htmlHandler, cssHandler, jsHandler, preProcessJs } = getOptions(options);
222
+ if (disabled) {
223
+ return {
224
+ name: pluginName
225
+ };
226
+ }
227
+ return {
228
+ name: pluginName,
229
+ enforce: "pre",
230
+ async buildStart() {
231
+ await initConfig();
232
+ },
233
+ transformInclude(id) {
234
+ return isInclude(id);
235
+ },
236
+ transform(code, id) {
237
+ const replaceMap = getReplaceMap();
238
+ if (id.endsWith(".js") || id.endsWith(".ts") || id.endsWith(".tsx") || id.endsWith(".jsx")) {
239
+ const str = preProcessJs({
240
+ code,
241
+ replaceMap,
242
+ addToUsedBy,
243
+ id
244
+ });
245
+ return str;
246
+ } else {
247
+ for (const [key, value] of replaceMap) {
248
+ code = code.replaceAll(key, value);
249
+ }
250
+ }
251
+ return code;
252
+ },
253
+ vite: {
254
+ generateBundle: {
255
+ async handler(options2, bundle) {
256
+ const replaceMap = getReplaceMap();
257
+ const groupedEntries = getGroupedEntries(Object.entries(bundle));
258
+ if (Array.isArray(groupedEntries.css) && groupedEntries.css.length > 0) {
259
+ for (let i = 0; i < groupedEntries.css.length; i++) {
260
+ const [file, cssSource] = groupedEntries.css[i];
261
+ const { css } = await cssHandler(cssSource.source.toString(), {
262
+ file,
263
+ replaceMap,
264
+ classGenerator
265
+ });
266
+ cssSource.source = css;
267
+ }
268
+ }
269
+ }
270
+ }
271
+ },
272
+ webpack(compiler) {
273
+ const { Compilation, sources } = compiler.webpack;
274
+ const { ConcatSource } = sources;
275
+ compiler.hooks.compilation.tap(pluginName, (compilation) => {
276
+ compilation.hooks.processAssets.tapPromise(
277
+ {
278
+ name: pluginName,
279
+ stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
280
+ },
281
+ async (assets) => {
282
+ const replaceMap = getReplaceMap();
283
+ const groupedEntries = getGroupedEntries(Object.entries(assets));
284
+ if (groupedEntries.js.length > 0) {
285
+ for (let i = 0; i < groupedEntries.js.length; i++) {
286
+ const [file, chunk] = groupedEntries.js[i];
287
+ const code = jsHandler(chunk.source().toString(), {
288
+ replaceMap,
289
+ classGenerator
290
+ }).code;
291
+ if (code) {
292
+ const source = new ConcatSource(code);
293
+ compilation.updateAsset(file, source);
294
+ }
295
+ }
296
+ }
297
+ if (groupedEntries.css.length > 0) {
298
+ for (let i = 0; i < groupedEntries.css.length; i++) {
299
+ const [file, cssSource] = groupedEntries.css[i];
300
+ const { css } = await cssHandler(cssSource.source().toString(), {
301
+ replaceMap,
302
+ file,
303
+ classGenerator
304
+ });
305
+ const source = new ConcatSource(css);
306
+ compilation.updateAsset(file, source);
307
+ }
308
+ }
309
+ if (groupedEntries.html.length > 0) {
310
+ for (let i = 0; i < groupedEntries.html.length; i++) {
311
+ const [file, asset] = groupedEntries.html[i];
312
+ const html = htmlHandler(asset.source().toString(), {
313
+ classGenerator,
314
+ replaceMap
315
+ });
316
+ const source = new ConcatSource(html);
317
+ compilation.updateAsset(file, source);
318
+ }
319
+ }
320
+ }
321
+ );
322
+ });
323
+ },
324
+ writeBundle() {
325
+ const entries = Object.entries(classGenerator.newClassMap);
326
+ if (entries.length > 0 && classMapOutputOptions) {
327
+ cacheDump(
328
+ classMapOutputOptions.filename,
329
+ entries.map((x) => {
330
+ return {
331
+ origin: x[0],
332
+ replacement: x[1].name,
333
+ usedBy: [...x[1].usedBy]
334
+ };
335
+ }),
336
+ classMapOutputOptions.dir
337
+ );
338
+ }
339
+ }
340
+ };
341
+ });
342
+
343
+ module.exports = unplugin;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import type { Options } from './types';
2
- export { defaultMangleClassFilter } from 'tailwindcss-mangle-shared';
3
- export declare const unplugin: import("unplugin").UnpluginInstance<Options | undefined, boolean>;
4
- export declare const vitePlugin: (options?: Options | undefined) => import("vite").Plugin | import("vite").Plugin[];
5
- export declare const webpackPlugin: (options?: Options | undefined) => import("webpack").WebpackPluginInstance;
1
+ import * as _unplugin from 'unplugin';
2
+ import { O as Options } from './types-3f814672.js';
3
+ import '@tailwindcss-mangle/shared';
4
+
5
+ declare const unplugin: _unplugin.UnpluginInstance<Options | undefined, boolean>;
6
+
7
+ export { unplugin as default };