/
register.ts
129 lines (117 loc) · 3.97 KB
/
register.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { join } from 'path';
import { logger, NX_PREFIX, stripIndent } from './logger';
/**
* Optionally, if swc-node and tsconfig-paths are available in the current workspace, apply the require
* register hooks so that .ts files can be used for writing custom workspace projects.
*
* If ts-node and tsconfig-paths are not available, the user can still provide an index.js file in
* the root of their project and the fundamentals will still work (but
* workspace path mapping will not, for example).
*
* @returns cleanup function
*/
export const registerTsProject = (
path: string,
configFilename = 'tsconfig.json'
): (() => void) => {
// Function to register transpiler that returns cleanup function
let registerTranspiler: () => () => void;
const tsConfigPath = join(path, configFilename);
const cleanupFunctions = [registerTsConfigPaths(tsConfigPath)];
const swcNodeInstalled = packageIsInstalled('@swc-node/register');
if (swcNodeInstalled) {
// These are requires to prevent it from registering when it shouldn't
const { register } =
require('@swc-node/register/register') as typeof import('@swc-node/register/register');
const {
readDefaultTsConfig,
} = require('@swc-node/register/read-default-tsconfig');
const tsConfig = readDefaultTsConfig(tsConfigPath);
registerTranspiler = () => register(tsConfig);
} else {
// We can fall back on ts-node if its available
const tsNodeInstalled = packageIsInstalled('ts-node/register');
if (tsNodeInstalled) {
const { register } = require('ts-node') as typeof import('ts-node');
// ts-node doesn't provide a cleanup method
registerTranspiler = () => {
const service = register({
project: tsConfigPath,
transpileOnly: true,
compilerOptions: {
module: 'commonjs',
},
});
// Don't warn if a faster transpiler is enabled
if (!service.options.transpiler && !service.options.swc) {
warnTsNodeUsage();
}
return () => {};
};
}
}
if (registerTranspiler) {
cleanupFunctions.push(registerTranspiler());
} else {
warnNoTranspiler();
}
// Overall cleanup method cleans up tsconfig path resolution
// as well as ts transpiler
return () => {
for (const f of cleanupFunctions) {
f();
}
};
};
/**
* @param tsConfigPath Adds the paths from a tsconfig file into node resolutions
* @returns cleanup function
*/
export function registerTsConfigPaths(tsConfigPath): () => void {
try {
/**
* Load the ts config from the source project
*/
const tsconfigPaths: typeof import('tsconfig-paths') = require('tsconfig-paths');
const tsConfigResult = tsconfigPaths.loadConfig(tsConfigPath);
/**
* Register the custom workspace path mappings with node so that workspace libraries
* can be imported and used within project
*/
if (tsConfigResult.resultType === 'success') {
return tsconfigPaths.register({
baseUrl: tsConfigResult.absoluteBaseUrl,
paths: tsConfigResult.paths,
});
}
} catch (err) {
warnNoTsconfigPaths();
}
return () => {};
}
function warnTsNodeUsage() {
logger.warn(
stripIndent(`${NX_PREFIX} Falling back to ts-node for local typescript execution. This may be a little slower.
- To fix this, ensure @swc-node/register and @swc/core have been installed`)
);
}
function warnNoTsconfigPaths() {
logger.warn(
stripIndent(`${NX_PREFIX} Unable to load tsconfig-paths, workspace libraries may be inaccessible.
- To fix this, install tsconfig-paths with npm/yarn/pnpm`)
);
}
function warnNoTranspiler() {
logger.warn(
stripIndent(`${NX_PREFIX} Unable to locate swc-node or ts-node. Nx will be unable to run local ts files without transpiling.
- To fix this, ensure @swc-node/register and @swc/core have been installed`)
);
}
function packageIsInstalled(m: string) {
try {
const p = require.resolve(m);
return true;
} catch {
return false;
}
}