@travetto/compiler 4.0.2 → 4.0.4
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 +1 -0
- package/bin/trvc.js +2 -0
- package/package.json +4 -4
- package/src/compiler.ts +3 -3
- package/support/entry.trvc.ts +1 -1
- package/support/server/client.ts +29 -25
- package/support/server/process-handle.ts +2 -2
- package/support/server/server.ts +5 -5
- package/support/types.ts +1 -1
- package/support/util.ts +20 -2
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ The compiler cli supports the following operations:
|
|
|
31
31
|
* `clean` - Clean out the output and compiler caches
|
|
32
32
|
* `info` - Retrieve the compiler information, if running
|
|
33
33
|
* `event <log|progress|state>` - Watch events in realtime as newline delimited JSON
|
|
34
|
+
* `exec <file> [...args]` - Allow for compiling and executing an entrypoint file
|
|
34
35
|
* `manifest --prod [output]` - Generate the project manifest
|
|
35
36
|
In addition to the normal output, the compiler supports an environment variable `TRV_BUILD` that supports the following values: `debug`, `info`, `warn` or `none`. This provides different level of logging during the build process which is helpful to diagnose any odd behaviors. When invoking an unknown command (e.g. `<other>` from above), the default level is `warn`. Otherwise the default logging level is `info`.
|
|
36
37
|
|
package/bin/trvc.js
CHANGED
|
@@ -14,6 +14,7 @@ const help = () => [
|
|
|
14
14
|
' * clean - Clean out the output and compiler caches',
|
|
15
15
|
' * info - Retrieve the compiler information, if running',
|
|
16
16
|
' * event <log|progress|state> - Watch events in realtime as newline delimited JSON',
|
|
17
|
+
' * exec <file> [...args] - Allow for compiling and executing an entrypoint file',
|
|
17
18
|
' * manifest --prod [output] - Generate the project manifest',
|
|
18
19
|
].join('\n');
|
|
19
20
|
|
|
@@ -35,6 +36,7 @@ getEntry().then(async (ops) => {
|
|
|
35
36
|
});
|
|
36
37
|
case 'clean': return ops.clean();
|
|
37
38
|
case 'manifest': return ops.manifest(args[0], flags.some(x => x === '--prod'));
|
|
39
|
+
case 'exec': return ops.getLoader().then(v => v(args[0], all.slice(1)));
|
|
38
40
|
case 'start':
|
|
39
41
|
case 'watch': return ops.watch();
|
|
40
42
|
case 'build': return ops.build();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/compiler",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.4",
|
|
4
4
|
"description": "The compiler infrastructure for the Travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compiler",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@parcel/watcher": "^2.4.0",
|
|
34
|
-
"@travetto/manifest": "^4.0.
|
|
35
|
-
"@travetto/transformer": "^4.0.
|
|
34
|
+
"@travetto/manifest": "^4.0.1",
|
|
35
|
+
"@travetto/transformer": "^4.0.2",
|
|
36
36
|
"@types/node": "^20.11.16"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@travetto/cli": "^4.0.
|
|
39
|
+
"@travetto/cli": "^4.0.4"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@travetto/cli": {
|
package/src/compiler.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import timers from 'node:timers/promises';
|
|
2
1
|
import fs from 'node:fs/promises';
|
|
3
2
|
import { setMaxListeners } from 'node:events';
|
|
4
3
|
|
|
@@ -11,6 +10,7 @@ import { CompileEmitEvent, CompileEmitter } from './types';
|
|
|
11
10
|
import { EventUtil } from './event';
|
|
12
11
|
|
|
13
12
|
import { IpcLogger } from '../support/log';
|
|
13
|
+
import { CommonUtil } from '../support/util';
|
|
14
14
|
|
|
15
15
|
const log = new IpcLogger({ level: 'debug' });
|
|
16
16
|
|
|
@@ -82,7 +82,7 @@ export class Compiler {
|
|
|
82
82
|
process.removeAllListeners('disconnect');
|
|
83
83
|
process.removeAllListeners('message');
|
|
84
84
|
this.#ctrl.abort();
|
|
85
|
-
|
|
85
|
+
CommonUtil.nonBlockingTimeout(1000).then(() => process.exit()); // Allow upto 1s to shutdown gracefully
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
/**
|
|
@@ -113,7 +113,7 @@ export class Compiler {
|
|
|
113
113
|
}
|
|
114
114
|
EventUtil.sendEvent('progress', { total: files.length, idx: files.length, message: 'Complete', operation: 'compile', complete: true });
|
|
115
115
|
|
|
116
|
-
await
|
|
116
|
+
await CommonUtil.queueMacroTask();
|
|
117
117
|
|
|
118
118
|
log.debug(`Compiled ${i} files`);
|
|
119
119
|
}
|
package/support/entry.trvc.ts
CHANGED
|
@@ -91,7 +91,7 @@ export const main = (ctx: ManifestContext) => {
|
|
|
91
91
|
},
|
|
92
92
|
|
|
93
93
|
/** Build and return a loader */
|
|
94
|
-
async getLoader(): Promise<(mod: string) => Promise<unknown>> {
|
|
94
|
+
async getLoader(): Promise<(mod: string, args?: string[]) => Promise<unknown>> {
|
|
95
95
|
Log.initLevel('none');
|
|
96
96
|
if (!(await client.isWatching())) { // Short circuit if we can
|
|
97
97
|
Log.initLevel('error');
|
package/support/server/client.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { ManifestContext } from '@travetto/manifest';
|
|
|
6
6
|
|
|
7
7
|
import type { CompilerEvent, CompilerEventType, CompilerServerInfo, CompilerStateType } from '../types';
|
|
8
8
|
import type { LogShape } from '../log';
|
|
9
|
+
import { CommonUtil } from '../util';
|
|
9
10
|
import { ProcessHandle } from './process-handle';
|
|
10
11
|
|
|
11
12
|
type FetchEventsConfig<T> = {
|
|
@@ -14,6 +15,12 @@ type FetchEventsConfig<T> = {
|
|
|
14
15
|
enforceIteration?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
18
|
+
const streamAgent = new Agent({
|
|
19
|
+
keepAlive: true,
|
|
20
|
+
keepAliveMsecs: 10000,
|
|
21
|
+
timeout: 1000 * 60 * 60 * 24
|
|
22
|
+
});
|
|
23
|
+
|
|
17
24
|
/**
|
|
18
25
|
* Compiler Client Operations
|
|
19
26
|
*/
|
|
@@ -37,23 +44,26 @@ export class CompilerClient {
|
|
|
37
44
|
return this.#url;
|
|
38
45
|
}
|
|
39
46
|
|
|
40
|
-
async #fetch(rel: string, opts?: RequestInit & { timeout?: number }, logTimeout = true): Promise<
|
|
47
|
+
async #fetch(rel: string, opts?: RequestInit & { timeout?: number }, logTimeout = true): Promise<{ ok: boolean, text: string }> {
|
|
41
48
|
const ctrl = new AbortController();
|
|
49
|
+
const timeoutCtrl = new AbortController();
|
|
50
|
+
|
|
42
51
|
opts?.signal?.addEventListener('abort', () => ctrl.abort());
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
timers.setTimeout(opts?.timeout ?? 100, undefined, { ref: false, signal: timeoutCtrl.signal })
|
|
53
|
+
.then(() => {
|
|
54
|
+
logTimeout && this.#log.error(`Timeout on request to ${this.#url}${rel}`);
|
|
55
|
+
ctrl.abort('TIMEOUT');
|
|
56
|
+
})
|
|
57
|
+
.catch(() => { });
|
|
58
|
+
const res = await fetch(`${this.#url}${rel}`, { ...opts, signal: ctrl.signal });
|
|
59
|
+
const out = { ok: res.ok, text: await res.text() };
|
|
60
|
+
timeoutCtrl.abort();
|
|
61
|
+
return out;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
/** Get server information, if server is running */
|
|
55
65
|
info(): Promise<CompilerServerInfo | undefined> {
|
|
56
|
-
return this.#fetch('/info', { timeout: 200 }, false).then(v => v.
|
|
66
|
+
return this.#fetch('/info', { timeout: 200 }, false).then(v => JSON.parse(v.text), () => undefined)
|
|
57
67
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
58
68
|
.then(v => v as CompilerServerInfo);
|
|
59
69
|
}
|
|
@@ -110,22 +120,16 @@ export class CompilerClient {
|
|
|
110
120
|
const quit = (): void => ctrl.abort();
|
|
111
121
|
try {
|
|
112
122
|
signal.addEventListener('abort', quit);
|
|
113
|
-
const
|
|
114
|
-
http.get(`${this.#url}/event/${type}`, {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}),
|
|
120
|
-
signal: ctrl.signal
|
|
121
|
-
}, res => resolve(res))
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
for await (const line of rl.createInterface(res)) {
|
|
123
|
+
const response = await new Promise<http.IncomingMessage>((resolve, reject) =>
|
|
124
|
+
http.get(`${this.#url}/event/${type}`, { agent: streamAgent, signal: ctrl.signal }, resolve)
|
|
125
|
+
.on('error', reject)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
for await (const line of rl.createInterface(response)) {
|
|
125
129
|
if (line.trim().charAt(0) === '{') {
|
|
126
130
|
const val = JSON.parse(line);
|
|
127
131
|
if (cfg.until?.(val)) {
|
|
128
|
-
await
|
|
132
|
+
await CommonUtil.queueMacroTask();
|
|
129
133
|
ctrl.abort();
|
|
130
134
|
}
|
|
131
135
|
yield val;
|
|
@@ -136,7 +140,7 @@ export class CompilerClient {
|
|
|
136
140
|
}
|
|
137
141
|
signal.removeEventListener('abort', quit);
|
|
138
142
|
|
|
139
|
-
await
|
|
143
|
+
await CommonUtil.queueMacroTask();
|
|
140
144
|
|
|
141
145
|
info = await this.info();
|
|
142
146
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import timers from 'node:timers/promises';
|
|
4
3
|
|
|
5
4
|
import type { ManifestContext } from '@travetto/manifest';
|
|
6
5
|
import { Log, Logger } from '../log';
|
|
6
|
+
import { CommonUtil } from '../util';
|
|
7
7
|
|
|
8
8
|
export class ProcessHandle {
|
|
9
9
|
|
|
@@ -56,7 +56,7 @@ export class ProcessHandle {
|
|
|
56
56
|
if (!await this.isRunning()) {
|
|
57
57
|
return true;
|
|
58
58
|
}
|
|
59
|
-
await
|
|
59
|
+
await CommonUtil.nonBlockingTimeout(100);
|
|
60
60
|
}
|
|
61
61
|
try {
|
|
62
62
|
this.#log.debug('Force Killing', pid);
|
package/support/server/server.ts
CHANGED
|
@@ -77,7 +77,7 @@ export class CompilerServer {
|
|
|
77
77
|
.on('close', () => log.debug('Server close event'));
|
|
78
78
|
|
|
79
79
|
const url = new URL(this.#url);
|
|
80
|
-
|
|
80
|
+
CommonUtil.queueMacroTask().then(() => this.#server.listen(+url.port, url.hostname)); // Run async
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
if (output === 'retry') {
|
|
@@ -86,7 +86,7 @@ export class CompilerServer {
|
|
|
86
86
|
}
|
|
87
87
|
log.info('Waiting for build to finish, before retrying');
|
|
88
88
|
// Let the server finish
|
|
89
|
-
await this.#client.waitForState(['
|
|
89
|
+
await this.#client.waitForState(['closed'], 'Server closed', this.signal);
|
|
90
90
|
return this.#tryListen(attempt + 1);
|
|
91
91
|
} else if (output === 'ok') {
|
|
92
92
|
await this.#handle.server.writePid(this.info.serverPid);
|
|
@@ -121,7 +121,7 @@ export class CompilerServer {
|
|
|
121
121
|
async #disconnectActive(): Promise<void> {
|
|
122
122
|
log.info('Server disconnect requested');
|
|
123
123
|
this.info.iteration = Date.now();
|
|
124
|
-
await
|
|
124
|
+
await CommonUtil.nonBlockingTimeout(20);
|
|
125
125
|
for (const el of Object.values(this.#listeners)) {
|
|
126
126
|
try { el.res.end(); } catch { }
|
|
127
127
|
}
|
|
@@ -204,9 +204,9 @@ export class CompilerServer {
|
|
|
204
204
|
|
|
205
205
|
try {
|
|
206
206
|
await new Promise((resolve, reject) => {
|
|
207
|
-
|
|
207
|
+
CommonUtil.nonBlockingTimeout(2000).then(reject); // Wait 2s max
|
|
208
208
|
this.#server.close(resolve);
|
|
209
|
-
this.#emitEvent({ type: 'state', payload: { state: '
|
|
209
|
+
this.#emitEvent({ type: 'state', payload: { state: 'closed' } });
|
|
210
210
|
setImmediate(() => {
|
|
211
211
|
this.#server.closeAllConnections();
|
|
212
212
|
this.#shutdown.abort();
|
package/support/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type CompilerMode = 'build' | 'watch';
|
|
2
2
|
|
|
3
|
-
export type CompilerStateType = 'startup' | 'init' | 'compile-start' | 'compile-end' | 'watch-start' | 'watch-end' | 'reset' | '
|
|
3
|
+
export type CompilerStateType = 'startup' | 'init' | 'compile-start' | 'compile-end' | 'watch-start' | 'watch-end' | 'reset' | 'closed';
|
|
4
4
|
export type CompilerChangeEvent = { file: string, action: 'create' | 'update' | 'delete', output: string, module: string, time: number };
|
|
5
5
|
export type CompilerLogLevel = 'info' | 'debug' | 'warn' | 'error';
|
|
6
6
|
export type CompilerLogEvent = { level: CompilerLogLevel, message: string, time?: number, args?: unknown[], scope?: string };
|
package/support/util.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import timers from 'node:timers/promises';
|
|
3
4
|
import { setMaxListeners } from 'node:events';
|
|
4
5
|
|
|
5
6
|
import type { ManifestContext } from '@travetto/manifest';
|
|
@@ -95,11 +96,28 @@ export class CommonUtil {
|
|
|
95
96
|
* Create a module loader given a context, and assuming build is complete
|
|
96
97
|
* @param ctx
|
|
97
98
|
*/
|
|
98
|
-
static moduleLoader(ctx: ManifestContext): (mod: string) => Promise<unknown> {
|
|
99
|
-
return (mod) => {
|
|
99
|
+
static moduleLoader(ctx: ManifestContext): (mod: string, args?: string[]) => Promise<unknown> {
|
|
100
|
+
return (mod, args) => {
|
|
100
101
|
const outputRoot = path.resolve(ctx.workspace.path, ctx.build.outputFolder);
|
|
101
102
|
process.env.TRV_MANIFEST = path.resolve(outputRoot, 'node_modules', ctx.main.name); // Setup for running
|
|
103
|
+
if (args) {
|
|
104
|
+
process.argv = [process.argv0, mod, ...args];
|
|
105
|
+
}
|
|
102
106
|
return import(path.join(outputRoot, 'node_modules', mod)); // Return function to run import on a module
|
|
103
107
|
};
|
|
104
108
|
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Non-blocking timeout, that is cancellable
|
|
112
|
+
*/
|
|
113
|
+
static nonBlockingTimeout(time: number): Promise<void> {
|
|
114
|
+
return timers.setTimeout(time, undefined, { ref: false }).catch(() => { });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Queue new macrotask
|
|
119
|
+
*/
|
|
120
|
+
static queueMacroTask(): Promise<void> {
|
|
121
|
+
return timers.setImmediate(undefined);
|
|
122
|
+
}
|
|
105
123
|
}
|