@gravity-ui/app-builder 0.28.1-beta.0 → 0.28.1-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/commands/build/build-service/server.js +40 -0
- package/dist/commands/dev/index.js +7 -85
- package/dist/commands/dev/server.js +58 -26
- package/dist/common/config.js +1 -0
- package/dist/common/models/index.d.ts +8 -1
- package/dist/common/swc/compile.d.ts +9 -0
- package/dist/common/swc/compile.js +73 -0
- package/dist/common/swc/index.d.ts +2 -0
- package/dist/common/swc/index.js +7 -0
- package/dist/common/swc/watch.d.ts +10 -0
- package/dist/common/swc/watch.js +68 -0
- package/package.json +2 -4
- package/dist/commands/dev/ui/LogCollector.d.ts +0 -13
- package/dist/commands/dev/ui/LogCollector.js +0 -89
- package/dist/commands/dev/ui/TerminalTabs.d.ts +0 -25
- package/dist/commands/dev/ui/TerminalTabs.js +0 -183
- package/dist/commands/dev/ui/demo.d.ts +0 -2
- package/dist/commands/dev/ui/demo.js +0 -61
package/README.md
CHANGED
|
@@ -143,6 +143,8 @@ All server settings are used only in dev mode:
|
|
|
143
143
|
- `watchThrottle` (`number`) — use to add an extra throttle, or delay restarting.
|
|
144
144
|
- `inspect/inspectBrk` (`number | true`) — listen for a debugging client on specified port.
|
|
145
145
|
If specified `true`, try to listen on `9229`.
|
|
146
|
+
- `compiler` (`'typescript' | 'swc'`) — choose TypeScript compiler for server code compilation.
|
|
147
|
+
Default is `'typescript'`. Set to `'swc'` for faster compilation with SWC.
|
|
146
148
|
|
|
147
149
|
### Client
|
|
148
150
|
|
|
@@ -1,15 +1,55 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.buildServer = buildServer;
|
|
30
|
+
const path = __importStar(require("node:path"));
|
|
7
31
|
const signal_exit_1 = require("signal-exit");
|
|
8
32
|
const controllable_script_1 = require("../../../common/child-process/controllable-script");
|
|
33
|
+
const logger_1 = require("../../../common/logger");
|
|
9
34
|
const paths_1 = __importDefault(require("../../../common/paths"));
|
|
10
35
|
const utils_1 = require("../../../common/utils");
|
|
36
|
+
const swc = __importStar(require("../../../common/swc"));
|
|
11
37
|
function buildServer(config) {
|
|
12
38
|
(0, utils_1.createRunFolder)();
|
|
39
|
+
if (config.server.compiler === 'swc') {
|
|
40
|
+
// Используем SWC для компиляции
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const logger = new logger_1.Logger('server', config.verbose);
|
|
43
|
+
const serverPath = path.resolve(paths_1.default.appDist, 'server');
|
|
44
|
+
swc.compile({
|
|
45
|
+
projectPath: paths_1.default.appServer,
|
|
46
|
+
outputPath: serverPath,
|
|
47
|
+
logger,
|
|
48
|
+
enableSourceMap: false,
|
|
49
|
+
}).then(() => resolve(), (error) => reject(new Error(`SWC compilation failed: ${error}`)));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Используем TypeScript для компиляции (по умолчанию)
|
|
13
53
|
return new Promise((resolve, reject) => {
|
|
14
54
|
const build = new controllable_script_1.ControllableScript(`
|
|
15
55
|
let ts;
|
|
@@ -34,70 +34,8 @@ const rimraf_1 = require("rimraf");
|
|
|
34
34
|
const utils_1 = require("../../common/utils");
|
|
35
35
|
const logger_1 = __importDefault(require("../../common/logger"));
|
|
36
36
|
const paths_1 = __importDefault(require("../../common/paths"));
|
|
37
|
-
// Импортируем систему табов для логирования
|
|
38
|
-
const TerminalTabs_1 = require("./ui/TerminalTabs");
|
|
39
|
-
// Глобальная система табов
|
|
40
|
-
let terminalTabs;
|
|
41
|
-
// Функция для добавления лога в систему табов
|
|
42
|
-
function addLogToTabs(type, message, level = 'message') {
|
|
43
|
-
if (terminalTabs && process.stdout.isTTY) {
|
|
44
|
-
terminalTabs.addLog({
|
|
45
|
-
type,
|
|
46
|
-
message,
|
|
47
|
-
timestamp: Date.now(),
|
|
48
|
-
level,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// Обёртка для logger с интеграцией в табы
|
|
53
|
-
function createLoggerWrapper(type) {
|
|
54
|
-
return {
|
|
55
|
-
message: (...args) => {
|
|
56
|
-
const message = args.join(' ');
|
|
57
|
-
addLogToTabs(type, message, 'message');
|
|
58
|
-
if (!process.stdout.isTTY) {
|
|
59
|
-
logger_1.default.message(`[${type}]`, message);
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
success: (...args) => {
|
|
63
|
-
const message = args.join(' ');
|
|
64
|
-
addLogToTabs(type, message, 'success');
|
|
65
|
-
if (!process.stdout.isTTY) {
|
|
66
|
-
logger_1.default.success(`[${type}]`, message);
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
warning: (...args) => {
|
|
70
|
-
const message = args.join(' ');
|
|
71
|
-
addLogToTabs(type, message, 'warning');
|
|
72
|
-
if (!process.stdout.isTTY) {
|
|
73
|
-
logger_1.default.warning(`[${type}]`, message);
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
error: (...args) => {
|
|
77
|
-
const message = args.join(' ');
|
|
78
|
-
addLogToTabs(type, message, 'error');
|
|
79
|
-
if (!process.stdout.isTTY) {
|
|
80
|
-
logger_1.default.error(`[${type}]`, message);
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
verbose: (...args) => {
|
|
84
|
-
const message = args.join(' ');
|
|
85
|
-
addLogToTabs(type, message, 'verbose');
|
|
86
|
-
if (!process.stdout.isTTY) {
|
|
87
|
-
logger_1.default.verbose(`[${type}]`, message);
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
37
|
async function default_1(config) {
|
|
93
38
|
process.env.NODE_ENV = 'development';
|
|
94
|
-
// Инициализируем систему табов только в TTY
|
|
95
|
-
if (process.stdout.isTTY) {
|
|
96
|
-
terminalTabs = new TerminalTabs_1.TerminalTabs();
|
|
97
|
-
terminalTabs.initialize();
|
|
98
|
-
// Добавляем начальный лог
|
|
99
|
-
addLogToTabs('all', 'Запуск режима разработки...', 'message');
|
|
100
|
-
}
|
|
101
39
|
const shouldCompileClient = (0, utils_1.shouldCompileTarget)(config.target, 'client');
|
|
102
40
|
const shouldCompileServer = (0, utils_1.shouldCompileTarget)(config.target, 'server');
|
|
103
41
|
if (shouldCompileClient && shouldCompileServer) {
|
|
@@ -110,8 +48,7 @@ async function default_1(config) {
|
|
|
110
48
|
const { inspect, inspectBrk } = config.server;
|
|
111
49
|
const startNodemon = () => {
|
|
112
50
|
if (needToStartNodemon && serverCompiled && clientCompiled) {
|
|
113
|
-
|
|
114
|
-
serverLogger.message('Starting application at', serverPath);
|
|
51
|
+
logger_1.default.message('Starting application at', serverPath);
|
|
115
52
|
const nodeArgs = ['--enable-source-maps'];
|
|
116
53
|
if (inspect || inspectBrk) {
|
|
117
54
|
nodeArgs.push(`--${inspect ? 'inspect' : 'inspect-brk'}=:::${inspect || inspectBrk}`);
|
|
@@ -140,8 +77,6 @@ async function default_1(config) {
|
|
|
140
77
|
serverCompilation.onMessage((msg) => {
|
|
141
78
|
if (typeof msg === 'object' && 'type' in msg && msg.type === 'Emitted') {
|
|
142
79
|
serverCompiled = true;
|
|
143
|
-
const serverLogger = createLoggerWrapper('server');
|
|
144
|
-
serverLogger.success('Server compilation completed');
|
|
145
80
|
startNodemon();
|
|
146
81
|
}
|
|
147
82
|
});
|
|
@@ -150,38 +85,25 @@ async function default_1(config) {
|
|
|
150
85
|
if (shouldCompileClient) {
|
|
151
86
|
const { watchClientCompilation } = await import('./client.js');
|
|
152
87
|
clientCompilation = await watchClientCompilation(config, () => {
|
|
153
|
-
|
|
154
|
-
clientLogger.success('Manifest was compiled successfully');
|
|
88
|
+
logger_1.default.success('Manifest was compiled successfully');
|
|
155
89
|
clientCompiled = true;
|
|
156
90
|
startNodemon();
|
|
157
91
|
});
|
|
158
92
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
terminalTabs.destroy();
|
|
162
|
-
}
|
|
93
|
+
process.on('SIGINT', async () => {
|
|
94
|
+
logger_1.default.success('\nCleaning up...');
|
|
163
95
|
await serverCompilation?.stop('SIGINT');
|
|
164
96
|
await clientCompilation?.stop();
|
|
165
|
-
};
|
|
166
|
-
process.on('SIGINT', async () => {
|
|
167
|
-
if (!process.stdout.isTTY) {
|
|
168
|
-
logger_1.default.success('\nCleaning up...');
|
|
169
|
-
}
|
|
170
|
-
await cleanup();
|
|
171
97
|
process.exit(1);
|
|
172
98
|
});
|
|
173
99
|
process.on('SIGTERM', async () => {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
await cleanup();
|
|
100
|
+
logger_1.default.success('\nCleaning up...');
|
|
101
|
+
await serverCompilation?.stop('SIGTERM');
|
|
102
|
+
await clientCompilation?.stop();
|
|
178
103
|
process.exit(1);
|
|
179
104
|
});
|
|
180
105
|
(0, signal_exit_1.onExit)((_code, signal) => {
|
|
181
106
|
serverCompilation?.stop(signal);
|
|
182
107
|
clientCompilation?.stop();
|
|
183
|
-
if (terminalTabs) {
|
|
184
|
-
terminalTabs.destroy();
|
|
185
|
-
}
|
|
186
108
|
});
|
|
187
109
|
}
|
|
@@ -32,36 +32,68 @@ const rimraf_1 = require("rimraf");
|
|
|
32
32
|
const controllable_script_1 = require("../../common/child-process/controllable-script");
|
|
33
33
|
const utils_1 = require("../../common/utils");
|
|
34
34
|
const paths_1 = __importDefault(require("../../common/paths"));
|
|
35
|
+
function createTypescriptBuildScript(config) {
|
|
36
|
+
return `
|
|
37
|
+
let ts;
|
|
38
|
+
try {
|
|
39
|
+
ts = require('typescript');
|
|
40
|
+
} catch (e) {
|
|
41
|
+
if (e.code !== 'MODULE_NOT_FOUND') {
|
|
42
|
+
throw e;
|
|
43
|
+
}
|
|
44
|
+
ts = require(${JSON.stringify(require.resolve('typescript'))});
|
|
45
|
+
}
|
|
46
|
+
const {Logger} = require(${JSON.stringify(require.resolve('../../common/logger'))});
|
|
47
|
+
const {watch} = require(${JSON.stringify(require.resolve('../../common/typescript/watch'))});
|
|
48
|
+
|
|
49
|
+
const logger = new Logger('server', ${config.verbose});
|
|
50
|
+
watch(
|
|
51
|
+
ts,
|
|
52
|
+
${JSON.stringify(paths_1.default.appServer)},
|
|
53
|
+
{
|
|
54
|
+
logger,
|
|
55
|
+
onAfterFilesEmitted: () => {
|
|
56
|
+
process.send({type: 'Emitted'});
|
|
57
|
+
},
|
|
58
|
+
enableSourceMap: true
|
|
59
|
+
}
|
|
60
|
+
);`;
|
|
61
|
+
}
|
|
62
|
+
function createSWCBuildScript(config) {
|
|
63
|
+
return `
|
|
64
|
+
let swcCli;
|
|
65
|
+
try {
|
|
66
|
+
swcCli = require('@swc/cli');
|
|
67
|
+
} catch (e) {
|
|
68
|
+
if (e.code !== 'MODULE_NOT_FOUND') {
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
swcCli = require(${JSON.stringify(require.resolve('@swc/cli'))});
|
|
72
|
+
}
|
|
73
|
+
const {swcDir} = swcCli;
|
|
74
|
+
const {Logger} = require(${JSON.stringify(require.resolve('../../common/logger'))});
|
|
75
|
+
const {watch} = require(${JSON.stringify(require.resolve('../../common/swc/watch'))});
|
|
76
|
+
|
|
77
|
+
const logger = new Logger('server', ${config.verbose});
|
|
78
|
+
watch(
|
|
79
|
+
swcDir,
|
|
80
|
+
${JSON.stringify(paths_1.default.appServer)},
|
|
81
|
+
{
|
|
82
|
+
logger,
|
|
83
|
+
onAfterFilesEmitted: () => {
|
|
84
|
+
process.send({type: 'Emitted'});
|
|
85
|
+
},
|
|
86
|
+
enableSourceMap: true
|
|
87
|
+
}
|
|
88
|
+
);`;
|
|
89
|
+
}
|
|
35
90
|
async function watchServerCompilation(config) {
|
|
36
91
|
const serverPath = path.resolve(paths_1.default.appDist, 'server');
|
|
37
92
|
rimraf_1.rimraf.sync(serverPath);
|
|
38
93
|
(0, utils_1.createRunFolder)();
|
|
39
|
-
const build = new controllable_script_1.ControllableScript(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
ts = require('typescript');
|
|
43
|
-
} catch (e) {
|
|
44
|
-
if (e.code !== 'MODULE_NOT_FOUND') {
|
|
45
|
-
throw e;
|
|
46
|
-
}
|
|
47
|
-
ts = require(${JSON.stringify(require.resolve('typescript'))});
|
|
48
|
-
}
|
|
49
|
-
const {Logger} = require(${JSON.stringify(require.resolve('../../common/logger'))});
|
|
50
|
-
const {watch} = require(${JSON.stringify(require.resolve('../../common/typescript/watch'))});
|
|
51
|
-
|
|
52
|
-
const logger = new Logger('server', ${config.verbose});
|
|
53
|
-
watch(
|
|
54
|
-
ts,
|
|
55
|
-
${JSON.stringify(paths_1.default.appServer)},
|
|
56
|
-
{
|
|
57
|
-
logger,
|
|
58
|
-
onAfterFilesEmitted: () => {
|
|
59
|
-
process.send({type: 'Emitted'});
|
|
60
|
-
},
|
|
61
|
-
enableSourceMap: true
|
|
62
|
-
}
|
|
63
|
-
);
|
|
64
|
-
`, null);
|
|
94
|
+
const build = new controllable_script_1.ControllableScript(config.server.compiler === 'swc'
|
|
95
|
+
? createSWCBuildScript(config)
|
|
96
|
+
: createTypescriptBuildScript(config), null);
|
|
65
97
|
await build.start();
|
|
66
98
|
return build;
|
|
67
99
|
}
|
package/dist/common/config.js
CHANGED
|
@@ -18,6 +18,7 @@ import type { TerserOptions } from 'terser-webpack-plugin';
|
|
|
18
18
|
import type { ReactRefreshPluginOptions } from '@pmmmwh/react-refresh-webpack-plugin/types/lib/types';
|
|
19
19
|
type Bundler = 'webpack' | 'rspack';
|
|
20
20
|
type JavaScriptLoader = 'babel' | 'swc';
|
|
21
|
+
type ServerCompiler = 'typescript' | 'swc';
|
|
21
22
|
export type SwcConfig = Swc.Config & Pick<Swc.Options, 'isModule'>;
|
|
22
23
|
export interface Entities<T> {
|
|
23
24
|
data: Record<string, T>;
|
|
@@ -266,6 +267,11 @@ export interface ServerConfig {
|
|
|
266
267
|
watchThrottle?: number;
|
|
267
268
|
inspect?: number | true;
|
|
268
269
|
inspectBrk?: number | true;
|
|
270
|
+
/**
|
|
271
|
+
* Compiler for server code compilation
|
|
272
|
+
* @default 'typescript'
|
|
273
|
+
*/
|
|
274
|
+
compiler?: ServerCompiler;
|
|
269
275
|
}
|
|
270
276
|
export interface ServiceConfig {
|
|
271
277
|
target?: 'client' | 'server';
|
|
@@ -306,11 +312,12 @@ export type NormalizedClientConfig = Omit<ClientConfig, 'publicPathPrefix' | 'pu
|
|
|
306
312
|
}) => SwcConfig | Promise<SwcConfig>;
|
|
307
313
|
reactRefresh: NonNullable<ClientConfig['reactRefresh']>;
|
|
308
314
|
};
|
|
309
|
-
export type NormalizedServerConfig = Omit<ServerConfig, 'port' | 'inspect' | 'inspectBrk'> & {
|
|
315
|
+
export type NormalizedServerConfig = Omit<ServerConfig, 'port' | 'inspect' | 'inspectBrk' | 'compiler'> & {
|
|
310
316
|
port?: number;
|
|
311
317
|
verbose?: boolean;
|
|
312
318
|
inspect?: number;
|
|
313
319
|
inspectBrk?: number;
|
|
320
|
+
compiler: ServerCompiler;
|
|
314
321
|
};
|
|
315
322
|
export type NormalizedServiceConfig = Omit<ServiceConfig, 'client' | 'server'> & {
|
|
316
323
|
client: NormalizedClientConfig;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Logger } from '../logger';
|
|
2
|
+
interface SwcCompileOptions {
|
|
3
|
+
projectPath: string;
|
|
4
|
+
outputPath: string;
|
|
5
|
+
logger: Logger;
|
|
6
|
+
enableSourceMap?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function compile({ projectPath, outputPath, logger, enableSourceMap, }: SwcCompileOptions): Promise<void>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compile = compile;
|
|
4
|
+
const rimraf_1 = require("rimraf");
|
|
5
|
+
// @ts-ignore - @swc/cli не имеет типов
|
|
6
|
+
const cli_1 = require("@swc/cli");
|
|
7
|
+
const pretty_time_1 = require("../logger/pretty-time");
|
|
8
|
+
async function compile({ projectPath, outputPath, logger, enableSourceMap = false, }) {
|
|
9
|
+
const start = process.hrtime.bigint();
|
|
10
|
+
logger.message('Start SWC compilation');
|
|
11
|
+
// Очищаем выходную директорию
|
|
12
|
+
rimraf_1.rimraf.sync(outputPath);
|
|
13
|
+
const swcConfig = {
|
|
14
|
+
module: {
|
|
15
|
+
type: 'commonjs',
|
|
16
|
+
},
|
|
17
|
+
jsc: {
|
|
18
|
+
parser: {
|
|
19
|
+
syntax: 'typescript',
|
|
20
|
+
tsx: true,
|
|
21
|
+
},
|
|
22
|
+
target: 'es2020',
|
|
23
|
+
transform: {
|
|
24
|
+
decoratorMetadata: true,
|
|
25
|
+
},
|
|
26
|
+
externalHelpers: false,
|
|
27
|
+
},
|
|
28
|
+
sourceMaps: enableSourceMap,
|
|
29
|
+
};
|
|
30
|
+
const cliOptions = {
|
|
31
|
+
filenames: [projectPath],
|
|
32
|
+
outDir: outputPath,
|
|
33
|
+
watch: false,
|
|
34
|
+
quiet: false,
|
|
35
|
+
sourceMaps: enableSourceMap,
|
|
36
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'],
|
|
37
|
+
stripLeadingPaths: true,
|
|
38
|
+
deleteDirOnStart: false,
|
|
39
|
+
copyFiles: false,
|
|
40
|
+
includeDotfiles: false,
|
|
41
|
+
sync: false,
|
|
42
|
+
workers: 1,
|
|
43
|
+
};
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const callbacks = {
|
|
46
|
+
onSuccess: (_result) => {
|
|
47
|
+
logger.success(`SWC compiled successfully in ${(0, pretty_time_1.elapsedTime)(start)}`);
|
|
48
|
+
resolve();
|
|
49
|
+
},
|
|
50
|
+
onFail: (result) => {
|
|
51
|
+
logger.error(`SWC compilation failed in ${result.duration}ms`);
|
|
52
|
+
if (result.reasons) {
|
|
53
|
+
for (const [filename, error] of result.reasons) {
|
|
54
|
+
logger.error(`${filename}: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
logger.error(`Error compile, elapsed time ${(0, pretty_time_1.elapsedTime)(start)}`);
|
|
58
|
+
reject(new Error('SWC compilation failed'));
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
try {
|
|
62
|
+
(0, cli_1.swcDir)({
|
|
63
|
+
cliOptions,
|
|
64
|
+
swcOptions: swcConfig,
|
|
65
|
+
callbacks,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
logger.error(`Failed to start SWC compilation: ${error}`);
|
|
70
|
+
reject(error);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.watch = exports.compile = void 0;
|
|
4
|
+
var compile_1 = require("./compile");
|
|
5
|
+
Object.defineProperty(exports, "compile", { enumerable: true, get: function () { return compile_1.compile; } });
|
|
6
|
+
var watch_1 = require("./watch");
|
|
7
|
+
Object.defineProperty(exports, "watch", { enumerable: true, get: function () { return watch_1.watch; } });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Logger } from '../logger';
|
|
2
|
+
interface SwcWatchOptions {
|
|
3
|
+
projectPath: string;
|
|
4
|
+
outputPath: string;
|
|
5
|
+
logger: Logger;
|
|
6
|
+
onAfterFilesEmitted?: () => void;
|
|
7
|
+
enableSourceMap?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function watch(swcDir: any, { projectPath, outputPath, logger, onAfterFilesEmitted, enableSourceMap, }: SwcWatchOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.watch = watch;
|
|
4
|
+
const rimraf_1 = require("rimraf");
|
|
5
|
+
const getSwcConfig = () => {
|
|
6
|
+
return {
|
|
7
|
+
jsc: {
|
|
8
|
+
target: 'es2020',
|
|
9
|
+
parser: {
|
|
10
|
+
syntax: 'typescript',
|
|
11
|
+
decorators: false,
|
|
12
|
+
dynamicImport: false,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
sourceMaps: true,
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
async function watch(
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
swcDir, { projectPath, outputPath, logger, onAfterFilesEmitted, enableSourceMap = false, }) {
|
|
21
|
+
logger.message('Start SWC compilation in watch mode');
|
|
22
|
+
// Очищаем выходную директорию
|
|
23
|
+
rimraf_1.rimraf.sync(outputPath);
|
|
24
|
+
const swcConfig = getSwcConfig();
|
|
25
|
+
const cliOptions = {
|
|
26
|
+
filenames: [projectPath],
|
|
27
|
+
outDir: outputPath,
|
|
28
|
+
watch: true,
|
|
29
|
+
quiet: false,
|
|
30
|
+
sourceMaps: enableSourceMap,
|
|
31
|
+
extensions: ['.js', '.ts', '.mjs', '.cjs'],
|
|
32
|
+
stripLeadingPaths: true,
|
|
33
|
+
deleteDirOnStart: false,
|
|
34
|
+
copyFiles: false,
|
|
35
|
+
includeDotfiles: false,
|
|
36
|
+
sync: false,
|
|
37
|
+
workers: 1,
|
|
38
|
+
logWatchCompilation: true,
|
|
39
|
+
};
|
|
40
|
+
const callbacks = {
|
|
41
|
+
onSuccess: (result) => {
|
|
42
|
+
if (result.filename) {
|
|
43
|
+
logger.verbose(`Successfully compiled ${result.filename} in ${result.duration}ms`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
logger.message(`Successfully compiled ${result.compiled || 0} files in ${result.duration}ms`);
|
|
47
|
+
}
|
|
48
|
+
onAfterFilesEmitted?.();
|
|
49
|
+
},
|
|
50
|
+
onFail: (result) => {
|
|
51
|
+
logger.error(`SWC compilation failed in ${result.duration}ms`);
|
|
52
|
+
if (result.reasons) {
|
|
53
|
+
for (const [filename, error] of result.reasons) {
|
|
54
|
+
logger.error(`${filename}: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
onWatchReady: () => {
|
|
59
|
+
logger.message('SWC watching for file changes');
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
// Запускаем swcDir
|
|
63
|
+
await swcDir({
|
|
64
|
+
cliOptions,
|
|
65
|
+
swcOptions: swcConfig,
|
|
66
|
+
callbacks,
|
|
67
|
+
});
|
|
68
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/app-builder",
|
|
3
|
-
"version": "0.28.1-beta.
|
|
3
|
+
"version": "0.28.1-beta.5",
|
|
4
4
|
"description": "Develop and build your React client-server projects, powered by typescript and webpack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -82,9 +82,9 @@
|
|
|
82
82
|
"@svgr/core": "^8.1.0",
|
|
83
83
|
"@svgr/plugin-jsx": "^8.1.0",
|
|
84
84
|
"@svgr/webpack": "^8.1.0",
|
|
85
|
+
"@swc/cli": "^0.7.8",
|
|
85
86
|
"@swc/core": "1.11.24",
|
|
86
87
|
"@swc/plugin-transform-imports": "7.0.3",
|
|
87
|
-
"@types/react": "^19.1.6",
|
|
88
88
|
"babel-loader": "^9.2.1",
|
|
89
89
|
"babel-plugin-import": "^1.13.8",
|
|
90
90
|
"babel-plugin-inline-react-svg": "^2.0.2",
|
|
@@ -108,8 +108,6 @@
|
|
|
108
108
|
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
|
109
109
|
"fs-extra": "^11.2.0",
|
|
110
110
|
"get-port": "^7.1.0",
|
|
111
|
-
"ink": "^5.2.1",
|
|
112
|
-
"keypress": "^0.2.1",
|
|
113
111
|
"mime-types": "^2.1.35",
|
|
114
112
|
"mini-css-extract-plugin": "^2.9.1",
|
|
115
113
|
"moment-timezone-data-webpack-plugin": "^1.5.1",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import { BaseLogger } from '../../../common/logger';
|
|
3
|
-
import type { LogEntry } from './TerminalTabs';
|
|
4
|
-
export declare class LogCollector extends EventEmitter {
|
|
5
|
-
private logs;
|
|
6
|
-
private maxLogs;
|
|
7
|
-
constructor(maxLogs?: number);
|
|
8
|
-
addLog(entry: LogEntry): void;
|
|
9
|
-
getLogs(): LogEntry[];
|
|
10
|
-
clear(): void;
|
|
11
|
-
createLogger(type: 'server' | 'client', namespace?: string, verbose?: boolean): BaseLogger;
|
|
12
|
-
}
|
|
13
|
-
export declare const globalLogCollector: LogCollector;
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.globalLogCollector = exports.LogCollector = void 0;
|
|
4
|
-
const events_1 = require("events");
|
|
5
|
-
const logger_1 = require("../../../common/logger");
|
|
6
|
-
class LogCollector extends events_1.EventEmitter {
|
|
7
|
-
logs = [];
|
|
8
|
-
maxLogs = 1000;
|
|
9
|
-
constructor(maxLogs = 1000) {
|
|
10
|
-
super();
|
|
11
|
-
this.maxLogs = maxLogs;
|
|
12
|
-
}
|
|
13
|
-
addLog(entry) {
|
|
14
|
-
this.logs.push(entry);
|
|
15
|
-
if (this.logs.length > this.maxLogs) {
|
|
16
|
-
this.logs = this.logs.slice(-this.maxLogs);
|
|
17
|
-
}
|
|
18
|
-
this.emit('log', entry);
|
|
19
|
-
}
|
|
20
|
-
getLogs() {
|
|
21
|
-
return [...this.logs];
|
|
22
|
-
}
|
|
23
|
-
clear() {
|
|
24
|
-
this.logs = [];
|
|
25
|
-
this.emit('clear');
|
|
26
|
-
}
|
|
27
|
-
createLogger(type, namespace, verbose = false) {
|
|
28
|
-
const logger = new logger_1.Logger(namespace, verbose);
|
|
29
|
-
// Перехватываем методы логирования
|
|
30
|
-
const originalMessage = logger.message.bind(logger);
|
|
31
|
-
const originalSuccess = logger.success.bind(logger);
|
|
32
|
-
const originalWarning = logger.warning.bind(logger);
|
|
33
|
-
const originalError = logger.error.bind(logger);
|
|
34
|
-
const originalVerbose = logger.verbose.bind(logger);
|
|
35
|
-
logger.message = (...args) => {
|
|
36
|
-
const message = args.join(' ');
|
|
37
|
-
this.addLog({
|
|
38
|
-
type,
|
|
39
|
-
message,
|
|
40
|
-
timestamp: Date.now(),
|
|
41
|
-
level: 'message',
|
|
42
|
-
});
|
|
43
|
-
return originalMessage(...args);
|
|
44
|
-
};
|
|
45
|
-
logger.success = (...args) => {
|
|
46
|
-
const message = args.join(' ');
|
|
47
|
-
this.addLog({
|
|
48
|
-
type,
|
|
49
|
-
message,
|
|
50
|
-
timestamp: Date.now(),
|
|
51
|
-
level: 'success',
|
|
52
|
-
});
|
|
53
|
-
return originalSuccess(...args);
|
|
54
|
-
};
|
|
55
|
-
logger.warning = (...args) => {
|
|
56
|
-
const message = args.join(' ');
|
|
57
|
-
this.addLog({
|
|
58
|
-
type,
|
|
59
|
-
message,
|
|
60
|
-
timestamp: Date.now(),
|
|
61
|
-
level: 'warning',
|
|
62
|
-
});
|
|
63
|
-
return originalWarning(...args);
|
|
64
|
-
};
|
|
65
|
-
logger.error = (...args) => {
|
|
66
|
-
const message = args.join(' ');
|
|
67
|
-
this.addLog({
|
|
68
|
-
type,
|
|
69
|
-
message,
|
|
70
|
-
timestamp: Date.now(),
|
|
71
|
-
level: 'error',
|
|
72
|
-
});
|
|
73
|
-
return originalError(...args);
|
|
74
|
-
};
|
|
75
|
-
logger.verbose = (...args) => {
|
|
76
|
-
const message = args.join(' ');
|
|
77
|
-
this.addLog({
|
|
78
|
-
type,
|
|
79
|
-
message,
|
|
80
|
-
timestamp: Date.now(),
|
|
81
|
-
level: 'verbose',
|
|
82
|
-
});
|
|
83
|
-
return originalVerbose(...args);
|
|
84
|
-
};
|
|
85
|
-
return logger;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
exports.LogCollector = LogCollector;
|
|
89
|
-
exports.globalLogCollector = new LogCollector();
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
export interface LogEntry {
|
|
3
|
-
type: 'server' | 'client' | 'all';
|
|
4
|
-
message: string;
|
|
5
|
-
timestamp: number;
|
|
6
|
-
level: 'message' | 'success' | 'warning' | 'error' | 'verbose';
|
|
7
|
-
}
|
|
8
|
-
export declare class TerminalTabs extends EventEmitter {
|
|
9
|
-
private logs;
|
|
10
|
-
private activeTab;
|
|
11
|
-
private maxLogs;
|
|
12
|
-
private rl;
|
|
13
|
-
private isInitialized;
|
|
14
|
-
constructor(maxLogs?: number);
|
|
15
|
-
initialize(): void;
|
|
16
|
-
addLog(entry: LogEntry): void;
|
|
17
|
-
destroy(): void;
|
|
18
|
-
private setupKeyHandlers;
|
|
19
|
-
private clearLogs;
|
|
20
|
-
private render;
|
|
21
|
-
private renderTabs;
|
|
22
|
-
private renderLogs;
|
|
23
|
-
private formatLogMessage;
|
|
24
|
-
private renderHelp;
|
|
25
|
-
}
|
|
@@ -1,183 +0,0 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.TerminalTabs = void 0;
|
|
27
|
-
const readline = __importStar(require("readline"));
|
|
28
|
-
const events_1 = require("events");
|
|
29
|
-
// ANSI escape codes для цветов
|
|
30
|
-
const ansi = {
|
|
31
|
-
reset: '\x1b[0m',
|
|
32
|
-
bold: '\x1b[1m',
|
|
33
|
-
dim: '\x1b[2m',
|
|
34
|
-
cyan: '\x1b[36m',
|
|
35
|
-
blue: '\x1b[34m',
|
|
36
|
-
green: '\x1b[32m',
|
|
37
|
-
yellow: '\x1b[33m',
|
|
38
|
-
red: '\x1b[31m',
|
|
39
|
-
white: '\x1b[37m',
|
|
40
|
-
bgBlue: '\x1b[44m',
|
|
41
|
-
};
|
|
42
|
-
const tabs = [
|
|
43
|
-
{ key: 'all', title: 'Все логи', filter: () => true },
|
|
44
|
-
{ key: 'server', title: 'Сервер', filter: (log) => log.type === 'server' },
|
|
45
|
-
{ key: 'client', title: 'Клиент', filter: (log) => log.type === 'client' },
|
|
46
|
-
];
|
|
47
|
-
class TerminalTabs extends events_1.EventEmitter {
|
|
48
|
-
logs = [];
|
|
49
|
-
activeTab = 0;
|
|
50
|
-
maxLogs = 1000;
|
|
51
|
-
rl;
|
|
52
|
-
isInitialized = false;
|
|
53
|
-
constructor(maxLogs = 1000) {
|
|
54
|
-
super();
|
|
55
|
-
this.maxLogs = maxLogs;
|
|
56
|
-
this.rl = readline.createInterface({
|
|
57
|
-
input: process.stdin,
|
|
58
|
-
output: process.stdout,
|
|
59
|
-
});
|
|
60
|
-
this.setupKeyHandlers();
|
|
61
|
-
}
|
|
62
|
-
initialize() {
|
|
63
|
-
if (this.isInitialized)
|
|
64
|
-
return;
|
|
65
|
-
this.isInitialized = true;
|
|
66
|
-
console.clear();
|
|
67
|
-
this.render();
|
|
68
|
-
}
|
|
69
|
-
addLog(entry) {
|
|
70
|
-
this.logs.push(entry);
|
|
71
|
-
if (this.logs.length > this.maxLogs) {
|
|
72
|
-
this.logs = this.logs.slice(-this.maxLogs);
|
|
73
|
-
}
|
|
74
|
-
// Обновляем только если таб инициализирован
|
|
75
|
-
if (this.isInitialized) {
|
|
76
|
-
this.render();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
destroy() {
|
|
80
|
-
if (process.stdin.isTTY) {
|
|
81
|
-
process.stdin.setRawMode(false);
|
|
82
|
-
}
|
|
83
|
-
this.rl.close();
|
|
84
|
-
}
|
|
85
|
-
setupKeyHandlers() {
|
|
86
|
-
if (process.stdin.isTTY) {
|
|
87
|
-
process.stdin.setRawMode(true);
|
|
88
|
-
process.stdin.setEncoding('utf8');
|
|
89
|
-
process.stdin.on('data', (key) => {
|
|
90
|
-
// Ctrl+C
|
|
91
|
-
if (key === '\u0003') {
|
|
92
|
-
process.exit();
|
|
93
|
-
}
|
|
94
|
-
switch (key) {
|
|
95
|
-
case '\u001b[D': // Стрелка влево
|
|
96
|
-
case 'h':
|
|
97
|
-
this.activeTab = this.activeTab > 0 ? this.activeTab - 1 : tabs.length - 1;
|
|
98
|
-
this.render();
|
|
99
|
-
break;
|
|
100
|
-
case '\u001b[C': // Стрелка вправо
|
|
101
|
-
case 'l':
|
|
102
|
-
this.activeTab = this.activeTab < tabs.length - 1 ? this.activeTab + 1 : 0;
|
|
103
|
-
this.render();
|
|
104
|
-
break;
|
|
105
|
-
case 'c':
|
|
106
|
-
this.clearLogs();
|
|
107
|
-
break;
|
|
108
|
-
case 'q':
|
|
109
|
-
process.exit();
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
clearLogs() {
|
|
116
|
-
this.logs = [];
|
|
117
|
-
this.render();
|
|
118
|
-
}
|
|
119
|
-
render() {
|
|
120
|
-
if (!process.stdout.isTTY)
|
|
121
|
-
return;
|
|
122
|
-
// Очищаем экран
|
|
123
|
-
console.clear();
|
|
124
|
-
// Рендерим табы
|
|
125
|
-
this.renderTabs();
|
|
126
|
-
// Рендерим логи для активного таба
|
|
127
|
-
this.renderLogs();
|
|
128
|
-
// Рендерим справку
|
|
129
|
-
this.renderHelp();
|
|
130
|
-
}
|
|
131
|
-
renderTabs() {
|
|
132
|
-
let tabsLine = '';
|
|
133
|
-
tabs.forEach((tab, index) => {
|
|
134
|
-
const isActive = index === this.activeTab;
|
|
135
|
-
const title = ` ${tab.title} `;
|
|
136
|
-
if (isActive) {
|
|
137
|
-
tabsLine += `${ansi.cyan}${ansi.bold}${ansi.bgBlue}${title}${ansi.reset}`;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
tabsLine += `${ansi.white}${title}${ansi.reset}`;
|
|
141
|
-
}
|
|
142
|
-
tabsLine += ' ';
|
|
143
|
-
});
|
|
144
|
-
console.log(tabsLine);
|
|
145
|
-
console.log(`${ansi.dim}${'─'.repeat(process.stdout.columns || 80)}${ansi.reset}`);
|
|
146
|
-
}
|
|
147
|
-
renderLogs() {
|
|
148
|
-
const currentTab = tabs[this.activeTab];
|
|
149
|
-
if (!currentTab)
|
|
150
|
-
return;
|
|
151
|
-
const filteredLogs = this.logs.filter(currentTab.filter);
|
|
152
|
-
const displayLogs = filteredLogs.slice(-40); // Показываем последние 40 логов
|
|
153
|
-
displayLogs.forEach((log) => {
|
|
154
|
-
console.log(this.formatLogMessage(log));
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
formatLogMessage(log) {
|
|
158
|
-
const timestamp = new Date(log.timestamp).toLocaleTimeString();
|
|
159
|
-
const prefix = `${ansi.dim}[${timestamp}] ${ansi.reset}`;
|
|
160
|
-
let colorCode = ansi.white;
|
|
161
|
-
switch (log.level) {
|
|
162
|
-
case 'success':
|
|
163
|
-
colorCode = ansi.green;
|
|
164
|
-
break;
|
|
165
|
-
case 'warning':
|
|
166
|
-
colorCode = ansi.yellow;
|
|
167
|
-
break;
|
|
168
|
-
case 'error':
|
|
169
|
-
colorCode = ansi.red;
|
|
170
|
-
break;
|
|
171
|
-
case 'verbose':
|
|
172
|
-
colorCode = ansi.dim;
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
return `${prefix}${colorCode}${log.message}${ansi.reset}`;
|
|
176
|
-
}
|
|
177
|
-
renderHelp() {
|
|
178
|
-
const filteredCount = this.logs.filter(tabs[this.activeTab]?.filter || (() => true)).length;
|
|
179
|
-
const help = `${ansi.dim}\nУправление: ← → (или h/l) - переключение табов | c - очистить | q - выход | Показано: ${filteredCount} логов${ansi.reset}`;
|
|
180
|
-
console.log(help);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
exports.TerminalTabs = TerminalTabs;
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const TerminalTabs_1 = require("./TerminalTabs");
|
|
5
|
-
const tabs = new TerminalTabs_1.TerminalTabs();
|
|
6
|
-
// Инициализируем интерфейс табов
|
|
7
|
-
tabs.initialize();
|
|
8
|
-
// Симулируем логи от сервера и клиента
|
|
9
|
-
let logCounter = 0;
|
|
10
|
-
const addServerLog = () => {
|
|
11
|
-
tabs.addLog({
|
|
12
|
-
type: 'server',
|
|
13
|
-
message: `Server log message ${++logCounter}`,
|
|
14
|
-
timestamp: Date.now(),
|
|
15
|
-
level: Math.random() > 0.7 ? 'success' : 'message',
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
const addClientLog = () => {
|
|
19
|
-
tabs.addLog({
|
|
20
|
-
type: 'client',
|
|
21
|
-
message: `Client build progress ${++logCounter}`,
|
|
22
|
-
timestamp: Date.now(),
|
|
23
|
-
level: Math.random() > 0.8 ? 'warning' : 'message',
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
const addErrorLog = () => {
|
|
27
|
-
const type = Math.random() > 0.5 ? 'server' : 'client';
|
|
28
|
-
tabs.addLog({
|
|
29
|
-
type,
|
|
30
|
-
message: `Error in ${type}: Something went wrong ${++logCounter}`,
|
|
31
|
-
timestamp: Date.now(),
|
|
32
|
-
level: 'error',
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
// Добавляем начальные логи
|
|
36
|
-
tabs.addLog({
|
|
37
|
-
type: 'all',
|
|
38
|
-
message: 'Демонстрация системы табов запущена',
|
|
39
|
-
timestamp: Date.now(),
|
|
40
|
-
level: 'success',
|
|
41
|
-
});
|
|
42
|
-
// Симулируем активность
|
|
43
|
-
setInterval(() => {
|
|
44
|
-
const rand = Math.random();
|
|
45
|
-
if (rand > 0.7) {
|
|
46
|
-
addServerLog();
|
|
47
|
-
}
|
|
48
|
-
else if (rand > 0.4) {
|
|
49
|
-
addClientLog();
|
|
50
|
-
}
|
|
51
|
-
else if (rand > 0.9) {
|
|
52
|
-
addErrorLog();
|
|
53
|
-
}
|
|
54
|
-
}, 500);
|
|
55
|
-
// Обработка выхода
|
|
56
|
-
process.on('SIGINT', () => {
|
|
57
|
-
tabs.destroy();
|
|
58
|
-
console.log('\nДемонстрация завершена');
|
|
59
|
-
process.exit(0);
|
|
60
|
-
});
|
|
61
|
-
console.log('Нажмите Ctrl+C для выхода, стрелки влево/вправо для переключения табов, c для очистки');
|