@travetto/compiler 3.4.3 → 4.0.0-rc.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.
- package/README.md +31 -29
- package/bin/common.js +37 -45
- package/bin/trvc.js +19 -11
- package/package.json +5 -6
- package/src/compiler.ts +37 -15
- package/src/event.ts +3 -3
- package/src/internal/watch-core.ts +23 -20
- package/src/log.ts +1 -1
- package/src/state.ts +4 -4
- package/src/util.ts +2 -2
- package/src/watch.ts +17 -30
- package/support/entry.trvc.ts +31 -26
- package/support/log.ts +56 -23
- package/support/queue.ts +5 -6
- package/support/server/client.ts +86 -73
- package/support/server/runner.ts +27 -59
- package/support/server/server.ts +40 -29
- package/support/setup.ts +38 -36
- package/support/types.ts +2 -2
- package/support/util.ts +16 -23
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ This module expands upon the [Typescript](https://typescriptlang.org) compiler,
|
|
|
21
21
|
Beyond the [Typescript](https://typescriptlang.org) compiler functionality, the module provides the primary entry point into the development process.
|
|
22
22
|
|
|
23
23
|
## CLI
|
|
24
|
-
The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#
|
|
24
|
+
The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L5) is the entry point for compilation-related operations. It has the ability to check for active builds, and ongoing watch operations to ensure only one process is building at a time. Within the framework, regardless of mono-repo or not, the compilation always targets the entire project. With the efficient caching behavior, this leads to generally a minimal overhead but allows for centralization of all operations.
|
|
25
25
|
|
|
26
26
|
The compiler cli supports the following operations:
|
|
27
27
|
* `start|watch` - Run the compiler in watch mode
|
|
@@ -30,7 +30,8 @@ The compiler cli supports the following operations:
|
|
|
30
30
|
* `build` - Ensure the project is built and upto date
|
|
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
|
+
* `manifest --prod [output]` - Generate the project manifest
|
|
34
35
|
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`.
|
|
35
36
|
|
|
36
37
|
**Terminal: Sample trv output with debug logging**
|
|
@@ -38,34 +39,35 @@ In addition to the normal output, the compiler supports an environment variable
|
|
|
38
39
|
$ TRV_BUILD=debug trvc build
|
|
39
40
|
|
|
40
41
|
2029-03-14T04:00:00.618Z info [compiler-server] Starting server http://127.0.0.1:25539
|
|
41
|
-
2029-03-14T04:00:00.837Z debug [compiler
|
|
42
|
+
2029-03-14T04:00:00.837Z debug [compiler ] Started, streaming logs
|
|
42
43
|
2029-03-14T04:00:01.510Z debug [event-stream ] Started event stream
|
|
43
44
|
2029-03-14T04:00:02.450Z debug [precompile ] Started
|
|
44
|
-
2029-03-14T04:00:02.762Z debug [compiler-server] Receive request { action: '
|
|
45
|
-
2029-03-14T04:00:02.947Z debug [
|
|
46
|
-
2029-03-14T04:00:03.093Z debug [
|
|
47
|
-
2029-03-14T04:00:04.003Z debug [precompile ] Skipped @travetto/
|
|
48
|
-
2029-03-14T04:00:04.495Z debug [precompile ] Skipped @travetto/
|
|
49
|
-
2029-03-14T04:00:05.066Z debug [precompile ]
|
|
50
|
-
2029-03-14T04:00:05.307Z debug [
|
|
51
|
-
2029-03-14T04:00:05.952Z debug [manifest ]
|
|
52
|
-
2029-03-14T04:00:06.859Z debug [
|
|
53
|
-
2029-03-14T04:00:07.720Z debug [transformers ]
|
|
54
|
-
2029-03-14T04:00:08.179Z debug [transformers ] Skipped @travetto/
|
|
55
|
-
2029-03-14T04:00:08.588Z debug [transformers ] Skipped @travetto/
|
|
56
|
-
2029-03-14T04:00:09.493Z debug [transformers ] Skipped @travetto/
|
|
57
|
-
2029-03-14T04:00:10.395Z debug [transformers ] Skipped @travetto/
|
|
58
|
-
2029-03-14T04:00:10.407Z debug [transformers ]
|
|
59
|
-
2029-03-14T04:00:10.799Z debug [
|
|
60
|
-
2029-03-14T04:00:11.013Z debug [delta ]
|
|
61
|
-
2029-03-14T04:00:11.827Z debug [
|
|
62
|
-
2029-03-14T04:00:11.894Z debug [manifest ]
|
|
63
|
-
2029-03-14T04:00:12.133Z debug [manifest ]
|
|
64
|
-
2029-03-14T04:00:13.123Z
|
|
65
|
-
2029-03-14T04:00:14.014Z
|
|
66
|
-
2029-03-14T04:00:14.924Z debug [
|
|
67
|
-
2029-03-14T04:00:15.690Z
|
|
68
|
-
2029-03-14T04:00:15.865Z
|
|
45
|
+
2029-03-14T04:00:02.762Z debug [compiler-server] Receive request { action: 'info', subAction: undefined }
|
|
46
|
+
2029-03-14T04:00:02.947Z debug [client.server ] Starting watch for events of type "log"
|
|
47
|
+
2029-03-14T04:00:03.093Z debug [compiler-server] Receive request { action: 'event', subAction: 'log' }
|
|
48
|
+
2029-03-14T04:00:04.003Z debug [precompile ] Skipped @travetto/manifest
|
|
49
|
+
2029-03-14T04:00:04.495Z debug [precompile ] Skipped @travetto/transformer
|
|
50
|
+
2029-03-14T04:00:05.066Z debug [precompile ] Skipped @travetto/compiler
|
|
51
|
+
2029-03-14T04:00:05.307Z debug [precompile ] Completed
|
|
52
|
+
2029-03-14T04:00:05.952Z debug [manifest ] Started
|
|
53
|
+
2029-03-14T04:00:06.859Z debug [manifest ] Completed
|
|
54
|
+
2029-03-14T04:00:07.720Z debug [transformers ] Started
|
|
55
|
+
2029-03-14T04:00:08.179Z debug [transformers ] Skipped @travetto/base
|
|
56
|
+
2029-03-14T04:00:08.588Z debug [transformers ] Skipped @travetto/cli
|
|
57
|
+
2029-03-14T04:00:09.493Z debug [transformers ] Skipped @travetto/manifest
|
|
58
|
+
2029-03-14T04:00:10.395Z debug [transformers ] Skipped @travetto/registry
|
|
59
|
+
2029-03-14T04:00:10.407Z debug [transformers ] Skipped @travetto/schema
|
|
60
|
+
2029-03-14T04:00:10.799Z debug [transformers ] Completed
|
|
61
|
+
2029-03-14T04:00:11.013Z debug [delta ] Started
|
|
62
|
+
2029-03-14T04:00:11.827Z debug [delta ] Completed
|
|
63
|
+
2029-03-14T04:00:11.894Z debug [manifest ] Started
|
|
64
|
+
2029-03-14T04:00:12.133Z debug [manifest ] Wrote manifest @travetto-doc/compiler
|
|
65
|
+
2029-03-14T04:00:13.123Z debug [manifest ] Completed
|
|
66
|
+
2029-03-14T04:00:14.014Z info [compiler-server] State changed: compile-end
|
|
67
|
+
2029-03-14T04:00:14.924Z debug [compiler-exec ] Skipped
|
|
68
|
+
2029-03-14T04:00:15.690Z debug [event-stream ] Finished event stream
|
|
69
|
+
2029-03-14T04:00:15.865Z info [compiler-server] Closing down server
|
|
70
|
+
2029-03-14T04:00:16.757Z debug [client.server ] Stopping watch for events of type "log"
|
|
69
71
|
```
|
|
70
72
|
|
|
71
73
|
**Terminal: Sample trv output with default log level**
|
|
@@ -86,4 +88,4 @@ The compiler will move through the following phases on a given compilation execu
|
|
|
86
88
|
* `Invoke Compiler` - Run [Typescript](https://typescriptlang.org) compiler with the aforementioned enhancements
|
|
87
89
|
|
|
88
90
|
### Bootstrapping
|
|
89
|
-
Given that the framework is distributed as [Typescript](https://typescriptlang.org) only files, there is a bootstrapping problem that needs to be mitigated. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#
|
|
91
|
+
Given that the framework is distributed as [Typescript](https://typescriptlang.org) only files, there is a bootstrapping problem that needs to be mitigated. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L5) entrypoint, along with a small context utility in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching") are the only [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript) files needed to run the project. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L5) entry point will compile `@travetto/compiler/support/*` files as the set that is used at startup. These files are also accessible to the compiler as they get re-compiled after the fact.
|
package/bin/common.js
CHANGED
|
@@ -1,55 +1,47 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { createRequire } from 'module';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
6
4
|
|
|
7
5
|
import { getManifestContext } from '@travetto/manifest/bin/context.js';
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
/** @typedef {import('@travetto/manifest').ManifestContext} Ctx */
|
|
8
|
+
/** @typedef {(ctx: Ctx, content:string) => (string | Promise<string>)} Transform */
|
|
9
|
+
|
|
10
|
+
const stat = (/** @type {string}*/ file) => fs.stat(file).then(s => Math.max(s.mtimeMs, s.ctimeMs)).catch(() => 0);
|
|
11
|
+
const TS_EXT = /[.]tsx?$/;
|
|
12
|
+
|
|
13
|
+
const /** @type {Transform} */ transpile = async (ctx, content, tsconfig = path.resolve(ctx.workspace.path, 'tsconfig.json')) => {
|
|
14
|
+
await fs.stat(tsconfig).catch(() => fs.writeFile(tsconfig, JSON.stringify({ extends: '@travetto/compiler/tsconfig.trv.json' }), 'utf8'));
|
|
15
|
+
const ts = (await import('typescript')).default;
|
|
16
|
+
const module = ctx.workspace.type === 'module' ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS;
|
|
17
|
+
return ts.transpile(content, { target: ts.ScriptTarget.ES2022, module, esModuleInterop: true, allowSyntheticDefaultImports: true });
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const /** @type {Transform} */ rewritePackage = (ctx, content) =>
|
|
21
|
+
JSON.stringify(Object.assign(JSON.parse(content), { type: ctx.workspace.type }), null, 2);
|
|
22
|
+
|
|
23
|
+
async function outputIfChanged(/** @type {Ctx} */ ctx, /** @type {string} */ file, /** @type {Transform} */ transform) {
|
|
24
|
+
const target = path.resolve(ctx.workspace.path, ctx.build.compilerFolder, 'node_modules', '@travetto/compiler', file).replace(TS_EXT, '.js');
|
|
25
|
+
const src = path.resolve(ctx.workspace.path, ctx.build.compilerModuleFolder, file);
|
|
26
|
+
|
|
27
|
+
if (await stat(src) > await stat(target)) {
|
|
28
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
29
|
+
const content = await fs.readFile(src, 'utf8');
|
|
30
|
+
await fs.writeFile(target, await transform(ctx, content), 'utf8');
|
|
31
|
+
}
|
|
32
|
+
return target;
|
|
33
|
+
}
|
|
10
34
|
|
|
11
|
-
/** @return {Promise<ReturnType<import('@travetto/compiler/support/entry.trvc').main>>} */
|
|
12
35
|
export const getEntry = async () => {
|
|
13
36
|
const ctx = await getManifestContext();
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const compMod = path.dirname(createRequire(path.resolve(ctx.workspacePath, 'node_modules')).resolve('@travetto/compiler/package.json'));
|
|
19
|
-
const files = [];
|
|
20
|
-
|
|
21
|
-
for (const file of COMPILER_FILES) {
|
|
22
|
-
const target = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', '@travetto/compiler', file).replace(/[.]tsx?$/, '.js');
|
|
23
|
-
const src = path.resolve(compMod, file);
|
|
24
|
-
|
|
25
|
-
const targetTime = await fs.stat(target).then(s => Math.max(s.mtimeMs, s.ctimeMs)).catch(() => 0);
|
|
26
|
-
const srcTime = await fs.stat(src).then(s => Math.max(s.mtimeMs, s.ctimeMs));
|
|
27
|
-
// If stale
|
|
28
|
-
if (srcTime > targetTime) {
|
|
29
|
-
const ts = (await import('typescript')).default;
|
|
30
|
-
const module = ctx.moduleType === 'module' ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS;
|
|
31
|
-
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
32
|
-
const text = await fs.readFile(src, 'utf8');
|
|
33
|
-
if (/[.]tsx?$/.test(file)) {
|
|
34
|
-
const content = ts.transpile(
|
|
35
|
-
text,
|
|
36
|
-
{ target: ts.ScriptTarget.ES2022, module, esModuleInterop: true, allowSyntheticDefaultImports: true }
|
|
37
|
-
)
|
|
38
|
-
.replace(/^((?:im|ex)port .*from '[.][^']+)(')/mg, (_, a, b) => `${a}.js${b}`)
|
|
39
|
-
.replace(/^(import [^\n]*from '[^.][^\n/]+[/][^\n/]+[/][^\n']+)(')/mg, (_, a, b) => `${a}.js${b}`);
|
|
40
|
-
await fs.writeFile(target, content, 'utf8');
|
|
41
|
-
} else {
|
|
42
|
-
const pkg = JSON.parse(text);
|
|
43
|
-
pkg.type = ctx.moduleType;
|
|
44
|
-
await fs.writeFile(target, JSON.stringify(pkg, null, 2), 'utf8');
|
|
45
|
-
}
|
|
46
|
-
// Compile
|
|
47
|
-
}
|
|
48
|
-
files.push(target);
|
|
49
|
-
}
|
|
37
|
+
const entry = await outputIfChanged(ctx, 'support/entry.trvc.ts', transpile);
|
|
38
|
+
const run = (/** @type {import('@travetto/compiler/support/entry.trvc')} */ mod) => mod.main(ctx);
|
|
39
|
+
|
|
40
|
+
await outputIfChanged(ctx, 'package.json', rewritePackage);
|
|
50
41
|
|
|
51
|
-
|
|
42
|
+
await fs.readdir(path.resolve(ctx.workspace.path, ctx.build.compilerModuleFolder, 'support'), { recursive: true }).then(files =>
|
|
43
|
+
Promise.all(files.filter(x => TS_EXT.test(x)).map(f => outputIfChanged(ctx, `support/${f}`, transpile))));
|
|
52
44
|
|
|
53
|
-
try { return require(
|
|
54
|
-
catch { return import(
|
|
45
|
+
try { return run(require(entry)); }
|
|
46
|
+
catch { return import(entry).then(run); }
|
|
55
47
|
};
|
package/bin/trvc.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env -S node --disable-proto=delete --enable-source-maps
|
|
2
|
+
process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --enable-source-maps --disable-proto=delete`;
|
|
2
3
|
|
|
3
4
|
// @ts-check
|
|
4
5
|
import { getEntry } from './common.js';
|
|
@@ -7,18 +8,20 @@ const help = () => [
|
|
|
7
8
|
'npx trvc [command]',
|
|
8
9
|
'',
|
|
9
10
|
'Available Commands:',
|
|
10
|
-
' * start|watch
|
|
11
|
-
' * stop
|
|
12
|
-
' * restart
|
|
13
|
-
' * build
|
|
14
|
-
' * clean
|
|
15
|
-
' * info
|
|
16
|
-
' *
|
|
11
|
+
' * start|watch - Run the compiler in watch mode',
|
|
12
|
+
' * stop - Stop the compiler if running',
|
|
13
|
+
' * restart - Restart the compiler in watch mode',
|
|
14
|
+
' * build - Ensure the project is built and upto date',
|
|
15
|
+
' * clean - Clean out the output and compiler caches',
|
|
16
|
+
' * info - Retrieve the compiler information, if running',
|
|
17
|
+
' * event <log|progress|state> - Watch events in realtime as newline delimited JSON',
|
|
18
|
+
' * manifest --prod [output] - Generate the project manifest',
|
|
17
19
|
].join('\n');
|
|
18
20
|
|
|
19
21
|
getEntry().then(async (ops) => {
|
|
20
|
-
const [op, ...
|
|
21
|
-
const
|
|
22
|
+
const [op, ...all] = process.argv.slice(2);
|
|
23
|
+
const args = all.filter(x => !x.startsWith('-'));
|
|
24
|
+
const flags = all.filter(x => x.startsWith('-'));
|
|
22
25
|
|
|
23
26
|
switch (op) {
|
|
24
27
|
case undefined:
|
|
@@ -26,8 +29,13 @@ getEntry().then(async (ops) => {
|
|
|
26
29
|
case 'restart': return ops.stop().then(() => ops.compile('watch'));
|
|
27
30
|
case 'stop': return ops.stop();
|
|
28
31
|
case 'info': return ops.info().then(v => console.log(JSON.stringify(v, null, 2)));
|
|
32
|
+
case 'event': return ops.events(args[0], v => {
|
|
33
|
+
if (!process.stdout.write(`${JSON.stringify(v)}\n`)) {
|
|
34
|
+
return new Promise(r => process.stdout.once('drain', r));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
29
37
|
case 'clean': return ops.clean();
|
|
30
|
-
case 'manifest': return ops.manifest(
|
|
38
|
+
case 'manifest': return ops.manifest(args[0], flags.some(x => x === '--prod'));
|
|
31
39
|
case 'start': return ops.compile('watch');
|
|
32
40
|
case 'watch':
|
|
33
41
|
case 'build': return ops.compile(op);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/compiler",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-rc.0",
|
|
4
4
|
"description": "The compiler infrastructure for the Travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compiler",
|
|
@@ -31,13 +31,12 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@parcel/watcher": "^2.3.0",
|
|
34
|
-
"@travetto/manifest": "^
|
|
35
|
-
"@travetto/
|
|
36
|
-
"@
|
|
37
|
-
"@types/node": "^20.9.2"
|
|
34
|
+
"@travetto/manifest": "^4.0.0-rc.0",
|
|
35
|
+
"@travetto/transformer": "^4.0.0-rc.0",
|
|
36
|
+
"@types/node": "^20.10.3"
|
|
38
37
|
},
|
|
39
38
|
"peerDependencies": {
|
|
40
|
-
"@travetto/cli": "^
|
|
39
|
+
"@travetto/cli": "^4.0.0-rc.0"
|
|
41
40
|
},
|
|
42
41
|
"peerDependenciesMeta": {
|
|
43
42
|
"@travetto/cli": {
|
package/src/compiler.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { install } from 'source-map-support';
|
|
2
1
|
import ts from 'typescript';
|
|
3
|
-
import
|
|
2
|
+
import timers from 'node:timers/promises';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import { setMaxListeners } from 'node:events';
|
|
4
5
|
|
|
5
|
-
import { ManifestModuleUtil,
|
|
6
|
+
import { ManifestModuleUtil, RuntimeIndex } from '@travetto/manifest';
|
|
6
7
|
|
|
7
8
|
import { CompilerUtil } from './util';
|
|
8
9
|
import { CompilerState } from './state';
|
|
@@ -21,15 +22,17 @@ export class Compiler {
|
|
|
21
22
|
*/
|
|
22
23
|
static async main(): Promise<void> {
|
|
23
24
|
const [dirty, watch] = process.argv.slice(2);
|
|
24
|
-
const state = await CompilerState.get(
|
|
25
|
+
const state = await CompilerState.get(RuntimeIndex);
|
|
26
|
+
Log.debug('Running compiler with dirty file', dirty);
|
|
25
27
|
const dirtyFiles = ManifestModuleUtil.getFileType(dirty) === 'ts' ? [dirty] : (await fs.readFile(dirty, 'utf8')).split(/\n/).filter(x => !!x);
|
|
26
28
|
await new Compiler(state, dirtyFiles, watch === 'true').run();
|
|
27
|
-
process.exit();
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
#state: CompilerState;
|
|
31
32
|
#dirtyFiles: string[];
|
|
32
33
|
#watch?: boolean;
|
|
34
|
+
#ctrl: AbortController;
|
|
35
|
+
#signal: AbortSignal;
|
|
33
36
|
|
|
34
37
|
constructor(state: CompilerState, dirtyFiles: string[], watch?: boolean) {
|
|
35
38
|
this.#state = state;
|
|
@@ -37,6 +40,11 @@ export class Compiler {
|
|
|
37
40
|
this.#state.getAllFiles() :
|
|
38
41
|
dirtyFiles.map(f => this.#state.getBySource(f)!.input);
|
|
39
42
|
this.#watch = watch;
|
|
43
|
+
|
|
44
|
+
this.#ctrl = new AbortController();
|
|
45
|
+
this.#signal = this.#ctrl.signal;
|
|
46
|
+
setMaxListeners(1000, this.#signal);
|
|
47
|
+
process.once('disconnect', () => this.#ctrl.abort()).once('SIGINT', () => this.#ctrl.abort());
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/**
|
|
@@ -50,6 +58,7 @@ export class Compiler {
|
|
|
50
58
|
if (needsNewProgram) {
|
|
51
59
|
program = this.#state.createProgram(program);
|
|
52
60
|
}
|
|
61
|
+
await timers.setImmediate();
|
|
53
62
|
const result = this.#state.writeInputFile(program, inputFile);
|
|
54
63
|
if (result?.diagnostics?.length) {
|
|
55
64
|
return result.diagnostics;
|
|
@@ -72,6 +81,7 @@ export class Compiler {
|
|
|
72
81
|
async * emit(files: string[], emitter: CompileEmitter): AsyncIterable<CompileEmitEvent> {
|
|
73
82
|
let i = 0;
|
|
74
83
|
let lastSent = Date.now();
|
|
84
|
+
|
|
75
85
|
for (const file of files) {
|
|
76
86
|
const err = await emitter(file);
|
|
77
87
|
const imp = file.replace(/.*node_modules\//, '');
|
|
@@ -80,8 +90,14 @@ export class Compiler {
|
|
|
80
90
|
lastSent = Date.now();
|
|
81
91
|
EventUtil.sendEvent('progress', { total: files.length, idx: i, message: imp, operation: 'compile' });
|
|
82
92
|
}
|
|
93
|
+
if (this.#signal.aborted) {
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
83
96
|
}
|
|
84
97
|
EventUtil.sendEvent('progress', { total: files.length, idx: files.length, message: 'Complete', operation: 'compile', complete: true });
|
|
98
|
+
|
|
99
|
+
await timers.setTimeout(1);
|
|
100
|
+
|
|
85
101
|
Log.debug(`Compiled ${i} files`);
|
|
86
102
|
}
|
|
87
103
|
|
|
@@ -89,16 +105,10 @@ export class Compiler {
|
|
|
89
105
|
* Run the compiler
|
|
90
106
|
*/
|
|
91
107
|
async run(): Promise<void> {
|
|
92
|
-
install();
|
|
93
|
-
|
|
94
108
|
Log.debug('Compilation started');
|
|
95
109
|
|
|
96
110
|
EventUtil.sendEvent('state', { state: 'init', extra: { pid: process.pid } });
|
|
97
111
|
|
|
98
|
-
if (process.send) {
|
|
99
|
-
process.on('disconnect', () => process.exit(0));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
112
|
const emitter = await this.getCompiler();
|
|
103
113
|
let failed = false;
|
|
104
114
|
|
|
@@ -114,9 +124,12 @@ export class Compiler {
|
|
|
114
124
|
EventUtil.sendEvent('log', { level: 'error', message: compileError.toString(), time: Date.now() });
|
|
115
125
|
}
|
|
116
126
|
}
|
|
117
|
-
if (
|
|
127
|
+
if (this.#signal.aborted) {
|
|
128
|
+
Log.debug('Compilation aborted');
|
|
129
|
+
} else if (failed) {
|
|
118
130
|
Log.debug('Compilation failed');
|
|
119
|
-
process.
|
|
131
|
+
process.exitCode = 1;
|
|
132
|
+
return;
|
|
120
133
|
} else {
|
|
121
134
|
Log.debug('Compilation succeeded');
|
|
122
135
|
}
|
|
@@ -128,15 +141,16 @@ export class Compiler {
|
|
|
128
141
|
|
|
129
142
|
EventUtil.sendEvent('state', { state: 'compile-end' });
|
|
130
143
|
|
|
131
|
-
if (this.#watch) {
|
|
144
|
+
if (this.#watch && !this.#signal.aborted) {
|
|
132
145
|
Log.info('Watch is ready');
|
|
133
146
|
|
|
134
147
|
EventUtil.sendEvent('state', { state: 'watch-start' });
|
|
135
148
|
|
|
136
|
-
for await (const ev of CompilerWatcher
|
|
149
|
+
for await (const ev of new CompilerWatcher(this.#state, this.#signal).watchChanges()) {
|
|
137
150
|
if (ev.action === 'reset') {
|
|
138
151
|
Log.info(`Triggering reset due to change in ${ev.file}`);
|
|
139
152
|
EventUtil.sendEvent('state', { state: 'reset' });
|
|
153
|
+
this.#ctrl.abort();
|
|
140
154
|
return;
|
|
141
155
|
}
|
|
142
156
|
const { action, entry } = ev;
|
|
@@ -166,5 +180,13 @@ export class Compiler {
|
|
|
166
180
|
|
|
167
181
|
EventUtil.sendEvent('state', { state: 'watch-end' });
|
|
168
182
|
}
|
|
183
|
+
|
|
184
|
+
// No longer listen to disconnect
|
|
185
|
+
process.removeAllListeners('disconnect');
|
|
186
|
+
|
|
187
|
+
if (this.#ctrl.signal.aborted) {
|
|
188
|
+
process.exitCode = 2;
|
|
189
|
+
Log.error('Shutting down manually');
|
|
190
|
+
}
|
|
169
191
|
}
|
|
170
192
|
}
|
package/src/event.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CompilerEvent, CompilerEventType } from '../support/types';
|
|
2
2
|
|
|
3
3
|
export class EventUtil {
|
|
4
|
-
static sendEvent<K extends
|
|
5
|
-
process.send
|
|
4
|
+
static sendEvent<K extends CompilerEventType, T extends CompilerEvent & { type: K }>(type: K, payload: T['payload']): void {
|
|
5
|
+
process.connected && process.send!({ type, payload });
|
|
6
6
|
}
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
2
|
|
|
3
|
-
import { IndexedModule, ManifestContext, ManifestModuleUtil,
|
|
3
|
+
import { IndexedModule, ManifestContext, ManifestModuleUtil, path } from '@travetto/manifest';
|
|
4
4
|
|
|
5
5
|
import { AsyncQueue } from '../../support/queue';
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ const VALID_TYPES = new Set(['ts', 'typings', 'js', 'package-json']);
|
|
|
13
13
|
type ToWatch = { file: string, actions: string[] };
|
|
14
14
|
|
|
15
15
|
/** Watch file for reset */
|
|
16
|
-
|
|
16
|
+
function watchForReset(q: AsyncQueue<WatchEvent>, root: string, files: ToWatch[], signal: AbortSignal): void {
|
|
17
17
|
const watchers: Record<string, { folder: string, files: Map<string, (ToWatch & { name: string, actionSet: Set<string> })> }> = {};
|
|
18
18
|
// Group by base path
|
|
19
19
|
for (const el of files) {
|
|
@@ -26,15 +26,19 @@ async function watchForReset(q: AsyncQueue<WatchEvent>, root: string, files: ToW
|
|
|
26
26
|
|
|
27
27
|
// Fire them all off
|
|
28
28
|
Object.values(watchers).map(async (watcher) => {
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
try {
|
|
30
|
+
for await (const ev of fs.watch(watcher.folder, { persistent: true, encoding: 'utf8', signal })) {
|
|
31
|
+
const toWatch = watcher.files.get(ev.filename!);
|
|
32
|
+
if (toWatch) {
|
|
33
|
+
const stat = await fs.stat(path.resolve(root, ev.filename!)).catch(() => undefined);
|
|
34
|
+
const action = !stat ? 'delete' : ((Date.now() - stat.ctimeMs) < CREATE_THRESHOLD) ? 'create' : 'update';
|
|
35
|
+
if (toWatch.actionSet.has(action)) {
|
|
36
|
+
q.add({ action: 'reset', file: ev.filename! });
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
39
|
}
|
|
40
|
+
} catch (err) {
|
|
41
|
+
// Ignore
|
|
38
42
|
}
|
|
39
43
|
});
|
|
40
44
|
}
|
|
@@ -44,7 +48,7 @@ async function watchFolder(ctx: ManifestContext, q: AsyncQueue<WatchEvent>, src:
|
|
|
44
48
|
const lib = await import('@parcel/watcher');
|
|
45
49
|
const ignore = [
|
|
46
50
|
'node_modules', '**/.trv',
|
|
47
|
-
...((!ctx.
|
|
51
|
+
...((!ctx.workspace.mono || src === ctx.workspace.path) ? [ctx.build.compilerFolder, ctx.build.outputFolder] : []),
|
|
48
52
|
...(await fs.readdir(src)).filter(x => x.startsWith('.'))
|
|
49
53
|
];
|
|
50
54
|
|
|
@@ -78,24 +82,23 @@ async function watchFolder(ctx: ManifestContext, q: AsyncQueue<WatchEvent>, src:
|
|
|
78
82
|
export async function* fileWatchEvents(manifest: ManifestContext, modules: IndexedModule[], signal: AbortSignal): AsyncIterable<WatchEvent> {
|
|
79
83
|
const q = new AsyncQueue<WatchEvent>(signal);
|
|
80
84
|
|
|
81
|
-
for (const m of modules.filter(x => !manifest.
|
|
82
|
-
watchFolder(manifest, q, m.sourcePath, m.sourcePath, signal);
|
|
85
|
+
for (const m of modules.filter(x => !manifest.workspace.mono || x.sourcePath !== manifest.workspace.path)) {
|
|
86
|
+
await watchFolder(manifest, q, m.sourcePath, m.sourcePath, signal);
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
// Add monorepo folders
|
|
86
|
-
if (manifest.
|
|
87
|
-
const mono = modules.find(x => x.sourcePath === manifest.
|
|
90
|
+
if (manifest.workspace.mono) {
|
|
91
|
+
const mono = modules.find(x => x.sourcePath === manifest.workspace.path)!;
|
|
88
92
|
for (const folder of Object.keys(mono.files)) {
|
|
89
93
|
if (!folder.startsWith('$')) {
|
|
90
|
-
watchFolder(manifest, q, path.resolve(mono.sourcePath, folder), mono.sourcePath, signal);
|
|
94
|
+
await watchFolder(manifest, q, path.resolve(mono.sourcePath, folder), mono.sourcePath, signal);
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
|
|
95
|
-
watchForReset(q,
|
|
96
|
-
{ file:
|
|
97
|
-
{ file:
|
|
98
|
-
{ file: RootIndex.manifest.toolFolder, actions: ['delete'] },
|
|
99
|
+
watchForReset(q, manifest.workspace.path, [
|
|
100
|
+
{ file: manifest.build.outputFolder, actions: ['delete'] },
|
|
101
|
+
{ file: manifest.build.compilerFolder, actions: ['delete'] },
|
|
99
102
|
{ file: 'package-lock.json', actions: ['delete', 'update', 'create'] },
|
|
100
103
|
{ file: 'package.json', actions: ['delete', 'update', 'create'] }
|
|
101
104
|
], signal);
|
package/src/log.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { EventUtil } from './event';
|
|
|
3
3
|
|
|
4
4
|
function log(level: CompilerLogLevel, message: string, ...args: unknown[]): void {
|
|
5
5
|
EventUtil.sendEvent('log', { level, message, args, time: Date.now(), scope: 'compiler-exec' });
|
|
6
|
-
if (!process.
|
|
6
|
+
if (!process.connected) {
|
|
7
7
|
// eslint-disable-next-line no-console
|
|
8
8
|
console[level](message, ...args);
|
|
9
9
|
}
|
package/src/state.ts
CHANGED
|
@@ -46,11 +46,11 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
46
46
|
async init(idx: ManifestIndex): Promise<this> {
|
|
47
47
|
this.#manifestIndex = idx;
|
|
48
48
|
this.#manifest = idx.manifest;
|
|
49
|
-
const mapper = folderMapper(this.#manifest.
|
|
49
|
+
const mapper = folderMapper(this.#manifest.workspace.path, '##');
|
|
50
50
|
this.#rootDir = mapper.dir;
|
|
51
51
|
this.#inputPathToSource = mapper.translate;
|
|
52
52
|
|
|
53
|
-
this.#outputPath = path.resolve(this.#manifest.
|
|
53
|
+
this.#outputPath = path.resolve(this.#manifest.workspace.path, this.#manifest.build.outputFolder);
|
|
54
54
|
this.#modules = Object.values(this.#manifest.modules);
|
|
55
55
|
|
|
56
56
|
// Register all inputs
|
|
@@ -91,7 +91,7 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
resolveOutputFile(file: string): string {
|
|
94
|
-
return path.resolve(this.#manifest.
|
|
94
|
+
return path.resolve(this.#manifest.workspace.path, this.#manifest.build.outputFolder, file);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
getArbitraryInputFile(): string {
|
|
@@ -125,7 +125,7 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
125
125
|
|
|
126
126
|
registerInput(module: ManifestModule, moduleFile: string): CompileStateEntry {
|
|
127
127
|
const relativeInput = `${module.outputFolder}/${moduleFile}`;
|
|
128
|
-
const sourceFile = path.resolve(this.#manifest.
|
|
128
|
+
const sourceFile = path.resolve(this.#manifest.workspace.path, module.sourceFolder, moduleFile);
|
|
129
129
|
const sourceFolder = path.dirname(sourceFile);
|
|
130
130
|
const inputFile = path.resolve(this.#rootDir, relativeInput); // Ensure input is isolated
|
|
131
131
|
const inputFolder = path.dirname(inputFile);
|
package/src/util.ts
CHANGED
|
@@ -31,7 +31,7 @@ export class CompilerUtil {
|
|
|
31
31
|
*/
|
|
32
32
|
static rewriteSourceMap(ctx: ManifestContext, text: string, outputToSource: OutputToSource): string {
|
|
33
33
|
const data: { sourceRoot?: string, sources: string[] } = JSON.parse(text);
|
|
34
|
-
const output = ManifestModuleUtil.sourceToOutputExt(path.resolve(ctx.
|
|
34
|
+
const output = ManifestModuleUtil.sourceToOutputExt(path.resolve(ctx.workspace.path, ctx.build.outputFolder, data.sources[0]));
|
|
35
35
|
const { source: file } = outputToSource(output) ?? {};
|
|
36
36
|
|
|
37
37
|
if (file) {
|
|
@@ -81,7 +81,7 @@ export class CompilerUtil {
|
|
|
81
81
|
if (pkg.main) {
|
|
82
82
|
pkg.main = ManifestModuleUtil.sourceToOutputExt(pkg.main);
|
|
83
83
|
}
|
|
84
|
-
pkg.type = manifest.
|
|
84
|
+
pkg.type = manifest.workspace.type;
|
|
85
85
|
for (const key of ['devDependencies', 'dependencies', 'peerDependencies'] as const) {
|
|
86
86
|
if (key in pkg) {
|
|
87
87
|
for (const dep of Object.keys(pkg[key] ?? {})) {
|