@joystick.js/cli-canary 0.0.0-canary.7 → 0.0.0-canary.70

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.
Files changed (37) hide show
  1. package/dist/functions/start/index.js +4 -470
  2. package/dist/functions/start/onWarn.js +1 -1
  3. package/dist/lib/build/buildFiles.js +61 -5
  4. package/dist/lib/build/buildPlugins.js +18 -15
  5. package/dist/lib/build/getCodeFrame.js +3 -4
  6. package/dist/lib/build/onWarn.js +1 -1
  7. package/dist/lib/build/removeDeletedDependenciesFromMap.js +1 -1
  8. package/dist/lib/dev/databases/mongodb/index.js +1 -1
  9. package/dist/lib/dev/databases/postgresql/index.js +2 -2
  10. package/dist/lib/dev/databases/providerMap.js +1 -1
  11. package/dist/lib/dev/index.js +100 -26
  12. package/dist/lib/dev/isWindows.js +5 -0
  13. package/dist/lib/dev/loadSettings.js +1 -3
  14. package/dist/lib/dev/startApp.js +43 -3
  15. package/dist/lib/dev/startDatabases.js +12 -5
  16. package/dist/lib/dev/startHMR.js +30 -5
  17. package/dist/lib/getProcessIdFromPort.js +60 -0
  18. package/dist/lib/types.js +6 -0
  19. package/package.json +1 -1
  20. package/src/functions/start/index.js +615 -612
  21. package/src/functions/start/onWarn.js +1 -1
  22. package/src/lib/build/buildFiles.js +72 -6
  23. package/src/lib/build/buildPlugins.js +29 -22
  24. package/src/lib/build/getCodeFrame.js +3 -4
  25. package/src/lib/build/onWarn.js +1 -1
  26. package/src/lib/build/removeDeletedDependenciesFromMap.js +1 -1
  27. package/src/lib/dev/databases/mongodb/index.js +1 -1
  28. package/src/lib/dev/databases/postgresql/index.js +2 -2
  29. package/src/lib/dev/databases/providerMap.js +1 -1
  30. package/src/lib/dev/index.js +118 -33
  31. package/src/lib/dev/isWindows.js +3 -0
  32. package/src/lib/dev/loadSettings.js +1 -3
  33. package/src/lib/dev/startApp.js +52 -6
  34. package/src/lib/dev/startDatabases.js +12 -6
  35. package/src/lib/dev/startHMR.js +36 -7
  36. package/src/lib/getProcessIdFromPort.js +92 -0
  37. package/src/lib/types.js +3 -0
@@ -21,243 +21,243 @@
21
21
  //import wait from "../../lib/wait.js";
22
22
  import dev from "../../lib/dev/index.js";
23
23
 
24
- const majorVersion = parseInt(
25
- process?.version?.split(".")[0]?.replace("v", ""),
26
- 10
27
- );
28
-
29
- const __filename = fileURLToPath(import.meta.url);
30
- const __dirname = dirname(__filename);
31
-
32
- const killProcess = (pid = 0) => {
33
- return new Promise((resolve) => {
34
- ps.kill(pid, () => {
35
- resolve();
36
- });
37
- });
38
- };
39
-
40
- const watchlist = [
41
- { path: "ui" },
42
- { path: "lib" },
43
- { path: "i18n" },
44
- { path: "api" },
45
- { path: "email" },
46
- { path: "fixtures" },
47
- { path: "routes" },
48
- { path: "index.client.js" },
49
- { path: "index.server.js" },
50
- ...filesToCopy,
51
- ];
52
-
53
- const requiredFileCheck = () => {
54
- return new Promise((resolve) => {
55
- const requiredFiles = [
56
- { path: "index.server.js", type: "file" },
57
- { path: "index.html", type: "file" },
58
- { path: "index.client.js", type: "file" },
59
- { path: "api", type: "directory" },
60
- { path: "i18n", type: "directory" },
61
- { path: "lib", type: "directory" },
62
- { path: "public", type: "directory" },
63
- { path: "ui", type: "directory" },
64
- { path: "ui/components", type: "directory" },
65
- { path: "ui/layouts", type: "directory" },
66
- { path: "ui/pages", type: "directory" },
67
- ];
68
-
69
- requiredFiles.forEach((requiredFile) => {
70
- const exists = fs.existsSync(`${process.cwd()}/${requiredFile.path}`);
71
- const stats =
72
- exists && fs.statSync(`${process.cwd()}/${requiredFile.path}`);
73
- const isFile = stats && stats.isFile();
74
- const isDirectory = stats && stats.isDirectory();
75
-
76
- if (requiredFile && requiredFile.type === "file") {
77
- if (!exists || (exists && !isFile)) {
78
- CLILog(
79
- `The path ${requiredFile.path} must exist in your project and must be a file (not a directory).`,
80
- {
81
- level: "danger",
82
- docs: "https://github.com/cheatcode/joystick#folder-and-file-structure",
83
- }
84
- );
85
- process.exit(0);
86
- }
87
- }
88
-
89
- if (requiredFile && requiredFile.type === "directory") {
90
- if (!exists || (exists && !isDirectory)) {
91
- CLILog(
92
- `The path ${requiredFile.path} must exist in your project and must be a directory (not a file).`,
93
- {
94
- level: "danger",
95
- docs: "https://github.com/cheatcode/joystick#folder-and-file-structure",
96
- }
97
- );
98
- process.exit(0);
99
- }
100
- }
101
- });
102
-
103
- resolve();
104
- });
105
- };
106
-
107
- const handleCleanup = async (
108
- processIds = [process?.serverProcess?.pid, process?.hmrProcess?.pid]
109
- ) => {
110
- for (let i = 0; i < processIds?.length; i += 1) {
111
- const processId = processIds[i];
112
-
113
- if (processId) {
114
- await killProcess(processId);
115
- }
116
- }
117
-
118
- const databases = Object.entries(process._databases || {});
119
-
120
- for (let i = 0; i < databases?.length; i += 1) {
121
- const [provider, providerConnection] = databases[i];
122
-
123
- if (providerConnection?.pid) {
124
- await killProcess(providerConnection.pid);
125
- }
126
-
127
- if (!providerConnection?.pid) {
128
- const providerConnections = Object.entries(providerConnection);
129
-
130
- for (let pc = 0; pc < providerConnections?.length; pc += 1) {
131
- const [_connectionName, connection] = providerConnections[pc];
132
-
133
- if (connection?.pid) {
134
- await killProcess(connection?.pid);
135
- }
136
- }
137
- }
138
- }
139
- };
140
-
141
- const getDatabaseProcessIds = () => {
142
- const databaseProcessIds = [];
143
- const databases = Object.entries(process._databases || {});
144
-
145
- for (let i = 0; i < databases?.length; i += 1) {
146
- const [_provider, providerConnection] = databases[i];
147
-
148
- if (providerConnection?.pid) {
149
- databaseProcessIds.push(providerConnection.pid);
150
- }
151
-
152
- if (!providerConnection?.pid) {
153
- const providerConnections = Object.entries(providerConnection);
154
-
155
- for (let pc = 0; pc < providerConnections?.length; pc += 1) {
156
- const [_connectionName, connection] = providerConnections[pc];
157
-
158
- if (connection?.pid) {
159
- databaseProcessIds.push(connection.pid);
160
- }
161
- }
162
- }
163
- }
164
-
165
- return databaseProcessIds;
166
- };
167
-
168
- const handleSignalEvents = (processIds = []) => {
169
- const execArgv = ["--no-warnings"];
170
-
171
- if (majorVersion < 19) {
172
- execArgv.push("--experimental-specifier-resolution=node");
173
- }
174
-
175
- const cleanupProcess = child_process.fork(
176
- path.resolve(`${__dirname}/cleanup/index.js`),
177
- [],
178
- {
179
- // NOTE: Run in detached mode so when parent process dies, the child still runs
180
- // and cleanup completes.
181
- detached: true,
182
- execArgv,
183
- // NOTE: Pipe stdin, stdout, and stderr. IPC establishes a message channel so we
184
- // communicate with the child_process.
185
- silent: true,
186
- }
187
- );
188
-
189
- process.on("SIGINT", async () => {
190
- const databaseProcessIds = getDatabaseProcessIds();
191
- cleanupProcess.send(JSON.stringify(({ processIds: [...processIds, ...databaseProcessIds] })));
192
- process.exit();
193
- });
194
-
195
- process.on("SIGTERM", async () => {
196
- const databaseProcessIds = getDatabaseProcessIds();
197
- cleanupProcess.send(JSON.stringify(({ processIds: [...processIds, ...databaseProcessIds] })));
198
- process.exit();
199
- });
200
- };
201
-
202
- const handleHMRProcessMessages = () => {
203
- process.hmrProcess.on("message", (message) => {
204
- const processMessages = [
205
- "SERVER_CLOSED",
206
- "HAS_HMR_CONNECTIONS",
207
- "HAS_NO_HMR_CONNECTIONS",
208
- "HMR_UPDATE_COMPLETED",
209
- ];
210
-
211
- if (!processMessages.includes(message?.type)) {
212
- process.loader.stable(message);
213
- }
214
-
215
- if (message?.type === "HAS_HMR_CONNECTIONS") {
216
- process.hmrProcess.hasConnections = true;
217
- }
218
-
219
- if (message?.type === "HAS_NO_HMR_CONNECTIONS") {
220
- process.hmrProcess.hasConnections = false;
221
- }
222
-
223
- if (message?.type === "HMR_UPDATE_COMPLETED") {
224
- // NOTE: Do a setTimeout to ensure that server is still available while the HMR update completes.
225
- // Necessary because some updates are instance, but others might mount a UI that needs a server
226
- // available (e.g., runs API requests).
227
- setTimeout(() => {
228
- restartApplicationProcess(message?.sessions);
229
- }, 500);
230
- }
231
- });
232
- };
233
-
234
- const handleHMRProcessSTDIO = () => {
235
- try {
236
- if (process.hmrProcess) {
237
- process.hmrProcess.on("error", (error) => {
238
- CLILog(error.toString(), {
239
- level: "danger",
240
- docs: "https://github.com/cheatcode/joystick",
241
- });
242
- });
243
-
244
- process.hmrProcess.stdout.on("data", (data) => {
245
- console.log(data.toString());
246
- });
247
-
248
- process.hmrProcess.stderr.on("data", (data) => {
249
- process.loader.stop();
250
- CLILog(data.toString(), {
251
- level: "danger",
252
- docs: "https://github.com/cheatcode/joystick",
253
- });
254
- });
255
- }
256
- } catch (exception) {
257
- throw new Error(`[dev.handleHMRProcessSTDIO] ${exception.message}`);
258
- }
259
- };
260
-
24
+ //const majorVersion = parseInt(
25
+ // process?.version?.split(".")[0]?.replace("v", ""),
26
+ // 10
27
+ //);
28
+ //
29
+ //const __filename = fileURLToPath(import.meta.url);
30
+ //const __dirname = dirname(__filename);
31
+ //
32
+ //const killProcess = (pid = 0) => {
33
+ // return new Promise((resolve) => {
34
+ // ps.kill(pid, () => {
35
+ // resolve();
36
+ // });
37
+ // });
38
+ //};
39
+ //
40
+ //const watchlist = [
41
+ // { path: "ui" },
42
+ // { path: "lib" },
43
+ // { path: "i18n" },
44
+ // { path: "api" },
45
+ // { path: "email" },
46
+ // { path: "fixtures" },
47
+ // { path: "routes" },
48
+ // { path: "index.client.js" },
49
+ // { path: "index.server.js" },
50
+ // ...filesToCopy,
51
+ //];
52
+ //
53
+ //const requiredFileCheck = () => {
54
+ // return new Promise((resolve) => {
55
+ // const requiredFiles = [
56
+ // { path: "index.server.js", type: "file" },
57
+ // { path: "index.html", type: "file" },
58
+ // { path: "index.client.js", type: "file" },
59
+ // { path: "api", type: "directory" },
60
+ // { path: "i18n", type: "directory" },
61
+ // { path: "lib", type: "directory" },
62
+ // { path: "public", type: "directory" },
63
+ // { path: "ui", type: "directory" },
64
+ // { path: "ui/components", type: "directory" },
65
+ // { path: "ui/layouts", type: "directory" },
66
+ // { path: "ui/pages", type: "directory" },
67
+ // ];
68
+ //
69
+ // requiredFiles.forEach((requiredFile) => {
70
+ // const exists = fs.existsSync(`${process.cwd()}/${requiredFile.path}`);
71
+ // const stats =
72
+ // exists && fs.statSync(`${process.cwd()}/${requiredFile.path}`);
73
+ // const isFile = stats && stats.isFile();
74
+ // const isDirectory = stats && stats.isDirectory();
75
+ //
76
+ // if (requiredFile && requiredFile.type === "file") {
77
+ // if (!exists || (exists && !isFile)) {
78
+ // CLILog(
79
+ // `The path ${requiredFile.path} must exist in your project and must be a file (not a directory).`,
80
+ // {
81
+ // level: "danger",
82
+ // docs: "https://github.com/cheatcode/joystick#folder-and-file-structure",
83
+ // }
84
+ // );
85
+ // process.exit(0);
86
+ // }
87
+ // }
88
+ //
89
+ // if (requiredFile && requiredFile.type === "directory") {
90
+ // if (!exists || (exists && !isDirectory)) {
91
+ // CLILog(
92
+ // `The path ${requiredFile.path} must exist in your project and must be a directory (not a file).`,
93
+ // {
94
+ // level: "danger",
95
+ // docs: "https://github.com/cheatcode/joystick#folder-and-file-structure",
96
+ // }
97
+ // );
98
+ // process.exit(0);
99
+ // }
100
+ // }
101
+ // });
102
+ //
103
+ // resolve();
104
+ // });
105
+ //};
106
+ //
107
+ //const handleCleanup = async (
108
+ // processIds = [process?.serverProcess?.pid, process?.hmrProcess?.pid]
109
+ //) => {
110
+ // for (let i = 0; i < processIds?.length; i += 1) {
111
+ // const processId = processIds[i];
112
+ //
113
+ // if (processId) {
114
+ // await killProcess(processId);
115
+ // }
116
+ // }
117
+ //
118
+ // const databases = Object.entries(process._databases || {});
119
+ //
120
+ // for (let i = 0; i < databases?.length; i += 1) {
121
+ // const [provider, providerConnection] = databases[i];
122
+ //
123
+ // if (providerConnection?.pid) {
124
+ // await killProcess(providerConnection.pid);
125
+ // }
126
+ //
127
+ // if (!providerConnection?.pid) {
128
+ // const providerConnections = Object.entries(providerConnection);
129
+ //
130
+ // for (let pc = 0; pc < providerConnections?.length; pc += 1) {
131
+ // const [_connectionName, connection] = providerConnections[pc];
132
+ //
133
+ // if (connection?.pid) {
134
+ // await killProcess(connection?.pid);
135
+ // }
136
+ // }
137
+ // }
138
+ // }
139
+ //};
140
+ //
141
+ //const getDatabaseProcessIds = () => {
142
+ // const databaseProcessIds = [];
143
+ // const databases = Object.entries(process._databases || {});
144
+ //
145
+ // for (let i = 0; i < databases?.length; i += 1) {
146
+ // const [_provider, providerConnection] = databases[i];
147
+ //
148
+ // if (providerConnection?.pid) {
149
+ // databaseProcessIds.push(providerConnection.pid);
150
+ // }
151
+ //
152
+ // if (!providerConnection?.pid) {
153
+ // const providerConnections = Object.entries(providerConnection);
154
+ //
155
+ // for (let pc = 0; pc < providerConnections?.length; pc += 1) {
156
+ // const [_connectionName, connection] = providerConnections[pc];
157
+ //
158
+ // if (connection?.pid) {
159
+ // databaseProcessIds.push(connection.pid);
160
+ // }
161
+ // }
162
+ // }
163
+ // }
164
+ //
165
+ // return databaseProcessIds;
166
+ //};
167
+ //
168
+ //const handleSignalEvents = (processIds = []) => {
169
+ // const execArgv = ["--no-warnings"];
170
+ //
171
+ // if (majorVersion < 19) {
172
+ // execArgv.push("--experimental-specifier-resolution=node");
173
+ // }
174
+ //
175
+ // const cleanupProcess = child_process.fork(
176
+ // path.resolve(`${__dirname}/cleanup/index.js`),
177
+ // [],
178
+ // {
179
+ // // NOTE: Run in detached mode so when parent process dies, the child still runs
180
+ // // and cleanup completes.
181
+ // detached: true,
182
+ // execArgv,
183
+ // // NOTE: Pipe stdin, stdout, and stderr. IPC establishes a message channel so we
184
+ // // communicate with the child_process.
185
+ // silent: true,
186
+ // }
187
+ // );
188
+ //
189
+ // process.on("SIGINT", async () => {
190
+ // const databaseProcessIds = getDatabaseProcessIds();
191
+ // cleanupProcess.send(JSON.stringify(({ processIds: [...processIds, ...databaseProcessIds] })));
192
+ // process.exit();
193
+ // });
194
+ //
195
+ // process.on("SIGTERM", async () => {
196
+ // const databaseProcessIds = getDatabaseProcessIds();
197
+ // cleanupProcess.send(JSON.stringify(({ processIds: [...processIds, ...databaseProcessIds] })));
198
+ // process.exit();
199
+ // });
200
+ //};
201
+ //
202
+ //const handleHMRProcessMessages = () => {
203
+ // process.hmrProcess.on("message", (message) => {
204
+ // const processMessages = [
205
+ // "SERVER_CLOSED",
206
+ // "HAS_HMR_CONNECTIONS",
207
+ // "HAS_NO_HMR_CONNECTIONS",
208
+ // "HMR_UPDATE_COMPLETED",
209
+ // ];
210
+ //
211
+ // if (!processMessages.includes(message?.type)) {
212
+ // process.loader.stable(message);
213
+ // }
214
+ //
215
+ // if (message?.type === "HAS_HMR_CONNECTIONS") {
216
+ // process.hmrProcess.hasConnections = true;
217
+ // }
218
+ //
219
+ // if (message?.type === "HAS_NO_HMR_CONNECTIONS") {
220
+ // process.hmrProcess.hasConnections = false;
221
+ // }
222
+ //
223
+ // if (message?.type === "HMR_UPDATE_COMPLETED") {
224
+ // // NOTE: Do a setTimeout to ensure that server is still available while the HMR update completes.
225
+ // // Necessary because some updates are instance, but others might mount a UI that needs a server
226
+ // // available (e.g., runs API requests).
227
+ // setTimeout(() => {
228
+ // restartApplicationProcess(message?.sessions);
229
+ // }, 500);
230
+ // }
231
+ // });
232
+ //};
233
+ //
234
+ //const handleHMRProcessSTDIO = () => {
235
+ // try {
236
+ // if (process.hmrProcess) {
237
+ // process.hmrProcess.on("error", (error) => {
238
+ // CLILog(error.toString(), {
239
+ // level: "danger",
240
+ // docs: "https://github.com/cheatcode/joystick",
241
+ // });
242
+ // });
243
+ //
244
+ // process.hmrProcess.stdout.on("data", (data) => {
245
+ // console.log(data.toString());
246
+ // });
247
+ //
248
+ // process.hmrProcess.stderr.on("data", (data) => {
249
+ // process.loader.stop();
250
+ // CLILog(data.toString(), {
251
+ // level: "danger",
252
+ // docs: "https://github.com/cheatcode/joystick",
253
+ // });
254
+ // });
255
+ // }
256
+ // } catch (exception) {
257
+ // throw new Error(`[dev.handleHMRProcessSTDIO] ${exception.message}`);
258
+ // }
259
+ //};
260
+ //
261
261
  const startHMRProcess = () => {
262
262
  const execArgv = ["--no-warnings"];
263
263
 
@@ -281,385 +281,388 @@ const startHMRProcess = () => {
281
281
  handleHMRProcessSTDIO();
282
282
  handleHMRProcessMessages();
283
283
  };
284
-
285
- const notifyHMRClients = (indexHTMLChanged = false) => {
286
- const settings = loadSettings(process.env.NODE_ENV);
287
- process.hmrProcess.send(
288
- JSON.stringify({
289
- type: "RESTART_SERVER",
290
- settings,
291
- indexHTMLChanged,
292
- })
293
- );
294
- };
295
-
296
- const handleServerProcessMessages = () => {
297
- process.serverProcess.on("message", (message) => {
298
- const processMessages = ["SERVER_CLOSED"];
299
-
300
- if (!processMessages.includes(message)) {
301
- process.loader.stable(message);
302
- }
303
- });
304
- };
305
-
306
- const handleServerProcessSTDIO = () => {
307
- try {
308
- if (process.serverProcess) {
309
- process.serverProcess.on("error", (error) => {
310
- console.log(error);
311
- });
312
-
313
- process.serverProcess.stdout.on("data", (data) => {
314
- const message = data.toString();
315
-
316
- if (message && message.includes("App running at:")) {
317
- process.loader.stable(message);
318
- } else {
319
- if (message && !message.includes("BUILD_ERROR")) {
320
- console.log(message);
321
- }
322
- }
323
- });
324
-
325
- process.serverProcess.stderr.on("data", (data) => {
326
- process.loader.stop();
327
- CLILog(data.toString(), {
328
- level: "danger",
329
- docs: "https://github.com/cheatcode/joystick",
330
- });
331
- });
332
- }
333
- } catch (exception) {
334
- throw new Error(`[dev.handleServerProcessSTDIO] ${exception.message}`);
335
- }
336
- };
337
-
338
- const startApplicationProcess = (sessionsBeforeHMRUpdate = null) => {
339
- const execArgv = ["--no-warnings"];
340
-
341
- if (majorVersion < 19) {
342
- execArgv.push("--experimental-specifier-resolution=node");
343
- }
344
-
345
- if (
346
- process.env.NODE_ENV === "development" &&
347
- process.env.IS_DEBUG_MODE === "true"
348
- ) {
349
- execArgv.push("--inspect");
350
- }
351
-
352
- const serverProcess = child_process.fork(
353
- path.resolve(".joystick/build/index.server.js"),
354
- [],
355
- {
356
- execArgv,
357
- // NOTE: Pipe stdin, stdout, and stderr. IPC establishes a message channel so we
358
- // communicate with the child_process.
359
- silent: true,
360
- env: {
361
- FORCE_COLOR: "1",
362
- LOGS_PATH: process.env.LOGS_PATH,
363
- NODE_ENV: process.env.NODE_ENV,
364
- ROOT_URL: process.env.ROOT_URL,
365
- PORT: process.env.PORT,
366
- JOYSTICK_SETTINGS: process.env.JOYSTICK_SETTINGS,
367
- HMR_SESSIONS: sessionsBeforeHMRUpdate,
368
- },
369
- }
370
- );
371
-
372
- process.serverProcess = serverProcess;
373
-
374
- handleServerProcessSTDIO();
375
- handleServerProcessMessages();
376
-
377
- return serverProcess;
378
- };
379
-
380
- const restartApplicationProcess = async (sessionsBeforeHMRUpdate = null) => {
381
- if (process.serverProcess && process.serverProcess.pid) {
382
- process.loader.text("Restarting app...");
383
- process.serverProcess.kill();
384
- startApplicationProcess(sessionsBeforeHMRUpdate);
385
- return Promise.resolve();
386
- }
387
-
388
- // NOTE: Original process was never initialized due to an error.
389
- process.loader.text("Starting app...");
390
- startApplicationProcess();
391
-
392
- if (!process.hmrProcess) {
393
- startHMRProcess();
394
- }
395
- };
396
-
397
- const initialBuild = async (buildSettings = {}) => {
398
- const buildPath = `.joystick/build`;
399
- const fileMapPath = `.joystick/build/fileMap.json`;
400
-
401
- if (!fs.existsSync(buildPath)) {
402
- fs.mkdirSync(".joystick/build");
403
- }
404
-
405
- if (fs.existsSync(fileMapPath)) {
406
- fs.unlinkSync(fileMapPath);
407
- }
408
-
409
- process.loader.text("Building app...");
410
-
411
- await requiredFileCheck();
412
-
413
- const filesToBuild = getFilesToBuild(buildSettings?.excludedPaths, "start");
414
- const fileResults = await buildFiles(
415
- filesToBuild,
416
- null,
417
- process.env.NODE_ENV
418
- );
419
-
420
- const hasErrors = [...fileResults]
421
- .filter((result) => !!result)
422
- .map(({ success }) => success)
423
- .includes(false);
424
-
425
- if (!hasErrors) {
426
- startApplicationProcess();
427
- startHMRProcess();
428
- // If the file has errors on startup, no way to trigger a restart w/o a watcher.
429
- }
430
- };
431
-
432
- const startWatcher = async (buildSettings = {}) => {
433
- await initialBuild(buildSettings);
434
-
435
- const watcher = chokidar.watch(
436
- watchlist.map(({ path }) => path),
437
- {
438
- ignoreInitial: true,
439
- }
440
- );
441
-
442
- watcher.on("all", async (event, path) => {
443
- await requiredFileCheck();
444
- process.loader.text("Rebuilding app...");
445
- const isHTMLUpdate = path === "index.html";
446
- const isUIPath = path?.includes("ui/") || path === 'index.css' || isHTMLUpdate;
447
- const isUIUpdate =
448
- (process.hmrProcess.hasConnections && isUIPath) || false;
449
-
450
- if (
451
- ["addDir"].includes(event) &&
452
- fs.existsSync(path) &&
453
- fs.lstatSync(path).isDirectory() &&
454
- !fs.existsSync(`./.joystick/build/${path}`)
455
- ) {
456
- fs.mkdirSync(`./.joystick/build/${path}`);
457
-
458
- if (isUIUpdate) {
459
- notifyHMRClients(isHTMLUpdate);
460
- } else {
461
- restartApplicationProcess();
462
- }
463
-
464
- return;
465
- }
466
-
467
- // If path is file to copy...
468
- if (!!filesToCopy.find((fileToCopy) => fileToCopy.path === path)) {
469
- const isDirectory = fs.statSync(path).isDirectory();
470
-
471
- // If path to copy is a directory and doesn't exist in the build...
472
- if (isDirectory && !fs.existsSync(`./.joystick/build/${path}`)) {
473
- fs.mkdirSync(`./.joystick/build/${path}`);
474
- }
475
-
476
- // If path to copy is not a directory...
477
- if (!isDirectory) {
478
- fs.writeFileSync(`./.joystick/build/${path}`, fs.readFileSync(path));
479
- }
480
-
481
- // Load settings in case we copied new values over...
482
- loadSettings(process.env.NODE_ENV);
483
-
484
- if (isUIUpdate) {
485
- notifyHMRClients(isHTMLUpdate);
486
- } else {
487
- restartApplicationProcess();
488
- }
489
-
490
- return;
491
- }
492
-
493
- if (["add", "change"].includes(event) && fs.existsSync(path)) {
494
- const codependencies = getCodependenciesForFile(path);
495
- const fileResults = await buildFiles(
496
- [path, ...(codependencies?.existing || [])],
497
- null,
498
- process.env.NODE_ENV
499
- );
500
- const fileResultsHaveErrors = fileResults
501
- .filter((result) => !!result)
502
- .map(({ success }) => success)
503
- .includes(false);
504
-
505
- removeDeletedDependenciesFromMap(codependencies.deleted);
506
-
507
- const hasErrors = fileResultsHaveErrors;
508
-
509
- if (process.serverProcess && hasErrors) {
510
- process.serverProcess.send(
511
- JSON.stringify({
512
- error: "BUILD_ERROR",
513
- paths: fileResults
514
- .filter(({ success }) => !success)
515
- .map(({ path: pathWithError, error }) => ({
516
- path: pathWithError,
517
- error,
518
- })),
519
- })
520
- );
521
-
522
- return;
523
- }
524
-
525
- if (!hasErrors) {
526
- process.initialBuildComplete = true;
527
-
528
- if (isUIUpdate) {
529
- notifyHMRClients(isHTMLUpdate);
530
- } else {
531
- restartApplicationProcess();
532
- }
533
-
534
- return;
535
- }
536
- }
537
-
538
- if (
539
- ["unlink", "unlinkDir"].includes(event) &&
540
- !fs.existsSync(`./.joystick/build/${path}`)
541
- ) {
542
- if (isUIUpdate) {
543
- notifyHMRClients(isHTMLUpdate);
544
- } else {
545
- restartApplicationProcess();
546
- }
547
-
548
- return;
549
- }
550
-
551
- if (
552
- ["unlink", "unlinkDir"].includes(event) &&
553
- fs.existsSync(`./.joystick/build/${path}`)
554
- ) {
555
- const pathToUnlink = `./.joystick/build/${path}`;
556
- const stats = fs.lstatSync(pathToUnlink);
557
-
558
- if (stats.isDirectory()) {
559
- fs.rmdirSync(pathToUnlink, { recursive: true });
560
- }
561
-
562
- if (stats.isFile()) {
563
- fs.unlinkSync(pathToUnlink);
564
- }
565
-
566
- if (isUIUpdate) {
567
- notifyHMRClients(isHTMLUpdate);
568
- } else {
569
- restartApplicationProcess();
570
- }
571
-
572
- return;
573
- }
574
- });
575
- };
576
-
577
- const startDatabase = async (database = {}, databasePort = 2610, hasMultipleOfProvider = false) => {
578
- process._databases = {
579
- ...(process._databases || {}),
580
- [database.provider]: !hasMultipleOfProvider ? await startDatabaseProvider(database, databasePort) : {
581
- ...((process._databases && process._databases[database.provider]) || {}),
582
- [database?.name || `${database.provider}_${databasePort}`]: await startDatabaseProvider(database, databasePort)
583
- },
584
- };
585
-
586
- return Promise.resolve(process._databases);
587
- };
588
-
589
- const startDatabases = async (databasePortStart = 2610) => {
590
- try {
591
- const hasSettings = !!process.env.JOYSTICK_SETTINGS;
592
- const settings = hasSettings && JSON.parse(process.env.JOYSTICK_SETTINGS);
593
- const databases = settings?.config?.databases || [];
594
-
595
- if (databases && Array.isArray(databases) && databases.length > 0) {
596
- validateDatabasesFromSettings(databases);
597
-
598
- for (let i = 0; i < databases?.length; i += 1) {
599
- const database = databases[i];
600
- const hasMultipleOfProvider = (databases?.filter((database) => database?.provider === database?.provider))?.length > 1;
601
-
602
- // NOTE: Increment each database port using index in the databases array from settings.
603
- await startDatabase(database, databasePortStart + i, hasMultipleOfProvider);
604
- }
605
-
606
- return Promise.resolve();
607
- }
608
-
609
- return Promise.resolve();
610
- } catch (exception) {
611
- console.warn(exception);
612
- }
613
- };
614
-
615
- const loadSettings = () => {
616
- const environment = process.env.NODE_ENV;
617
- const settingsFilePath = `${process.cwd()}/settings.${environment}.json`;
618
- const hasSettingsFile = fs.existsSync(settingsFilePath);
619
-
620
- if (!hasSettingsFile) {
621
- CLILog(
622
- `A settings file could not be found for this environment (${environment}). Create a settings.${environment}.json file at the root of your project and restart Joystick.`,
623
- {
624
- level: "danger",
625
- docs: "https://github.com/cheatcode/joystick#settings",
626
- }
627
- );
628
- process.exit(0);
629
- }
630
-
631
- const rawSettingsFile = fs.readFileSync(settingsFilePath, "utf-8");
632
- const isValidJSON = isValidJSONString(rawSettingsFile);
633
-
634
- if (!isValidJSON) {
635
- CLILog(
636
- `Failed to parse settings file. Double-check the syntax in your settings.${environment}.json file at the root of your project and restart Joystick.`,
637
- {
638
- level: "danger",
639
- docs: "https://github.com/cheatcode/joystick#settings",
640
- tools: [{ title: "JSON Linter", url: "https://jsonlint.com/" }],
641
- }
642
- );
643
-
644
- process.exit(0);
645
- }
646
-
647
- const settingsFile = isValidJSON ? rawSettingsFile : "{}";
648
-
649
- // NOTE: Child process will inherit this env var from this parent process.
650
- process.env.JOYSTICK_SETTINGS = settingsFile;
651
-
652
- return JSON.parse(settingsFile);
653
- };
654
-
655
- const checkIfJoystickProject = () => {
656
- return fs.existsSync(`${process.cwd()}/.joystick`);
657
- };
284
+ //
285
+ //const notifyHMRClients = (indexHTMLChanged = false) => {
286
+ // const settings = loadSettings(process.env.NODE_ENV);
287
+ // process.hmrProcess.send(
288
+ // JSON.stringify({
289
+ // type: "RESTART_SERVER",
290
+ // settings,
291
+ // indexHTMLChanged,
292
+ // })
293
+ // );
294
+ //};
295
+ //
296
+ //const handleServerProcessMessages = () => {
297
+ // process.serverProcess.on("message", (message) => {
298
+ // const processMessages = ["SERVER_CLOSED"];
299
+ //
300
+ // if (!processMessages.includes(message)) {
301
+ // process.loader.stable(message);
302
+ // }
303
+ // });
304
+ //};
305
+ //
306
+ //const handleServerProcessSTDIO = () => {
307
+ // try {
308
+ // if (process.serverProcess) {
309
+ // process.serverProcess.on("error", (error) => {
310
+ // console.log(error);
311
+ // });
312
+ //
313
+ // process.serverProcess.stdout.on("data", (data) => {
314
+ // const message = data.toString();
315
+ //
316
+ // if (message && message.includes("App running at:")) {
317
+ // process.loader.stable(message);
318
+ // } else {
319
+ // if (message && !message.includes("BUILD_ERROR")) {
320
+ // console.log(message);
321
+ // }
322
+ // }
323
+ // });
324
+ //
325
+ // process.serverProcess.stderr.on("data", (data) => {
326
+ // process.loader.stop();
327
+ // CLILog(data.toString(), {
328
+ // level: "danger",
329
+ // docs: "https://github.com/cheatcode/joystick",
330
+ // });
331
+ // });
332
+ // }
333
+ // } catch (exception) {
334
+ // throw new Error(`[dev.handleServerProcessSTDIO] ${exception.message}`);
335
+ // }
336
+ //};
337
+ //
338
+ //const startApplicationProcess = (sessionsBeforeHMRUpdate = null) => {
339
+ // const execArgv = ["--no-warnings"];
340
+ //
341
+ // if (majorVersion < 19) {
342
+ // execArgv.push("--experimental-specifier-resolution=node");
343
+ // }
344
+ //
345
+ // if (
346
+ // process.env.NODE_ENV === "development" &&
347
+ // process.env.IS_DEBUG_MODE === "true"
348
+ // ) {
349
+ // execArgv.push("--inspect");
350
+ // }
351
+ //
352
+ // const serverProcess = child_process.fork(
353
+ // path.resolve(".joystick/build/index.server.js"),
354
+ // [],
355
+ // {
356
+ // execArgv,
357
+ // // NOTE: Pipe stdin, stdout, and stderr. IPC establishes a message channel so we
358
+ // // communicate with the child_process.
359
+ // silent: true,
360
+ // env: {
361
+ // FORCE_COLOR: "1",
362
+ // LOGS_PATH: process.env.LOGS_PATH,
363
+ // NODE_ENV: process.env.NODE_ENV,
364
+ // ROOT_URL: process.env.ROOT_URL,
365
+ // PORT: process.env.PORT,
366
+ // JOYSTICK_SETTINGS: process.env.JOYSTICK_SETTINGS,
367
+ // HMR_SESSIONS: sessionsBeforeHMRUpdate,
368
+ // },
369
+ // }
370
+ // );
371
+ //
372
+ // process.serverProcess = serverProcess;
373
+ //
374
+ // handleServerProcessSTDIO();
375
+ // handleServerProcessMessages();
376
+ //
377
+ // return serverProcess;
378
+ //};
379
+ //
380
+ //const restartApplicationProcess = async (sessionsBeforeHMRUpdate = null) => {
381
+ // if (process.serverProcess && process.serverProcess.pid) {
382
+ // process.loader.text("Restarting app...");
383
+ // process.serverProcess.kill();
384
+ // startApplicationProcess(sessionsBeforeHMRUpdate);
385
+ // return Promise.resolve();
386
+ // }
387
+ //
388
+ // // NOTE: Original process was never initialized due to an error.
389
+ // process.loader.text("Starting app...");
390
+ // startApplicationProcess();
391
+ //
392
+ // if (!process.hmrProcess) {
393
+ // startHMRProcess();
394
+ // }
395
+ //};
396
+ //
397
+ //const initialBuild = async (buildSettings = {}) => {
398
+ // const buildPath = `.joystick/build`;
399
+ // const fileMapPath = `.joystick/build/fileMap.json`;
400
+ //
401
+ // if (!fs.existsSync(buildPath)) {
402
+ // fs.mkdirSync(".joystick/build");
403
+ // }
404
+ //
405
+ // if (fs.existsSync(fileMapPath)) {
406
+ // fs.unlinkSync(fileMapPath);
407
+ // }
408
+ //
409
+ // process.loader.text("Building app...");
410
+ //
411
+ // await requiredFileCheck();
412
+ //
413
+ // const filesToBuild = getFilesToBuild(buildSettings?.excludedPaths, "start");
414
+ // const fileResults = await buildFiles(
415
+ // filesToBuild,
416
+ // null,
417
+ // process.env.NODE_ENV
418
+ // );
419
+ //
420
+ // const hasErrors = [...fileResults]
421
+ // .filter((result) => !!result)
422
+ // .map(({ success }) => success)
423
+ // .includes(false);
424
+ //
425
+ // if (!hasErrors) {
426
+ // startApplicationProcess();
427
+ // startHMRProcess();
428
+ // // If the file has errors on startup, no way to trigger a restart w/o a watcher.
429
+ // }
430
+ //};
431
+ //
432
+ //const startWatcher = async (buildSettings = {}) => {
433
+ // await initialBuild(buildSettings);
434
+ //
435
+ // const watcher = chokidar.watch(
436
+ // watchlist.map(({ path }) => path),
437
+ // {
438
+ // ignoreInitial: true,
439
+ // }
440
+ // );
441
+ //
442
+ // watcher.on("all", async (event, path) => {
443
+ // await requiredFileCheck();
444
+ // process.loader.text("Rebuilding app...");
445
+ // const isHTMLUpdate = path === "index.html";
446
+ // const isUIPath = path?.includes("ui/") || path === 'index.css' || isHTMLUpdate;
447
+ // const isUIUpdate =
448
+ // (process.hmrProcess.hasConnections && isUIPath) || false;
449
+ //
450
+ // if (
451
+ // ["addDir"].includes(event) &&
452
+ // fs.existsSync(path) &&
453
+ // fs.lstatSync(path).isDirectory() &&
454
+ // !fs.existsSync(`./.joystick/build/${path}`)
455
+ // ) {
456
+ // fs.mkdirSync(`./.joystick/build/${path}`);
457
+ //
458
+ // if (isUIUpdate) {
459
+ // notifyHMRClients(isHTMLUpdate);
460
+ // } else {
461
+ // restartApplicationProcess();
462
+ // }
463
+ //
464
+ // return;
465
+ // }
466
+ //
467
+ // // If path is file to copy...
468
+ // if (!!filesToCopy.find((fileToCopy) => fileToCopy.path === path)) {
469
+ // const isDirectory = fs.statSync(path).isDirectory();
470
+ //
471
+ // // If path to copy is a directory and doesn't exist in the build...
472
+ // if (isDirectory && !fs.existsSync(`./.joystick/build/${path}`)) {
473
+ // fs.mkdirSync(`./.joystick/build/${path}`);
474
+ // }
475
+ //
476
+ // // If path to copy is not a directory...
477
+ // if (!isDirectory) {
478
+ // fs.writeFileSync(`./.joystick/build/${path}`, fs.readFileSync(path));
479
+ // }
480
+ //
481
+ // // Load settings in case we copied new values over...
482
+ // loadSettings(process.env.NODE_ENV);
483
+ //
484
+ // if (isUIUpdate) {
485
+ // notifyHMRClients(isHTMLUpdate);
486
+ // } else {
487
+ // restartApplicationProcess();
488
+ // }
489
+ //
490
+ // return;
491
+ // }
492
+ //
493
+ // if (["add", "change"].includes(event) && fs.existsSync(path)) {
494
+ // const codependencies = getCodependenciesForFile(path);
495
+ // const fileResults = await buildFiles(
496
+ // [path, ...(codependencies?.existing || [])],
497
+ // null,
498
+ // process.env.NODE_ENV
499
+ // );
500
+ // const fileResultsHaveErrors = fileResults
501
+ // .filter((result) => !!result)
502
+ // .map(({ success }) => success)
503
+ // .includes(false);
504
+ //
505
+ // removeDeletedDependenciesFromMap(codependencies.deleted);
506
+ //
507
+ // const hasErrors = fileResultsHaveErrors;
508
+ //
509
+ // if (process.serverProcess && hasErrors) {
510
+ // process.serverProcess.send(
511
+ // JSON.stringify({
512
+ // error: "BUILD_ERROR",
513
+ // paths: fileResults
514
+ // .filter(({ success }) => !success)
515
+ // .map(({ path: pathWithError, error }) => ({
516
+ // path: pathWithError,
517
+ // error,
518
+ // })),
519
+ // })
520
+ // );
521
+ //
522
+ // return;
523
+ // }
524
+ //
525
+ // if (!hasErrors) {
526
+ // process.initialBuildComplete = true;
527
+ //
528
+ // if (isUIUpdate) {
529
+ // notifyHMRClients(isHTMLUpdate);
530
+ // } else {
531
+ // restartApplicationProcess();
532
+ // }
533
+ //
534
+ // return;
535
+ // }
536
+ // }
537
+ //
538
+ // if (
539
+ // ["unlink", "unlinkDir"].includes(event) &&
540
+ // !fs.existsSync(`./.joystick/build/${path}`)
541
+ // ) {
542
+ // if (isUIUpdate) {
543
+ // notifyHMRClients(isHTMLUpdate);
544
+ // } else {
545
+ // restartApplicationProcess();
546
+ // }
547
+ //
548
+ // return;
549
+ // }
550
+ //
551
+ // if (
552
+ // ["unlink", "unlinkDir"].includes(event) &&
553
+ // fs.existsSync(`./.joystick/build/${path}`)
554
+ // ) {
555
+ // const pathToUnlink = `./.joystick/build/${path}`;
556
+ // const stats = fs.lstatSync(pathToUnlink);
557
+ //
558
+ // if (stats.isDirectory()) {
559
+ // fs.rmdirSync(pathToUnlink, { recursive: true });
560
+ // }
561
+ //
562
+ // if (stats.isFile()) {
563
+ // fs.unlinkSync(pathToUnlink);
564
+ // }
565
+ //
566
+ // if (isUIUpdate) {
567
+ // notifyHMRClients(isHTMLUpdate);
568
+ // } else {
569
+ // restartApplicationProcess();
570
+ // }
571
+ //
572
+ // return;
573
+ // }
574
+ // });
575
+ //};
576
+ //
577
+ //const startDatabase = async (database = {}, databasePort = 2610, hasMultipleOfProvider = false) => {
578
+ // process._databases = {
579
+ // ...(process._databases || {}),
580
+ // [database.provider]: !hasMultipleOfProvider ? await startDatabaseProvider(database, databasePort) : {
581
+ // ...((process._databases && process._databases[database.provider]) || {}),
582
+ // [database?.name || `${database.provider}_${databasePort}`]: await startDatabaseProvider(database, databasePort)
583
+ // },
584
+ // };
585
+ //
586
+ // return Promise.resolve(process._databases);
587
+ //};
588
+ //
589
+ //const startDatabases = async (databasePortStart = 2610) => {
590
+ // try {
591
+ // const hasSettings = !!process.env.JOYSTICK_SETTINGS;
592
+ // const settings = hasSettings && JSON.parse(process.env.JOYSTICK_SETTINGS);
593
+ // const databases = settings?.config?.databases || [];
594
+ //
595
+ // if (databases && Array.isArray(databases) && databases.length > 0) {
596
+ // validateDatabasesFromSettings(databases);
597
+ //
598
+ // for (let i = 0; i < databases?.length; i += 1) {
599
+ // const database = databases[i];
600
+ // const hasMultipleOfProvider = (databases?.filter((database) => database?.provider === database?.provider))?.length > 1;
601
+ //
602
+ // // NOTE: Increment each database port using index in the databases array from settings.
603
+ // await startDatabase(database, databasePortStart + i, hasMultipleOfProvider);
604
+ // }
605
+ //
606
+ // return Promise.resolve();
607
+ // }
608
+ //
609
+ // return Promise.resolve();
610
+ // } catch (exception) {
611
+ // console.warn(exception);
612
+ // }
613
+ //};
614
+ //
615
+ //const loadSettings = () => {
616
+ // const environment = process.env.NODE_ENV;
617
+ // const settingsFilePath = `${process.cwd()}/settings.${environment}.json`;
618
+ // const hasSettingsFile = fs.existsSync(settingsFilePath);
619
+ //
620
+ // if (!hasSettingsFile) {
621
+ // CLILog(
622
+ // `A settings file could not be found for this environment (${environment}). Create a settings.${environment}.json file at the root of your project and restart Joystick.`,
623
+ // {
624
+ // level: "danger",
625
+ // docs: "https://github.com/cheatcode/joystick#settings",
626
+ // }
627
+ // );
628
+ // process.exit(0);
629
+ // }
630
+ //
631
+ // const rawSettingsFile = fs.readFileSync(settingsFilePath, "utf-8");
632
+ // const isValidJSON = isValidJSONString(rawSettingsFile);
633
+ //
634
+ // if (!isValidJSON) {
635
+ // CLILog(
636
+ // `Failed to parse settings file. Double-check the syntax in your settings.${environment}.json file at the root of your project and restart Joystick.`,
637
+ // {
638
+ // level: "danger",
639
+ // docs: "https://github.com/cheatcode/joystick#settings",
640
+ // tools: [{ title: "JSON Linter", url: "https://jsonlint.com/" }],
641
+ // }
642
+ // );
643
+ //
644
+ // process.exit(0);
645
+ // }
646
+ //
647
+ // const settingsFile = isValidJSON ? rawSettingsFile : "{}";
648
+ //
649
+ // // NOTE: Child process will inherit this env var from this parent process.
650
+ // process.env.JOYSTICK_SETTINGS = settingsFile;
651
+ //
652
+ // return JSON.parse(settingsFile);
653
+ //};
654
+ //
655
+ //const checkIfJoystickProject = () => {
656
+ // return fs.existsSync(`${process.cwd()}/.joystick`);
657
+ //};
658
658
 
659
659
  export default async (args = {}, options = {}) => {
660
+ const port = options?.port ? parseInt(options?.port) : 2600;
661
+
660
662
  await dev({
661
- environment: options?.environment,
663
+ environment: args?.environment || 'development',
662
664
  process,
665
+ port,
663
666
  });
664
667
  // process.loader = new Loader({ defaultMessage: "Starting app..." });
665
668
  //