@joystick.js/cli-canary 0.0.0-canary.9 → 0.0.0-canary.90
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/dist/cli.js +7 -0
- package/dist/functions/index.js +21 -0
- package/dist/functions/start/index.js +3 -489
- package/dist/functions/start/onWarn.js +1 -1
- package/dist/functions/start/setComponentId.js +1 -1
- package/dist/functions/test/index.js +7 -26
- package/dist/lib/build/buildFiles.js +63 -7
- package/dist/lib/build/buildPlugins.js +18 -15
- package/dist/lib/build/getCodeFrame.js +3 -4
- package/dist/lib/build/onWarn.js +1 -1
- package/dist/lib/dev/cleanup.js +15 -27
- package/dist/lib/dev/databases/mongodb/index.js +1 -1
- package/dist/lib/dev/databases/postgresql/index.js +2 -2
- package/dist/lib/dev/databases/providerMap.js +1 -1
- package/dist/lib/dev/index.js +104 -28
- package/dist/lib/dev/isWindows.js +5 -0
- package/dist/lib/dev/loadSettings.js +1 -3
- package/dist/lib/dev/startApp.js +43 -3
- package/dist/lib/dev/startDatabases.js +12 -5
- package/dist/lib/dev/startHMR.js +30 -5
- package/dist/lib/getProcessIdFromPort.js +60 -0
- package/dist/lib/types.js +6 -0
- package/package.json +1 -1
- package/src/cli.js +9 -0
- package/src/functions/index.js +21 -0
- package/src/functions/start/index.js +2 -691
- package/src/functions/start/onWarn.js +1 -1
- package/src/functions/start/setComponentId.js +1 -1
- package/src/functions/test/index.js +7 -32
- package/src/lib/build/buildFiles.js +74 -8
- package/src/lib/build/buildPlugins.js +29 -22
- package/src/lib/build/getCodeFrame.js +3 -4
- package/src/lib/build/onWarn.js +1 -1
- package/src/lib/dev/cleanup.js +20 -28
- package/src/lib/dev/databases/mongodb/index.js +1 -1
- package/src/lib/dev/databases/postgresql/index.js +2 -2
- package/src/lib/dev/databases/providerMap.js +1 -1
- package/src/lib/dev/index.js +124 -41
- package/src/lib/dev/isWindows.js +3 -0
- package/src/lib/dev/loadSettings.js +1 -3
- package/src/lib/dev/startApp.js +52 -6
- package/src/lib/dev/startDatabases.js +12 -6
- package/src/lib/dev/startHMR.js +36 -7
- package/src/lib/getProcessIdFromPort.js +92 -0
- package/src/lib/types.js +3 -0
|
@@ -3,7 +3,7 @@ import generateId from "./generateId.js";
|
|
|
3
3
|
|
|
4
4
|
export default (file = "") => {
|
|
5
5
|
const componentMapPath =
|
|
6
|
-
process.env.NODE_ENV
|
|
6
|
+
['development', 'test'].includes(process.env.NODE_ENV)
|
|
7
7
|
? `./.joystick/build/componentMap.json`
|
|
8
8
|
: `./.build/componentMap.json`;
|
|
9
9
|
const componentMapExists = fs.existsSync(componentMapPath);
|
|
@@ -1,34 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import dev from "../../lib/dev/index.js";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const validateOptions = (options) => {
|
|
12
|
-
try {
|
|
13
|
-
if (!options) throw new Error('options object is required.');
|
|
14
|
-
if (!options.someOption) throw new Error('options.someOption is required.');
|
|
15
|
-
} catch (exception) {
|
|
16
|
-
throw new Error(`[test.validateOptions] ${exception.message}`);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const test = (options, { resolve, reject }) => {
|
|
21
|
-
try {
|
|
22
|
-
validateOptions(options);
|
|
23
|
-
// Call action methods in sequence here.
|
|
24
|
-
resolve();
|
|
25
|
-
} catch (exception) {
|
|
26
|
-
reject(`[test] ${exception.message}`);
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export default (options) =>
|
|
31
|
-
new Promise((resolve, reject) => {
|
|
32
|
-
test(options, { resolve, reject });
|
|
3
|
+
export default async (args = {}, options = {}) => {
|
|
4
|
+
await dev({
|
|
5
|
+
environment: 'test',
|
|
6
|
+
process,
|
|
7
|
+
port: 1977,
|
|
33
8
|
});
|
|
34
|
-
|
|
9
|
+
};
|
|
@@ -8,6 +8,43 @@ import browserPathExclusions from "./browserPathExclusions.js";
|
|
|
8
8
|
import nodePaths from "./nodePaths.js";
|
|
9
9
|
import nodePathExclusions from "./nodePathExclusions.js";
|
|
10
10
|
import buildPlugins from "./buildPlugins.js";
|
|
11
|
+
import getCodeFrame from "./getCodeFrame.js";
|
|
12
|
+
import onWarn from "./onWarn.js";
|
|
13
|
+
|
|
14
|
+
const handleBuildException = (exception = {}, file = '') => {
|
|
15
|
+
try {
|
|
16
|
+
const error = exception?.errors && exception?.errors[0];
|
|
17
|
+
const snippet = fs.existsSync(file)
|
|
18
|
+
? getCodeFrame(file, {
|
|
19
|
+
line: error?.location?.line,
|
|
20
|
+
column: error?.location?.column,
|
|
21
|
+
})
|
|
22
|
+
: null;
|
|
23
|
+
|
|
24
|
+
onWarn({
|
|
25
|
+
file,
|
|
26
|
+
stack: exception?.stack,
|
|
27
|
+
line: error?.location?.line,
|
|
28
|
+
column: error?.location?.column,
|
|
29
|
+
snippet,
|
|
30
|
+
lineWithError: error?.location?.lineText?.trim(),
|
|
31
|
+
message: error?.text,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return snippet;
|
|
35
|
+
} catch (exception) {
|
|
36
|
+
throw new Error(`[actionName.handleBuildException] ${exception.message}`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const handleParseFilePathFromException = (exception = {}) => {
|
|
41
|
+
try {
|
|
42
|
+
const rawErrorMessage = exception?.message?.split(':');
|
|
43
|
+
return rawErrorMessage[1] && rawErrorMessage[1]?.replace('\n', '') || '';
|
|
44
|
+
} catch (exception) {
|
|
45
|
+
throw new Error(`[actionName.handleParseFilePathFromException] ${exception.message}`);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
11
48
|
|
|
12
49
|
const handleBuildForNode = (nodePaths = [], options = {}) => {
|
|
13
50
|
try {
|
|
@@ -63,8 +100,10 @@ const handleCopyFiles = (files = [], outputPath = '') => {
|
|
|
63
100
|
for (let i = 0; i < files?.length; i += 1) {
|
|
64
101
|
const file = files[i];
|
|
65
102
|
const fileContents = fs.readFileSync(file.path);
|
|
66
|
-
|
|
67
|
-
fs.
|
|
103
|
+
|
|
104
|
+
// NOTE: Using fs.outputFileSync() from fs-extra to ensure parent path is created
|
|
105
|
+
// if it doesn't exist (avoids need for separate fs.mkdirSync()).
|
|
106
|
+
fs.outputFileSync(
|
|
68
107
|
`${outputPath || "./.joystick/build"}/${file.path}`,
|
|
69
108
|
fileContents
|
|
70
109
|
);
|
|
@@ -76,7 +115,7 @@ const handleCopyFiles = (files = [], outputPath = '') => {
|
|
|
76
115
|
|
|
77
116
|
const isNodePath = (path = '') => {
|
|
78
117
|
try {
|
|
79
|
-
return nodePaths.some((nodePath) => {
|
|
118
|
+
return !isNotJavaScript(path) && nodePaths.some((nodePath) => {
|
|
80
119
|
return path.includes(nodePath);
|
|
81
120
|
}) &&
|
|
82
121
|
!nodePathExclusions.some((nodeExclusionPath) => {
|
|
@@ -89,7 +128,7 @@ const isNodePath = (path = '') => {
|
|
|
89
128
|
|
|
90
129
|
const isBrowserPath = (path = '') => {
|
|
91
130
|
try {
|
|
92
|
-
return browserPaths.some((browserPath) => {
|
|
131
|
+
return !isNotJavaScript(path) && browserPaths.some((browserPath) => {
|
|
93
132
|
return path.includes(browserPath);
|
|
94
133
|
}) &&
|
|
95
134
|
!browserPathExclusions.some((browserExclusionPath) => {
|
|
@@ -181,9 +220,36 @@ const buildFiles = async (options, { resolve, reject }) => {
|
|
|
181
220
|
|
|
182
221
|
handleCopyFiles(copyFiles, options?.outputPath);
|
|
183
222
|
|
|
184
|
-
await Promise.all([
|
|
185
|
-
handleBuildForBrowser(browserFiles, options)
|
|
186
|
-
|
|
223
|
+
const fileResults = await Promise.all([
|
|
224
|
+
handleBuildForBrowser(browserFiles, options).then(() => {
|
|
225
|
+
return { success: true };
|
|
226
|
+
}).catch((exception) => {
|
|
227
|
+
const file = handleParseFilePathFromException(exception);
|
|
228
|
+
console.log(file, exception);
|
|
229
|
+
const snippet = handleBuildException(exception, file);
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
success: false,
|
|
233
|
+
path: file,
|
|
234
|
+
error: {
|
|
235
|
+
stack: exception?.stack,
|
|
236
|
+
snippet,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}),
|
|
240
|
+
handleBuildForNode(nodeFiles, options).catch((exception) => {
|
|
241
|
+
const file = handleParseFilePathFromException(exception);
|
|
242
|
+
const snippet = handleBuildException(exception, file);
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
success: false,
|
|
246
|
+
path: file,
|
|
247
|
+
error: {
|
|
248
|
+
stack: exception?.stack,
|
|
249
|
+
snippet,
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}),
|
|
187
253
|
]);
|
|
188
254
|
|
|
189
255
|
if (options?.environment !== 'development') {
|
|
@@ -192,7 +258,7 @@ const buildFiles = async (options, { resolve, reject }) => {
|
|
|
192
258
|
}));
|
|
193
259
|
}
|
|
194
260
|
|
|
195
|
-
resolve();
|
|
261
|
+
resolve(fileResults);
|
|
196
262
|
} catch (exception) {
|
|
197
263
|
reject(`[buildFiles] ${exception.message}`);
|
|
198
264
|
}
|
|
@@ -25,22 +25,25 @@ export default {
|
|
|
25
25
|
(bootstrapTarget) => {
|
|
26
26
|
return args.path.includes(bootstrapTarget);
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
);
|
|
29
|
+
|
|
29
30
|
const isLayoutComponent = [getPlatformSafePath("ui/layouts")].some(
|
|
30
31
|
(bootstrapTarget) => {
|
|
31
32
|
return args.path.includes(bootstrapTarget);
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
+
);
|
|
35
|
+
|
|
34
36
|
const isPageComponent = [getPlatformSafePath("ui/pages")].some(
|
|
35
37
|
(bootstrapTarget) => {
|
|
36
38
|
return args.path.includes(bootstrapTarget);
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
);
|
|
41
|
+
|
|
39
42
|
const isEmailComponent = [getPlatformSafePath("email/")].some(
|
|
40
43
|
(bootstrapTarget) => {
|
|
41
44
|
return args.path.includes(bootstrapTarget);
|
|
42
45
|
}
|
|
43
|
-
|
|
46
|
+
);
|
|
44
47
|
|
|
45
48
|
if (
|
|
46
49
|
shouldSetSSRId ||
|
|
@@ -51,7 +54,7 @@ export default {
|
|
|
51
54
|
const code = fs.readFileSync(
|
|
52
55
|
getPlatformSafePath(args.path),
|
|
53
56
|
"utf-8"
|
|
54
|
-
|
|
57
|
+
);
|
|
55
58
|
|
|
56
59
|
// NOTE: Check to see if we have a valid component file.
|
|
57
60
|
const joystickUIMatches = code.match(JOYSTICK_UI_REGEX) || [];
|
|
@@ -65,8 +68,8 @@ export default {
|
|
|
65
68
|
console.warn(
|
|
66
69
|
chalk.yellowBright(
|
|
67
70
|
`All Joystick components in the ui directory must have an export default statement (e.g., export default MyComponent, export default MyLayout, or export default MyPage). Please check the file at ${args.path}.`
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
)
|
|
72
|
+
);
|
|
70
73
|
console.log(" ");
|
|
71
74
|
return;
|
|
72
75
|
}
|
|
@@ -110,7 +113,7 @@ export default {
|
|
|
110
113
|
|
|
111
114
|
export default ${componentName};
|
|
112
115
|
`
|
|
113
|
-
|
|
116
|
+
);
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
if (componentName && isPageComponent) {
|
|
@@ -128,7 +131,7 @@ export default {
|
|
|
128
131
|
|
|
129
132
|
export default ${componentName};
|
|
130
133
|
`
|
|
131
|
-
|
|
134
|
+
);
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
return {
|
|
@@ -143,25 +146,29 @@ export default {
|
|
|
143
146
|
|
|
144
147
|
build.onEnd(() => {
|
|
145
148
|
return new Promise((resolve) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
for (let i = 0; i < build?.initialOptions?.entryPoints?.length; i += 1) {
|
|
150
|
+
const entryPoint = build?.initialOptions?.entryPoints[i];
|
|
151
|
+
const shouldSetComponentId = [
|
|
152
|
+
getPlatformSafePath("ui/"),
|
|
153
|
+
getPlatformSafePath("email/"),
|
|
149
154
|
].some((bootstrapTarget) => {
|
|
150
|
-
return
|
|
155
|
+
return entryPoint.includes(bootstrapTarget);
|
|
151
156
|
});
|
|
152
157
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
if (shouldSetComponentId) {
|
|
159
|
+
const file = fs.readFileSync(`${build?.initialOptions?.outdir}/${entryPoint}`, "utf-8");
|
|
160
|
+
const joystickUIMatches =
|
|
156
161
|
file?.match(JOYSTICK_COMPONENT_REGEX) || [];
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
if (joystickUIMatches?.length > 0) {
|
|
164
|
+
let contents = setComponentId(file)?.replace(
|
|
165
|
+
/\.component\(\/\*\*\//g,
|
|
166
|
+
".component("
|
|
162
167
|
);
|
|
163
|
-
|
|
164
|
-
|
|
168
|
+
|
|
169
|
+
fs.writeFileSync(`${build?.initialOptions?.outdir}/${entryPoint}`, contents);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
165
172
|
}
|
|
166
173
|
|
|
167
174
|
resolve();
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import { codeFrameColumns } from "@babel/code-frame";
|
|
3
3
|
|
|
4
|
-
export default (
|
|
5
|
-
const file = fs.readFileSync(
|
|
6
|
-
|
|
7
|
-
return frame;
|
|
4
|
+
export default (path = "", location = {}) => {
|
|
5
|
+
const file = fs.readFileSync(path, "utf-8");
|
|
6
|
+
return codeFrameColumns(file, { start: location });
|
|
8
7
|
};
|
package/src/lib/build/onWarn.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { OBJECT_REGEX } from "../regexes.js";
|
|
3
3
|
import rainbowRoad from '../rainbowRoad.js';
|
|
4
|
-
import getCodeFrame from "
|
|
4
|
+
import getCodeFrame from "./getCodeFrame.js";
|
|
5
5
|
|
|
6
6
|
const removeLocationDataFromStackTrace = (stackTrace = "") => {
|
|
7
7
|
return stackTrace.replace(OBJECT_REGEX, "");
|
package/src/lib/dev/cleanup.js
CHANGED
|
@@ -1,34 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
// NOTE: This module is intended to be run as a child_process as part of
|
|
2
|
+
// a SIGINT or SIGTERM event.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
try {
|
|
5
|
-
// Perform a single step in your action here.
|
|
6
|
-
} catch (exception) {
|
|
7
|
-
throw new Error(`[cleanup.actionMethod] ${exception.message}`);
|
|
8
|
-
}
|
|
9
|
-
};
|
|
4
|
+
import ps from "ps-node";
|
|
10
5
|
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
if (!options) throw new Error('options object is required.');
|
|
14
|
-
if (!options.someOption) throw new Error('options.someOption is required.');
|
|
15
|
-
} catch (exception) {
|
|
16
|
-
throw new Error(`[cleanup.validateOptions] ${exception.message}`);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
6
|
+
process.title = "joystick_cleanup";
|
|
19
7
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
reject(`[cleanup] ${exception.message}`);
|
|
27
|
-
}
|
|
8
|
+
const killProcess = (pid = 0) => {
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
ps.kill(pid, () => {
|
|
11
|
+
resolve();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
28
14
|
};
|
|
29
15
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
16
|
+
process.on('message', async (message) => {
|
|
17
|
+
const parsedMessage = JSON.parse(message);
|
|
18
|
+
const processIds = parsedMessage?.processIds;
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < processIds?.length; i += 1) {
|
|
21
|
+
const processId = processIds[i];
|
|
22
|
+
await killProcess(processId);
|
|
23
|
+
}
|
|
34
24
|
|
|
25
|
+
process.exit();
|
|
26
|
+
});
|
|
@@ -4,7 +4,7 @@ import child_process from "child_process";
|
|
|
4
4
|
import { kill as killPortProcess } from 'cross-port-killer';
|
|
5
5
|
import isWindows from "../../isWindows.js";
|
|
6
6
|
import CLILog from "../../../../lib/CLILog.js";
|
|
7
|
-
import getProcessIdFromPort from "
|
|
7
|
+
import getProcessIdFromPort from "../../../getProcessIdFromPort.js";
|
|
8
8
|
|
|
9
9
|
const getMongoProcessId = async (port = 2601) => {
|
|
10
10
|
const pids = await getProcessIdFromPort(port);
|
|
@@ -4,8 +4,8 @@ import util from "util";
|
|
|
4
4
|
import commandExists from "command-exists";
|
|
5
5
|
import child_process from "child_process";
|
|
6
6
|
import { kill as killPortProcess } from 'cross-port-killer';
|
|
7
|
-
import getProcessIdFromPort from "
|
|
8
|
-
import CLILog from "
|
|
7
|
+
import getProcessIdFromPort from "../../../getProcessIdFromPort.js";
|
|
8
|
+
import CLILog from "../../../CLILog.js";
|
|
9
9
|
|
|
10
10
|
const exec = util.promisify(child_process.exec);
|
|
11
11
|
|
package/src/lib/dev/index.js
CHANGED
|
@@ -10,7 +10,6 @@ import loadSettings from "./loadSettings.js";
|
|
|
10
10
|
import Loader from "../loader.js";
|
|
11
11
|
import startDatabases from "./startDatabases.js";
|
|
12
12
|
import runTests from "./runTests.js";
|
|
13
|
-
import cleanup from "./cleanup.js";
|
|
14
13
|
import startHMR from "./startHMR.js";
|
|
15
14
|
import startApp from "./startApp.js";
|
|
16
15
|
import requiredFiles from "./requiredFiles.js";
|
|
@@ -21,14 +20,7 @@ import filesToCopy from "../filesToCopy.js";
|
|
|
21
20
|
import { SETTINGS_FILE_NAME_REGEX } from "../regexes.js";
|
|
22
21
|
import getCodependenciesForFile from "./getCodependenciesForFile.js";
|
|
23
22
|
import removeDeletedDependenciesFromMap from "../build/removeDeletedDependenciesFromMap.js";
|
|
24
|
-
|
|
25
|
-
const nodeMajorVersion = parseInt(
|
|
26
|
-
process?.version?.split(".")[0]?.replace("v", ""),
|
|
27
|
-
10
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
31
|
-
const __dirname = dirname(__filename);
|
|
23
|
+
import chalk from "chalk";
|
|
32
24
|
|
|
33
25
|
const getDatabaseProcessIds = () => {
|
|
34
26
|
try {
|
|
@@ -61,7 +53,7 @@ const getDatabaseProcessIds = () => {
|
|
|
61
53
|
}
|
|
62
54
|
};
|
|
63
55
|
|
|
64
|
-
const handleSignalEvents = (processIds = []) => {
|
|
56
|
+
const handleSignalEvents = (processIds = [], nodeMajorVersion = 0, __dirname = '') => {
|
|
65
57
|
try {
|
|
66
58
|
const execArgv = ["--no-warnings"];
|
|
67
59
|
|
|
@@ -70,7 +62,7 @@ const handleSignalEvents = (processIds = []) => {
|
|
|
70
62
|
}
|
|
71
63
|
|
|
72
64
|
const cleanupProcess = child_process.fork(
|
|
73
|
-
path.resolve(`${__dirname}/cleanup
|
|
65
|
+
path.resolve(`${__dirname}/cleanup.js`),
|
|
74
66
|
[],
|
|
75
67
|
{
|
|
76
68
|
// NOTE: Run in detached mode so when parent process dies, the child still runs
|
|
@@ -99,6 +91,53 @@ const handleSignalEvents = (processIds = []) => {
|
|
|
99
91
|
}
|
|
100
92
|
};
|
|
101
93
|
|
|
94
|
+
const handleServerProcessMessages = () => {
|
|
95
|
+
try {
|
|
96
|
+
process.serverProcess.on("message", (message) => {
|
|
97
|
+
const processMessages = ["SERVER_CLOSED"];
|
|
98
|
+
|
|
99
|
+
if (!processMessages.includes(message)) {
|
|
100
|
+
process.loader.stable(message);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} catch (exception) {
|
|
104
|
+
throw new Error(`[dev.handleServerProcessMessages] ${exception.message}`);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const handleServerProcessSTDIO = () => {
|
|
109
|
+
try {
|
|
110
|
+
if (process.serverProcess) {
|
|
111
|
+
process.serverProcess.on("error", (error) => {
|
|
112
|
+
console.log(error);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
process.serverProcess.stdout.on("data", (data) => {
|
|
116
|
+
const message = data.toString();
|
|
117
|
+
|
|
118
|
+
if (message && message.includes("App running at:")) {
|
|
119
|
+
process.loader.stable(message);
|
|
120
|
+
} else {
|
|
121
|
+
if (message && !message.includes("BUILD_ERROR")) {
|
|
122
|
+
console.log(message);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
process.serverProcess.stderr.on("data", (data) => {
|
|
128
|
+
process.loader.stop();
|
|
129
|
+
|
|
130
|
+
CLILog(data.toString(), {
|
|
131
|
+
level: "danger",
|
|
132
|
+
docs: "https://cheatcode.co/docs/joystick",
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
} catch (exception) {
|
|
137
|
+
throw new Error(`[dev.handleServerProcessSTDIO] ${exception.message}`);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
102
141
|
const handleAddOrChangeFile = async (context = {}, path = '') => {
|
|
103
142
|
try {
|
|
104
143
|
if (context.isAddingOrChangingFile) {
|
|
@@ -228,7 +267,7 @@ const getWatchChangeContext = (event = '', path = '') => {
|
|
|
228
267
|
try {
|
|
229
268
|
const isHTMLUpdate = path === "index.html";
|
|
230
269
|
const isUIPath = path?.includes("ui/") || path === 'index.css' || isHTMLUpdate;
|
|
231
|
-
const isUIUpdate = (process.hmrProcess.hasConnections && isUIPath) || false;
|
|
270
|
+
const isUIUpdate = (process.hmrProcess && process.hmrProcess.hasConnections && isUIPath) || false;
|
|
232
271
|
const isSettingsUpdate = path?.match(SETTINGS_FILE_NAME_REGEX)?.length > 0;
|
|
233
272
|
const isDirectory = fs.statSync(path).isDirectory();
|
|
234
273
|
const isFile = fs.statSync(path).isFile();
|
|
@@ -292,21 +331,26 @@ const startFileWatcher = (options = {}) => {
|
|
|
292
331
|
|
|
293
332
|
const runInitialBuild = async (buildSettings = {}) => {
|
|
294
333
|
try {
|
|
334
|
+
process.loader.text('Building app...');
|
|
335
|
+
|
|
295
336
|
const filesToBuild = getFilesToBuild(buildSettings?.excludedPaths, "start");
|
|
296
|
-
const fileResults = await buildFiles(
|
|
297
|
-
filesToBuild,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
);
|
|
337
|
+
const fileResults = await buildFiles({
|
|
338
|
+
files: filesToBuild,
|
|
339
|
+
environment: process.env.NODE_ENV
|
|
340
|
+
});
|
|
301
341
|
|
|
302
342
|
const hasErrors = [...fileResults]
|
|
303
343
|
.filter((result) => !!result)
|
|
304
344
|
.map(({ success }) => success)
|
|
305
345
|
.includes(false);
|
|
306
346
|
|
|
307
|
-
//
|
|
308
|
-
|
|
347
|
+
// NOTE: If the initial build fails, exit the startup process.
|
|
348
|
+
if (hasErrors) {
|
|
349
|
+
console.log(chalk.redBright('Failed to start app. Correct the errors above and run joystick start again.\n'));
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
309
352
|
} catch (exception) {
|
|
353
|
+
console.warn(exception);
|
|
310
354
|
throw new Error(`[dev.runInitialBuild] ${exception.message}`);
|
|
311
355
|
}
|
|
312
356
|
};
|
|
@@ -352,18 +396,22 @@ const checkForRequiredFiles = () => {
|
|
|
352
396
|
|
|
353
397
|
let error = `The following paths are missing and required in a Joystick project:\n\n`;
|
|
354
398
|
|
|
355
|
-
|
|
399
|
+
if (files?.length > 0) {
|
|
400
|
+
error += ` > Required Files:\n\n`;
|
|
356
401
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
402
|
+
for (let i = 0; i < files?.length; i += 1) {
|
|
403
|
+
const file = files[i];
|
|
404
|
+
error += ` /${file.path}\n`;
|
|
405
|
+
}
|
|
360
406
|
}
|
|
361
407
|
|
|
362
|
-
|
|
408
|
+
if (directories?.length > 0) {
|
|
409
|
+
error += ` > Required Directories:\n\n`;
|
|
363
410
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
411
|
+
for (let i = 0; i < directories?.length; i += 1) {
|
|
412
|
+
const file = directories[i];
|
|
413
|
+
error += ` /${file.path}\n`;
|
|
414
|
+
}
|
|
367
415
|
}
|
|
368
416
|
|
|
369
417
|
CLILog(error, {
|
|
@@ -395,7 +443,7 @@ const warnInvalidJoystickEnvironment = () => {
|
|
|
395
443
|
process.exit(0);
|
|
396
444
|
}
|
|
397
445
|
|
|
398
|
-
if (process.env.NODE_ENV !== 'test' &&
|
|
446
|
+
if (process.env.NODE_ENV !== 'test' && !hasJoystickFolder) {
|
|
399
447
|
CLILog(
|
|
400
448
|
"joystick start must be run in a directory with a .joystick folder.",
|
|
401
449
|
{
|
|
@@ -425,29 +473,61 @@ const dev = async (options, { resolve, reject }) => {
|
|
|
425
473
|
validateOptions(options);
|
|
426
474
|
initProcess(options);
|
|
427
475
|
|
|
476
|
+
const nodeMajorVersion = parseInt(
|
|
477
|
+
process?.version?.split(".")[0]?.replace("v", ""),
|
|
478
|
+
10
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
482
|
+
const __dirname = dirname(__filename);
|
|
483
|
+
|
|
428
484
|
warnInvalidJoystickEnvironment();
|
|
429
485
|
checkForRequiredFiles();
|
|
430
486
|
|
|
431
487
|
const settings = await loadSettings({
|
|
432
488
|
environment: options.environment,
|
|
433
|
-
process: options.process,
|
|
434
489
|
});
|
|
435
490
|
|
|
436
|
-
await startDatabases(
|
|
491
|
+
await startDatabases({
|
|
492
|
+
environment: options.environment,
|
|
493
|
+
port: options.port,
|
|
494
|
+
settings: settings.parsed
|
|
495
|
+
});
|
|
437
496
|
|
|
438
497
|
await runInitialBuild(settings?.parsed?.config?.build);
|
|
439
498
|
await startFileWatcher(options);
|
|
440
499
|
|
|
441
|
-
|
|
500
|
+
const serverProcess = await startApp({
|
|
501
|
+
nodeMajorVersion,
|
|
502
|
+
port: options?.port,
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
if (serverProcess) {
|
|
506
|
+
process.serverProcess = serverProcess;
|
|
507
|
+
handleServerProcessSTDIO();
|
|
508
|
+
handleServerProcessMessages();
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// NOTE: Scope this out here so we can reference the processId below.
|
|
512
|
+
let hmrProcess;
|
|
442
513
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
514
|
+
if (options?.environment !== 'test') {
|
|
515
|
+
hmrProcess = await startHMR({
|
|
516
|
+
nodeMajorVersion,
|
|
517
|
+
__dirname,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
handleSignalEvents(
|
|
522
|
+
[serverProcess.pid, hmrProcess.pid],
|
|
523
|
+
nodeMajorVersion,
|
|
524
|
+
__dirname
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
if (options?.environment === 'test') {
|
|
528
|
+
process.loader.text('Running tests...');
|
|
529
|
+
// await runTests(options);
|
|
530
|
+
}
|
|
451
531
|
|
|
452
532
|
/*
|
|
453
533
|
TODO:
|
|
@@ -456,14 +536,17 @@ const dev = async (options, { resolve, reject }) => {
|
|
|
456
536
|
- [x] If environment === 'test', check that both a .joystick fo lder exists AND a /tests folder
|
|
457
537
|
exists. If no /tests, log out docs on how to scaffold your tests.
|
|
458
538
|
- [x] Load settings.<environment>.json.
|
|
459
|
-
- [
|
|
460
|
-
- [
|
|
539
|
+
- [x] Start databases relative to options.environment (development|test) from settings.<environment>.json.
|
|
540
|
+
- [x] Run the initial build
|
|
541
|
+
- [x] Start the file watcher
|
|
542
|
+
- [x] Start the app as normal from the build directory.
|
|
461
543
|
- [ ] If environment === 'test', run the tests.
|
|
462
544
|
- [ ] If environment === 'test', after tests, run process.exit(0).
|
|
463
545
|
*/
|
|
464
546
|
|
|
465
547
|
resolve();
|
|
466
548
|
} catch (exception) {
|
|
549
|
+
console.warn(exception);
|
|
467
550
|
reject(`[dev] ${exception.message}`);
|
|
468
551
|
}
|
|
469
552
|
};
|
|
@@ -73,9 +73,7 @@ const loadSettings = (options, { resolve, reject }) => {
|
|
|
73
73
|
const settings = getSettings(settingsPath);
|
|
74
74
|
warnIfInvalidJSONInSettings(settings);
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
options.process.env.JOYSTICK_SETTINGS = settings;
|
|
78
|
-
}
|
|
76
|
+
process.env.JOYSTICK_SETTINGS = settings;
|
|
79
77
|
|
|
80
78
|
resolve({
|
|
81
79
|
parsed: JSON.parse(settings),
|