Ditch webpack-dev-middleware

afccb8517a09c71edc87138b0610a1d2292add02

Cohee <18619528+Cohee1207@users.noreply.github.com>

5 files changed, +39 -264Showing whitespace changes
package-lock.json+0 -253
@@ -67,7 +67,6 @@
67 "vectra": "^0.2.2",67 "vectra": "^0.2.2",
68 "wavefile": "^11.0.0",68 "wavefile": "^11.0.0",
69 "webpack": "^5.95.0",69 "webpack": "^5.95.0",
70 "webpack-dev-middleware": "^7.4.2",
71 "write-file-atomic": "^5.0.1",70 "write-file-atomic": "^5.0.1",
72 "ws": "^8.17.1",71 "ws": "^8.17.1",
73 "yaml": "^2.3.4",72 "yaml": "^2.3.4",
@@ -866,60 +865,6 @@
866 "@jridgewell/sourcemap-codec": "^1.4.14"865 "@jridgewell/sourcemap-codec": "^1.4.14"
867 }866 }
868 },867 },
869 "node_modules/@jsonjoy.com/base64": {
870 "version": "1.1.2",
871 "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz",
872 "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==",
873 "license": "Apache-2.0",
874 "engines": {
875 "node": ">=10.0"
876 },
877 "funding": {
878 "type": "github",
879 "url": "https://github.com/sponsors/streamich"
880 },
881 "peerDependencies": {
882 "tslib": "2"
883 }
884 },
885 "node_modules/@jsonjoy.com/json-pack": {
886 "version": "1.1.0",
887 "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz",
888 "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==",
889 "license": "Apache-2.0",
890 "dependencies": {
891 "@jsonjoy.com/base64": "^1.1.1",
892 "@jsonjoy.com/util": "^1.1.2",
893 "hyperdyperid": "^1.2.0",
894 "thingies": "^1.20.0"
895 },
896 "engines": {
897 "node": ">=10.0"
898 },
899 "funding": {
900 "type": "github",
901 "url": "https://github.com/sponsors/streamich"
902 },
903 "peerDependencies": {
904 "tslib": "2"
905 }
906 },
907 "node_modules/@jsonjoy.com/util": {
908 "version": "1.5.0",
909 "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz",
910 "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==",
911 "license": "Apache-2.0",
912 "engines": {
913 "node": ">=10.0"
914 },
915 "funding": {
916 "type": "github",
917 "url": "https://github.com/sponsors/streamich"
918 },
919 "peerDependencies": {
920 "tslib": "2"
921 }
922 },
923 "node_modules/@kwsites/file-exists": {868 "node_modules/@kwsites/file-exists": {
924 "version": "1.1.1",869 "version": "1.1.1",
925 "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",870 "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
@@ -1803,45 +1748,6 @@
1803 "url": "https://github.com/sponsors/epoberezkin"1748 "url": "https://github.com/sponsors/epoberezkin"
1804 }1749 }
1805 },1750 },
1806 "node_modules/ajv-formats": {
1807 "version": "2.1.1",
1808 "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
1809 "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
1810 "license": "MIT",
1811 "dependencies": {
1812 "ajv": "^8.0.0"
1813 },
1814 "peerDependencies": {
1815 "ajv": "^8.0.0"
1816 },
1817 "peerDependenciesMeta": {
1818 "ajv": {
1819 "optional": true
1820 }
1821 }
1822 },
1823 "node_modules/ajv-formats/node_modules/ajv": {
1824 "version": "8.17.1",
1825 "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
1826 "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
1827 "license": "MIT",
1828 "dependencies": {
1829 "fast-deep-equal": "^3.1.3",
1830 "fast-uri": "^3.0.1",
1831 "json-schema-traverse": "^1.0.0",
1832 "require-from-string": "^2.0.2"
1833 },
1834 "funding": {
1835 "type": "github",
1836 "url": "https://github.com/sponsors/epoberezkin"
1837 }
1838 },
1839 "node_modules/ajv-formats/node_modules/json-schema-traverse": {
1840 "version": "1.0.0",
1841 "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
1842 "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
1843 "license": "MIT"
1844 },
1845 "node_modules/ajv-keywords": {1751 "node_modules/ajv-keywords": {
1846 "version": "3.5.2",1752 "version": "3.5.2",
1847 "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",1753 "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -2602,12 +2508,6 @@
2602 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",2508 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
2603 "license": "MIT"2509 "license": "MIT"
2604 },2510 },
2605 "node_modules/colorette": {
2606 "version": "2.0.20",
2607 "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
2608 "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
2609 "license": "MIT"
2610 },
2611 "node_modules/combined-stream": {2511 "node_modules/combined-stream": {
2612 "version": "1.0.8",2512 "version": "1.0.8",
2613 "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",2513 "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -3785,12 +3685,6 @@
3785 "dev": true,3685 "dev": true,
3786 "license": "MIT"3686 "license": "MIT"
3787 },3687 },
3788 "node_modules/fast-uri": {
3789 "version": "3.0.3",
3790 "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
3791 "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
3792 "license": "BSD-3-Clause"
3793 },
3794 "node_modules/fastq": {3688 "node_modules/fastq": {
3795 "version": "1.15.0",3689 "version": "1.15.0",
3796 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",3690 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
@@ -4541,15 +4435,6 @@
4541 "ms": "^2.0.0"4435 "ms": "^2.0.0"
4542 }4436 }
4543 },4437 },
4544 "node_modules/hyperdyperid": {
4545 "version": "1.2.0",
4546 "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz",
4547 "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==",
4548 "license": "MIT",
4549 "engines": {
4550 "node": ">=10.18"
4551 }
4552 },
4553 "node_modules/iconv-lite": {4438 "node_modules/iconv-lite": {
4554 "version": "0.6.3",4439 "version": "0.6.3",
4555 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",4440 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -5176,25 +5061,6 @@
5176 "node": ">= 0.6"5061 "node": ">= 0.6"
5177 }5062 }
5178 },5063 },
5179 "node_modules/memfs": {
5180 "version": "4.14.0",
5181 "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz",
5182 "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==",
5183 "license": "Apache-2.0",
5184 "dependencies": {
5185 "@jsonjoy.com/json-pack": "^1.0.3",
5186 "@jsonjoy.com/util": "^1.3.0",
5187 "tree-dump": "^1.0.1",
5188 "tslib": "^2.0.0"
5189 },
5190 "engines": {
5191 "node": ">= 4.0.0"
5192 },
5193 "funding": {
5194 "type": "github",
5195 "url": "https://github.com/sponsors/streamich"
5196 }
5197 },
5198 "node_modules/merge-descriptors": {5064 "node_modules/merge-descriptors": {
5199 "version": "1.0.3",5065 "version": "1.0.3",
5200 "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",5066 "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
@@ -6310,15 +6176,6 @@
6310 "node": ">=0.10.0"6176 "node": ">=0.10.0"
6311 }6177 }
6312 },6178 },
6313 "node_modules/require-from-string": {
6314 "version": "2.0.2",
6315 "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
6316 "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
6317 "license": "MIT",
6318 "engines": {
6319 "node": ">=0.10.0"
6320 }
6321 },
6322 "node_modules/resolve-alpn": {6179 "node_modules/resolve-alpn": {
6323 "version": "1.2.1",6180 "version": "1.2.1",
6324 "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",6181 "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
@@ -6447,59 +6304,6 @@
6447 "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",6304 "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
6448 "license": "ISC"6305 "license": "ISC"
6449 },6306 },
6450 "node_modules/schema-utils": {
6451 "version": "4.2.0",
6452 "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
6453 "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
6454 "license": "MIT",
6455 "dependencies": {
6456 "@types/json-schema": "^7.0.9",
6457 "ajv": "^8.9.0",
6458 "ajv-formats": "^2.1.1",
6459 "ajv-keywords": "^5.1.0"
6460 },
6461 "engines": {
6462 "node": ">= 12.13.0"
6463 },
6464 "funding": {
6465 "type": "opencollective",
6466 "url": "https://opencollective.com/webpack"
6467 }
6468 },
6469 "node_modules/schema-utils/node_modules/ajv": {
6470 "version": "8.17.1",
6471 "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
6472 "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
6473 "license": "MIT",
6474 "dependencies": {
6475 "fast-deep-equal": "^3.1.3",
6476 "fast-uri": "^3.0.1",
6477 "json-schema-traverse": "^1.0.0",
6478 "require-from-string": "^2.0.2"
6479 },
6480 "funding": {
6481 "type": "github",
6482 "url": "https://github.com/sponsors/epoberezkin"
6483 }
6484 },
6485 "node_modules/schema-utils/node_modules/ajv-keywords": {
6486 "version": "5.1.0",
6487 "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
6488 "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
6489 "license": "MIT",
6490 "dependencies": {
6491 "fast-deep-equal": "^3.1.3"
6492 },
6493 "peerDependencies": {
6494 "ajv": "^8.8.2"
6495 }
6496 },
6497 "node_modules/schema-utils/node_modules/json-schema-traverse": {
6498 "version": "1.0.0",
6499 "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
6500 "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
6501 "license": "MIT"
6502 },
6503 "node_modules/seedrandom": {6307 "node_modules/seedrandom": {
6504 "version": "3.0.5",6308 "version": "3.0.5",
6505 "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",6309 "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
@@ -7038,18 +6842,6 @@
7038 "dev": true,6842 "dev": true,
7039 "license": "MIT"6843 "license": "MIT"
7040 },6844 },
7041 "node_modules/thingies": {
7042 "version": "1.21.0",
7043 "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz",
7044 "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==",
7045 "license": "Unlicense",
7046 "engines": {
7047 "node": ">=10.18"
7048 },
7049 "peerDependencies": {
7050 "tslib": "^2"
7051 }
7052 },
7053 "node_modules/tiktoken": {6845 "node_modules/tiktoken": {
7054 "version": "1.0.16",6846 "version": "1.0.16",
7055 "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.16.tgz",6847 "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.16.tgz",
@@ -7106,22 +6898,6 @@
7106 "node": ">=18"6898 "node": ">=18"
7107 }6899 }
7108 },6900 },
7109 "node_modules/tree-dump": {
7110 "version": "1.0.2",
7111 "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz",
7112 "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==",
7113 "license": "Apache-2.0",
7114 "engines": {
7115 "node": ">=10.0"
7116 },
7117 "funding": {
7118 "type": "github",
7119 "url": "https://github.com/sponsors/streamich"
7120 },
7121 "peerDependencies": {
7122 "tslib": "2"
7123 }
7124 },
7125 "node_modules/truncate-utf8-bytes": {6901 "node_modules/truncate-utf8-bytes": {
7126 "version": "1.0.2",6902 "version": "1.0.2",
7127 "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",6903 "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
@@ -7425,35 +7201,6 @@
7425 }7201 }
7426 }7202 }
7427 },7203 },
7428 "node_modules/webpack-dev-middleware": {
7429 "version": "7.4.2",
7430 "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz",
7431 "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==",
7432 "license": "MIT",
7433 "dependencies": {
7434 "colorette": "^2.0.10",
7435 "memfs": "^4.6.0",
7436 "mime-types": "^2.1.31",
7437 "on-finished": "^2.4.1",
7438 "range-parser": "^1.2.1",
7439 "schema-utils": "^4.0.0"
7440 },
7441 "engines": {
7442 "node": ">= 18.12.0"
7443 },
7444 "funding": {
7445 "type": "opencollective",
7446 "url": "https://opencollective.com/webpack"
7447 },
7448 "peerDependencies": {
7449 "webpack": "^5.0.0"
7450 },
7451 "peerDependenciesMeta": {
7452 "webpack": {
7453 "optional": true
7454 }
7455 }
7456 },
7457 "node_modules/webpack-sources": {7204 "node_modules/webpack-sources": {
7458 "version": "3.2.3",7205 "version": "3.2.3",
7459 "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",7206 "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
package.json+0 -1
@@ -57,7 +57,6 @@
57 "vectra": "^0.2.2",57 "vectra": "^0.2.2",
58 "wavefile": "^11.0.0",58 "wavefile": "^11.0.0",
59 "webpack": "^5.95.0",59 "webpack": "^5.95.0",
60 "webpack-dev-middleware": "^7.4.2",
61 "write-file-atomic": "^5.0.1",60 "write-file-atomic": "^5.0.1",
62 "ws": "^8.17.1",61 "ws": "^8.17.1",
63 "yaml": "^2.3.4",62 "yaml": "^2.3.4",
server.js+1 -5
@@ -627,10 +627,6 @@ const tavernUrl = new URL(
627 (':' + server_port),627 (':' + server_port),
628);628);
629629
630function prepareFrontendBundle() {
631 return new Promise((resolve) => webpackMiddleware.waitUntilValid(resolve));
632}
633
634/**630/**
635 * Tasks that need to be run before the server starts listening.631 * Tasks that need to be run before the server starts listening.
636 */632 */
@@ -682,7 +678,7 @@ const preSetupTasks = async function () {
682 initRequestProxy({ enabled: proxyEnabled, url: proxyUrl, bypass: proxyBypass });678 initRequestProxy({ enabled: proxyEnabled, url: proxyUrl, bypass: proxyBypass });
683679
684 // Wait for frontend libs to compile680 // Wait for frontend libs to compile
685 await prepareFrontendBundle();681 await webpackMiddleware.runWebpackCompiler();
686};682};
687683
688/**684/**
src/middleware/webpack-serve.js+34 -5
@@ -1,10 +1,11 @@
1import process from 'node:process';1import process from 'node:process';
2import fs from 'node:fs';2import path from 'node:path';
3import webpack from 'webpack';3import webpack from 'webpack';
4import middleware from 'webpack-dev-middleware';
5import { publicLibConfig } from '../../webpack.config.js';4import { publicLibConfig } from '../../webpack.config.js';
65
7export default function getWebpackServeMiddleware() {6export default function getWebpackServeMiddleware() {
7 const outputPath = publicLibConfig.output?.path;
8 const outputFile = publicLibConfig.output?.filename;
8 const compiler = webpack(publicLibConfig);9 const compiler = webpack(publicLibConfig);
910
10 if (process.env.NODE_ENV === 'production' || process.platform === 'android') {11 if (process.env.NODE_ENV === 'production' || process.platform === 'android') {
@@ -17,8 +18,36 @@ export default function getWebpackServeMiddleware() {
17 });18 });
18 }19 }
1920
20 return middleware(compiler, {21 /**
21 // @ts-ignore Use actual file system to ease on heap memory usage22 * A very spartan recreation of webpack-dev-middleware.
22 outputFileSystem: fs,23 * @param {import('express').Request} req Request object.
24 * @param {import('express').Response} res Response object.
25 * @param {import('express').NextFunction} next Next function.
26 * @type {import('express').RequestHandler}
27 */
28 async function devMiddleware(req, res, next) {
29 if (req.method === 'GET' && path.parse(req.path).base === outputFile) {
30 return res.sendFile(outputFile, { root: outputPath });
31 }
32
33 next();
34 }
35
36 /**
37 * Wait until Webpack is done compiling.
38 * @returns {Promise<void>}
39 */
40 devMiddleware.runWebpackCompiler = () => {
41 return new Promise((resolve) => {
42 compiler.run((_error, stats) => {
43 const output = stats?.toString(publicLibConfig.stats);
44 if (output) {
45 console.log(output);
46 }
47 resolve();
48 });
23 });49 });
50 };
51
52 return devMiddleware;
24}53}
webpack.config.js+4 -0
@@ -8,6 +8,8 @@ export const publicLibConfig = {
8 cache: {8 cache: {
9 type: 'filesystem',9 type: 'filesystem',
10 cacheDirectory: path.resolve(process.cwd(), 'dist/webpack'),10 cacheDirectory: path.resolve(process.cwd(), 'dist/webpack'),
11 store: 'pack',
12 compression: 'gzip',
11 },13 },
12 devtool: false,14 devtool: false,
13 watch: false,15 watch: false,
@@ -16,6 +18,8 @@ export const publicLibConfig = {
16 preset: 'minimal',18 preset: 'minimal',
17 assets: false,19 assets: false,
18 modules: false,20 modules: false,
21 colors: true,
22 timings: true,
19 },23 },
20 experiments: {24 experiments: {
21 outputModule: true,25 outputModule: true,