classnames-minifier 0.2.2 → 4.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/LICENSE +1 -1
- package/README.md +35 -35
- package/dist/{ClassnamesMinifier.d.ts → cjs/ClassnamesMinifier.d.ts} +1 -0
- package/dist/{ClassnamesMinifier.js → cjs/ClassnamesMinifier.js} +38 -11
- package/dist/{lib → cjs/lib}/ConverterMinified.d.ts +1 -1
- package/dist/{lib → cjs/lib}/ConverterMinified.js +3 -2
- package/dist/{lib → cjs/lib}/classnames-minifier-preloader.js +4 -1
- package/dist/cjs/lib/constants/configuration.d.ts +6 -0
- package/dist/cjs/lib/constants/configuration.js +9 -0
- package/dist/cjs/lib/removeDist.d.ts +2 -0
- package/dist/{lib/rmDist.js → cjs/lib/removeDist.js} +2 -2
- package/dist/cjs/lib/types/plugin.d.ts +60 -0
- package/dist/{lib → cjs/lib}/validateConfig.js +12 -4
- package/dist/{lib → cjs/lib}/validateDist.js +6 -6
- package/dist/esm/ClassnamesMinifier.d.ts +22 -0
- package/dist/esm/ClassnamesMinifier.js +79 -0
- package/dist/esm/lib/ConverterMinified.d.ts +31 -0
- package/dist/esm/lib/ConverterMinified.js +203 -0
- package/dist/esm/lib/classnames-minifier-postloader.d.ts +5 -0
- package/dist/esm/lib/classnames-minifier-postloader.js +14 -0
- package/dist/esm/lib/classnames-minifier-preloader.d.ts +5 -0
- package/dist/esm/lib/classnames-minifier-preloader.js +16 -0
- package/dist/esm/lib/constants/configuration.d.ts +6 -0
- package/dist/esm/lib/constants/configuration.js +6 -0
- package/dist/esm/lib/removeDist.d.ts +2 -0
- package/dist/esm/lib/removeDist.js +7 -0
- package/dist/esm/lib/types/plugin.d.ts +60 -0
- package/dist/esm/lib/types/plugin.js +1 -0
- package/dist/esm/lib/validateConfig.d.ts +3 -0
- package/dist/esm/lib/validateConfig.js +33 -0
- package/dist/esm/lib/validateDist.d.ts +3 -0
- package/dist/esm/lib/validateDist.js +51 -0
- package/package.json +26 -21
- package/dist/lib/constants/configuration.d.ts +0 -1
- package/dist/lib/constants/configuration.js +0 -4
- package/dist/lib/rmDist.d.ts +0 -2
- package/dist/lib/types/plugin.d.ts +0 -11
- package/dist/{lib → cjs/lib}/classnames-minifier-postloader.d.ts +0 -0
- package/dist/{lib → cjs/lib}/classnames-minifier-postloader.js +1 -1
- /package/dist/{lib → cjs/lib}/classnames-minifier-preloader.d.ts +0 -0
- /package/dist/{lib → cjs/lib}/types/plugin.js +0 -0
- /package/dist/{lib → cjs/lib}/validateConfig.d.ts +0 -0
- /package/dist/{lib → cjs/lib}/validateDist.d.ts +0 -0
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2021 Alex Savelyev <dev@alexdln.com>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -4,19 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
Library for configuring style _(css/scss/sass)_ modules to generate compressed classes (`.header` -> `.a`, `.nav` -> `.b`, ..., `.footer` -> `.aad`, etc.) with support for changes and rebuilding without clearing the built application.
|
|
6
6
|
|
|
7
|
-
*The logic of minifying is taken out of the [next-classnames-minifier](https://github.com/vordgi/next-classnames-minifier) library.*
|
|
8
|
-
|
|
9
7
|
## Reasons
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
_Compressing classes_ can reduce the size of the generated html and css by up to _20%_, which will have a positive effect on page rendering and metrics (primarily [FCP](https://web.dev/first-contentful-paint/))
|
|
11
10
|
|
|
12
11
|
## Installation
|
|
13
12
|
|
|
14
13
|
**Using npm:**
|
|
14
|
+
|
|
15
15
|
```bash
|
|
16
16
|
npm i classnames-minifier
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
**Using yarn:**
|
|
20
|
+
|
|
20
21
|
```bash
|
|
21
22
|
yarn add classnames-minifier
|
|
22
23
|
```
|
|
@@ -25,32 +26,31 @@ yarn add classnames-minifier
|
|
|
25
26
|
|
|
26
27
|
### Options
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
- `prefix` - custom prefix that will be added to each updated class;
|
|
30
|
+
- `reservedNames` - array of reserved names that should not be used by this package (must include prefix);
|
|
31
|
+
- `cacheDir` - directory where this library will write the cache. Passing this parameter will enable caching. Use this option only if your framework really needs it;
|
|
32
|
+
- `distDir` - directory where the project is being assembled. Used only when caching is enabled to synchronize caches between this library and the project;
|
|
33
|
+
- `disableDistDeletion` - option that allows you to disable the automatic deletion of the dist folder if necessary (_f.e. differences in package setup in cache and now or first launch_);
|
|
33
34
|
|
|
34
35
|
Configuration example:
|
|
36
|
+
|
|
35
37
|
```js
|
|
36
38
|
// webpack.config.js
|
|
37
39
|
const classnamesMinifier = new ClassnamesMinifier({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
prefix: "_",
|
|
41
|
+
reservedNames: ["_en", "_de"],
|
|
40
42
|
});
|
|
41
43
|
// ...
|
|
42
|
-
loaders.push(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
getLocalIdent: classnamesMinifier.getLocalIdent,
|
|
50
|
-
},
|
|
51
|
-
},
|
|
44
|
+
loaders.push({
|
|
45
|
+
loader: require.resolve("css-loader"),
|
|
46
|
+
options: {
|
|
47
|
+
importLoaders: 3,
|
|
48
|
+
modules: {
|
|
49
|
+
mode: "local",
|
|
50
|
+
getLocalIdent: classnamesMinifier.getLocalIdent,
|
|
52
51
|
},
|
|
53
|
-
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
If the framework you are using utilizes component caching between builds, you can configure caching in classnames-minifier as well. As a result, module classes between builds will use the same compressed classes.
|
|
@@ -58,26 +58,26 @@ If the framework you are using utilizes component caching between builds, you ca
|
|
|
58
58
|
```js
|
|
59
59
|
// webpack.config.js
|
|
60
60
|
const classnamesMinifier = new ClassnamesMinifier({
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
distDir: path.join(process.cwd(), "build"),
|
|
62
|
+
cacheDir: path.join(process.cwd(), "build/cache"),
|
|
63
63
|
});
|
|
64
64
|
// ...
|
|
65
65
|
loaders.push(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
},
|
|
66
|
+
classnamesMinifier.postLoader,
|
|
67
|
+
{
|
|
68
|
+
loader: require.resolve("css-loader"),
|
|
69
|
+
options: {
|
|
70
|
+
importLoaders: 3,
|
|
71
|
+
modules: {
|
|
72
|
+
mode: "local",
|
|
73
|
+
getLocalIdent: classnamesMinifier.getLocalIdent,
|
|
74
|
+
},
|
|
76
75
|
},
|
|
77
|
-
|
|
76
|
+
},
|
|
77
|
+
classnamesMinifier.preLoader
|
|
78
78
|
);
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
## License
|
|
82
82
|
|
|
83
|
-
[MIT](https://github.com/
|
|
83
|
+
[MIT](https://github.com/alexdln/classnames-minifier/blob/main/LICENSE)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { LoaderContext } from "webpack";
|
|
2
2
|
import type { Config } from "./lib/types/plugin";
|
|
3
3
|
import ConverterMinified from "./lib/ConverterMinified";
|
|
4
|
+
export * from "./lib/types/plugin";
|
|
4
5
|
declare class ClassnamesMinifier {
|
|
5
6
|
converterMinified: ConverterMinified;
|
|
6
7
|
constructor(config: Config);
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
18
|
};
|
|
@@ -9,7 +23,8 @@ const configuration_1 = require("./lib/constants/configuration");
|
|
|
9
23
|
const validateConfig_1 = __importDefault(require("./lib/validateConfig"));
|
|
10
24
|
const ConverterMinified_1 = __importDefault(require("./lib/ConverterMinified"));
|
|
11
25
|
const validateDist_1 = __importDefault(require("./lib/validateDist"));
|
|
12
|
-
const
|
|
26
|
+
const removeDist_1 = __importDefault(require("./lib/removeDist"));
|
|
27
|
+
__exportStar(require("./lib/types/plugin"), exports);
|
|
13
28
|
class ClassnamesMinifier {
|
|
14
29
|
constructor(config) {
|
|
15
30
|
(0, validateConfig_1.default)(config);
|
|
@@ -20,32 +35,44 @@ class ClassnamesMinifier {
|
|
|
20
35
|
else {
|
|
21
36
|
const manifestDir = path_1.default.join(config.cacheDir, "ncm-meta");
|
|
22
37
|
const manifestPath = path_1.default.join(manifestDir, "manifest.json");
|
|
38
|
+
const { distDeletionPolicy = "error" } = config;
|
|
23
39
|
let distCleared = false;
|
|
24
40
|
if (config.cacheDir) {
|
|
25
41
|
const errors = (0, validateDist_1.default)(config, manifestPath);
|
|
26
42
|
if (errors) {
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
console.log(`classnames-minifier: "distDeletionPolicy" option was set to "${distDeletionPolicy}"`);
|
|
44
|
+
if (distDeletionPolicy === "auto") {
|
|
45
|
+
(0, removeDist_1.default)(config.distDir, errors);
|
|
29
46
|
distCleared = true;
|
|
30
47
|
}
|
|
48
|
+
else if (distDeletionPolicy === "error") {
|
|
49
|
+
throw new Error(`classnames-minifier: Please, remove dist dir manually. ${errors}`);
|
|
50
|
+
}
|
|
31
51
|
else {
|
|
32
|
-
console.
|
|
52
|
+
console.warn(`classnames-minifier: Please, remove dist dir manually. ${errors}`);
|
|
33
53
|
}
|
|
34
54
|
}
|
|
35
55
|
}
|
|
36
|
-
const {
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
56
|
+
const { syncFreedNames, freedNamesLimit = 100000 } = config.experimental || {};
|
|
57
|
+
if (!syncFreedNames && this.converterMinified.freeClasses.length > freedNamesLimit && config.distDir) {
|
|
58
|
+
console.log(`classnames-minifier: "distDeletionPolicy" option was set to "${distDeletionPolicy}"`);
|
|
59
|
+
if (distDeletionPolicy === "auto") {
|
|
60
|
+
(0, removeDist_1.default)(config.distDir, `Freed names exceeds the limit (${freedNamesLimit})`);
|
|
61
|
+
distCleared = true;
|
|
62
|
+
}
|
|
63
|
+
else if (distDeletionPolicy === "error") {
|
|
64
|
+
throw new Error(`Please, remove dist dir manually. Freed names exceeds the limit (${freedNamesLimit})`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.warn(`Please, remove dist dir manually. Freed names exceeds the limit (${freedNamesLimit})`);
|
|
68
|
+
}
|
|
42
69
|
}
|
|
43
70
|
if (distCleared) {
|
|
44
71
|
this.converterMinified.reset();
|
|
45
72
|
}
|
|
46
73
|
if (!fs_1.default.existsSync(manifestDir))
|
|
47
74
|
fs_1.default.mkdirSync(manifestDir, { recursive: true });
|
|
48
|
-
fs_1.default.writeFileSync(manifestPath, JSON.stringify(
|
|
75
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify({ ...config, version: configuration_1.CODE_VERSION }), { encoding: "utf-8" });
|
|
49
76
|
}
|
|
50
77
|
}
|
|
51
78
|
get getLocalIdent() {
|
|
@@ -146,7 +146,7 @@ class ConverterMinified {
|
|
|
146
146
|
};
|
|
147
147
|
this.prefix = prefix;
|
|
148
148
|
this.reservedNames = reservedNames;
|
|
149
|
-
this.
|
|
149
|
+
this.syncFreedNames = Boolean(experimental === null || experimental === void 0 ? void 0 : experimental.syncFreedNames);
|
|
150
150
|
if (cacheDir)
|
|
151
151
|
this.invalidateCache(path_1.default.join(cacheDir, "ncm"));
|
|
152
152
|
}
|
|
@@ -174,7 +174,7 @@ class ConverterMinified {
|
|
|
174
174
|
}
|
|
175
175
|
getTargetClassName(origName) {
|
|
176
176
|
let targetClassName;
|
|
177
|
-
if (this.freeClasses.length && this.
|
|
177
|
+
if (this.freeClasses.length && this.syncFreedNames) {
|
|
178
178
|
targetClassName = this.freeClasses.shift();
|
|
179
179
|
}
|
|
180
180
|
else {
|
|
@@ -186,6 +186,7 @@ class ConverterMinified {
|
|
|
186
186
|
}
|
|
187
187
|
return targetClassName;
|
|
188
188
|
}
|
|
189
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
190
|
getLocalIdent({ resourcePath }, _localIdent, origName) {
|
|
190
191
|
if (!this.dirtyСache[resourcePath]) {
|
|
191
192
|
this.dirtyСache[resourcePath] = {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = default_1;
|
|
3
4
|
function default_1(source, map, meta) {
|
|
4
5
|
const options = this.getOptions();
|
|
5
6
|
const classnamesMinifier = options.classnamesMinifier;
|
|
6
7
|
const maybeClassesList = source.match(/\.-?[_a-zA-Z]+[_a-zA-Z0-9-]*/g);
|
|
7
8
|
const cache = classnamesMinifier.dirtyСache[this.resourcePath];
|
|
9
|
+
/**
|
|
10
|
+
* if some class has ceased to be used since the last time the file was loaded, we remove it from the cache
|
|
11
|
+
*/
|
|
8
12
|
if (cache && cache.matchings) {
|
|
9
13
|
cache.matchings = maybeClassesList
|
|
10
14
|
? Object.fromEntries(Object.entries(cache.matchings).filter(([key]) => maybeClassesList === null || maybeClassesList === void 0 ? void 0 : maybeClassesList.includes(`.${key}`)))
|
|
@@ -13,4 +17,3 @@ function default_1(source, map, meta) {
|
|
|
13
17
|
this.callback(null, source, map, meta);
|
|
14
18
|
return;
|
|
15
19
|
}
|
|
16
|
-
exports.default = default_1;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Just a version of the code whose change means that the logic has a critical update
|
|
3
|
+
* and minifying the previous version is not compatible with the current one,
|
|
4
|
+
* which would mean that we should clean dist folder
|
|
5
|
+
*/
|
|
6
|
+
export declare const CODE_VERSION = "parrot";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CODE_VERSION = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Just a version of the code whose change means that the logic has a critical update
|
|
6
|
+
* and minifying the previous version is not compatible with the current one,
|
|
7
|
+
* which would mean that we should clean dist folder
|
|
8
|
+
*/
|
|
9
|
+
exports.CODE_VERSION = "parrot";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const fs_1 = require("fs");
|
|
4
|
-
const
|
|
4
|
+
const removeDist = (distDir, message) => {
|
|
5
5
|
console.log(`classnames-minifier: ${message}Cleaning the dist folder...`);
|
|
6
6
|
(0, fs_1.rmSync)(distDir, { recursive: true, force: true });
|
|
7
7
|
console.log("classnames-minifier: Dist folder cleared");
|
|
8
8
|
};
|
|
9
|
-
exports.default =
|
|
9
|
+
exports.default = removeDist;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type Config = {
|
|
2
|
+
/**
|
|
3
|
+
* The directory where the package cache will be written
|
|
4
|
+
*/
|
|
5
|
+
cacheDir?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Directory where the project is built
|
|
8
|
+
*/
|
|
9
|
+
distDir?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Prefix which will be added to each generated name
|
|
12
|
+
*/
|
|
13
|
+
prefix?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Reserved minified names. Use this option if you are adding short classes manually
|
|
16
|
+
*/
|
|
17
|
+
reservedNames?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Package policy to resolve potential problems with minified classes
|
|
20
|
+
*
|
|
21
|
+
* This may happen due to the following reasons:
|
|
22
|
+
*
|
|
23
|
+
* 1. Launching the package for the first time. Package need clean next.js cache to put everything in the correct order
|
|
24
|
+
* 2. Changing the package configuration. Package need clean next.js cache to rebuild it with classes according to the new rules
|
|
25
|
+
* 3. Exceeding the limit on freed classes (these are classes that were used before, but are now *probably* no longer used)
|
|
26
|
+
*
|
|
27
|
+
* @param "warning" - a warning message will simply be displayed.
|
|
28
|
+
* With this option, there is a high risk of errors and duplicates of generated classes.
|
|
29
|
+
*
|
|
30
|
+
* @param "error" - an error will be thrown, and as a result the build will stop.
|
|
31
|
+
* If this option occurs, delete the next.js cache manually and restart the build.
|
|
32
|
+
*
|
|
33
|
+
* @param "auto" - the package will automatically delete the next.js cache directory.
|
|
34
|
+
*
|
|
35
|
+
* @default "error"
|
|
36
|
+
*/
|
|
37
|
+
distDeletionPolicy?: "warning" | "error" | "auto";
|
|
38
|
+
/**
|
|
39
|
+
* Additional check of the dist directory for freshness
|
|
40
|
+
*/
|
|
41
|
+
checkDistFreshness?: () => boolean;
|
|
42
|
+
experimental?: {
|
|
43
|
+
/**
|
|
44
|
+
* Automatically synchronize freed classes (for example, if you deleted the original styles)
|
|
45
|
+
* Such classes will be reused in new locations. In this case, there may be situations that the package
|
|
46
|
+
* will mistakenly consider them freed and reuse the class again, thereby creating duplicates.
|
|
47
|
+
*
|
|
48
|
+
* Be careful using this option
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
syncFreedNames?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Limit of unused minified classes. Such classes are not reused by default,
|
|
54
|
+
* since the package cannot be sure of this at this time.
|
|
55
|
+
*
|
|
56
|
+
* @default 100000
|
|
57
|
+
*/
|
|
58
|
+
freedNamesLimit?: number;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const validKeys = [
|
|
3
|
+
const validKeys = [
|
|
4
|
+
"prefix",
|
|
5
|
+
"reservedNames",
|
|
6
|
+
"cacheDir",
|
|
7
|
+
"distDir",
|
|
8
|
+
"distDeletionPolicy",
|
|
9
|
+
"experimental",
|
|
10
|
+
"checkDistFreshness",
|
|
11
|
+
];
|
|
4
12
|
const validateIsObject = (config) => {
|
|
5
13
|
if (!config)
|
|
6
14
|
return false;
|
|
7
15
|
if (typeof config !== "object" || Array.isArray(config)) {
|
|
8
|
-
console.error(`classnames-minifier: Invalid configuration. Expected object, received ${typeof config}. See https://github.com/
|
|
16
|
+
console.error(`classnames-minifier: Invalid configuration. Expected object, received ${typeof config}. See https://github.com/alexdln/classnames-minifier#configuration`);
|
|
9
17
|
process.exit();
|
|
10
18
|
}
|
|
11
19
|
const isValidKeys = Object.keys(config).every((key) => validKeys.includes(key));
|
|
12
20
|
if (!isValidKeys) {
|
|
13
|
-
console.error(`classnames-minifier: Invalid configuration. Valid keys are: ${validKeys.join(", ")}. See https://github.com/
|
|
21
|
+
console.error(`classnames-minifier: Invalid configuration. Valid keys are: ${validKeys.join(", ")}. See https://github.com/alexdln/classnames-minifier#configuration`);
|
|
14
22
|
process.exit();
|
|
15
23
|
}
|
|
16
24
|
return true;
|
|
@@ -19,7 +27,7 @@ const validateConfig = (config = {}) => {
|
|
|
19
27
|
if (!validateIsObject(config))
|
|
20
28
|
return {};
|
|
21
29
|
if (config.prefix && !config.prefix.match(/^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/)) {
|
|
22
|
-
console.error(`classnames-minifier: Invalid prefix. It should match following rule: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". See https://github.com/
|
|
30
|
+
console.error(`classnames-minifier: Invalid prefix. It should match following rule: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". See https://github.com/alexdln/classnames-minifier#configuration`);
|
|
23
31
|
process.exit();
|
|
24
32
|
}
|
|
25
33
|
return config;
|
|
@@ -10,13 +10,13 @@ const readManifest = (manifestPath) => {
|
|
|
10
10
|
const prevData = fs_1.default.readFileSync(manifestPath, { encoding: "utf-8" });
|
|
11
11
|
return JSON.parse(prevData);
|
|
12
12
|
}
|
|
13
|
-
catch
|
|
13
|
+
catch {
|
|
14
14
|
return {};
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
const validateDist = (pluginOptions, manifestPath) => {
|
|
18
18
|
var _a, _b, _c;
|
|
19
|
-
const { cacheDir, distDir, prefix, reservedNames,
|
|
19
|
+
const { cacheDir, distDir, prefix, reservedNames, distDeletionPolicy, checkDistFreshness } = pluginOptions;
|
|
20
20
|
if (!cacheDir || !distDir) {
|
|
21
21
|
console.log("classnames-minifier: Failed to check the dist folder because cacheDir or distDir is not specified");
|
|
22
22
|
return;
|
|
@@ -41,14 +41,14 @@ const validateDist = (pluginOptions, manifestPath) => {
|
|
|
41
41
|
if (prevData.version !== configuration_1.CODE_VERSION) {
|
|
42
42
|
configDiffMessages.push(`Different package version: "${prevData.version}" -> "${configuration_1.CODE_VERSION}"`);
|
|
43
43
|
}
|
|
44
|
-
if (prevData.
|
|
45
|
-
configDiffMessages.push(`"
|
|
44
|
+
if (prevData.distDeletionPolicy && !distDeletionPolicy) {
|
|
45
|
+
configDiffMessages.push(`"distDeletionPolicy" set to "${distDeletionPolicy}"`);
|
|
46
46
|
}
|
|
47
47
|
if (configDiffMessages.length) {
|
|
48
|
-
configurationError = `Changes found in package configuration: \n${configDiffMessages.map((message) => `- ${message};\n`)}`;
|
|
48
|
+
configurationError = `Changes found in package configuration: \n${configDiffMessages.map((message) => `- ${message};\n`).join("")}`;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
else {
|
|
51
|
+
else if (!(checkDistFreshness === null || checkDistFreshness === void 0 ? void 0 : checkDistFreshness())) {
|
|
52
52
|
configurationError = `Can not find the package cache manifest at ${manifestPath}\n`;
|
|
53
53
|
}
|
|
54
54
|
return configurationError;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LoaderContext } from "webpack";
|
|
2
|
+
import type { Config } from "./lib/types/plugin";
|
|
3
|
+
import ConverterMinified from "./lib/ConverterMinified";
|
|
4
|
+
export * from "./lib/types/plugin";
|
|
5
|
+
declare class ClassnamesMinifier {
|
|
6
|
+
converterMinified: ConverterMinified;
|
|
7
|
+
constructor(config: Config);
|
|
8
|
+
get getLocalIdent(): ({ resourcePath }: LoaderContext<any>, _localIdent: string, origName: string) => string;
|
|
9
|
+
get preLoader(): {
|
|
10
|
+
loader: string;
|
|
11
|
+
options: {
|
|
12
|
+
classnamesMinifier: ConverterMinified;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
get postLoader(): {
|
|
16
|
+
loader: string;
|
|
17
|
+
options: {
|
|
18
|
+
classnamesMinifier: ConverterMinified;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export default ClassnamesMinifier;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { CODE_VERSION } from "./lib/constants/configuration";
|
|
4
|
+
import validateConfig from "./lib/validateConfig";
|
|
5
|
+
import ConverterMinified from "./lib/ConverterMinified";
|
|
6
|
+
import validateDist from "./lib/validateDist";
|
|
7
|
+
import removeDist from "./lib/removeDist";
|
|
8
|
+
export * from "./lib/types/plugin";
|
|
9
|
+
class ClassnamesMinifier {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
validateConfig(config);
|
|
12
|
+
this.converterMinified = new ConverterMinified(config);
|
|
13
|
+
if (!config.cacheDir || !config.distDir) {
|
|
14
|
+
console.log("classnames-minifier: Failed to check the dist folder because cacheDir or distDir is not specified");
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const manifestDir = path.join(config.cacheDir, "ncm-meta");
|
|
18
|
+
const manifestPath = path.join(manifestDir, "manifest.json");
|
|
19
|
+
const { distDeletionPolicy = "error" } = config;
|
|
20
|
+
let distCleared = false;
|
|
21
|
+
if (config.cacheDir) {
|
|
22
|
+
const errors = validateDist(config, manifestPath);
|
|
23
|
+
if (errors) {
|
|
24
|
+
console.log(`classnames-minifier: "distDeletionPolicy" option was set to "${distDeletionPolicy}"`);
|
|
25
|
+
if (distDeletionPolicy === "auto") {
|
|
26
|
+
removeDist(config.distDir, errors);
|
|
27
|
+
distCleared = true;
|
|
28
|
+
}
|
|
29
|
+
else if (distDeletionPolicy === "error") {
|
|
30
|
+
throw new Error(`classnames-minifier: Please, remove dist dir manually. ${errors}`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.warn(`classnames-minifier: Please, remove dist dir manually. ${errors}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const { syncFreedNames, freedNamesLimit = 100000 } = config.experimental || {};
|
|
38
|
+
if (!syncFreedNames && this.converterMinified.freeClasses.length > freedNamesLimit && config.distDir) {
|
|
39
|
+
console.log(`classnames-minifier: "distDeletionPolicy" option was set to "${distDeletionPolicy}"`);
|
|
40
|
+
if (distDeletionPolicy === "auto") {
|
|
41
|
+
removeDist(config.distDir, `Freed names exceeds the limit (${freedNamesLimit})`);
|
|
42
|
+
distCleared = true;
|
|
43
|
+
}
|
|
44
|
+
else if (distDeletionPolicy === "error") {
|
|
45
|
+
throw new Error(`Please, remove dist dir manually. Freed names exceeds the limit (${freedNamesLimit})`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.warn(`Please, remove dist dir manually. Freed names exceeds the limit (${freedNamesLimit})`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (distCleared) {
|
|
52
|
+
this.converterMinified.reset();
|
|
53
|
+
}
|
|
54
|
+
if (!fs.existsSync(manifestDir))
|
|
55
|
+
fs.mkdirSync(manifestDir, { recursive: true });
|
|
56
|
+
fs.writeFileSync(manifestPath, JSON.stringify({ ...config, version: CODE_VERSION }), { encoding: "utf-8" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
get getLocalIdent() {
|
|
60
|
+
return this.converterMinified.getLocalIdent.bind(this.converterMinified);
|
|
61
|
+
}
|
|
62
|
+
get preLoader() {
|
|
63
|
+
return {
|
|
64
|
+
loader: path.join(__dirname, "./lib/classnames-minifier-preloader.js"),
|
|
65
|
+
options: {
|
|
66
|
+
classnamesMinifier: this.converterMinified,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
get postLoader() {
|
|
71
|
+
return {
|
|
72
|
+
loader: path.join(__dirname, "./lib/classnames-minifier-postloader.js"),
|
|
73
|
+
options: {
|
|
74
|
+
classnamesMinifier: this.converterMinified,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export default ClassnamesMinifier;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LoaderContext } from "webpack";
|
|
2
|
+
import type { Config } from "./types/plugin";
|
|
3
|
+
type CacheType = {
|
|
4
|
+
[resourcePath: string]: {
|
|
5
|
+
cachePath: string;
|
|
6
|
+
matchings: {
|
|
7
|
+
[origClass: string]: string;
|
|
8
|
+
};
|
|
9
|
+
type: "new" | "updated" | "old";
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
declare class ConverterMinified {
|
|
13
|
+
private cacheDir?;
|
|
14
|
+
private prefix;
|
|
15
|
+
private reservedNames;
|
|
16
|
+
private syncFreedNames;
|
|
17
|
+
private symbols;
|
|
18
|
+
dirtyСache: CacheType;
|
|
19
|
+
freeClasses: string[];
|
|
20
|
+
lastIndex: number;
|
|
21
|
+
private nextLoopEndsWith;
|
|
22
|
+
private currentLoopLength;
|
|
23
|
+
private nameMap;
|
|
24
|
+
constructor({ cacheDir, prefix, reservedNames, experimental }: Config);
|
|
25
|
+
reset: () => void;
|
|
26
|
+
private invalidateCache;
|
|
27
|
+
private generateClassName;
|
|
28
|
+
private getTargetClassName;
|
|
29
|
+
getLocalIdent({ resourcePath }: LoaderContext<any>, _localIdent: string, origName: string): string;
|
|
30
|
+
}
|
|
31
|
+
export default ConverterMinified;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "fs";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import path from "path";
|
|
4
|
+
class ConverterMinified {
|
|
5
|
+
constructor({ cacheDir, prefix = "", reservedNames = [], experimental }) {
|
|
6
|
+
this.symbols = [
|
|
7
|
+
"a",
|
|
8
|
+
"b",
|
|
9
|
+
"c",
|
|
10
|
+
"d",
|
|
11
|
+
"e",
|
|
12
|
+
"f",
|
|
13
|
+
"g",
|
|
14
|
+
"h",
|
|
15
|
+
"i",
|
|
16
|
+
"j",
|
|
17
|
+
"k",
|
|
18
|
+
"l",
|
|
19
|
+
"m",
|
|
20
|
+
"n",
|
|
21
|
+
"o",
|
|
22
|
+
"p",
|
|
23
|
+
"q",
|
|
24
|
+
"r",
|
|
25
|
+
"s",
|
|
26
|
+
"t",
|
|
27
|
+
"u",
|
|
28
|
+
"v",
|
|
29
|
+
"w",
|
|
30
|
+
"x",
|
|
31
|
+
"y",
|
|
32
|
+
"z",
|
|
33
|
+
"A",
|
|
34
|
+
"B",
|
|
35
|
+
"C",
|
|
36
|
+
"D",
|
|
37
|
+
"E",
|
|
38
|
+
"F",
|
|
39
|
+
"G",
|
|
40
|
+
"H",
|
|
41
|
+
"I",
|
|
42
|
+
"J",
|
|
43
|
+
"K",
|
|
44
|
+
"L",
|
|
45
|
+
"M",
|
|
46
|
+
"N",
|
|
47
|
+
"O",
|
|
48
|
+
"P",
|
|
49
|
+
"Q",
|
|
50
|
+
"R",
|
|
51
|
+
"S",
|
|
52
|
+
"T",
|
|
53
|
+
"U",
|
|
54
|
+
"V",
|
|
55
|
+
"W",
|
|
56
|
+
"X",
|
|
57
|
+
"Y",
|
|
58
|
+
"Z",
|
|
59
|
+
"0",
|
|
60
|
+
"1",
|
|
61
|
+
"2",
|
|
62
|
+
"3",
|
|
63
|
+
"4",
|
|
64
|
+
"5",
|
|
65
|
+
"6",
|
|
66
|
+
"7",
|
|
67
|
+
"8",
|
|
68
|
+
"9",
|
|
69
|
+
];
|
|
70
|
+
this.dirtyСache = {};
|
|
71
|
+
this.freeClasses = [];
|
|
72
|
+
this.lastIndex = 0;
|
|
73
|
+
this.nextLoopEndsWith = 26;
|
|
74
|
+
this.currentLoopLength = 0;
|
|
75
|
+
this.nameMap = [0];
|
|
76
|
+
this.reset = () => {
|
|
77
|
+
this.dirtyСache = {};
|
|
78
|
+
this.freeClasses = [];
|
|
79
|
+
this.lastIndex = 0;
|
|
80
|
+
this.nextLoopEndsWith = 26;
|
|
81
|
+
this.currentLoopLength = 0;
|
|
82
|
+
this.nameMap = [0];
|
|
83
|
+
if (this.cacheDir) {
|
|
84
|
+
this.invalidateCache(this.cacheDir);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
this.invalidateCache = (cacheDir) => {
|
|
88
|
+
this.cacheDir = cacheDir;
|
|
89
|
+
if (!existsSync(cacheDir))
|
|
90
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
91
|
+
const cachedFiles = readdirSync(cacheDir);
|
|
92
|
+
if (cachedFiles.length) {
|
|
93
|
+
console.log("classnames-minifier: Restoring pairs of classes...");
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const usedClassNames = [];
|
|
99
|
+
const dirtyСache = {};
|
|
100
|
+
let prevLastIndex = 0;
|
|
101
|
+
cachedFiles.forEach((file) => {
|
|
102
|
+
const filePath = path.join(cacheDir, file);
|
|
103
|
+
const dirtyCacheFile = readFileSync(filePath, { encoding: "utf8" });
|
|
104
|
+
const [resourcePath, lastIndex, ...classnames] = dirtyCacheFile.split(",");
|
|
105
|
+
if (lastIndex && +lastIndex > prevLastIndex)
|
|
106
|
+
prevLastIndex = +lastIndex;
|
|
107
|
+
if (existsSync(resourcePath)) {
|
|
108
|
+
const cachedMatchings = classnames.reduce((acc, cur) => {
|
|
109
|
+
const [origClass, newClass] = cur.split("=");
|
|
110
|
+
acc[origClass] = newClass;
|
|
111
|
+
if (!usedClassNames.includes(newClass)) {
|
|
112
|
+
usedClassNames.push(newClass);
|
|
113
|
+
}
|
|
114
|
+
return acc;
|
|
115
|
+
}, {});
|
|
116
|
+
dirtyСache[resourcePath] = {
|
|
117
|
+
cachePath: filePath,
|
|
118
|
+
matchings: cachedMatchings,
|
|
119
|
+
type: "old",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
rmSync(filePath);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
for (let i = 0; i <= prevLastIndex; i++) {
|
|
127
|
+
const newClass = this.generateClassName();
|
|
128
|
+
this.lastIndex += 1;
|
|
129
|
+
const usedClassNameIndex = usedClassNames.indexOf(newClass);
|
|
130
|
+
if (usedClassNameIndex !== -1) {
|
|
131
|
+
usedClassNames.splice(usedClassNameIndex, 1);
|
|
132
|
+
}
|
|
133
|
+
else if (!this.reservedNames.includes(newClass)) {
|
|
134
|
+
this.freeClasses.push(newClass);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (cachedFiles.length) {
|
|
138
|
+
console.log("classnames-minifier: Pairs restored");
|
|
139
|
+
}
|
|
140
|
+
this.dirtyСache = dirtyСache;
|
|
141
|
+
};
|
|
142
|
+
this.prefix = prefix;
|
|
143
|
+
this.reservedNames = reservedNames;
|
|
144
|
+
this.syncFreedNames = Boolean(experimental === null || experimental === void 0 ? void 0 : experimental.syncFreedNames);
|
|
145
|
+
if (cacheDir)
|
|
146
|
+
this.invalidateCache(path.join(cacheDir, "ncm"));
|
|
147
|
+
}
|
|
148
|
+
generateClassName() {
|
|
149
|
+
const symbolsCount = 62;
|
|
150
|
+
if (this.lastIndex >= this.nextLoopEndsWith) {
|
|
151
|
+
if (this.nextLoopEndsWith === 26)
|
|
152
|
+
this.nextLoopEndsWith = 62 * symbolsCount;
|
|
153
|
+
else
|
|
154
|
+
this.nextLoopEndsWith = this.nextLoopEndsWith * symbolsCount;
|
|
155
|
+
this.nameMap.push(0);
|
|
156
|
+
this.currentLoopLength += 1;
|
|
157
|
+
}
|
|
158
|
+
const currentClassname = this.prefix + this.nameMap.map((e) => this.symbols[e]).join("");
|
|
159
|
+
for (let i = this.currentLoopLength; i >= 0; i--) {
|
|
160
|
+
if (this.nameMap[i] === symbolsCount - 1 || (i === 0 && this.nameMap[i] === 25)) {
|
|
161
|
+
this.nameMap[i] = 0;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this.nameMap[i] += 1;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return currentClassname;
|
|
169
|
+
}
|
|
170
|
+
getTargetClassName(origName) {
|
|
171
|
+
let targetClassName;
|
|
172
|
+
if (this.freeClasses.length && this.syncFreedNames) {
|
|
173
|
+
targetClassName = this.freeClasses.shift();
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
targetClassName = this.generateClassName();
|
|
177
|
+
}
|
|
178
|
+
if (this.reservedNames.includes(targetClassName)) {
|
|
179
|
+
targetClassName = this.getTargetClassName(origName);
|
|
180
|
+
this.lastIndex += 1;
|
|
181
|
+
}
|
|
182
|
+
return targetClassName;
|
|
183
|
+
}
|
|
184
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
|
+
getLocalIdent({ resourcePath }, _localIdent, origName) {
|
|
186
|
+
if (!this.dirtyСache[resourcePath]) {
|
|
187
|
+
this.dirtyСache[resourcePath] = {
|
|
188
|
+
cachePath: this.cacheDir ? path.join(this.cacheDir, uuidv4()) : "",
|
|
189
|
+
matchings: {},
|
|
190
|
+
type: "new",
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const currentCache = this.dirtyСache[resourcePath];
|
|
194
|
+
if (currentCache.matchings[origName])
|
|
195
|
+
return currentCache.matchings[origName];
|
|
196
|
+
const targetClassName = this.getTargetClassName(origName);
|
|
197
|
+
currentCache.matchings[origName] = targetClassName;
|
|
198
|
+
currentCache.type = "updated";
|
|
199
|
+
this.lastIndex += 1;
|
|
200
|
+
return targetClassName;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export default ConverterMinified;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
export default function (source, map, meta) {
|
|
3
|
+
const options = this.getOptions();
|
|
4
|
+
const classnamesMinifier = options.classnamesMinifier;
|
|
5
|
+
Object.entries(classnamesMinifier.dirtyСache).forEach(([resourcePath, data]) => {
|
|
6
|
+
if (data.type !== "old") {
|
|
7
|
+
fs.writeFileSync(data.cachePath, `${resourcePath},${classnamesMinifier.lastIndex},${Object.entries(data.matchings)
|
|
8
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
9
|
+
.join(",")}`);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
this.callback(null, source, map, meta);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default function (source, map, meta) {
|
|
2
|
+
const options = this.getOptions();
|
|
3
|
+
const classnamesMinifier = options.classnamesMinifier;
|
|
4
|
+
const maybeClassesList = source.match(/\.-?[_a-zA-Z]+[_a-zA-Z0-9-]*/g);
|
|
5
|
+
const cache = classnamesMinifier.dirtyСache[this.resourcePath];
|
|
6
|
+
/**
|
|
7
|
+
* if some class has ceased to be used since the last time the file was loaded, we remove it from the cache
|
|
8
|
+
*/
|
|
9
|
+
if (cache && cache.matchings) {
|
|
10
|
+
cache.matchings = maybeClassesList
|
|
11
|
+
? Object.fromEntries(Object.entries(cache.matchings).filter(([key]) => maybeClassesList === null || maybeClassesList === void 0 ? void 0 : maybeClassesList.includes(`.${key}`)))
|
|
12
|
+
: {};
|
|
13
|
+
}
|
|
14
|
+
this.callback(null, source, map, meta);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Just a version of the code whose change means that the logic has a critical update
|
|
3
|
+
* and minifying the previous version is not compatible with the current one,
|
|
4
|
+
* which would mean that we should clean dist folder
|
|
5
|
+
*/
|
|
6
|
+
export declare const CODE_VERSION = "parrot";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { rmSync } from "fs";
|
|
2
|
+
const removeDist = (distDir, message) => {
|
|
3
|
+
console.log(`classnames-minifier: ${message}Cleaning the dist folder...`);
|
|
4
|
+
rmSync(distDir, { recursive: true, force: true });
|
|
5
|
+
console.log("classnames-minifier: Dist folder cleared");
|
|
6
|
+
};
|
|
7
|
+
export default removeDist;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type Config = {
|
|
2
|
+
/**
|
|
3
|
+
* The directory where the package cache will be written
|
|
4
|
+
*/
|
|
5
|
+
cacheDir?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Directory where the project is built
|
|
8
|
+
*/
|
|
9
|
+
distDir?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Prefix which will be added to each generated name
|
|
12
|
+
*/
|
|
13
|
+
prefix?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Reserved minified names. Use this option if you are adding short classes manually
|
|
16
|
+
*/
|
|
17
|
+
reservedNames?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Package policy to resolve potential problems with minified classes
|
|
20
|
+
*
|
|
21
|
+
* This may happen due to the following reasons:
|
|
22
|
+
*
|
|
23
|
+
* 1. Launching the package for the first time. Package need clean next.js cache to put everything in the correct order
|
|
24
|
+
* 2. Changing the package configuration. Package need clean next.js cache to rebuild it with classes according to the new rules
|
|
25
|
+
* 3. Exceeding the limit on freed classes (these are classes that were used before, but are now *probably* no longer used)
|
|
26
|
+
*
|
|
27
|
+
* @param "warning" - a warning message will simply be displayed.
|
|
28
|
+
* With this option, there is a high risk of errors and duplicates of generated classes.
|
|
29
|
+
*
|
|
30
|
+
* @param "error" - an error will be thrown, and as a result the build will stop.
|
|
31
|
+
* If this option occurs, delete the next.js cache manually and restart the build.
|
|
32
|
+
*
|
|
33
|
+
* @param "auto" - the package will automatically delete the next.js cache directory.
|
|
34
|
+
*
|
|
35
|
+
* @default "error"
|
|
36
|
+
*/
|
|
37
|
+
distDeletionPolicy?: "warning" | "error" | "auto";
|
|
38
|
+
/**
|
|
39
|
+
* Additional check of the dist directory for freshness
|
|
40
|
+
*/
|
|
41
|
+
checkDistFreshness?: () => boolean;
|
|
42
|
+
experimental?: {
|
|
43
|
+
/**
|
|
44
|
+
* Automatically synchronize freed classes (for example, if you deleted the original styles)
|
|
45
|
+
* Such classes will be reused in new locations. In this case, there may be situations that the package
|
|
46
|
+
* will mistakenly consider them freed and reuse the class again, thereby creating duplicates.
|
|
47
|
+
*
|
|
48
|
+
* Be careful using this option
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
syncFreedNames?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Limit of unused minified classes. Such classes are not reused by default,
|
|
54
|
+
* since the package cannot be sure of this at this time.
|
|
55
|
+
*
|
|
56
|
+
* @default 100000
|
|
57
|
+
*/
|
|
58
|
+
freedNamesLimit?: number;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const validKeys = [
|
|
2
|
+
"prefix",
|
|
3
|
+
"reservedNames",
|
|
4
|
+
"cacheDir",
|
|
5
|
+
"distDir",
|
|
6
|
+
"distDeletionPolicy",
|
|
7
|
+
"experimental",
|
|
8
|
+
"checkDistFreshness",
|
|
9
|
+
];
|
|
10
|
+
const validateIsObject = (config) => {
|
|
11
|
+
if (!config)
|
|
12
|
+
return false;
|
|
13
|
+
if (typeof config !== "object" || Array.isArray(config)) {
|
|
14
|
+
console.error(`classnames-minifier: Invalid configuration. Expected object, received ${typeof config}. See https://github.com/alexdln/classnames-minifier#configuration`);
|
|
15
|
+
process.exit();
|
|
16
|
+
}
|
|
17
|
+
const isValidKeys = Object.keys(config).every((key) => validKeys.includes(key));
|
|
18
|
+
if (!isValidKeys) {
|
|
19
|
+
console.error(`classnames-minifier: Invalid configuration. Valid keys are: ${validKeys.join(", ")}. See https://github.com/alexdln/classnames-minifier#configuration`);
|
|
20
|
+
process.exit();
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
};
|
|
24
|
+
const validateConfig = (config = {}) => {
|
|
25
|
+
if (!validateIsObject(config))
|
|
26
|
+
return {};
|
|
27
|
+
if (config.prefix && !config.prefix.match(/^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/)) {
|
|
28
|
+
console.error(`classnames-minifier: Invalid prefix. It should match following rule: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". See https://github.com/alexdln/classnames-minifier#configuration`);
|
|
29
|
+
process.exit();
|
|
30
|
+
}
|
|
31
|
+
return config;
|
|
32
|
+
};
|
|
33
|
+
export default validateConfig;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { CODE_VERSION } from "./constants/configuration";
|
|
3
|
+
const readManifest = (manifestPath) => {
|
|
4
|
+
try {
|
|
5
|
+
const prevData = fs.readFileSync(manifestPath, { encoding: "utf-8" });
|
|
6
|
+
return JSON.parse(prevData);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return {};
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const validateDist = (pluginOptions, manifestPath) => {
|
|
13
|
+
var _a, _b, _c;
|
|
14
|
+
const { cacheDir, distDir, prefix, reservedNames, distDeletionPolicy, checkDistFreshness } = pluginOptions;
|
|
15
|
+
if (!cacheDir || !distDir) {
|
|
16
|
+
console.log("classnames-minifier: Failed to check the dist folder because cacheDir or distDir is not specified");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
let configurationError = "";
|
|
20
|
+
if (fs.existsSync(manifestPath)) {
|
|
21
|
+
const prevData = readManifest(manifestPath);
|
|
22
|
+
const configDiffMessages = [];
|
|
23
|
+
if (prevData.prefix !== prefix) {
|
|
24
|
+
configDiffMessages.push(`Different "prefix": "${prevData.prefix}" -> "${prefix}"`);
|
|
25
|
+
}
|
|
26
|
+
if (prevData.cacheDir !== cacheDir) {
|
|
27
|
+
configDiffMessages.push(`Different "cacheDir": "${prevData.cacheDir}" -> "${cacheDir}"`);
|
|
28
|
+
}
|
|
29
|
+
if (prevData.distDir !== distDir) {
|
|
30
|
+
configDiffMessages.push(`Different "distDir": "${prevData.distDir}" -> "${distDir}"`);
|
|
31
|
+
}
|
|
32
|
+
if (((_a = prevData.reservedNames) === null || _a === void 0 ? void 0 : _a.length) !== (reservedNames === null || reservedNames === void 0 ? void 0 : reservedNames.length) ||
|
|
33
|
+
((_b = prevData.reservedNames) === null || _b === void 0 ? void 0 : _b.some((name) => !(reservedNames === null || reservedNames === void 0 ? void 0 : reservedNames.includes(name))))) {
|
|
34
|
+
configDiffMessages.push(`Different "reservedNames": "${(_c = prevData.reservedNames) === null || _c === void 0 ? void 0 : _c.join(", ")}" -> "${reservedNames === null || reservedNames === void 0 ? void 0 : reservedNames.join(", ")}"`);
|
|
35
|
+
}
|
|
36
|
+
if (prevData.version !== CODE_VERSION) {
|
|
37
|
+
configDiffMessages.push(`Different package version: "${prevData.version}" -> "${CODE_VERSION}"`);
|
|
38
|
+
}
|
|
39
|
+
if (prevData.distDeletionPolicy && !distDeletionPolicy) {
|
|
40
|
+
configDiffMessages.push(`"distDeletionPolicy" set to "${distDeletionPolicy}"`);
|
|
41
|
+
}
|
|
42
|
+
if (configDiffMessages.length) {
|
|
43
|
+
configurationError = `Changes found in package configuration: \n${configDiffMessages.map((message) => `- ${message};\n`).join("")}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (!(checkDistFreshness === null || checkDistFreshness === void 0 ? void 0 : checkDistFreshness())) {
|
|
47
|
+
configurationError = `Can not find the package cache manifest at ${manifestPath}\n`;
|
|
48
|
+
}
|
|
49
|
+
return configurationError;
|
|
50
|
+
};
|
|
51
|
+
export default validateDist;
|
package/package.json
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "classnames-minifier",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Library for configuring style modules to generate compressed classes",
|
|
5
|
-
"main": "
|
|
6
|
-
"
|
|
5
|
+
"main": "dist/cjs/ClassnamesMinifier.js",
|
|
6
|
+
"module": "dist/esm/ClassnamesMinifier.mjs",
|
|
7
|
+
"types": "dist/cjs/ClassnamesMinifier.d.ts",
|
|
7
8
|
"files": [
|
|
8
9
|
"dist"
|
|
9
10
|
],
|
|
10
11
|
"scripts": {
|
|
11
|
-
"build": "
|
|
12
|
+
"build": "pnpm run build:cjs && pnpm run build:esm",
|
|
13
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
14
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
12
15
|
"lint": "eslint .",
|
|
13
16
|
"eslint": "eslint",
|
|
14
17
|
"prepare": "husky"
|
|
15
18
|
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/cjs/ClassnamesMinifier.d.ts",
|
|
22
|
+
"import": "./dist/esm/ClassnamesMinifier.mjs",
|
|
23
|
+
"require": "./dist/cjs/ClassnamesMinifier.js",
|
|
24
|
+
"default": "./dist/esm/ClassnamesMinifier.mjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
16
27
|
"keywords": [
|
|
17
28
|
"classname",
|
|
18
29
|
"class",
|
|
@@ -26,31 +37,25 @@
|
|
|
26
37
|
],
|
|
27
38
|
"repository": {
|
|
28
39
|
"type": "git",
|
|
29
|
-
"url": "git://github.com/
|
|
40
|
+
"url": "git://github.com/alexdln/nimpl-classnames-minifier.git"
|
|
30
41
|
},
|
|
31
42
|
"author": {
|
|
32
|
-
"name": "Savelyev
|
|
33
|
-
"email": "
|
|
34
|
-
"url": "https://github.com/
|
|
43
|
+
"name": "Alex Savelyev",
|
|
44
|
+
"email": "dev@alexdln.com",
|
|
45
|
+
"url": "https://github.com/alexdln/"
|
|
35
46
|
},
|
|
36
47
|
"license": "MIT",
|
|
37
48
|
"devDependencies": {
|
|
38
|
-
"@types/node": "
|
|
39
|
-
"@types/uuid": "
|
|
40
|
-
"@types/webpack": "5.28.
|
|
41
|
-
"css-loader": "
|
|
42
|
-
"typescript": "5.
|
|
43
|
-
"eslint": "8.57.0",
|
|
44
|
-
"eslint-config-prettier": "^9.1.0",
|
|
45
|
-
"eslint-plugin-prettier": "^5.1.3",
|
|
46
|
-
"husky": "^9.0.11",
|
|
47
|
-
"prettier": "^3.2.5",
|
|
48
|
-
"typescript-eslint": "^7.6.0"
|
|
49
|
+
"@types/node": "25.0.3",
|
|
50
|
+
"@types/uuid": "11.0.0",
|
|
51
|
+
"@types/webpack": "5.28.5",
|
|
52
|
+
"css-loader": "7.1.2",
|
|
53
|
+
"typescript": "5.9.3"
|
|
49
54
|
},
|
|
50
55
|
"peerDependencies": {
|
|
51
56
|
"css-loader": ">=4.0.0"
|
|
52
57
|
},
|
|
53
58
|
"dependencies": {
|
|
54
|
-
"uuid": "
|
|
59
|
+
"uuid": "13.0.0"
|
|
55
60
|
}
|
|
56
|
-
}
|
|
61
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const CODE_VERSION = "rabbit";
|
package/dist/lib/rmDist.d.ts
DELETED
|
File without changes
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = default_1;
|
|
6
7
|
const fs_1 = __importDefault(require("fs"));
|
|
7
8
|
function default_1(source, map, meta) {
|
|
8
9
|
const options = this.getOptions();
|
|
@@ -17,4 +18,3 @@ function default_1(source, map, meta) {
|
|
|
17
18
|
this.callback(null, source, map, meta);
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
|
-
exports.default = default_1;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|