@kabel-project/kabel 1.0.7

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.
Files changed (152) hide show
  1. package/(1.0.7)kabel.md +18 -0
  2. package/README.md +96 -0
  3. package/_READ_ME_MEDIA_/documentation/docs.md +293 -0
  4. package/_READ_ME_MEDIA_/workspace.png +0 -0
  5. package/comment-renderer/renderer.ts +228 -0
  6. package/controllers/base.ts +186 -0
  7. package/controllers/wasd.ts +132 -0
  8. package/docs/README.md +98 -0
  9. package/docs/_media/docs.md +289 -0
  10. package/docs/_media/index.html +168 -0
  11. package/docs/_media/workspace.png +0 -0
  12. package/docs/classes/CommentModel.md +271 -0
  13. package/docs/classes/CommentRenderer.md +457 -0
  14. package/docs/classes/ConnectableField.md +597 -0
  15. package/docs/classes/Connection.md +191 -0
  16. package/docs/classes/ContextMenuHTML.md +163 -0
  17. package/docs/classes/Coordinates.md +187 -0
  18. package/docs/classes/DropdownContainer.md +300 -0
  19. package/docs/classes/DummyField.md +393 -0
  20. package/docs/classes/Eventer.md +185 -0
  21. package/docs/classes/Field.md +461 -0
  22. package/docs/classes/InjectMsg.md +85 -0
  23. package/docs/classes/NodeSvg.md +1011 -0
  24. package/docs/classes/NumberField.md +559 -0
  25. package/docs/classes/OptConnectField.md +624 -0
  26. package/docs/classes/Renderer.md +1636 -0
  27. package/docs/classes/RendererConstants.md +343 -0
  28. package/docs/classes/Representer.md +95 -0
  29. package/docs/classes/RepresenterNode.md +175 -0
  30. package/docs/classes/TextField.md +559 -0
  31. package/docs/classes/Toolbox.md +172 -0
  32. package/docs/classes/WASDController.md +616 -0
  33. package/docs/classes/Widget.md +195 -0
  34. package/docs/classes/WorkspaceController.md +385 -0
  35. package/docs/classes/WorkspaceCoords.md +218 -0
  36. package/docs/classes/WorkspaceSvg.md +1380 -0
  37. package/docs/functions/clearMainWorkspace.md +20 -0
  38. package/docs/functions/getMainWorkspace.md +19 -0
  39. package/docs/functions/inject.md +35 -0
  40. package/docs/functions/setMainWorkspace.md +28 -0
  41. package/docs/globals.md +95 -0
  42. package/docs/interfaces/ColorStyle.md +43 -0
  43. package/docs/interfaces/ConnectorToFrom.md +57 -0
  44. package/docs/interfaces/DrawState.md +81 -0
  45. package/docs/interfaces/FieldConnectionData.md +25 -0
  46. package/docs/interfaces/FieldOptions.md +63 -0
  47. package/docs/interfaces/FieldRawBoxData.md +25 -0
  48. package/docs/interfaces/FieldVisualInfo.md +65 -0
  49. package/docs/interfaces/GridOptions.md +61 -0
  50. package/docs/interfaces/InjectOptions.md +133 -0
  51. package/docs/interfaces/InputFieldJson.md +50 -0
  52. package/docs/interfaces/KabelCommentRendering.md +31 -0
  53. package/docs/interfaces/KabelInterface.md +469 -0
  54. package/docs/interfaces/KabelNodeRendering.md +77 -0
  55. package/docs/interfaces/KabelUIX.md +105 -0
  56. package/docs/interfaces/KabelUtils.md +215 -0
  57. package/docs/interfaces/NodeEvents.md +42 -0
  58. package/docs/interfaces/NodeJson.md +104 -0
  59. package/docs/interfaces/NodePrototype.md +82 -0
  60. package/docs/interfaces/RegisteredEl.md +53 -0
  61. package/docs/interfaces/SerializedNode.md +128 -0
  62. package/docs/interfaces/TblxCategoryStruct.md +41 -0
  63. package/docs/interfaces/TblxFieldStruct.md +28 -0
  64. package/docs/interfaces/TblxNodeStruct.md +35 -0
  65. package/docs/interfaces/WidgetOptions.md +115 -0
  66. package/docs/interfaces/WidgetPrototypeList.md +15 -0
  67. package/docs/type-aliases/AnyField.md +13 -0
  68. package/docs/type-aliases/AnyFieldCls.md +13 -0
  69. package/docs/type-aliases/Color.md +13 -0
  70. package/docs/type-aliases/Connectable.md +13 -0
  71. package/docs/type-aliases/EventArgs.md +11 -0
  72. package/docs/type-aliases/EventSetupFn.md +25 -0
  73. package/docs/type-aliases/Hex.md +13 -0
  74. package/docs/type-aliases/RGBObject.md +37 -0
  75. package/docs/type-aliases/RGBString.md +13 -0
  76. package/docs/type-aliases/RGBTuple.md +13 -0
  77. package/docs/type-aliases/TblxObjStruct.md +52 -0
  78. package/docs/variables/CategoryColors.md +29 -0
  79. package/docs/variables/FieldMap.md +41 -0
  80. package/docs/variables/NodePrototypes.md +18 -0
  81. package/docs/variables/default.md +11 -0
  82. package/events/comment-drag-handle.ts +61 -0
  83. package/events/comment-input.ts +291 -0
  84. package/events/connection-line.ts +68 -0
  85. package/events/connector.ts +116 -0
  86. package/events/draggable.ts +119 -0
  87. package/events/events.ts +7 -0
  88. package/events/input-box.ts +213 -0
  89. package/events/node-x-btn.ts +25 -0
  90. package/index.d.ts +4 -0
  91. package/package.json +49 -0
  92. package/renderers/apollo/apollo.ts +21 -0
  93. package/renderers/apollo/constants.ts +40 -0
  94. package/renderers/apollo/renderer.ts +331 -0
  95. package/renderers/atlas/atlas.ts +15 -0
  96. package/renderers/constants.ts +87 -0
  97. package/renderers/renderer.ts +1288 -0
  98. package/renderers/representer-node.ts +52 -0
  99. package/renderers/representer.ts +25 -0
  100. package/src/category.ts +107 -0
  101. package/src/colors.ts +20 -0
  102. package/src/comment.ts +142 -0
  103. package/src/connection.ts +114 -0
  104. package/src/context-menu.ts +194 -0
  105. package/src/coordinates.ts +74 -0
  106. package/src/core.ts +202 -0
  107. package/src/ctx-menu-registry.ts +143 -0
  108. package/src/dropdown-menu.ts +215 -0
  109. package/src/field.ts +595 -0
  110. package/src/flyout.ts +165 -0
  111. package/src/fonts-manager.ts +38 -0
  112. package/src/grid.ts +162 -0
  113. package/src/headless-node.ts +27 -0
  114. package/src/index.ts +115 -0
  115. package/src/inject-headless.ts +18 -0
  116. package/src/inject.ts +213 -0
  117. package/src/main-workspace.ts +51 -0
  118. package/src/mutator.ts +40 -0
  119. package/src/node-types.ts +27 -0
  120. package/src/nodesvg.ts +756 -0
  121. package/src/prototypes.ts +9 -0
  122. package/src/renderer-map.ts +86 -0
  123. package/src/styles.css +224 -0
  124. package/src/toolbox.ts +125 -0
  125. package/src/types.ts +205 -0
  126. package/src/undo-redo.ts +87 -0
  127. package/src/visual-types.ts +29 -0
  128. package/src/widget-prototypes.ts +11 -0
  129. package/src/widget.ts +139 -0
  130. package/src/workspace-coords.ts +14 -0
  131. package/src/workspace-svg.ts +736 -0
  132. package/src/workspace.ts +155 -0
  133. package/test-server.js +61 -0
  134. package/themes/dark.ts +32 -0
  135. package/themes/default.ts +28 -0
  136. package/themes/themes.ts +9 -0
  137. package/tsconfig.json +25 -0
  138. package/typedoc.json +10 -0
  139. package/util/emitter.ts +33 -0
  140. package/util/env.ts +11 -0
  141. package/util/escape-html.ts +22 -0
  142. package/util/eventer.ts +108 -0
  143. package/util/has-prop.ts +4 -0
  144. package/util/parse-color.ts +42 -0
  145. package/util/path.ts +99 -0
  146. package/util/styler.ts +41 -0
  147. package/util/uid.ts +184 -0
  148. package/util/unescape-html.ts +22 -0
  149. package/util/user-state.ts +68 -0
  150. package/util/wait-anim-frames.ts +24 -0
  151. package/util/window-listeners.ts +62 -0
  152. package/webpack.config.js +80 -0
package/util/uid.ts ADDED
@@ -0,0 +1,184 @@
1
+ // uid.ts
2
+
3
+ /**
4
+ * Strategy used to generate UIDs.
5
+ */
6
+ export type UIDStrategy = "uuidv4" | "ulid" | "nanoid" | "short";
7
+
8
+ export interface UIDOptions {
9
+ /** For "nanoid": length of the id (default 21) */
10
+ size?: number;
11
+ /** For "nanoid": custom alphabet (default URL-safe) */
12
+ alphabet?: string;
13
+ }
14
+
15
+ /** Web Crypto shim (browser + Node 16+) */
16
+ const cryptoAPI: Crypto | null =
17
+ (typeof globalThis !== "undefined" && (globalThis as any).crypto) || null;
18
+
19
+ /**
20
+ * Returns a Uint8Array of random bytes.
21
+ * Uses Web Crypto if available; falls back to Math.random otherwise (not cryptographically secure).
22
+ *
23
+ * @param {number} len - Number of random bytes to generate.
24
+ * @returns {Uint8Array} Random bytes array.
25
+ */
26
+ function randBytes(len: number): Uint8Array {
27
+ if (cryptoAPI?.getRandomValues) {
28
+ const buf = new Uint8Array(len);
29
+ cryptoAPI.getRandomValues(buf);
30
+ return buf;
31
+ }
32
+ // Last resort (very old envs). Not cryptographically strong.
33
+ const buf = new Uint8Array(len);
34
+ for (let i = 0; i < len; i++) buf[i] = Math.floor(Math.random() * 256);
35
+ return buf;
36
+ }
37
+
38
+ /**
39
+ * Generates an RFC4122-compliant UUID v4.
40
+ * Uses `crypto.randomUUID` if available.
41
+ *
42
+ * @returns {string} UUID v4 string.
43
+ */
44
+ export function uuidv4(): string {
45
+ const g: any = globalThis as any;
46
+ if (g?.crypto?.randomUUID) return g.crypto.randomUUID();
47
+
48
+ const b = randBytes(16);
49
+ // Per RFC: set version + variant bits
50
+ // @ts-ignore
51
+ b[6] = (b[6] & 0x0f) | 0x40;
52
+ // @ts-ignore
53
+ b[8] = (b[8] & 0x3f) | 0x80;
54
+
55
+ const hex: string[] = [];
56
+ for (let i = 0; i < 256; i++) hex.push(i.toString(16).padStart(2, "0"));
57
+
58
+ return (
59
+ // @ts-ignore
60
+ hex[b[0]] + hex[b[1]] + hex[b[2]] + hex[b[3]] + "-" +
61
+ // @ts-ignore
62
+ hex[b[4]] + hex[b[5]] + "-" +
63
+ // @ts-ignore
64
+ hex[b[6]] + hex[b[7]] + "-" +
65
+ // @ts-ignore
66
+ hex[b[8]] + hex[b[9]] + "-" +
67
+ // @ts-ignore
68
+ hex[b[10]] + hex[b[11]] + hex[b[12]] + hex[b[13]] + hex[b[14]] + hex[b[15]]
69
+ );
70
+ }
71
+
72
+ /** Crockford Base32 alphabet for ULID */
73
+ const CROCK32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; // no I L O U
74
+
75
+ /**
76
+ * Generates a 26-character ULID (time-sortable unique ID).
77
+ *
78
+ * @param {number} [date] - Optional timestamp in milliseconds. Defaults to `Date.now()`.
79
+ * @returns {string} ULID string.
80
+ */
81
+ export function ulid(date?: number): string {
82
+ const time = (typeof date === "number" ? date : Date.now()) >>> 0; // low 32 bits
83
+ const timeHi = Math.floor((typeof date === "number" ? date : Date.now()) / 0x100000000) >>> 0; // high 32
84
+ // ULID uses 48-bit time; do base32 encode 48 bits
85
+ const time48 = new Uint8Array(6);
86
+ // write 48-bit big-endian
87
+ let t = BigInt(typeof date === "number" ? date : Date.now());
88
+ for (let i = 5; i >= 0; i--) {
89
+ time48[i] = Number(t & 0xffn);
90
+ t >>= 8n;
91
+ }
92
+ // first 10 chars = time
93
+ let out = "";
94
+ let acc = 0;
95
+ let bits = 0;
96
+ for (let i = 0; i < 6; i++) {
97
+ // @ts-ignore
98
+ acc = (acc << 8) | time48[i];
99
+ bits += 8;
100
+ while (bits >= 5) {
101
+ bits -= 5;
102
+ out += CROCK32[(acc >>> bits) & 31];
103
+ }
104
+ }
105
+ if (bits > 0) out += CROCK32[(acc << (5 - bits)) & 31];
106
+ out = out.slice(0, 10);
107
+
108
+ // last 16 chars = randomness (80 bits)
109
+ const rnd = randBytes(10);
110
+ acc = 0; bits = 0;
111
+ for (let i = 0; i < rnd.length; i++) {
112
+ // @ts-ignore
113
+ acc = (acc << 8) | rnd[i];
114
+ bits += 8;
115
+ while (bits >= 5) {
116
+ bits -= 5;
117
+ out += CROCK32[(acc >>> bits) & 31];
118
+ }
119
+ }
120
+ if (bits > 0) out += CROCK32[(acc << (5 - bits)) & 31];
121
+
122
+ return out.slice(0, 26);
123
+ }
124
+
125
+ /** NanoID-style: URL-safe alphabet by default, configurable length/alphabet */
126
+ const DEFAULT_ALPHABET =
127
+ "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
128
+ /**
129
+ * Generates a NanoID-style string.
130
+ *
131
+ * @param {number} [size=21] - Length of the generated ID.
132
+ * @param {string} [alphabet=DEFAULT_ALPHABET] - Alphabet to use.
133
+ * @returns {string} Generated NanoID string.
134
+ */
135
+ export function nanoid(size: number = 21, alphabet: string = DEFAULT_ALPHABET): string {
136
+ if (size <= 0) throw new Error("size must be > 0");
137
+ const mask = (1 << Math.ceil(Math.log2(alphabet.length))) - 1;
138
+ let id = "";
139
+ while (id.length < size) {
140
+ const bytes = randBytes(1);
141
+ // @ts-ignore
142
+ const idx = bytes[0] & mask;
143
+ if (idx < alphabet.length) id += alphabet[idx];
144
+ }
145
+ return id;
146
+ }
147
+
148
+ /**
149
+ * Generates a short, mostly-unique ID (timestamp + counter + random).
150
+ * Not cryptographically strong.
151
+ *
152
+ * @returns {string} Short UID string.
153
+ */
154
+ let _ctr = 0;
155
+ export function shortId(): string {
156
+ const ts = Date.now().toString(36);
157
+ _ctr = (_ctr + 1) & 0xfff; // 0..4095
158
+ const c = _ctr.toString(36).padStart(3, "0");
159
+ const r = Array.from(randBytes(3))
160
+ .map(b => (b & 0x3f).toString(36).padStart(2, "0"))
161
+ .join("")
162
+ .slice(0, 4);
163
+ return `${ts}${c}${r}`;
164
+ }
165
+
166
+ /**
167
+ * Generates a UID using the specified strategy.
168
+ *
169
+ * @param {UIDStrategy} [strategy="uuidv4"] - The UID strategy to use.
170
+ * @param {UIDOptions} [opts={}] - Options for the selected strategy.
171
+ * @returns {string} Generated UID.
172
+ */
173
+ export function generateUID(strategy: UIDStrategy = "uuidv4", opts: UIDOptions = {}): string {
174
+ switch (strategy) {
175
+ case "uuidv4": return uuidv4();
176
+ case "ulid": return ulid();
177
+ case "nanoid": return nanoid(opts.size ?? 21, opts.alphabet ?? DEFAULT_ALPHABET);
178
+ case "short": return shortId();
179
+ default: {
180
+ const _exhaustive: never = strategy;
181
+ return uuidv4();
182
+ }
183
+ }
184
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Converts HTML-escaped characters in a string back to their literal form.
3
+ *
4
+ * Specifically, it replaces:
5
+ * - `&lt;` with `<`
6
+ * - `&gt;` with `>`
7
+ * - `&quot;` with `"`
8
+ * - `&apos;` with `'`
9
+ * - `&amp;` with `&`
10
+ *
11
+ * @param {string} s - The string containing HTML-escaped characters.
12
+ * @returns {string} The unescaped string with HTML entities replaced by their literal characters.
13
+ */
14
+ function unescapeAttr(s: string): string {
15
+ return s.replace(/&lt;/g, "<")
16
+ .replace(/&gt;/g, ">")
17
+ .replace(/&quot;/g, '"')
18
+ .replace(/&apos;/g, "'")
19
+ .replace(/&amp;/g, "&");
20
+ }
21
+
22
+ export default unescapeAttr;
@@ -0,0 +1,68 @@
1
+ type StateChangeCallback = (addedOrRemoved: 0 | 1) => void;
2
+
3
+ class UserState {
4
+ private state: Set<string>;
5
+ private callbacks: Map<string, StateChangeCallback[]>;
6
+ /**
7
+ * Stores the user's current UIX state
8
+ * Ex: 'typing'
9
+ */
10
+ constructor() {
11
+ this.state = new Set();
12
+ this.callbacks = new Map();
13
+ }
14
+
15
+ /**
16
+ * Adds a state
17
+ * @param name - The name of the state (ex: 'typing')
18
+ */
19
+ setState(name: string) {
20
+ const wasPresent = this.state.has(name);
21
+ if (!wasPresent) {
22
+ this.state.add(name);
23
+ this.triggerCallbacks(name, 1);
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Removes a state
29
+ * @param name - The name of the state (ex: 'typing')
30
+ */
31
+ removeState(name: string) {
32
+ const wasPresent = this.state.has(name);
33
+ if (wasPresent) {
34
+ this.state.delete(name);
35
+ this.triggerCallbacks(name, 0);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Checks if a state is active
41
+ * @param name - The name of the state (ex: 'typing')
42
+ */
43
+ hasState(name: string) {
44
+ return this.state.has(name);
45
+ }
46
+
47
+ /**
48
+ * Registers a callback for state changes
49
+ * @param name - Name of the state to check changes for.
50
+ * @param cb - Callback to call on state change.
51
+ */
52
+ onStateChange(name: string, cb: StateChangeCallback) {
53
+ if (!this.callbacks.has(name)) this.callbacks.set(name, []);
54
+ this.callbacks.get(name)!.push(cb);
55
+ }
56
+
57
+ /** Internal: triggers callbacks for a state */
58
+ private triggerCallbacks(name: string, addedOrRemoved: 0 | 1) {
59
+ const cbs = this.callbacks.get(name);
60
+ if (!cbs) return;
61
+ for (const cb of cbs) cb(addedOrRemoved);
62
+ }
63
+ }
64
+ const userState = new UserState();
65
+ export default userState;
66
+ export {
67
+ UserState
68
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Delays execution of a callback by a specified number of animation frames.
3
+ *
4
+ * Uses `requestAnimationFrame` to count frames, then calls the provided callback.
5
+ *
6
+ * @param {number} frames - The number of animation frames to wait before executing the callback.
7
+ * @param {() => void} callback - The function to execute after the specified frames have passed.
8
+ */
9
+ function waitFrames(frames: number, callback: () => void): void {
10
+ let count = 0;
11
+
12
+ function step() {
13
+ count++;
14
+ if (count >= frames) {
15
+ callback();
16
+ } else {
17
+ requestAnimationFrame(step);
18
+ }
19
+ }
20
+
21
+ requestAnimationFrame(step);
22
+ }
23
+
24
+ export default waitFrames;
@@ -0,0 +1,62 @@
1
+ type WindowEventKeys =
2
+ | 'resize'
3
+ | 'scroll'
4
+ | 'blur'
5
+ | 'focus'
6
+ | 'visibilitychange'
7
+ | 'pointerlockchange'
8
+ | 'beforeunload';
9
+
10
+ type WindowListenersMap = Record<WindowEventKeys, Array<(event: Event) => void>>;
11
+
12
+ const windowListeners: WindowListenersMap = {
13
+ resize: [],
14
+ scroll: [],
15
+ blur: [],
16
+ focus: [],
17
+ visibilitychange: [],
18
+ pointerlockchange: [],
19
+ beforeunload: [],
20
+ };
21
+
22
+ function handleEvent(type: WindowEventKeys, event: Event) {
23
+ const list = windowListeners[type];
24
+ if (!list.length) return;
25
+ for (const fn of list) {
26
+ try {
27
+ fn(event);
28
+ } catch (err) {
29
+ console.error(`[Kabel] Error in window listener for '${type}':`, err);
30
+ }
31
+ }
32
+ }
33
+
34
+ // auto attach
35
+ (Object.keys(windowListeners) as WindowEventKeys[]).forEach((type) => {
36
+ window.addEventListener(type, (e) => handleEvent(type, e));
37
+ });
38
+
39
+ export function addWindowListener(
40
+ type: WindowEventKeys,
41
+ fn: (event: Event) => void
42
+ ) {
43
+ windowListeners[type].push(fn);
44
+ }
45
+
46
+ export function removeWindowListener(
47
+ type: WindowEventKeys,
48
+ fn: (event: Event) => void
49
+ ) {
50
+ const list = windowListeners[type];
51
+ const i = list.indexOf(fn);
52
+ if (i !== -1) list.splice(i, 1);
53
+ }
54
+
55
+ export function clearWindowListeners(type?: WindowEventKeys) {
56
+ if (type) windowListeners[type].length = 0;
57
+ else (Object.keys(windowListeners) as WindowEventKeys[]).forEach((k) => {
58
+ windowListeners[k].length = 0;
59
+ });
60
+ }
61
+
62
+ export default windowListeners;
@@ -0,0 +1,80 @@
1
+ const path = require('path');
2
+ const TerserPlugin = require('terser-webpack-plugin');
3
+ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
4
+
5
+ module.exports = {
6
+ mode: 'production', // <- production enables lots of optimizations automatically
7
+ entry: './src/index.ts',
8
+ output: {
9
+ filename: 'kabel.js',
10
+ path: path.resolve(__dirname, 'dist'),
11
+ library: {
12
+ name: 'Kabel',
13
+ type: 'umd',
14
+ },
15
+ globalObject: 'this',
16
+ libraryExport: 'default',
17
+ clean: {
18
+ keep: /index\.html/,
19
+ }
20
+ },
21
+ resolve: {
22
+ extensions: ['.ts', '.js'],
23
+ },
24
+ module: {
25
+ rules: [
26
+ {
27
+ test: /\.ts$/,
28
+ use: 'ts-loader',
29
+ exclude: /node_modules/,
30
+ },
31
+ {
32
+ enforce: 'pre',
33
+ test: /\.js$/,
34
+ loader: 'source-map-loader',
35
+ },
36
+ {
37
+ test: /\.(css|svg)$/,
38
+ use: 'raw-loader'
39
+ },
40
+ ],
41
+ },
42
+ optimization: {
43
+ minimize: true,
44
+ minimizer: [
45
+ new TerserPlugin({
46
+ terserOptions: {
47
+ compress: {
48
+ //drop_console: true, // kill console.logs
49
+ drop_debugger: true, // kill debugger;
50
+ pure_funcs: ['console.info', 'console.debug'],
51
+ // aggressive compress flags
52
+ booleans_as_integers: true,
53
+ hoist_funs: true,
54
+ passes: 3,
55
+ collapse_vars: true, // inline single-use vars
56
+ reduce_vars: true, // further optimizes var usage
57
+ join_vars: true, // join consecutive var statements
58
+ keep_fargs: false, // remove unused function args
59
+ if_return: true, // optimize if/return statements
60
+ conditionals: true, // convert if-else to conditional expressions
61
+ sequences: true, // join consecutive statements with comma
62
+ unused: true, // remove unused vars/functions
63
+ loops: true, // optimize loops
64
+ side_effects: true, // remove expressions without side-effects
65
+ },
66
+ mangle: {
67
+ //toplevel: false, // <- don’t scramble top-level/public names
68
+ },
69
+ format: {
70
+ comments: false,
71
+ },
72
+ },
73
+ extractComments: false,
74
+ parallel: true,
75
+ }),
76
+ new CssMinimizerPlugin(),
77
+ ],
78
+ },
79
+ devtool: 'source-map',
80
+ };