arui-scripts 20.0.0 → 20.2.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.
@@ -5,19 +5,20 @@ ts-jest[versions] (WARN) Version 29.7.0 of jest installed has not been tested wi
5
5
  ts-jest[versions] (WARN) Version 5.6.3 of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=4.3.0 <5.0.0-0). Please do not report issues in ts-jest if you are using unsupported versions.
6
6
  ts-jest[versions] (WARN) Version 5.6.3 of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=4.3.0 <5.0.0-0). Please do not report issues in ts-jest if you are using unsupported versions.
7
7
  ts-jest[versions] (WARN) Version 5.6.3 of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=4.3.0 <5.0.0-0). Please do not report issues in ts-jest if you are using unsupported versions.
8
- PASS src/plugins/postcss-global-variables/utils/__tests__/add-global-variable.tests.ts (26.801 s)
9
- PASS src/configs/app-configs/__tests__/update-with-presets.tests.ts (26.854 s)
8
+ PASS src/plugins/postcss-global-variables/utils/__tests__/add-global-variable.tests.ts (28.142 s)
9
+ PASS src/configs/app-configs/__tests__/update-with-presets.tests.ts (28.023 s)
10
10
  PASS src/configs/util/__tests__/apply-overrides.tests.ts
11
11
  PASS src/configs/app-configs/__tests__/update-with-package.tests.ts
12
12
  PASS src/configs/app-configs/__tests__/update-with-env.tests.ts
13
+ PASS src/configs/util/__tests__/compress-with-dcb.test.ts
13
14
  PASS src/configs/util/__tests__/get-polyfills.tests.ts
14
15
  PASS src/plugins/postcss-global-variables/utils/__tests__/parse-variables.tests.ts
15
16
  PASS src/plugins/postcss-global-variables/utils/__tests__/get-media-query-name.tests.ts
16
17
  PASS src/configs/app-configs/__tests__/validate-settings-keys.tests.ts
17
- PASS src/configs/util/__tests__/find-plugin.tests.ts (29.103 s)
18
+ PASS src/configs/util/__tests__/find-plugin.tests.ts (30.762 s)
18
19
 
19
- Test Suites: 10 passed, 10 total
20
- Tests: 24 passed, 24 total
20
+ Test Suites: 11 passed, 11 total
21
+ Tests: 25 passed, 25 total
21
22
  Snapshots: 0 total
22
- Time: 30.177 s
23
+ Time: 31.825 s
23
24
  Ran all test suites.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # [15.3.0](https://github.com/core-ds/arui-scripts/compare/v15.2.0...v15.3.0) (2023-06-30)
2
2
 
3
+ ## 20.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#352](https://github.com/core-ds/arui-scripts/pull/352) [`bcc3155`](https://github.com/core-ds/arui-scripts/commit/bcc3155b3450bf682f7d8d653d282b749853d7af) Thanks [@heymdall-legal](https://github.com/heymdall-legal)! - Обновление rspack до версии 1.4.11. Приносит дополнительное ускорение, исправление багов.
8
+ Основные фичи описаны в релиз-ноутах к версии [1.2](https://rspack.rs/blog/announcing-1-2), [1.3](https://rspack.rs/blog/announcing-1-3) и [1.4](https://rspack.rs/blog/announcing-1-4).
9
+
10
+ Кратко:
11
+
12
+ - меньше бинарник самого rspack
13
+ - более быстрый code-splitting
14
+ - из дефолтных watch-таргетов убраны node_modules, что ускоряет как старт, так и работу в дев режиме
15
+ - меньшее использование памяти
16
+ - более быстрый парсер кода
17
+ - улучшенный алгоритм tree-shaking - более компактные бандлы
18
+ - инкрементальная сборка в дев режиме - на 30% более быстрый HMR
19
+
20
+ С полным списком изменений можно ознакомится на [странице релизов rspack](https://github.com/web-infra-dev/rspack/releases?page=1).
21
+
22
+ ### Patch Changes
23
+
24
+ - [`43a7c5c`](https://github.com/core-ds/arui-scripts/commit/43a7c5c3dff8b933a75c1eaddfc738cdbdfb9e1b) Thanks [@Heymdall](https://github.com/Heymdall)! - Сжатие с DCB теперь просто использует compression plugin. Улучшен вывод статистики по собранным файлам
25
+
26
+ ## 20.1.0
27
+
28
+ ### Minor Changes
29
+
30
+ - [#328](https://github.com/core-ds/arui-scripts/pull/328) [`4e05165`](https://github.com/core-ds/arui-scripts/commit/4e0516568276f2af67a624a4d32d422c707ed125) Thanks [@heymdall-legal](https://github.com/heymdall-legal)! - Добавлена возможность сборки dcb архивов. Добавлен новый параметр `dictionaryCompression` для настройки сборки архивов.
31
+
3
32
  ## 20.0.0
4
33
 
5
34
  ### Major Changes
File without changes
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
@@ -9,31 +18,35 @@ const build_wrapper_1 = __importDefault(require("./build-wrapper"));
9
18
  const client_assets_sizes_1 = require("../util/client-assets-sizes");
10
19
  const webpack_client_prod_1 = require("../../configs/webpack.client.prod");
11
20
  console.log(chalk_1.default.magenta('Building client...'));
12
- (0, build_wrapper_1.default)(webpack_client_prod_1.webpackClientConfig)
13
- .then(({ stats, warnings }) => {
14
- if (warnings.length) {
15
- console.log(chalk_1.default.yellow('Client compiled with warnings.\n'));
16
- console.log(warnings.join('\n\n'));
17
- console.log(`Search for the ${chalk_1.default.underline(chalk_1.default.yellow('keywords'))} to learn more about each warning.`);
18
- console.log(`To ignore, add ${chalk_1.default.cyan('// eslint-disable-next-line')} to the line before.`);
19
- }
20
- else {
21
- console.log(chalk_1.default.green('Client compiled successfully.\n'));
22
- }
23
- function printOutputSizes(webpackConfig, stats) {
24
- var _a;
25
- const sizes = (0, client_assets_sizes_1.calculateAssetsSizes)(stats, (_a = webpackConfig === null || webpackConfig === void 0 ? void 0 : webpackConfig.output) === null || _a === void 0 ? void 0 : _a.path);
26
- (0, client_assets_sizes_1.printAssetsSizes)(sizes);
27
- }
28
- if (Array.isArray(webpack_client_prod_1.webpackClientConfig)) {
29
- webpack_client_prod_1.webpackClientConfig.forEach((conf, index) => printOutputSizes(conf, stats.stats[index]));
30
- }
31
- else {
32
- printOutputSizes(webpack_client_prod_1.webpackClientConfig, stats);
33
- }
34
- })
35
- .catch((err) => {
36
- console.log(chalk_1.default.red('Failed to compile client.\n'));
37
- (0, printBuildError_1.default)(err);
38
- process.exit(1);
39
- });
21
+ function main() {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ try {
24
+ const { stats, warnings } = yield (0, build_wrapper_1.default)(webpack_client_prod_1.webpackClientConfig);
25
+ if (warnings.length) {
26
+ console.log(chalk_1.default.yellow('Client compiled with warnings.\n'));
27
+ console.log(warnings.join('\n\n'));
28
+ console.log(`Search for the ${chalk_1.default.underline(chalk_1.default.yellow('keywords'))} to learn more about each warning.`);
29
+ console.log(`To ignore, add ${chalk_1.default.cyan('// eslint-disable-next-line')} to the line before.`);
30
+ }
31
+ else {
32
+ console.log(chalk_1.default.green('Client compiled successfully.\n'));
33
+ }
34
+ function printOutputSizes(webpackConfig, stats) {
35
+ console.log(chalk_1.default.bold(`Sizes for "${webpackConfig.name || 'main'}"`));
36
+ (0, client_assets_sizes_1.printAssetsSizes)(stats);
37
+ }
38
+ if (Array.isArray(webpack_client_prod_1.webpackClientConfig)) {
39
+ webpack_client_prod_1.webpackClientConfig.forEach((conf, index) => printOutputSizes(conf, stats.stats[index]));
40
+ }
41
+ else {
42
+ printOutputSizes(webpack_client_prod_1.webpackClientConfig, stats);
43
+ }
44
+ }
45
+ catch (err) {
46
+ console.log(chalk_1.default.red('Failed to compile client.\n'));
47
+ (0, printBuildError_1.default)(err);
48
+ process.exit(1);
49
+ }
50
+ });
51
+ }
52
+ main();
@@ -1,26 +1,2 @@
1
1
  import { Stats } from '@rspack/core';
2
- type AssetSize = {
3
- name: string;
4
- fullName: string;
5
- gzipSize: number;
6
- brotliSize: number;
7
- size: number;
8
- sizeLabel: string;
9
- gzipLabel: string;
10
- brotliLabel: string;
11
- };
12
- type TotalSizes = {
13
- size: number;
14
- sizeLabel: string;
15
- gzipSize: number;
16
- gzipLabel: string;
17
- brotliSize: number;
18
- brotliLabel: string;
19
- };
20
- type ClientAssetsSizes = {
21
- totalSizes: TotalSizes;
22
- assets: AssetSize[];
23
- };
24
- export declare function calculateAssetsSizes(webpackStats: Stats, rootDir?: string): ClientAssetsSizes;
25
- export declare function printAssetsSizes(sizes: ClientAssetsSizes): void;
26
- export {};
2
+ export declare function printAssetsSizes(webpackStats: Stats): void;
@@ -3,79 +3,67 @@ 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.calculateAssetsSizes = calculateAssetsSizes;
7
6
  exports.printAssetsSizes = printAssetsSizes;
8
- const fs_1 = __importDefault(require("fs"));
9
7
  const path_1 = __importDefault(require("path"));
10
8
  const chalk_1 = __importDefault(require("chalk"));
11
9
  const filesize_1 = __importDefault(require("filesize"));
12
- const gzip_size_1 = require("gzip-size");
13
- const strip_ansi_1 = __importDefault(require("strip-ansi"));
14
- let brotliSize = () => NaN;
15
- try {
16
- // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
17
- brotliSize = require('brotli-size').sync;
18
- }
19
- catch (error) {
20
- // empty error
21
- }
22
- function canReadAsset(asset) {
23
- return (/\.(js|css)$/.test(asset) &&
24
- !/service-worker\.js/.test(asset) &&
25
- !/precache-manifest\.[0-9a-f]+\.js/.test(asset));
26
- }
10
+ const app_configs_1 = require("../../configs/app-configs");
27
11
  function removeFileNameHash(fileName) {
28
- return fileName
12
+ const parts = fileName
29
13
  .replace(/\\/g, '/')
30
- .replace(/\/?(.*)(\.[0-9a-f]+)(\.chunk)?(\.js|\.css)/, (match, p1, p2, p3, p4) => p1 + p4);
14
+ .split('.');
15
+ const id = parts[0];
16
+ const isChunk = fileName.includes('.chunk.');
17
+ const extension = parts.find(p => ['js', 'css'].includes(p));
18
+ return `${id}${isChunk ? '.chunk' : ''}.${extension}`;
31
19
  }
32
- function calculateAssetsSizes(webpackStats, rootDir = '') {
20
+ function printAssetsSizes(webpackStats) {
33
21
  const assetsStats = webpackStats.toJson({ all: false, assets: true }).assets || [];
34
- const assets = assetsStats
35
- .filter((asset) => canReadAsset(asset.name))
36
- .map((asset) => {
37
- const fileContents = fs_1.default.readFileSync(path_1.default.join(rootDir, asset.name));
38
- const size = (0, gzip_size_1.sync)(fileContents);
39
- const brSize = brotliSize(fileContents);
40
- const filename = path_1.default.basename(asset.name);
41
- return {
42
- name: removeFileNameHash(filename),
43
- fullName: filename,
44
- gzipSize: size,
45
- brotliSize: brSize,
46
- size: asset.size,
47
- sizeLabel: (0, filesize_1.default)(asset.size),
48
- gzipLabel: (0, filesize_1.default)(size),
49
- brotliLabel: brSize ? (0, filesize_1.default)(brSize) : '-',
50
- };
22
+ const assetsMap = {};
23
+ const statExtensions = ['js', 'css', 'br', 'gz', 'dcb'];
24
+ assetsStats.forEach((asset) => {
25
+ if (asset.type !== 'asset') {
26
+ return;
27
+ }
28
+ const extension = path_1.default.parse(asset.name).ext.substring(1);
29
+ if (!statExtensions.includes(extension) || asset.name.endsWith('.dict.br')) {
30
+ return;
31
+ }
32
+ const assetName = removeFileNameHash(asset.name);
33
+ if (!assetsMap[assetName]) {
34
+ assetsMap[assetName] = {};
35
+ }
36
+ if (extension === 'js' || extension === 'css') {
37
+ assetsMap[assetName].size = asset.size;
38
+ }
39
+ if (extension === 'br') {
40
+ assetsMap[assetName].brSize = asset.size;
41
+ }
42
+ if (extension === 'gz') {
43
+ assetsMap[assetName].gzipSize = asset.size;
44
+ }
45
+ if (extension === 'dcb') {
46
+ assetsMap[assetName].dcbSize = asset.size;
47
+ }
51
48
  });
52
- const totalSizes = (assets || []).reduce((file, total) => ({
53
- size: total.size + file.size,
54
- gzipSize: total.gzipSize + file.gzipSize,
55
- brotliSize: total.brotliSize + file.brotliSize,
56
- }), { size: 0, gzipSize: 0, brotliSize: 0 });
57
- totalSizes.sizeLabel = (0, filesize_1.default)(totalSizes.size || 0);
58
- totalSizes.gzipLabel = (0, filesize_1.default)(totalSizes.gzipSize || 0);
59
- totalSizes.brotliLabel = totalSizes.brotliSize ? (0, filesize_1.default)(totalSizes.brotliSize) : '-';
60
- return {
61
- totalSizes: totalSizes,
62
- assets,
49
+ const totalSizes = {
50
+ size: 0,
51
+ gzipSize: 0,
52
+ brSize: 0,
53
+ dcbSize: 0,
63
54
  };
64
- }
65
- function printAssetsSizes(sizes) {
66
- const longestSizeLabelLength = Math.max.apply(null, sizes.assets.map((a) => {
67
- const sizeLength = (0, strip_ansi_1.default)(a.gzipLabel).length;
68
- return sizeLength + sizeLength + 8;
69
- }));
70
55
  console.log(chalk_1.default.blueBright('Assets sizes:'));
71
- sizes.assets.forEach((asset) => {
72
- let sizeLabel = `${asset.sizeLabel} (${asset.gzipLabel} gzip, ${asset.brotliLabel} br)`;
73
- const sizeLength = (0, strip_ansi_1.default)(sizeLabel).length;
74
- if (sizeLength < longestSizeLabelLength) {
75
- const rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength);
76
- sizeLabel += rightPadding;
77
- }
78
- console.log(` ${sizeLabel} ${chalk_1.default.cyan(asset.name)}`);
56
+ Object.keys(assetsMap).forEach((assetName) => {
57
+ const asset = assetsMap[assetName];
58
+ const size = asset.size || 0;
59
+ const gzipSize = asset.brSize || size;
60
+ const brSize = asset.brSize || gzipSize;
61
+ const dcbSize = asset.dcbSize || brSize;
62
+ totalSizes.size += size;
63
+ totalSizes.gzipSize += gzipSize;
64
+ totalSizes.brSize += brSize;
65
+ totalSizes.dcbSize += dcbSize;
66
+ console.log(` ${(0, filesize_1.default)(size)} (${(0, filesize_1.default)(gzipSize)} gzip, ${(0, filesize_1.default)(brSize)} br${app_configs_1.configs.dictionaryCompression.dictionaryPath.length > 0 ? `, ${(0, filesize_1.default)(dcbSize)} dcb` : ''}) ${chalk_1.default.cyan(assetName)}`);
79
67
  });
80
- console.log(`${chalk_1.default.blueBright('\nTotal size:\n')} ${sizes.totalSizes.sizeLabel} (${sizes.totalSizes.gzipLabel} gzip, ${sizes.totalSizes.brotliLabel} br)\n`);
68
+ console.log(`${chalk_1.default.blueBright('\nTotal size:\n')} ${(0, filesize_1.default)(totalSizes.size)} (${(0, filesize_1.default)(totalSizes.gzipSize)} gzip, ${(0, filesize_1.default)(totalSizes.brSize)} br${app_configs_1.configs.dictionaryCompression.dictionaryPath.length > 0 ? `, ${(0, filesize_1.default)(totalSizes.dcbSize)} dcb` : ''})\n`);
81
69
  }
@@ -34,5 +34,23 @@ function calculateDependentContext(config, context) {
34
34
  // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
35
35
  babelRuntimeVersion = require('@babel/runtime/package.json').version;
36
36
  }
37
- return Object.assign(Object.assign({}, context), { publicPath: `${config.assetsPath}/`, serverOutputPath: path_1.default.resolve(context.cwd, config.buildPath), clientOutputPath: path_1.default.resolve(context.cwd, config.buildPath, config.assetsPath), statsOutputPath: path_1.default.resolve(context.cwd, config.buildPath, config.statsOutputFilename), watchIgnorePath: ['node_modules', config.buildPath], babelRuntimeVersion });
37
+ const allDictionaryPath = config.dictionaryCompression.dictionaryPath
38
+ .map((p) => {
39
+ if (!path_1.default.isAbsolute(p)) {
40
+ return path_1.default.join(process.cwd(), p);
41
+ }
42
+ return p;
43
+ });
44
+ const singleFilesDictionaries = [];
45
+ const previousVersionPath = [];
46
+ allDictionaryPath.forEach((p) => {
47
+ const statResult = fs_1.default.statSync(p);
48
+ if (statResult.isFile()) {
49
+ singleFilesDictionaries.push(p);
50
+ }
51
+ else {
52
+ previousVersionPath.push(p);
53
+ }
54
+ });
55
+ return Object.assign(Object.assign({}, context), { publicPath: `${config.assetsPath}/`, serverOutputPath: path_1.default.resolve(context.cwd, config.buildPath), clientOutputPath: path_1.default.resolve(context.cwd, config.buildPath, config.assetsPath), statsOutputPath: path_1.default.resolve(context.cwd, config.buildPath, config.statsOutputFilename), watchIgnorePath: ['node_modules', config.buildPath], babelRuntimeVersion, compressionPredefinedDictionaryPath: singleFilesDictionaries, compressionPreviousVersionPath: previousVersionPath });
38
56
  }
@@ -47,6 +47,10 @@ function getDefaultAppConfig() {
47
47
  removeDevDependenciesDuringDockerBuild: true,
48
48
  // archive compilation configs
49
49
  archiveName: 'build.tar',
50
+ dictionaryCompression: {
51
+ dictionaryPath: [],
52
+ enablePreviousVersionHeaders: false,
53
+ },
50
54
  // build tuning
51
55
  keepPropTypes: false,
52
56
  codeLoader: 'swc',
@@ -135,5 +139,7 @@ function getDefaultAppContext() {
135
139
  changelogFeaturesPath: path_1.default.resolve(CWD, './changelog_features.tmp'),
136
140
  changelogBugfixesPath: path_1.default.resolve(CWD, './changelog_bugfixes.tmp'),
137
141
  changelogBreakingChangesPath: path_1.default.resolve(CWD, './changelog_breaking_changes.tmp'),
142
+ compressionPredefinedDictionaryPath: [],
143
+ compressionPreviousVersionPath: [],
138
144
  };
139
145
  }
@@ -34,6 +34,10 @@ export type AppConfigs = {
34
34
  runFromNonRootUser: boolean;
35
35
  removeDevDependenciesDuringDockerBuild: boolean;
36
36
  archiveName: string;
37
+ dictionaryCompression: {
38
+ dictionaryPath: string[];
39
+ enablePreviousVersionHeaders?: boolean;
40
+ };
37
41
  keepPropTypes: boolean;
38
42
  codeLoader: 'babel' | 'tsc' | 'swc';
39
43
  installServerSourceMaps: boolean;
@@ -121,6 +125,8 @@ export type AppContext = {
121
125
  changelogFeaturesPath: string;
122
126
  changelogBugfixesPath: string;
123
127
  changelogBreakingChangesPath: string;
128
+ compressionPreviousVersionPath: string[];
129
+ compressionPredefinedDictionaryPath: string[];
124
130
  };
125
131
  export type AppContextWithConfigs = AppContext & AppConfigs;
126
132
  export type PackageSettings = Partial<AppConfigs>;
@@ -1 +1,2 @@
1
- export declare const devServerConfig: import("webpack-dev-server").Configuration;
1
+ import { Configuration } from '@rspack/dev-server';
2
+ export declare const devServerConfig: Configuration;
@@ -1,6 +1,6 @@
1
1
  import type * as rspack from '@rspack/core';
2
+ import type { Configuration as RspackDevServerConfiguration } from '@rspack/dev-server';
2
3
  import type { Options as SwcOptions } from '@swc/core';
3
- import type { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server';
4
4
  import { AppContextWithConfigs } from '../app-configs/types';
5
5
  import { createSingleClientWebpackConfig } from '../webpack.client';
6
6
  import { findLoader } from './find-loader';
@@ -15,7 +15,7 @@ type Overrides = {
15
15
  webpackProd: rspack.Configuration;
16
16
  webpackClientProd: rspack.Configuration | rspack.Configuration[];
17
17
  webpackServerProd: rspack.Configuration;
18
- devServer: WebpackDevServerConfiguration;
18
+ devServer: RspackDevServerConfiguration;
19
19
  stats: rspack.RspackOptionsNormalized['stats'];
20
20
  babel: any;
21
21
  babelClient: any;
@@ -0,0 +1,2 @@
1
+ import { Buffer } from 'buffer';
2
+ export declare function compressWithDcb(inputFile: Buffer, dictionaryData: Buffer): Promise<Buffer>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.compressWithDcb = compressWithDcb;
16
+ const buffer_1 = require("buffer");
17
+ const crypto_1 = __importDefault(require("crypto"));
18
+ const brotli_dict_1 = require("brotli-dict");
19
+ function compressWithDcb(inputFile, dictionaryData) {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ const magicNumberHeader = buffer_1.Buffer.from([0xff, 0x44, 0x43, 0x42]);
22
+ const dictionaryHash = crypto_1.default.createHash('sha256').update(dictionaryData).digest();
23
+ const compressedData = yield (0, brotli_dict_1.compress)(inputFile, {
24
+ dictionary: dictionaryData,
25
+ });
26
+ return buffer_1.Buffer.concat([
27
+ magicNumberHeader,
28
+ dictionaryHash,
29
+ buffer_1.Buffer.from(compressedData),
30
+ ]);
31
+ });
32
+ }
@@ -0,0 +1,2 @@
1
+ import { CustomCompressionPlugin } from './dcb-compression-plugin';
2
+ export declare function compressionPluginsForDictionaries(): CustomCompressionPlugin[];
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.compressionPluginsForDictionaries = compressionPluginsForDictionaries;
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const app_configs_1 = require("../app-configs");
19
+ const compress_with_dcb_1 = require("./compress-with-dcb");
20
+ const dcb_compression_plugin_1 = require("./dcb-compression-plugin");
21
+ function compressionPluginsForDictionaries() {
22
+ const predefinedPlugins = app_configs_1.configs.compressionPredefinedDictionaryPath.map((dictionaryPath) => {
23
+ const dictionaryName = path_1.default.parse(dictionaryPath).name;
24
+ const dictionaryContent = fs_1.default.readFileSync(dictionaryPath, null);
25
+ return new dcb_compression_plugin_1.CustomCompressionPlugin({
26
+ test: /\.js$|\.css$/,
27
+ filename: ({ filename }) => `${filename}.${dictionaryName}.dcb`,
28
+ algorithm: (input) => (0, compress_with_dcb_1.compressWithDcb)(input, dictionaryContent),
29
+ threshold: 10240,
30
+ minRatio: 0.8,
31
+ });
32
+ });
33
+ const prevVersionPlugins = app_configs_1.configs.compressionPreviousVersionPath.map((dictionaryPath) => {
34
+ const dictionaries = fs_1.default.readdirSync(dictionaryPath);
35
+ const parsedDictionaries = dictionaries.reduce((map, current) => {
36
+ const parsed = parseFilename(current);
37
+ return (Object.assign(Object.assign({}, map), { [`${parsed.stableName}.${parsed.ext}`]: parsed }));
38
+ }, {});
39
+ return new dcb_compression_plugin_1.CustomCompressionPlugin({
40
+ test: /\.js$|\.css$/,
41
+ threshold: 10240,
42
+ minRatio: 0.8,
43
+ filename: (pathData) => {
44
+ const parsedFilename = parseFilename(pathData.filename || '');
45
+ const matchedDictionary = parsedDictionaries[`${parsedFilename.stableName}.${parsedFilename.ext}`];
46
+ if (!matchedDictionary) {
47
+ return '';
48
+ }
49
+ return `${parsedFilename.filename}.${matchedDictionary.hash}.dcb`;
50
+ },
51
+ algorithm: (input_1, _a) => __awaiter(this, [input_1, _a], void 0, function* (input, { filename }) {
52
+ const parsedFilename = parseFilename(filename);
53
+ const matchedDictionary = parsedDictionaries[`${parsedFilename.stableName}.${parsedFilename.ext}`];
54
+ if (!matchedDictionary) {
55
+ return input;
56
+ }
57
+ try {
58
+ const dictionaryContent = fs_1.default.readFileSync(path_1.default.join(dictionaryPath, matchedDictionary.filename), null);
59
+ return yield (0, compress_with_dcb_1.compressWithDcb)(input, dictionaryContent);
60
+ }
61
+ catch (e) {
62
+ return input;
63
+ }
64
+ })
65
+ });
66
+ });
67
+ return [
68
+ ...predefinedPlugins,
69
+ ...prevVersionPlugins,
70
+ ];
71
+ }
72
+ function parseFilename(filename) {
73
+ const parsedName = path_1.default.parse(filename);
74
+ const [stableName, hash] = parsedName.name.split('.');
75
+ return {
76
+ stableName,
77
+ hash,
78
+ ext: parsedName.ext.substring(1),
79
+ filename,
80
+ };
81
+ }
@@ -0,0 +1,22 @@
1
+ import { Assets, Compilation, Compiler } from '@rspack/core';
2
+ import { PathData } from '@rspack/core/dist/Compilation';
3
+ import { Rules } from 'compression-webpack-plugin';
4
+ type DcbCompressionOptions = {
5
+ test?: Rules;
6
+ include?: Rules;
7
+ exclude?: Rules;
8
+ algorithm: (input: Buffer, options: {
9
+ filename: string;
10
+ }) => Promise<Buffer>;
11
+ filename: (pathdata: PathData) => string;
12
+ threshold: number;
13
+ minRatio: number;
14
+ };
15
+ export declare class CustomCompressionPlugin {
16
+ protected options: DcbCompressionOptions;
17
+ constructor(options: DcbCompressionOptions);
18
+ runCompressionAlgorithm(input: Buffer, filename: string): Promise<Buffer>;
19
+ compress(compiler: Compiler, compilation: Compilation, assets: Assets): Promise<void>;
20
+ apply(compiler: Compiler): void;
21
+ }
22
+ export {};