@envin/cli 1.1.12 → 1.1.14-canary.79c6253
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/CHANGELOG.md +9 -0
- package/README.md +25 -0
- package/dist/cli/index.mjs +659 -849
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/build-manifest.json +2 -2
- package/dist/preview/.next/fallback-build-manifest.json +2 -2
- package/dist/preview/.next/prerender-manifest.json +3 -3
- package/dist/preview/.next/server/app/_global-error.html +2 -2
- package/dist/preview/.next/server/app/_global-error.rsc +1 -1
- package/dist/preview/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_not-found.html +1 -1
- package/dist/preview/.next/server/app/_not-found.rsc +1 -1
- package/dist/preview/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/preview/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/preview/.next/server/app/page/server-reference-manifest.json +4 -4
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__3aaf07ce._.js +1 -1
- package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__3aaf07ce._.js.map +1 -1
- package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e2e728e5._.js +1 -1
- package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e2e728e5._.js.map +1 -1
- package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e3d1c002._.js +20 -20
- package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e3d1c002._.js.map +1 -1
- package/dist/preview/.next/server/pages/404.html +1 -1
- package/dist/preview/.next/server/pages/500.html +2 -2
- package/dist/preview/.next/server/server-reference-manifest.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.json +5 -5
- package/dist/preview/.next/static/chunks/{9bd1b84742da96a1.js → bbb5fb736577afdc.js} +1 -1
- package/dist/preview/.next/trace +1 -1
- package/dist/preview/.next/trace-build +1 -1
- package/package.json +6 -6
- package/src/app/env.ts +23 -0
- package/src/app/page.tsx +3 -5
- package/src/lib/config.ts +10 -7
- package/src/lib/types.ts +7 -2
- package/src/lib/variables/index.ts +46 -26
- package/tsdown.config.ts +9 -0
- /package/dist/preview/.next/static/{y_m2KZXoqJPNnkobTFvMs → ON209q3dIHdNhaLOJAxJ0}/_buildManifest.js +0 -0
- /package/dist/preview/.next/static/{y_m2KZXoqJPNnkobTFvMs → ON209q3dIHdNhaLOJAxJ0}/_clientMiddlewareManifest.json +0 -0
- /package/dist/preview/.next/static/{y_m2KZXoqJPNnkobTFvMs → ON209q3dIHdNhaLOJAxJ0}/_ssgManifest.js +0 -0
package/dist/cli/index.mjs
CHANGED
|
@@ -1,894 +1,704 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/cli/index.ts
|
|
4
2
|
import { program } from "commander";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var package_default = {
|
|
8
|
-
name: "@envin/cli",
|
|
9
|
-
version: "1.1.12",
|
|
10
|
-
description: "Type-safe env validation with live previews",
|
|
11
|
-
keywords: [
|
|
12
|
-
"turbostarter",
|
|
13
|
-
"environment variables",
|
|
14
|
-
"validation",
|
|
15
|
-
"zod",
|
|
16
|
-
"arktype",
|
|
17
|
-
"valibot"
|
|
18
|
-
],
|
|
19
|
-
homepage: "https://envin.turbostarter.dev",
|
|
20
|
-
bugs: {
|
|
21
|
-
url: "https://github.com/turbostarter/envin/issues"
|
|
22
|
-
},
|
|
23
|
-
repository: {
|
|
24
|
-
type: "git",
|
|
25
|
-
url: "git+https://github.com/turbostarter/envin.git",
|
|
26
|
-
directory: "packages/cli"
|
|
27
|
-
},
|
|
28
|
-
license: "MIT",
|
|
29
|
-
author: "Bartosz Zagrodzki",
|
|
30
|
-
bin: {
|
|
31
|
-
envin: "dist/cli/index.mjs"
|
|
32
|
-
},
|
|
33
|
-
scripts: {
|
|
34
|
-
build: "tsup-node && bun run build:preview",
|
|
35
|
-
"build:preview": "node ./scripts/build-preview-server.mjs",
|
|
36
|
-
clean: "rm -rf dist .turbo node_modules .next",
|
|
37
|
-
dev: "tsup-node --watch",
|
|
38
|
-
"dev:preview": "cd ../../apps/example && tsx ../../packages/cli/src/cli/index.ts dev",
|
|
39
|
-
start: "node dist/cli/index.mjs",
|
|
40
|
-
typecheck: "tsc --noEmit",
|
|
41
|
-
prepack: "bun ../../scripts/replace-workspace-protocol.ts && bun ../../scripts/populate-readme.ts"
|
|
42
|
-
},
|
|
43
|
-
dependencies: {
|
|
44
|
-
"@babel/parser": "^7.27.0",
|
|
45
|
-
"@babel/traverse": "^7.27.0",
|
|
46
|
-
"@hookform/resolvers": "^5.2.1",
|
|
47
|
-
"@radix-ui/react-slot": "1.2.4",
|
|
48
|
-
"radix-ui": "catalog:",
|
|
49
|
-
"@svgr/webpack": "^8.1.0",
|
|
50
|
-
chalk: "^5.4.1",
|
|
51
|
-
chokidar: "^4.0.3",
|
|
52
|
-
commander: "^13.1.0",
|
|
53
|
-
consola: "^3.4.2",
|
|
54
|
-
debounce: "^2.2.0",
|
|
55
|
-
dotenv: "^16.5.0",
|
|
56
|
-
envin: "workspace:*",
|
|
57
|
-
esbuild: "^0.25.10",
|
|
58
|
-
"log-symbols": "^7.0.0",
|
|
59
|
-
"mime-types": "^3.0.1",
|
|
60
|
-
next: "catalog:",
|
|
61
|
-
ora: "^8.2.0",
|
|
62
|
-
"react-hook-form": "^7.62.0",
|
|
63
|
-
"socket.io": "^4.8.1",
|
|
64
|
-
"socket.io-client": "^4.8.1",
|
|
65
|
-
"tsconfig-paths": "^4.2.0",
|
|
66
|
-
zod: "catalog:"
|
|
67
|
-
},
|
|
68
|
-
devDependencies: {
|
|
69
|
-
"@babel/core": "7.26.10",
|
|
70
|
-
"@swc/core": "1.11.21",
|
|
71
|
-
"@tailwindcss/postcss": "catalog:",
|
|
72
|
-
"@types/babel__core": "7.20.5",
|
|
73
|
-
"@types/babel__traverse": "7.20.7",
|
|
74
|
-
"@types/mime-types": "2.1.4",
|
|
75
|
-
"@types/node": "catalog:",
|
|
76
|
-
"@types/react": "catalog:",
|
|
77
|
-
"@types/react-dom": "catalog:",
|
|
78
|
-
"class-variance-authority": "catalog:",
|
|
79
|
-
clsx: "catalog:",
|
|
80
|
-
"lucide-react": "catalog:",
|
|
81
|
-
postcss: "catalog:",
|
|
82
|
-
react: "catalog:",
|
|
83
|
-
"react-dom": "catalog:",
|
|
84
|
-
"source-map-js": "1.2.1",
|
|
85
|
-
"stacktrace-parser": "0.1.11",
|
|
86
|
-
"tailwind-merge": "catalog:",
|
|
87
|
-
tailwindcss: "catalog:",
|
|
88
|
-
tsup: "catalog:",
|
|
89
|
-
tsx: "^4.19.4",
|
|
90
|
-
"tw-animate-css": "catalog:",
|
|
91
|
-
typescript: "catalog:"
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// src/cli/commands/dev.ts
|
|
96
|
-
import fs4 from "fs";
|
|
97
|
-
|
|
98
|
-
// src/cli/utils/hot-reload/setup-hot-reloading.ts
|
|
99
|
-
import { promises as fs3 } from "fs";
|
|
100
|
-
import path6 from "path";
|
|
3
|
+
import fs, { existsSync, promises, statSync } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
101
5
|
import { watch } from "chokidar";
|
|
102
6
|
import debounce from "debounce";
|
|
103
|
-
import { Server
|
|
104
|
-
|
|
105
|
-
// src/cli/utils/logger.ts
|
|
7
|
+
import { Server } from "socket.io";
|
|
106
8
|
import { createConsola } from "consola";
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// src/cli/utils/hot-reload/create-dependency-graph.ts
|
|
110
|
-
import { existsSync as existsSync2, promises as fs2, statSync } from "fs";
|
|
111
|
-
import path5 from "path";
|
|
112
|
-
|
|
113
|
-
// src/cli/utils/preview/start-dev-server.ts
|
|
114
|
-
import http from "http";
|
|
115
|
-
import path3 from "path";
|
|
116
|
-
import url from "url";
|
|
9
|
+
import http from "node:http";
|
|
10
|
+
import url from "node:url";
|
|
117
11
|
import chalk from "chalk";
|
|
118
|
-
import
|
|
12
|
+
import logSymbols from "log-symbols";
|
|
119
13
|
import next from "next";
|
|
120
14
|
import ora from "ora";
|
|
15
|
+
import { lookup } from "mime-types";
|
|
16
|
+
import { parse } from "@babel/parser";
|
|
17
|
+
import traverseModule from "@babel/traverse";
|
|
18
|
+
import { createMatchPath, loadConfig } from "tsconfig-paths";
|
|
121
19
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
20
|
+
//#region package.json
|
|
21
|
+
var version = "1.1.13";
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/lib/types.ts
|
|
25
|
+
const Environment = {
|
|
26
|
+
DEVELOPMENT: "development",
|
|
27
|
+
PRODUCTION: "production"
|
|
28
|
+
};
|
|
29
|
+
const FILES = {
|
|
30
|
+
[Environment.DEVELOPMENT]: [
|
|
31
|
+
".env",
|
|
32
|
+
".env.local",
|
|
33
|
+
".env.development",
|
|
34
|
+
".env.development.local"
|
|
35
|
+
],
|
|
36
|
+
[Environment.PRODUCTION]: [
|
|
37
|
+
".env",
|
|
38
|
+
".env.local",
|
|
39
|
+
".env.production",
|
|
40
|
+
".env.production.local"
|
|
41
|
+
]
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/cli/utils/logger.ts
|
|
46
|
+
const logger = createConsola({});
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/utils/register-spinner-autostopping.ts
|
|
50
|
+
const spinners = /* @__PURE__ */ new Set();
|
|
125
51
|
process.on("SIGINT", () => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
});
|
|
52
|
+
spinners.forEach((spinner) => {
|
|
53
|
+
if (spinner.isSpinning) spinner.stop();
|
|
54
|
+
});
|
|
131
55
|
});
|
|
132
56
|
process.on("exit", (code) => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
spinner.stopAndPersist({
|
|
137
|
-
symbol: logSymbols.error
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
57
|
+
if (code !== 0) spinners.forEach((spinner) => {
|
|
58
|
+
if (spinner.isSpinning) spinner.stopAndPersist({ symbol: logSymbols.error });
|
|
59
|
+
});
|
|
142
60
|
});
|
|
143
|
-
|
|
144
|
-
|
|
61
|
+
const registerSpinnerAutostopping = (spinner) => {
|
|
62
|
+
spinners.add(spinner);
|
|
145
63
|
};
|
|
146
64
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/cli/utils/preview/get-env-variables.ts
|
|
67
|
+
const getEnvVariablesForPreviewApp = (relativePathToEnvDirectory, cwd, envDirAbsolutePaths, envFilePaths, envConfigPath) => {
|
|
68
|
+
return {
|
|
69
|
+
ENV_DIR_RELATIVE_PATH: relativePathToEnvDirectory,
|
|
70
|
+
ENV_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEnvDirectory),
|
|
71
|
+
ENV_DIR_ABSOLUTE_PATHS: JSON.stringify(envDirAbsolutePaths),
|
|
72
|
+
ENV_FILE_PATHS: JSON.stringify(envFilePaths),
|
|
73
|
+
ENV_CONFIG_PATH: envConfigPath,
|
|
74
|
+
USER_PROJECT_LOCATION: cwd,
|
|
75
|
+
NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
|
|
76
|
+
};
|
|
156
77
|
};
|
|
157
78
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
),
|
|
188
|
-
exception
|
|
189
|
-
);
|
|
190
|
-
res.statusCode = 500;
|
|
191
|
-
res.end(
|
|
192
|
-
"Could not read file to be served! Check your terminal for more information."
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/cli/utils/preview/serve-static-file.ts
|
|
81
|
+
const serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
|
|
82
|
+
const pathname = parsedUrl.pathname?.replace("/static", "./static") ?? "";
|
|
83
|
+
const ext = path.parse(pathname).ext;
|
|
84
|
+
const staticBaseDir = path.resolve(process.cwd(), staticDirRelativePath);
|
|
85
|
+
const fileAbsolutePath = path.resolve(staticBaseDir, pathname);
|
|
86
|
+
if (!fileAbsolutePath.startsWith(staticBaseDir)) {
|
|
87
|
+
res.statusCode = 403;
|
|
88
|
+
res.end();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const fileHandle = await promises.open(fileAbsolutePath, "r");
|
|
93
|
+
const fileData = await promises.readFile(fileHandle);
|
|
94
|
+
res.setHeader("Content-type", lookup(ext) || "text/plain");
|
|
95
|
+
res.end(fileData);
|
|
96
|
+
fileHandle.close();
|
|
97
|
+
} catch (exception) {
|
|
98
|
+
if (!existsSync(fileAbsolutePath)) {
|
|
99
|
+
res.statusCode = 404;
|
|
100
|
+
res.end();
|
|
101
|
+
} else {
|
|
102
|
+
const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
|
|
103
|
+
logger.error(/* @__PURE__ */ new Error(`Could not read file at ${sanitizedFilePath} to be served, here's the exception:`), exception);
|
|
104
|
+
res.statusCode = 500;
|
|
105
|
+
res.end("Could not read file to be served! Check your terminal for more information.");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
196
108
|
};
|
|
197
109
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
});
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/cli/utils/preview/start-dev-server.ts
|
|
112
|
+
let devServer;
|
|
113
|
+
const safeAsyncServerListen = (server, port) => {
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
server.listen(port, () => {
|
|
116
|
+
resolve({ portAlreadyInUse: false });
|
|
117
|
+
});
|
|
118
|
+
server.on("error", (e) => {
|
|
119
|
+
if (e.code === "EADDRINUSE") resolve({ portAlreadyInUse: true });
|
|
120
|
+
});
|
|
121
|
+
});
|
|
211
122
|
};
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
// passing in env here does not get the environment variables there
|
|
304
|
-
dev: isDev,
|
|
305
|
-
conf: {
|
|
306
|
-
images: {
|
|
307
|
-
// This is to avoid the warning with sharp
|
|
308
|
-
unoptimized: true
|
|
309
|
-
}
|
|
310
|
-
},
|
|
311
|
-
hostname: "localhost",
|
|
312
|
-
port,
|
|
313
|
-
dir: previewServerLocation
|
|
314
|
-
});
|
|
315
|
-
let isNextReady = false;
|
|
316
|
-
const nextReadyPromise = app.prepare();
|
|
317
|
-
await nextReadyPromise;
|
|
318
|
-
isNextReady = true;
|
|
319
|
-
const nextHandleRequest = app.getRequestHandler();
|
|
320
|
-
const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
|
|
321
|
-
spinner.stopAndPersist({
|
|
322
|
-
text: `Ready in ${secondsToNextReady}s
|
|
323
|
-
`,
|
|
324
|
-
symbol: logSymbols2.success
|
|
325
|
-
});
|
|
326
|
-
return devServer;
|
|
123
|
+
const filename = url.fileURLToPath(import.meta.url);
|
|
124
|
+
const dirname = path.dirname(filename);
|
|
125
|
+
const isDev = !filename.endsWith(path.join("cli", "index.mjs"));
|
|
126
|
+
const cliPackageLocation = isDev ? path.resolve(dirname, "../../../..") : path.resolve(dirname, "../..");
|
|
127
|
+
const previewServerLocation = isDev ? path.resolve(dirname, "../../../..") : path.resolve(dirname, "../preview");
|
|
128
|
+
const startDevServer = async ({ envDirRelativePath, staticBaseDirRelativePath, envDirAbsolutePaths, envFilePaths, envConfigPath, port, verbose }) => {
|
|
129
|
+
const [majorNodeVersion] = process.versions.node.split(".");
|
|
130
|
+
if (majorNodeVersion && Number.parseInt(majorNodeVersion) < 18) {
|
|
131
|
+
logger.error(`Node ${majorNodeVersion} is not supported. Please upgrade to Node 18 or higher.`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
devServer = http.createServer((req, res) => {
|
|
135
|
+
if (!req.url) {
|
|
136
|
+
res.end(404);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (verbose) logger.debug("Creating HTTP server...", {
|
|
140
|
+
envDirRelativePath,
|
|
141
|
+
staticBaseDirRelativePath,
|
|
142
|
+
envDirAbsolutePaths,
|
|
143
|
+
envFilePaths,
|
|
144
|
+
envConfigPath,
|
|
145
|
+
port
|
|
146
|
+
});
|
|
147
|
+
const parsedUrl = url.parse(req.url, true);
|
|
148
|
+
res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store");
|
|
149
|
+
res.setHeader("Pragma", "no-cache");
|
|
150
|
+
res.setHeader("Expires", "-1");
|
|
151
|
+
try {
|
|
152
|
+
if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
|
|
153
|
+
else if (!isNextReady) nextReadyPromise.then(() => nextHandleRequest?.(req, res, parsedUrl));
|
|
154
|
+
else nextHandleRequest?.(req, res, parsedUrl);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
logger.error(/* @__PURE__ */ new Error("Error while handling request!"), e);
|
|
157
|
+
res.writeHead(500);
|
|
158
|
+
res.end();
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
const { portAlreadyInUse } = await safeAsyncServerListen(devServer, port);
|
|
162
|
+
if (!portAlreadyInUse) {
|
|
163
|
+
logger.log(chalk.greenBright(`\n Envin ${version}`));
|
|
164
|
+
logger.log(` Running preview at: http://localhost:${port}\n`);
|
|
165
|
+
} else {
|
|
166
|
+
const nextPortToTry = port + 1;
|
|
167
|
+
logger.warn(`Port ${port} is already in use, trying ${nextPortToTry}...`);
|
|
168
|
+
return startDevServer({
|
|
169
|
+
envDirRelativePath,
|
|
170
|
+
staticBaseDirRelativePath,
|
|
171
|
+
envDirAbsolutePaths,
|
|
172
|
+
envFilePaths,
|
|
173
|
+
envConfigPath,
|
|
174
|
+
port: nextPortToTry,
|
|
175
|
+
verbose
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
devServer.on("close", async () => {
|
|
179
|
+
await app.close();
|
|
180
|
+
});
|
|
181
|
+
devServer.on("error", (e) => {
|
|
182
|
+
logger.error(/* @__PURE__ */ new Error("Preview server error!"), e);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
});
|
|
185
|
+
const spinner = ora({
|
|
186
|
+
text: "Getting envin preview server ready...\n",
|
|
187
|
+
prefixText: " "
|
|
188
|
+
}).start();
|
|
189
|
+
registerSpinnerAutostopping(spinner);
|
|
190
|
+
const timeBeforeNextReady = performance.now();
|
|
191
|
+
process.env = {
|
|
192
|
+
NODE_ENV: "development",
|
|
193
|
+
...process.env,
|
|
194
|
+
...getEnvVariablesForPreviewApp(path.normalize(envDirRelativePath), process.cwd(), envDirAbsolutePaths, envFilePaths, envConfigPath)
|
|
195
|
+
};
|
|
196
|
+
const app = next({
|
|
197
|
+
dev: isDev,
|
|
198
|
+
conf: { images: { unoptimized: true } },
|
|
199
|
+
hostname: "localhost",
|
|
200
|
+
port,
|
|
201
|
+
dir: previewServerLocation
|
|
202
|
+
});
|
|
203
|
+
let isNextReady = false;
|
|
204
|
+
const nextReadyPromise = app.prepare();
|
|
205
|
+
await nextReadyPromise;
|
|
206
|
+
isNextReady = true;
|
|
207
|
+
const nextHandleRequest = app.getRequestHandler();
|
|
208
|
+
const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
|
|
209
|
+
spinner.stopAndPersist({
|
|
210
|
+
text: `Ready in ${secondsToNextReady}s\n`,
|
|
211
|
+
symbol: logSymbols.success
|
|
212
|
+
});
|
|
213
|
+
return devServer;
|
|
327
214
|
};
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
process.exit(options.killWithErrorCode ? 1 : 0);
|
|
336
|
-
}
|
|
215
|
+
const makeExitHandler = (options) => (_codeOrSignal) => {
|
|
216
|
+
if (typeof devServer !== "undefined") {
|
|
217
|
+
logger.log("\nShutting down dev server...");
|
|
218
|
+
devServer.close();
|
|
219
|
+
devServer = void 0;
|
|
220
|
+
}
|
|
221
|
+
if (options?.shouldKillProcess) process.exit(options.killWithErrorCode ? 1 : 0);
|
|
337
222
|
};
|
|
338
223
|
process.on("exit", makeExitHandler());
|
|
339
|
-
process.on(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
);
|
|
343
|
-
process.on(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
);
|
|
347
|
-
process.on(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
);
|
|
351
|
-
process.on(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
);
|
|
224
|
+
process.on("SIGINT", makeExitHandler({
|
|
225
|
+
shouldKillProcess: true,
|
|
226
|
+
killWithErrorCode: false
|
|
227
|
+
}));
|
|
228
|
+
process.on("SIGUSR1", makeExitHandler({
|
|
229
|
+
shouldKillProcess: true,
|
|
230
|
+
killWithErrorCode: false
|
|
231
|
+
}));
|
|
232
|
+
process.on("SIGUSR2", makeExitHandler({
|
|
233
|
+
shouldKillProcess: true,
|
|
234
|
+
killWithErrorCode: false
|
|
235
|
+
}));
|
|
236
|
+
process.on("uncaughtException", makeExitHandler({
|
|
237
|
+
shouldKillProcess: true,
|
|
238
|
+
killWithErrorCode: true
|
|
239
|
+
}));
|
|
355
240
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const importPathNode = node.arguments[0];
|
|
394
|
-
if (importPathNode?.type === "StringLiteral") {
|
|
395
|
-
importedPaths.push(importPathNode.value);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
return importedPaths;
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/cli/utils/hot-reload/get-imported-modules.ts
|
|
243
|
+
const traverse = typeof traverseModule === "function" ? traverseModule : traverseModule.default;
|
|
244
|
+
const getImportedModules = (contents) => {
|
|
245
|
+
const importedPaths = [];
|
|
246
|
+
traverse(parse(contents, {
|
|
247
|
+
sourceType: "unambiguous",
|
|
248
|
+
strictMode: false,
|
|
249
|
+
errorRecovery: true,
|
|
250
|
+
plugins: [
|
|
251
|
+
"jsx",
|
|
252
|
+
"typescript",
|
|
253
|
+
"decorators"
|
|
254
|
+
]
|
|
255
|
+
}), {
|
|
256
|
+
ImportDeclaration({ node }) {
|
|
257
|
+
importedPaths.push(node.source.value);
|
|
258
|
+
},
|
|
259
|
+
ExportAllDeclaration({ node }) {
|
|
260
|
+
importedPaths.push(node.source.value);
|
|
261
|
+
},
|
|
262
|
+
ExportNamedDeclaration({ node }) {
|
|
263
|
+
if (node.source) importedPaths.push(node.source.value);
|
|
264
|
+
},
|
|
265
|
+
TSExternalModuleReference({ node }) {
|
|
266
|
+
importedPaths.push(node.expression.value);
|
|
267
|
+
},
|
|
268
|
+
CallExpression({ node }) {
|
|
269
|
+
if ("name" in node.callee && node.callee.name === "require") {
|
|
270
|
+
if (node.arguments.length === 1) {
|
|
271
|
+
const importPathNode = node.arguments[0];
|
|
272
|
+
if (importPathNode?.type === "StringLiteral") importedPaths.push(importPathNode.value);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
return importedPaths;
|
|
402
278
|
};
|
|
403
279
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
return `./${path4.relative(projectPath, unaliasedPath)}`;
|
|
425
|
-
}
|
|
426
|
-
return importedPath;
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
return importPaths;
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/cli/utils/hot-reload/resolve-path-aliases.ts
|
|
282
|
+
const resolvePathAliases = (importPaths, projectPath) => {
|
|
283
|
+
const configLoadResult = loadConfig(projectPath);
|
|
284
|
+
if (configLoadResult.resultType === "success") {
|
|
285
|
+
const matchPath = createMatchPath(configLoadResult.absoluteBaseUrl, configLoadResult.paths);
|
|
286
|
+
return importPaths.map((importedPath) => {
|
|
287
|
+
const unaliasedPath = matchPath(importedPath, void 0, void 0, [
|
|
288
|
+
".tsx",
|
|
289
|
+
".ts",
|
|
290
|
+
".js",
|
|
291
|
+
".jsx",
|
|
292
|
+
".cjs",
|
|
293
|
+
".mjs"
|
|
294
|
+
]);
|
|
295
|
+
if (unaliasedPath) return `./${path.relative(projectPath, unaliasedPath)}`;
|
|
296
|
+
return importedPath;
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
return importPaths;
|
|
430
300
|
};
|
|
431
301
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
allFilePaths.push(pathToDirent);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
return allFilePaths;
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/cli/utils/hot-reload/create-dependency-graph.ts
|
|
304
|
+
const readAllFilesInsideDirectory = async (directory) => {
|
|
305
|
+
let allFilePaths = [];
|
|
306
|
+
const topLevelDirents = await promises.readdir(directory, { withFileTypes: true });
|
|
307
|
+
for await (const dirent of topLevelDirents) {
|
|
308
|
+
const pathToDirent = path.join(directory, dirent.name);
|
|
309
|
+
if (dirent.isDirectory()) allFilePaths = allFilePaths.concat(await readAllFilesInsideDirectory(pathToDirent));
|
|
310
|
+
else allFilePaths.push(pathToDirent);
|
|
311
|
+
}
|
|
312
|
+
return allFilePaths;
|
|
447
313
|
};
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
314
|
+
const isJavascriptModule = (filePath) => {
|
|
315
|
+
const extensionName = path.extname(filePath);
|
|
316
|
+
return [
|
|
317
|
+
".js",
|
|
318
|
+
".ts",
|
|
319
|
+
".jsx",
|
|
320
|
+
".tsx",
|
|
321
|
+
".mjs",
|
|
322
|
+
".cjs"
|
|
323
|
+
].includes(extensionName);
|
|
451
324
|
};
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
if (existsSync2(`${pathWithoutExtension}.js`)) {
|
|
460
|
-
return `${pathWithoutExtension}.js`;
|
|
461
|
-
}
|
|
462
|
-
if (existsSync2(`${pathWithoutExtension}.jsx`)) {
|
|
463
|
-
return `${pathWithoutExtension}.jsx`;
|
|
464
|
-
}
|
|
465
|
-
if (existsSync2(`${pathWithoutExtension}.mjs`)) {
|
|
466
|
-
return `${pathWithoutExtension}.mjs`;
|
|
467
|
-
}
|
|
468
|
-
if (existsSync2(`${pathWithoutExtension}.cjs`)) {
|
|
469
|
-
return `${pathWithoutExtension}.cjs`;
|
|
470
|
-
}
|
|
325
|
+
const checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
|
|
326
|
+
if (existsSync(`${pathWithoutExtension}.ts`)) return `${pathWithoutExtension}.ts`;
|
|
327
|
+
if (existsSync(`${pathWithoutExtension}.tsx`)) return `${pathWithoutExtension}.tsx`;
|
|
328
|
+
if (existsSync(`${pathWithoutExtension}.js`)) return `${pathWithoutExtension}.js`;
|
|
329
|
+
if (existsSync(`${pathWithoutExtension}.jsx`)) return `${pathWithoutExtension}.jsx`;
|
|
330
|
+
if (existsSync(`${pathWithoutExtension}.mjs`)) return `${pathWithoutExtension}.mjs`;
|
|
331
|
+
if (existsSync(`${pathWithoutExtension}.cjs`)) return `${pathWithoutExtension}.cjs`;
|
|
471
332
|
};
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
`Loading the dependency path ${dependencyPath} did not initialize it at all. This is a bug in React Email.`
|
|
583
|
-
);
|
|
584
|
-
}
|
|
585
|
-
if (!dependencyModule.dependentPaths.includes(moduleFilePath)) {
|
|
586
|
-
dependencyModule.dependentPaths.push(moduleFilePath);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
const removeModuleFromGraph = (filePath) => {
|
|
591
|
-
const module = graph[filePath];
|
|
592
|
-
if (module) {
|
|
593
|
-
for (const dependencyPath of module.dependencyPaths) {
|
|
594
|
-
if (graph[dependencyPath]) {
|
|
595
|
-
graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter(
|
|
596
|
-
(dependentPath) => dependentPath !== filePath
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
delete graph[filePath];
|
|
601
|
-
}
|
|
602
|
-
};
|
|
603
|
-
return [
|
|
604
|
-
graph,
|
|
605
|
-
async (event, pathToModified) => {
|
|
606
|
-
switch (event) {
|
|
607
|
-
case "change":
|
|
608
|
-
if (isJavascriptModule(pathToModified)) {
|
|
609
|
-
await updateModuleDependenciesInGraph(pathToModified);
|
|
610
|
-
}
|
|
611
|
-
break;
|
|
612
|
-
case "add":
|
|
613
|
-
if (isJavascriptModule(pathToModified)) {
|
|
614
|
-
await updateModuleDependenciesInGraph(pathToModified);
|
|
615
|
-
}
|
|
616
|
-
break;
|
|
617
|
-
case "addDir": {
|
|
618
|
-
const filesInsideAddedDirectory = await readAllFilesInsideDirectory(pathToModified);
|
|
619
|
-
const modulesInsideAddedDirectory = filesInsideAddedDirectory.filter(isJavascriptModule);
|
|
620
|
-
for await (const filePath of modulesInsideAddedDirectory) {
|
|
621
|
-
await updateModuleDependenciesInGraph(filePath);
|
|
622
|
-
}
|
|
623
|
-
break;
|
|
624
|
-
}
|
|
625
|
-
case "unlink":
|
|
626
|
-
if (isJavascriptModule(pathToModified)) {
|
|
627
|
-
removeModuleFromGraph(pathToModified);
|
|
628
|
-
}
|
|
629
|
-
break;
|
|
630
|
-
case "unlinkDir": {
|
|
631
|
-
const filesInsideDeletedDirectory = await readAllFilesInsideDirectory(pathToModified);
|
|
632
|
-
const modulesInsideDeletedDirectory = filesInsideDeletedDirectory.filter(isJavascriptModule);
|
|
633
|
-
for await (const filePath of modulesInsideDeletedDirectory) {
|
|
634
|
-
removeModuleFromGraph(filePath);
|
|
635
|
-
}
|
|
636
|
-
break;
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
resolveDependentsOf: function resolveDependentsOf(pathToModule) {
|
|
642
|
-
const moduleEntry = graph[pathToModule];
|
|
643
|
-
const dependentPaths = [];
|
|
644
|
-
if (moduleEntry) {
|
|
645
|
-
for (const dependentPath of moduleEntry.dependentPaths) {
|
|
646
|
-
const dependentsOfDependent = resolveDependentsOf(dependentPath);
|
|
647
|
-
dependentPaths.push(...dependentsOfDependent);
|
|
648
|
-
dependentPaths.push(dependentPath);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
return dependentPaths;
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
];
|
|
333
|
+
/**
|
|
334
|
+
* Creates a stateful dependency graph that is structured in a way that you can get
|
|
335
|
+
* the dependents of a module from its path.
|
|
336
|
+
*
|
|
337
|
+
* Stateful in the sense that it provides a `getter` and an "`updater`". The updater
|
|
338
|
+
* will receive changes to the files, that can be perceived through some file watching mechanism,
|
|
339
|
+
* so that it doesn't need to recompute the entire dependency graph but only the parts changed.
|
|
340
|
+
*/
|
|
341
|
+
const createDependencyGraph = async (directory) => {
|
|
342
|
+
const modulePaths = (await readAllFilesInsideDirectory(directory)).filter(isJavascriptModule);
|
|
343
|
+
const graph = Object.fromEntries(modulePaths.map((path$1) => [path$1, {
|
|
344
|
+
path: path$1,
|
|
345
|
+
dependencyPaths: [],
|
|
346
|
+
dependentPaths: [],
|
|
347
|
+
moduleDependencies: []
|
|
348
|
+
}]));
|
|
349
|
+
const getDependencyPaths = async (filePath) => {
|
|
350
|
+
const contents = await promises.readFile(filePath, "utf8");
|
|
351
|
+
const importedPathsRelativeToDirectory = (isJavascriptModule(filePath) ? resolvePathAliases(getImportedModules(contents), path.dirname(filePath)) : []).map((dependencyPath) => {
|
|
352
|
+
if (!dependencyPath.startsWith(".") || path.isAbsolute(dependencyPath)) return dependencyPath;
|
|
353
|
+
let pathToDependencyFromDirectory = path.resolve(path.dirname(filePath), dependencyPath);
|
|
354
|
+
let isDirectory = false;
|
|
355
|
+
try {
|
|
356
|
+
isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
|
|
357
|
+
} catch (_) {}
|
|
358
|
+
if (isDirectory) {
|
|
359
|
+
const pathWithExtension = checkFileExtensionsUntilItExists(`${pathToDependencyFromDirectory}/index`);
|
|
360
|
+
if (pathWithExtension) pathToDependencyFromDirectory = pathWithExtension;
|
|
361
|
+
else if (isDev) logger.warn(`Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`);
|
|
362
|
+
}
|
|
363
|
+
const extension = path.extname(pathToDependencyFromDirectory);
|
|
364
|
+
const pathWithEnsuredExtension = (() => {
|
|
365
|
+
if (extension.length > 0 && existsSync(pathToDependencyFromDirectory)) return pathToDependencyFromDirectory;
|
|
366
|
+
return checkFileExtensionsUntilItExists(pathToDependencyFromDirectory.replace(extension, ""));
|
|
367
|
+
})();
|
|
368
|
+
if (pathWithEnsuredExtension) pathToDependencyFromDirectory = pathWithEnsuredExtension;
|
|
369
|
+
else if (isDev) logger.warn(`Could not find file at ${pathToDependencyFromDirectory}`);
|
|
370
|
+
return pathToDependencyFromDirectory;
|
|
371
|
+
});
|
|
372
|
+
const moduleDependencies = importedPathsRelativeToDirectory.filter((dependencyPath) => !dependencyPath.startsWith(".") && !path.isAbsolute(dependencyPath));
|
|
373
|
+
return {
|
|
374
|
+
dependencyPaths: importedPathsRelativeToDirectory.filter((dependencyPath) => dependencyPath.startsWith(".") || path.isAbsolute(dependencyPath)),
|
|
375
|
+
moduleDependencies
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
const updateModuleDependenciesInGraph = async (moduleFilePath) => {
|
|
379
|
+
if (graph[moduleFilePath] === void 0) graph[moduleFilePath] = {
|
|
380
|
+
path: moduleFilePath,
|
|
381
|
+
dependencyPaths: [],
|
|
382
|
+
dependentPaths: [],
|
|
383
|
+
moduleDependencies: []
|
|
384
|
+
};
|
|
385
|
+
const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
|
|
386
|
+
graph[moduleFilePath].moduleDependencies = moduleDependencies;
|
|
387
|
+
for (const dependencyPath of graph[moduleFilePath].dependencyPaths) {
|
|
388
|
+
if (newDependencyPaths.includes(dependencyPath)) continue;
|
|
389
|
+
const dependencyModule = graph[dependencyPath];
|
|
390
|
+
if (dependencyModule !== void 0) dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter((dependentPath) => dependentPath !== moduleFilePath);
|
|
391
|
+
}
|
|
392
|
+
graph[moduleFilePath].dependencyPaths = newDependencyPaths;
|
|
393
|
+
for await (const dependencyPath of newDependencyPaths) {
|
|
394
|
+
if (graph[dependencyPath] === void 0) await updateModuleDependenciesInGraph(dependencyPath);
|
|
395
|
+
const dependencyModule = graph[dependencyPath];
|
|
396
|
+
if (dependencyModule === void 0) throw new Error(`Loading the dependency path ${dependencyPath} did not initialize it at all. This is a bug in React Email.`);
|
|
397
|
+
if (!dependencyModule.dependentPaths.includes(moduleFilePath)) dependencyModule.dependentPaths.push(moduleFilePath);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
const removeModuleFromGraph = (filePath) => {
|
|
401
|
+
const module = graph[filePath];
|
|
402
|
+
if (module) {
|
|
403
|
+
for (const dependencyPath of module.dependencyPaths) if (graph[dependencyPath]) graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter((dependentPath) => dependentPath !== filePath);
|
|
404
|
+
delete graph[filePath];
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
return [
|
|
408
|
+
graph,
|
|
409
|
+
async (event, pathToModified) => {
|
|
410
|
+
switch (event) {
|
|
411
|
+
case "change":
|
|
412
|
+
if (isJavascriptModule(pathToModified)) await updateModuleDependenciesInGraph(pathToModified);
|
|
413
|
+
break;
|
|
414
|
+
case "add":
|
|
415
|
+
if (isJavascriptModule(pathToModified)) await updateModuleDependenciesInGraph(pathToModified);
|
|
416
|
+
break;
|
|
417
|
+
case "addDir": {
|
|
418
|
+
const modulesInsideAddedDirectory = (await readAllFilesInsideDirectory(pathToModified)).filter(isJavascriptModule);
|
|
419
|
+
for await (const filePath of modulesInsideAddedDirectory) await updateModuleDependenciesInGraph(filePath);
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
case "unlink":
|
|
423
|
+
if (isJavascriptModule(pathToModified)) removeModuleFromGraph(pathToModified);
|
|
424
|
+
break;
|
|
425
|
+
case "unlinkDir": {
|
|
426
|
+
const modulesInsideDeletedDirectory = (await readAllFilesInsideDirectory(pathToModified)).filter(isJavascriptModule);
|
|
427
|
+
for await (const filePath of modulesInsideDeletedDirectory) removeModuleFromGraph(filePath);
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
{ resolveDependentsOf: function resolveDependentsOf(pathToModule) {
|
|
433
|
+
const moduleEntry = graph[pathToModule];
|
|
434
|
+
const dependentPaths = [];
|
|
435
|
+
if (moduleEntry) for (const dependentPath of moduleEntry.dependentPaths) {
|
|
436
|
+
const dependentsOfDependent = resolveDependentsOf(dependentPath);
|
|
437
|
+
dependentPaths.push(...dependentsOfDependent);
|
|
438
|
+
dependentPaths.push(dependentPath);
|
|
439
|
+
}
|
|
440
|
+
return dependentPaths;
|
|
441
|
+
} }
|
|
442
|
+
];
|
|
655
443
|
};
|
|
656
444
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
445
|
+
//#endregion
|
|
446
|
+
//#region src/cli/utils/hot-reload/setup-hot-reloading.ts
|
|
447
|
+
const IGNORED_DIR_NAMES = [
|
|
448
|
+
"node_modules",
|
|
449
|
+
".git",
|
|
450
|
+
"dist",
|
|
451
|
+
"build",
|
|
452
|
+
"out",
|
|
453
|
+
"coverage",
|
|
454
|
+
".cache",
|
|
455
|
+
"tmp"
|
|
667
456
|
];
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
(dir) => normalized.includes(`/${dir}/`) || normalized.endsWith(`/${dir}`) || normalized.startsWith(`${dir}/`)
|
|
673
|
-
);
|
|
457
|
+
const normalizePath = (p) => p.split(path.sep).join("/");
|
|
458
|
+
const isPathInIgnoredDir = (p) => {
|
|
459
|
+
const normalized = normalizePath(p);
|
|
460
|
+
return IGNORED_DIR_NAMES.some((dir) => normalized.includes(`/${dir}/`) || normalized.endsWith(`/${dir}`) || normalized.startsWith(`${dir}/`));
|
|
674
461
|
};
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
`**/${pattern}/**`,
|
|
698
|
-
`${pattern}/**`,
|
|
699
|
-
`**/${pattern}`,
|
|
700
|
-
pattern
|
|
701
|
-
);
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
return globs;
|
|
705
|
-
} catch {
|
|
706
|
-
return [];
|
|
707
|
-
}
|
|
462
|
+
const toDirGlob = (dir) => [`**/${dir}/**`, `${dir}/**`];
|
|
463
|
+
const readGitignoreGlobs = async (baseDir) => {
|
|
464
|
+
try {
|
|
465
|
+
const gitignorePath = path.join(baseDir, ".gitignore");
|
|
466
|
+
const lines = (await promises.readFile(gitignorePath, "utf8")).split(/\r?\n/);
|
|
467
|
+
const globs = [];
|
|
468
|
+
for (const rawLine of lines) {
|
|
469
|
+
const line = rawLine.trim();
|
|
470
|
+
if (line.length === 0 || line.startsWith("#") || line.startsWith("!")) continue;
|
|
471
|
+
let pattern = line.replace(/^\//, "");
|
|
472
|
+
if (pattern.endsWith("/")) {
|
|
473
|
+
pattern = pattern.slice(0, -1);
|
|
474
|
+
globs.push(`**/${pattern}/**`, `${pattern}/**`);
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (pattern.includes("*") || pattern.includes("?")) globs.push(`**/${pattern}`, pattern);
|
|
478
|
+
else globs.push(`**/${pattern}/**`, `${pattern}/**`, `**/${pattern}`, pattern);
|
|
479
|
+
}
|
|
480
|
+
return globs;
|
|
481
|
+
} catch {
|
|
482
|
+
return [];
|
|
483
|
+
}
|
|
708
484
|
};
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
485
|
+
const buildIgnoredGlobs = async (baseDir) => {
|
|
486
|
+
const defaultIgnoredGlobs = IGNORED_DIR_NAMES.flatMap(toDirGlob);
|
|
487
|
+
const gitignoreGlobs = await readGitignoreGlobs(baseDir);
|
|
488
|
+
return [...defaultIgnoredGlobs, ...gitignoreGlobs];
|
|
713
489
|
};
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
490
|
+
const createEnvWatcher = async (baseDir) => {
|
|
491
|
+
return watch(["**/*.{js,ts,jsx,tsx,mjs,cjs}"], {
|
|
492
|
+
cwd: baseDir,
|
|
493
|
+
ignoreInitial: true,
|
|
494
|
+
ignored: await buildIgnoredGlobs(baseDir),
|
|
495
|
+
ignorePermissionErrors: true,
|
|
496
|
+
awaitWriteFinish: {
|
|
497
|
+
stabilityThreshold: 50,
|
|
498
|
+
pollInterval: 10
|
|
499
|
+
}
|
|
500
|
+
});
|
|
723
501
|
};
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if (!isPathInIgnoredDir(p)) {
|
|
727
|
-
w.add(p);
|
|
728
|
-
}
|
|
729
|
-
}
|
|
502
|
+
const addExternalFilesToWatcher = (w, files) => {
|
|
503
|
+
for (const p of files) if (!isPathInIgnoredDir(p)) w.add(p);
|
|
730
504
|
};
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
process.on("SIGINT", exit);
|
|
739
|
-
process.on("uncaughtException", exit);
|
|
505
|
+
const attachShutdownHandlers = (w, verbose) => {
|
|
506
|
+
const exit = async () => {
|
|
507
|
+
if (verbose) logger.info("Stopping file watcher and cleaning up...");
|
|
508
|
+
await w.close();
|
|
509
|
+
};
|
|
510
|
+
process.on("SIGINT", exit);
|
|
511
|
+
process.on("uncaughtException", exit);
|
|
740
512
|
};
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
const watcher = await createEnvWatcher(absolutePathToEnvDirectory);
|
|
798
|
-
const getFilesOutsideEnvDirectory = () => Object.keys(dependencyGraph).filter(
|
|
799
|
-
(p) => path6.relative(absolutePathToEnvDirectory, p).startsWith("..")
|
|
800
|
-
);
|
|
801
|
-
let filesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
|
|
802
|
-
addExternalFilesToWatcher(watcher, filesOutsideEnvDirectory);
|
|
803
|
-
attachShutdownHandlers(watcher, verbose);
|
|
804
|
-
watcher.on("all", async (event, relativePathToChangeTarget) => {
|
|
805
|
-
if (verbose) {
|
|
806
|
-
logger.debug("File system event", {
|
|
807
|
-
event,
|
|
808
|
-
file: relativePathToChangeTarget
|
|
809
|
-
});
|
|
810
|
-
}
|
|
811
|
-
const file = relativePathToChangeTarget.split(path6.sep);
|
|
812
|
-
if (file.length === 0) {
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
const pathToChangeTarget = path6.resolve(
|
|
816
|
-
absolutePathToEnvDirectory,
|
|
817
|
-
relativePathToChangeTarget
|
|
818
|
-
);
|
|
819
|
-
await updateDependencyGraph(event, pathToChangeTarget);
|
|
820
|
-
const newFilesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
|
|
821
|
-
for (const p of filesOutsideEnvDirectory) {
|
|
822
|
-
if (!newFilesOutsideEnvDirectory.includes(p)) {
|
|
823
|
-
watcher.unwatch(p);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
for (const p of newFilesOutsideEnvDirectory) {
|
|
827
|
-
if (!filesOutsideEnvDirectory.includes(p) && !isPathInIgnoredDir(p)) {
|
|
828
|
-
watcher.add(p);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
filesOutsideEnvDirectory = newFilesOutsideEnvDirectory;
|
|
832
|
-
changes.push({
|
|
833
|
-
event,
|
|
834
|
-
filename: relativePathToChangeTarget
|
|
835
|
-
});
|
|
836
|
-
for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
|
|
837
|
-
changes.push({
|
|
838
|
-
event: "change",
|
|
839
|
-
filename: path6.relative(absolutePathToEnvDirectory, dependentPath)
|
|
840
|
-
});
|
|
841
|
-
}
|
|
842
|
-
reload();
|
|
843
|
-
});
|
|
844
|
-
return watcher;
|
|
513
|
+
const setupHotreloading = async ({ devServer: devServer$1, envDirRelativePath, envDirAbsolutePaths, envFilePaths, verbose }) => {
|
|
514
|
+
if (verbose) logger.start("Initializing socket.io server for hot reloading...");
|
|
515
|
+
let clients = [];
|
|
516
|
+
new Server(devServer$1).on("connection", (client) => {
|
|
517
|
+
if (verbose) logger.debug("Client connected to hot reload socket");
|
|
518
|
+
clients.push(client);
|
|
519
|
+
client.on("disconnect", () => {
|
|
520
|
+
if (verbose) logger.debug("Client disconnected from hot reload socket");
|
|
521
|
+
clients = clients.filter((item) => item !== client);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
let changes = [];
|
|
525
|
+
const reload = debounce(() => {
|
|
526
|
+
if (verbose) logger.debug("Emitting reload event to", clients.length, "clients", changes);
|
|
527
|
+
clients.forEach((client) => {
|
|
528
|
+
client.emit("reload", changes.filter((change) => path.resolve(absolutePathToEnvDirectory, change.filename).startsWith(absolutePathToEnvDirectory)));
|
|
529
|
+
});
|
|
530
|
+
changes = [];
|
|
531
|
+
}, 150);
|
|
532
|
+
const absolutePathToEnvDirectory = path.resolve(process.cwd(), envDirRelativePath);
|
|
533
|
+
const [dependencyGraph, updateDependencyGraph, { resolveDependentsOf }] = await createDependencyGraph(absolutePathToEnvDirectory);
|
|
534
|
+
if (verbose) logger.info("Dependency graph created", {
|
|
535
|
+
modules: Object.keys(dependencyGraph).length,
|
|
536
|
+
root: absolutePathToEnvDirectory
|
|
537
|
+
});
|
|
538
|
+
const watcher = await createEnvWatcher(absolutePathToEnvDirectory);
|
|
539
|
+
const existingExtraEnvFiles = (envFilePaths.length ? envFilePaths : envDirAbsolutePaths.flatMap((dir) => [...FILES[Environment.DEVELOPMENT], ...FILES[Environment.PRODUCTION]].map((file) => path.join(dir, file)))).filter((filePath) => fs.existsSync(filePath));
|
|
540
|
+
const getFilesOutsideEnvDirectory = () => Object.keys(dependencyGraph).filter((p) => path.relative(absolutePathToEnvDirectory, p).startsWith(".."));
|
|
541
|
+
let filesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
|
|
542
|
+
addExternalFilesToWatcher(watcher, [...filesOutsideEnvDirectory, ...existingExtraEnvFiles]);
|
|
543
|
+
attachShutdownHandlers(watcher, verbose);
|
|
544
|
+
watcher.on("all", async (event, relativePathToChangeTarget) => {
|
|
545
|
+
if (verbose) logger.debug("File system event", {
|
|
546
|
+
event,
|
|
547
|
+
file: relativePathToChangeTarget
|
|
548
|
+
});
|
|
549
|
+
if (relativePathToChangeTarget.split(path.sep).length === 0) return;
|
|
550
|
+
const pathToChangeTarget = path.resolve(absolutePathToEnvDirectory, relativePathToChangeTarget);
|
|
551
|
+
await updateDependencyGraph(event, pathToChangeTarget);
|
|
552
|
+
const newFilesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
|
|
553
|
+
for (const p of filesOutsideEnvDirectory) if (!newFilesOutsideEnvDirectory.includes(p)) watcher.unwatch(p);
|
|
554
|
+
for (const p of newFilesOutsideEnvDirectory) if (!filesOutsideEnvDirectory.includes(p) && !isPathInIgnoredDir(p)) watcher.add(p);
|
|
555
|
+
filesOutsideEnvDirectory = newFilesOutsideEnvDirectory;
|
|
556
|
+
changes.push({
|
|
557
|
+
event,
|
|
558
|
+
filename: relativePathToChangeTarget
|
|
559
|
+
});
|
|
560
|
+
for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) changes.push({
|
|
561
|
+
event: "change",
|
|
562
|
+
filename: path.relative(absolutePathToEnvDirectory, dependentPath)
|
|
563
|
+
});
|
|
564
|
+
reload();
|
|
565
|
+
});
|
|
566
|
+
return watcher;
|
|
845
567
|
};
|
|
846
568
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
569
|
+
//#endregion
|
|
570
|
+
//#region src/cli/commands/dev.ts
|
|
571
|
+
const WORKSPACE_ROOT_FILE_MARKERS = [
|
|
572
|
+
"pnpm-workspace.yaml",
|
|
573
|
+
"turbo.json",
|
|
574
|
+
"nx.json",
|
|
575
|
+
"lerna.json",
|
|
576
|
+
"rush.json",
|
|
577
|
+
"WORKSPACE",
|
|
578
|
+
"WORKSPACE.bazel"
|
|
579
|
+
];
|
|
580
|
+
const findWorkspaceRoot = (startDir) => {
|
|
581
|
+
const readPackageJson = (candidateDir) => {
|
|
582
|
+
try {
|
|
583
|
+
const packageJsonPath = path.join(candidateDir, "package.json");
|
|
584
|
+
if (!fs.existsSync(packageJsonPath)) return null;
|
|
585
|
+
const raw = fs.readFileSync(packageJsonPath, "utf8");
|
|
586
|
+
return JSON.parse(raw);
|
|
587
|
+
} catch {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
const hasWorkspacePackageJson = (candidateDir) => {
|
|
592
|
+
const parsed = readPackageJson(candidateDir);
|
|
593
|
+
return Boolean(parsed?.workspaces);
|
|
594
|
+
};
|
|
595
|
+
const hasWorkspaceMarkers = (candidateDir) => WORKSPACE_ROOT_FILE_MARKERS.some((marker) => fs.existsSync(path.join(candidateDir, marker))) || hasWorkspacePackageJson(candidateDir);
|
|
596
|
+
const hasMonorepoFolderHints = (candidateDir) => {
|
|
597
|
+
const hasApps = fs.existsSync(path.join(candidateDir, "apps"));
|
|
598
|
+
const hasPackages = fs.existsSync(path.join(candidateDir, "packages"));
|
|
599
|
+
const packageJson = readPackageJson(candidateDir);
|
|
600
|
+
return (hasApps || hasPackages) && Boolean(packageJson?.private ?? false);
|
|
601
|
+
};
|
|
602
|
+
let currentDir = startDir;
|
|
603
|
+
let bestCandidate = null;
|
|
604
|
+
while (true) {
|
|
605
|
+
if (hasWorkspaceMarkers(currentDir)) return currentDir;
|
|
606
|
+
if (hasMonorepoFolderHints(currentDir)) bestCandidate = currentDir;
|
|
607
|
+
const parentDir = path.dirname(currentDir);
|
|
608
|
+
if (parentDir === currentDir || fs.existsSync(path.join(currentDir, ".git")) || fs.existsSync(path.join(currentDir, "node_modules"))) return bestCandidate ?? startDir;
|
|
609
|
+
currentDir = parentDir;
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
const uniquePaths = (paths) => {
|
|
613
|
+
const seen = /* @__PURE__ */ new Set();
|
|
614
|
+
return paths.filter((candidate) => {
|
|
615
|
+
const normalized = path.normalize(candidate);
|
|
616
|
+
if (seen.has(normalized)) return false;
|
|
617
|
+
seen.add(normalized);
|
|
618
|
+
return true;
|
|
619
|
+
});
|
|
620
|
+
};
|
|
621
|
+
const dev = async ({ dir: envDirRelativePath, config, env, cascade = false, port, verbose }) => {
|
|
622
|
+
try {
|
|
623
|
+
if (verbose) logger.debug("Starting dev command...", {
|
|
624
|
+
cwd: process.cwd(),
|
|
625
|
+
dir: envDirRelativePath,
|
|
626
|
+
config,
|
|
627
|
+
env,
|
|
628
|
+
cascade,
|
|
629
|
+
port
|
|
630
|
+
});
|
|
631
|
+
const cwd = process.cwd();
|
|
632
|
+
const resolveFromCwd = (targetPath) => path.isAbsolute(targetPath) ? targetPath : path.resolve(cwd, targetPath);
|
|
633
|
+
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
634
|
+
let envFilePaths = [];
|
|
635
|
+
let envDirPaths = [];
|
|
636
|
+
let primaryEnvDir = cwd;
|
|
637
|
+
if (env) {
|
|
638
|
+
const resolvedEnvPath = resolveFromCwd(env);
|
|
639
|
+
if (!fs.existsSync(resolvedEnvPath)) {
|
|
640
|
+
logger.error(`Missing ${resolvedEnvPath} path!`);
|
|
641
|
+
process.exit(1);
|
|
642
|
+
}
|
|
643
|
+
if (fs.statSync(resolvedEnvPath).isFile()) {
|
|
644
|
+
envFilePaths = [resolvedEnvPath];
|
|
645
|
+
primaryEnvDir = path.dirname(resolvedEnvPath);
|
|
646
|
+
} else {
|
|
647
|
+
envDirPaths = [resolvedEnvPath];
|
|
648
|
+
primaryEnvDir = resolvedEnvPath;
|
|
649
|
+
}
|
|
650
|
+
} else if (cascade) {
|
|
651
|
+
envDirPaths = uniquePaths([workspaceRoot, cwd]);
|
|
652
|
+
primaryEnvDir = envDirPaths[envDirPaths.length - 1] ?? cwd;
|
|
653
|
+
} else {
|
|
654
|
+
const resolvedDir = resolveFromCwd(envDirRelativePath);
|
|
655
|
+
envDirPaths = [resolvedDir];
|
|
656
|
+
primaryEnvDir = resolvedDir;
|
|
657
|
+
}
|
|
658
|
+
const resolvedEnvDirRelativePath = path.relative(cwd, primaryEnvDir) || ".";
|
|
659
|
+
if (!fs.existsSync(primaryEnvDir)) {
|
|
660
|
+
logger.error(`Missing ${primaryEnvDir} folder!`);
|
|
661
|
+
process.exit(1);
|
|
662
|
+
}
|
|
663
|
+
const resolveConfigPath = () => {
|
|
664
|
+
if (config) return resolveFromCwd(config);
|
|
665
|
+
if (!cascade) return path.join(primaryEnvDir, "env.config.ts");
|
|
666
|
+
return uniquePaths([path.join(primaryEnvDir, "env.config.ts"), path.join(workspaceRoot, "env.config.ts")]).find((candidate) => fs.existsSync(candidate));
|
|
667
|
+
};
|
|
668
|
+
const resolvedConfigPath = resolveConfigPath();
|
|
669
|
+
if (!resolvedConfigPath || !fs.existsSync(resolvedConfigPath)) {
|
|
670
|
+
logger.error("Missing env.config.ts file!");
|
|
671
|
+
process.exit(1);
|
|
672
|
+
}
|
|
673
|
+
const devServer$1 = await startDevServer({
|
|
674
|
+
envDirRelativePath: resolvedEnvDirRelativePath,
|
|
675
|
+
staticBaseDirRelativePath: resolvedEnvDirRelativePath,
|
|
676
|
+
envDirAbsolutePaths: envDirPaths.length ? envDirPaths : [primaryEnvDir],
|
|
677
|
+
envFilePaths,
|
|
678
|
+
envConfigPath: resolvedConfigPath,
|
|
679
|
+
port: Number.parseInt(port),
|
|
680
|
+
verbose
|
|
681
|
+
});
|
|
682
|
+
if (verbose) logger.start("Dev server started, setting up hot reloading...");
|
|
683
|
+
await setupHotreloading({
|
|
684
|
+
devServer: devServer$1,
|
|
685
|
+
envDirRelativePath: resolvedEnvDirRelativePath,
|
|
686
|
+
envDirAbsolutePaths: envDirPaths.length ? envDirPaths : [primaryEnvDir],
|
|
687
|
+
envFilePaths,
|
|
688
|
+
verbose
|
|
689
|
+
});
|
|
690
|
+
if (verbose) logger.success("Hot reloading setup complete");
|
|
691
|
+
} catch (error) {
|
|
692
|
+
logger.error(/* @__PURE__ */ new Error("Error while running dev!"), error);
|
|
693
|
+
process.exit(1);
|
|
694
|
+
}
|
|
882
695
|
};
|
|
883
696
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
program.name(
|
|
887
|
-
|
|
888
|
-
).version(package_default.version);
|
|
889
|
-
program.command("dev").description("Starts the live preview of your environment variables").option(
|
|
890
|
-
"-d, --dir <path>",
|
|
891
|
-
"Directory with your envin configuration and .env files",
|
|
892
|
-
"./"
|
|
893
|
-
).option("-p --port <port>", "Port to run dev server on", "3000").option("-v, --verbose", "Enable verbose logging", false).action(dev);
|
|
697
|
+
//#endregion
|
|
698
|
+
//#region src/cli/index.ts
|
|
699
|
+
program.name("@envin/cli").description("A live preview of your environment variables right in your browser").version(version);
|
|
700
|
+
program.command("dev").description("Starts the live preview of your environment variables").option("-d, --dir <path>", "Directory with your envin configuration and .env files", "./").option("-c, --config <path>", "Path to env.config.ts").option("-e, --env <path>", "Path to .env file or directory").option("--cascade", "Enable workspace env/config cascading", false).option("-p --port <port>", "Port to run dev server on", "3000").option("-v, --verbose", "Enable verbose logging", false).action(dev);
|
|
894
701
|
program.parse();
|
|
702
|
+
|
|
703
|
+
//#endregion
|
|
704
|
+
export { };
|