@envin/cli 0.0.1 → 1.1.1
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 +32 -0
- package/README.md +95 -0
- package/dist/cli/index.mjs +464 -55
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/app-build-manifest.json +6 -6
- package/dist/preview/.next/build-manifest.json +5 -5
- package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/preview/.next/next-server.js.nft.json +1 -1
- package/dist/preview/.next/prerender-manifest.json +3 -3
- package/dist/preview/.next/required-server-files.json +1 -1
- package/dist/preview/.next/server/app/_not-found/page.js +1 -1
- package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/_not-found.html +1 -1
- package/dist/preview/.next/server/app/_not-found.rsc +2 -2
- package/dist/preview/.next/server/app/favicon.ico/route.js +1 -1
- package/dist/preview/.next/server/app/index.html +1 -1
- package/dist/preview/.next/server/app/index.rsc +3 -3
- package/dist/preview/.next/server/app/page.js +8 -7
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/chunks/191.js +10 -10
- package/dist/preview/.next/server/chunks/496.js +3 -3
- package/dist/preview/.next/server/chunks/601.js +4 -4
- package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
- package/dist/preview/.next/server/pages/404.html +1 -1
- package/dist/preview/.next/server/pages/500.html +1 -1
- package/dist/preview/.next/server/pages/_app.js +1 -1
- package/dist/preview/.next/server/pages/_document.js +1 -1
- package/dist/preview/.next/server/pages/_error.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.json +1 -1
- package/dist/preview/.next/server/webpack-runtime.js +1 -1
- package/dist/preview/.next/static/chunks/985-f32f025f8cdc74d3.js +1 -0
- package/dist/preview/.next/static/chunks/app/page-781d5c4076d3b10d.js +1 -0
- package/dist/preview/.next/static/chunks/webpack-464ea5083b838c17.js +1 -0
- package/dist/preview/.next/static/css/8b2927e38b2520cf.css +3 -0
- package/dist/preview/.next/trace +14 -13
- package/package.json +17 -6
- package/src/app/page.tsx +11 -2
- package/src/components/variables/context.tsx +30 -18
- package/src/lib/config.ts +1 -18
- package/src/lib/hooks/use-hot-reload.ts +31 -0
- package/src/lib/types.ts +10 -0
- package/src/lib/validate.ts +3 -1
- package/src/lib/variables/index.ts +28 -6
- package/src/utils/get-config-file.ts +2 -0
- package/dist/preview/.next/static/chunks/174-5a80ff32c1746c12.js +0 -1
- package/dist/preview/.next/static/chunks/app/page-5dac690b5d4c8e8b.js +0 -1
- package/dist/preview/.next/static/chunks/webpack-e84142516ca52ef7.js +0 -1
- package/dist/preview/.next/static/css/6842db20c57f3076.css +0 -3
- /package/dist/preview/.next/static/{v9TlUn5liPNhAPJYeB3QH → ti02qYR7TtWD2j2orEzoT}/_buildManifest.js +0 -0
- /package/dist/preview/.next/static/{v9TlUn5liPNhAPJYeB3QH → ti02qYR7TtWD2j2orEzoT}/_ssgManifest.js +0 -0
package/dist/cli/index.mjs
CHANGED
|
@@ -6,7 +6,8 @@ import { program } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@envin/cli",
|
|
9
|
-
version: "
|
|
9
|
+
version: "1.1.1",
|
|
10
|
+
description: "Type-safe env validation with live previews",
|
|
10
11
|
keywords: [
|
|
11
12
|
"turbostarter",
|
|
12
13
|
"environment variables",
|
|
@@ -15,6 +16,10 @@ var package_default = {
|
|
|
15
16
|
"arktype",
|
|
16
17
|
"valibot"
|
|
17
18
|
],
|
|
19
|
+
homepage: "https://envin.turbostarter.dev",
|
|
20
|
+
bugs: {
|
|
21
|
+
url: "https://github.com/turbostarter/envin/issues"
|
|
22
|
+
},
|
|
18
23
|
repository: {
|
|
19
24
|
type: "git",
|
|
20
25
|
url: "git+https://github.com/turbostarter/envin.git",
|
|
@@ -32,7 +37,8 @@ var package_default = {
|
|
|
32
37
|
dev: "tsup-node --watch",
|
|
33
38
|
"dev:preview": "cd ../../apps/example && tsx ../../packages/cli/src/cli/index.ts dev",
|
|
34
39
|
start: "node dist/cli/index.mjs",
|
|
35
|
-
typecheck: "tsc --noEmit"
|
|
40
|
+
typecheck: "tsc --noEmit",
|
|
41
|
+
prepack: "bun ../../scripts/replace-workspace-protocol.ts && bun ../../scripts/populate-readme.ts"
|
|
36
42
|
},
|
|
37
43
|
dependencies: {
|
|
38
44
|
"@babel/parser": "^7.27.0",
|
|
@@ -47,16 +53,21 @@ var package_default = {
|
|
|
47
53
|
"@radix-ui/react-tooltip": "^1.2.4",
|
|
48
54
|
"@svgr/webpack": "^8.1.0",
|
|
49
55
|
chalk: "^5.4.1",
|
|
56
|
+
chokidar: "^4.0.3",
|
|
50
57
|
commander: "^13.1.0",
|
|
58
|
+
debounce: "^2.2.0",
|
|
51
59
|
dotenv: "^16.5.0",
|
|
52
60
|
envin: "workspace:*",
|
|
53
61
|
esbuild: "^0.25.0",
|
|
54
62
|
"log-symbols": "^7.0.0",
|
|
55
63
|
"mime-types": "^3.0.1",
|
|
56
|
-
next: "^15.3.
|
|
64
|
+
next: "^15.3.3",
|
|
57
65
|
ora: "^8.2.0",
|
|
58
66
|
"react-hook-form": "^7.56.4",
|
|
59
|
-
|
|
67
|
+
"socket.io": "^4.8.1",
|
|
68
|
+
"socket.io-client": "^4.8.1",
|
|
69
|
+
"tsconfig-paths": "^4.2.0",
|
|
70
|
+
zod: "^3.25.56"
|
|
60
71
|
},
|
|
61
72
|
devDependencies: {
|
|
62
73
|
"@babel/core": "7.26.10",
|
|
@@ -90,45 +101,17 @@ var package_default = {
|
|
|
90
101
|
};
|
|
91
102
|
|
|
92
103
|
// src/cli/commands/dev.ts
|
|
93
|
-
import
|
|
104
|
+
import fs3 from "fs";
|
|
94
105
|
|
|
95
|
-
// src/cli/utils/
|
|
96
|
-
import
|
|
97
|
-
import
|
|
98
|
-
import
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (!fileAbsolutePath.startsWith(staticBaseDir)) {
|
|
105
|
-
res.statusCode = 403;
|
|
106
|
-
res.end();
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
try {
|
|
110
|
-
const fileHandle = await fs.open(fileAbsolutePath, "r");
|
|
111
|
-
const fileData = await fs.readFile(fileHandle);
|
|
112
|
-
res.setHeader("Content-type", lookup(ext) || "text/plain");
|
|
113
|
-
res.end(fileData);
|
|
114
|
-
fileHandle.close();
|
|
115
|
-
} catch (exception) {
|
|
116
|
-
if (!existsSync(fileAbsolutePath)) {
|
|
117
|
-
res.statusCode = 404;
|
|
118
|
-
res.end();
|
|
119
|
-
} else {
|
|
120
|
-
const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
|
|
121
|
-
console.error(
|
|
122
|
-
`Could not read file at ${sanitizedFilePath} to be served, here's the exception:`,
|
|
123
|
-
exception
|
|
124
|
-
);
|
|
125
|
-
res.statusCode = 500;
|
|
126
|
-
res.end(
|
|
127
|
-
"Could not read file to be served! Check your terminal for more information."
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
};
|
|
106
|
+
// src/cli/utils/hot-reload/setup-hot-reloading.ts
|
|
107
|
+
import path6 from "path";
|
|
108
|
+
import { watch } from "chokidar";
|
|
109
|
+
import debounce from "debounce";
|
|
110
|
+
import { Server as SocketServer } from "socket.io";
|
|
111
|
+
|
|
112
|
+
// src/cli/utils/hot-reload/create-dependency-graph.ts
|
|
113
|
+
import { existsSync as existsSync2, promises as fs2, statSync } from "fs";
|
|
114
|
+
import path5 from "path";
|
|
132
115
|
|
|
133
116
|
// src/cli/utils/preview/start-dev-server.ts
|
|
134
117
|
import http from "http";
|
|
@@ -165,16 +148,54 @@ var registerSpinnerAutostopping = (spinner) => {
|
|
|
165
148
|
};
|
|
166
149
|
|
|
167
150
|
// src/cli/utils/preview/get-env-variables.ts
|
|
168
|
-
import
|
|
151
|
+
import path from "path";
|
|
169
152
|
var getEnvVariablesForPreviewApp = (relativePathToEnvDirectory, cwd) => {
|
|
170
153
|
return {
|
|
171
154
|
ENV_DIR_RELATIVE_PATH: relativePathToEnvDirectory,
|
|
172
|
-
ENV_DIR_ABSOLUTE_PATH:
|
|
155
|
+
ENV_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEnvDirectory),
|
|
173
156
|
USER_PROJECT_LOCATION: cwd,
|
|
174
157
|
NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
|
|
175
158
|
};
|
|
176
159
|
};
|
|
177
160
|
|
|
161
|
+
// src/cli/utils/preview/serve-static-file.ts
|
|
162
|
+
import { existsSync, promises as fs } from "fs";
|
|
163
|
+
import path2 from "path";
|
|
164
|
+
import { lookup } from "mime-types";
|
|
165
|
+
var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
|
|
166
|
+
const pathname = parsedUrl.pathname?.replace("/static", "./static") ?? "";
|
|
167
|
+
const ext = path2.parse(pathname).ext;
|
|
168
|
+
const staticBaseDir = path2.resolve(process.cwd(), staticDirRelativePath);
|
|
169
|
+
const fileAbsolutePath = path2.resolve(staticBaseDir, pathname);
|
|
170
|
+
if (!fileAbsolutePath.startsWith(staticBaseDir)) {
|
|
171
|
+
res.statusCode = 403;
|
|
172
|
+
res.end();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const fileHandle = await fs.open(fileAbsolutePath, "r");
|
|
177
|
+
const fileData = await fs.readFile(fileHandle);
|
|
178
|
+
res.setHeader("Content-type", lookup(ext) || "text/plain");
|
|
179
|
+
res.end(fileData);
|
|
180
|
+
fileHandle.close();
|
|
181
|
+
} catch (exception) {
|
|
182
|
+
if (!existsSync(fileAbsolutePath)) {
|
|
183
|
+
res.statusCode = 404;
|
|
184
|
+
res.end();
|
|
185
|
+
} else {
|
|
186
|
+
const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
|
|
187
|
+
console.error(
|
|
188
|
+
`Could not read file at ${sanitizedFilePath} to be served, here's the exception:`,
|
|
189
|
+
exception
|
|
190
|
+
);
|
|
191
|
+
res.statusCode = 500;
|
|
192
|
+
res.end(
|
|
193
|
+
"Could not read file to be served! Check your terminal for more information."
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
178
199
|
// src/cli/utils/preview/start-dev-server.ts
|
|
179
200
|
var devServer;
|
|
180
201
|
var safeAsyncServerListen = (server, port) => {
|
|
@@ -194,7 +215,7 @@ var dirname = path3.dirname(filename);
|
|
|
194
215
|
var isDev = !filename.endsWith(path3.join("cli", "index.mjs"));
|
|
195
216
|
var cliPackageLocation = isDev ? path3.resolve(dirname, "../../../..") : path3.resolve(dirname, "../..");
|
|
196
217
|
var previewServerLocation = isDev ? path3.resolve(dirname, "../../../..") : path3.resolve(dirname, "../preview");
|
|
197
|
-
var startDevServer = async (
|
|
218
|
+
var startDevServer = async (envDirRelativePath, staticBaseDirRelativePath, port) => {
|
|
198
219
|
devServer = http.createServer((req, res) => {
|
|
199
220
|
if (!req.url) {
|
|
200
221
|
res.end(404);
|
|
@@ -234,7 +255,7 @@ var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, po
|
|
|
234
255
|
` ${logSymbols2.warning} Port ${port} is already in use, trying ${nextPortToTry}`
|
|
235
256
|
);
|
|
236
257
|
return startDevServer(
|
|
237
|
-
|
|
258
|
+
envDirRelativePath,
|
|
238
259
|
staticBaseDirRelativePath,
|
|
239
260
|
nextPortToTry
|
|
240
261
|
);
|
|
@@ -259,7 +280,7 @@ var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, po
|
|
|
259
280
|
NODE_ENV: "development",
|
|
260
281
|
...process.env,
|
|
261
282
|
...getEnvVariablesForPreviewApp(
|
|
262
|
-
path3.normalize(
|
|
283
|
+
path3.normalize(envDirRelativePath),
|
|
263
284
|
process.cwd()
|
|
264
285
|
)
|
|
265
286
|
};
|
|
@@ -317,19 +338,403 @@ process.on(
|
|
|
317
338
|
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
|
|
318
339
|
);
|
|
319
340
|
|
|
341
|
+
// src/cli/utils/hot-reload/get-imported-modules.ts
|
|
342
|
+
import { parse } from "@babel/parser";
|
|
343
|
+
import traverseModule from "@babel/traverse";
|
|
344
|
+
var traverse = (
|
|
345
|
+
// we keep this check here so that this still works with the dev:preview
|
|
346
|
+
// script's use of tsx
|
|
347
|
+
typeof traverseModule === "function" ? traverseModule : (
|
|
348
|
+
// @ts-expect-error - this is a valid use case
|
|
349
|
+
traverseModule.default
|
|
350
|
+
)
|
|
351
|
+
);
|
|
352
|
+
var getImportedModules = (contents) => {
|
|
353
|
+
const importedPaths = [];
|
|
354
|
+
const parsedContents = parse(contents, {
|
|
355
|
+
sourceType: "unambiguous",
|
|
356
|
+
strictMode: false,
|
|
357
|
+
errorRecovery: true,
|
|
358
|
+
plugins: ["jsx", "typescript", "decorators"]
|
|
359
|
+
});
|
|
360
|
+
traverse(parsedContents, {
|
|
361
|
+
ImportDeclaration({ node }) {
|
|
362
|
+
importedPaths.push(node.source.value);
|
|
363
|
+
},
|
|
364
|
+
ExportAllDeclaration({ node }) {
|
|
365
|
+
importedPaths.push(node.source.value);
|
|
366
|
+
},
|
|
367
|
+
ExportNamedDeclaration({ node }) {
|
|
368
|
+
if (node.source) {
|
|
369
|
+
importedPaths.push(node.source.value);
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
TSExternalModuleReference({ node }) {
|
|
373
|
+
importedPaths.push(node.expression.value);
|
|
374
|
+
},
|
|
375
|
+
CallExpression({ node }) {
|
|
376
|
+
if ("name" in node.callee && node.callee.name === "require") {
|
|
377
|
+
if (node.arguments.length === 1) {
|
|
378
|
+
const importPathNode = node.arguments[0];
|
|
379
|
+
if (importPathNode?.type === "StringLiteral") {
|
|
380
|
+
importedPaths.push(importPathNode.value);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
return importedPaths;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// src/cli/utils/hot-reload/resolve-path-aliases.ts
|
|
390
|
+
import path4 from "path";
|
|
391
|
+
import { createMatchPath, loadConfig } from "tsconfig-paths";
|
|
392
|
+
var resolvePathAliases = (importPaths, projectPath) => {
|
|
393
|
+
const configLoadResult = loadConfig(projectPath);
|
|
394
|
+
if (configLoadResult.resultType === "success") {
|
|
395
|
+
const matchPath = createMatchPath(
|
|
396
|
+
configLoadResult.absoluteBaseUrl,
|
|
397
|
+
configLoadResult.paths
|
|
398
|
+
);
|
|
399
|
+
return importPaths.map((importedPath) => {
|
|
400
|
+
const unaliasedPath = matchPath(importedPath, void 0, void 0, [
|
|
401
|
+
".tsx",
|
|
402
|
+
".ts",
|
|
403
|
+
".js",
|
|
404
|
+
".jsx",
|
|
405
|
+
".cjs",
|
|
406
|
+
".mjs"
|
|
407
|
+
]);
|
|
408
|
+
if (unaliasedPath) {
|
|
409
|
+
return `./${path4.relative(projectPath, unaliasedPath)}`;
|
|
410
|
+
}
|
|
411
|
+
return importedPath;
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
return importPaths;
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// src/cli/utils/hot-reload/create-dependency-graph.ts
|
|
418
|
+
var readAllFilesInsideDirectory = async (directory) => {
|
|
419
|
+
let allFilePaths = [];
|
|
420
|
+
const topLevelDirents = await fs2.readdir(directory, { withFileTypes: true });
|
|
421
|
+
for await (const dirent of topLevelDirents) {
|
|
422
|
+
const pathToDirent = path5.join(directory, dirent.name);
|
|
423
|
+
if (dirent.isDirectory()) {
|
|
424
|
+
allFilePaths = allFilePaths.concat(
|
|
425
|
+
await readAllFilesInsideDirectory(pathToDirent)
|
|
426
|
+
);
|
|
427
|
+
} else {
|
|
428
|
+
allFilePaths.push(pathToDirent);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return allFilePaths;
|
|
432
|
+
};
|
|
433
|
+
var isJavascriptModule = (filePath) => {
|
|
434
|
+
const extensionName = path5.extname(filePath);
|
|
435
|
+
return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
|
|
436
|
+
};
|
|
437
|
+
var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
|
|
438
|
+
if (existsSync2(`${pathWithoutExtension}.ts`)) {
|
|
439
|
+
return `${pathWithoutExtension}.ts`;
|
|
440
|
+
}
|
|
441
|
+
if (existsSync2(`${pathWithoutExtension}.tsx`)) {
|
|
442
|
+
return `${pathWithoutExtension}.tsx`;
|
|
443
|
+
}
|
|
444
|
+
if (existsSync2(`${pathWithoutExtension}.js`)) {
|
|
445
|
+
return `${pathWithoutExtension}.js`;
|
|
446
|
+
}
|
|
447
|
+
if (existsSync2(`${pathWithoutExtension}.jsx`)) {
|
|
448
|
+
return `${pathWithoutExtension}.jsx`;
|
|
449
|
+
}
|
|
450
|
+
if (existsSync2(`${pathWithoutExtension}.mjs`)) {
|
|
451
|
+
return `${pathWithoutExtension}.mjs`;
|
|
452
|
+
}
|
|
453
|
+
if (existsSync2(`${pathWithoutExtension}.cjs`)) {
|
|
454
|
+
return `${pathWithoutExtension}.cjs`;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
var createDependencyGraph = async (directory) => {
|
|
458
|
+
const filePaths = await readAllFilesInsideDirectory(directory);
|
|
459
|
+
const modulePaths = filePaths.filter(isJavascriptModule);
|
|
460
|
+
const graph = Object.fromEntries(
|
|
461
|
+
modulePaths.map((path7) => [
|
|
462
|
+
path7,
|
|
463
|
+
{
|
|
464
|
+
path: path7,
|
|
465
|
+
dependencyPaths: [],
|
|
466
|
+
dependentPaths: [],
|
|
467
|
+
moduleDependencies: []
|
|
468
|
+
}
|
|
469
|
+
])
|
|
470
|
+
);
|
|
471
|
+
const getDependencyPaths = async (filePath) => {
|
|
472
|
+
const contents = await fs2.readFile(filePath, "utf8");
|
|
473
|
+
const importedPaths = isJavascriptModule(filePath) ? resolvePathAliases(getImportedModules(contents), path5.dirname(filePath)) : [];
|
|
474
|
+
const importedPathsRelativeToDirectory = importedPaths.map(
|
|
475
|
+
(dependencyPath) => {
|
|
476
|
+
const isModulePath = !dependencyPath.startsWith(".");
|
|
477
|
+
if (isModulePath || path5.isAbsolute(dependencyPath)) {
|
|
478
|
+
return dependencyPath;
|
|
479
|
+
}
|
|
480
|
+
let pathToDependencyFromDirectory = path5.resolve(
|
|
481
|
+
/*
|
|
482
|
+
path.resolve resolves paths differently from what imports on javascript do.
|
|
483
|
+
|
|
484
|
+
So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependency path of "./other-email"
|
|
485
|
+
would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
|
|
486
|
+
one the import is meant to go to
|
|
487
|
+
*/
|
|
488
|
+
path5.dirname(filePath),
|
|
489
|
+
dependencyPath
|
|
490
|
+
);
|
|
491
|
+
let isDirectory = false;
|
|
492
|
+
try {
|
|
493
|
+
isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
|
|
494
|
+
} catch (_) {
|
|
495
|
+
}
|
|
496
|
+
if (isDirectory) {
|
|
497
|
+
const pathToSubDirectory = pathToDependencyFromDirectory;
|
|
498
|
+
const pathWithExtension = checkFileExtensionsUntilItExists(
|
|
499
|
+
`${pathToSubDirectory}/index`
|
|
500
|
+
);
|
|
501
|
+
if (pathWithExtension) {
|
|
502
|
+
pathToDependencyFromDirectory = pathWithExtension;
|
|
503
|
+
} else if (isDev) {
|
|
504
|
+
console.warn(
|
|
505
|
+
`Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const extension = path5.extname(pathToDependencyFromDirectory);
|
|
510
|
+
const pathWithEnsuredExtension = (() => {
|
|
511
|
+
if (extension.length > 0 && existsSync2(pathToDependencyFromDirectory)) {
|
|
512
|
+
return pathToDependencyFromDirectory;
|
|
513
|
+
}
|
|
514
|
+
return checkFileExtensionsUntilItExists(
|
|
515
|
+
pathToDependencyFromDirectory.replace(extension, "")
|
|
516
|
+
);
|
|
517
|
+
})();
|
|
518
|
+
if (pathWithEnsuredExtension) {
|
|
519
|
+
pathToDependencyFromDirectory = pathWithEnsuredExtension;
|
|
520
|
+
} else if (isDev) {
|
|
521
|
+
console.warn(
|
|
522
|
+
`Could not find file at ${pathToDependencyFromDirectory}`
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
return pathToDependencyFromDirectory;
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
const moduleDependencies = importedPathsRelativeToDirectory.filter(
|
|
529
|
+
(dependencyPath) => !dependencyPath.startsWith(".") && !path5.isAbsolute(dependencyPath)
|
|
530
|
+
);
|
|
531
|
+
const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
|
|
532
|
+
(dependencyPath) => dependencyPath.startsWith(".") || path5.isAbsolute(dependencyPath)
|
|
533
|
+
);
|
|
534
|
+
return {
|
|
535
|
+
dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
|
|
536
|
+
moduleDependencies
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
const updateModuleDependenciesInGraph = async (moduleFilePath) => {
|
|
540
|
+
if (graph[moduleFilePath] === void 0) {
|
|
541
|
+
graph[moduleFilePath] = {
|
|
542
|
+
path: moduleFilePath,
|
|
543
|
+
dependencyPaths: [],
|
|
544
|
+
dependentPaths: [],
|
|
545
|
+
moduleDependencies: []
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
|
|
549
|
+
graph[moduleFilePath].moduleDependencies = moduleDependencies;
|
|
550
|
+
for (const dependencyPath of graph[moduleFilePath].dependencyPaths) {
|
|
551
|
+
if (newDependencyPaths.includes(dependencyPath)) continue;
|
|
552
|
+
const dependencyModule = graph[dependencyPath];
|
|
553
|
+
if (dependencyModule !== void 0) {
|
|
554
|
+
dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter(
|
|
555
|
+
(dependentPath) => dependentPath !== moduleFilePath
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
graph[moduleFilePath].dependencyPaths = newDependencyPaths;
|
|
560
|
+
for await (const dependencyPath of newDependencyPaths) {
|
|
561
|
+
if (graph[dependencyPath] === void 0) {
|
|
562
|
+
await updateModuleDependenciesInGraph(dependencyPath);
|
|
563
|
+
}
|
|
564
|
+
const dependencyModule = graph[dependencyPath];
|
|
565
|
+
if (dependencyModule === void 0) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
`Loading the dependency path ${dependencyPath} did not initialize it at all. This is a bug in React Email.`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
if (!dependencyModule.dependentPaths.includes(moduleFilePath)) {
|
|
571
|
+
dependencyModule.dependentPaths.push(moduleFilePath);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
const removeModuleFromGraph = (filePath) => {
|
|
576
|
+
const module = graph[filePath];
|
|
577
|
+
if (module) {
|
|
578
|
+
for (const dependencyPath of module.dependencyPaths) {
|
|
579
|
+
if (graph[dependencyPath]) {
|
|
580
|
+
graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter(
|
|
581
|
+
(dependentPath) => dependentPath !== filePath
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
delete graph[filePath];
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
return [
|
|
589
|
+
graph,
|
|
590
|
+
async (event, pathToModified) => {
|
|
591
|
+
switch (event) {
|
|
592
|
+
case "change":
|
|
593
|
+
if (isJavascriptModule(pathToModified)) {
|
|
594
|
+
await updateModuleDependenciesInGraph(pathToModified);
|
|
595
|
+
}
|
|
596
|
+
break;
|
|
597
|
+
case "add":
|
|
598
|
+
if (isJavascriptModule(pathToModified)) {
|
|
599
|
+
await updateModuleDependenciesInGraph(pathToModified);
|
|
600
|
+
}
|
|
601
|
+
break;
|
|
602
|
+
case "addDir": {
|
|
603
|
+
const filesInsideAddedDirectory = await readAllFilesInsideDirectory(pathToModified);
|
|
604
|
+
const modulesInsideAddedDirectory = filesInsideAddedDirectory.filter(isJavascriptModule);
|
|
605
|
+
for await (const filePath of modulesInsideAddedDirectory) {
|
|
606
|
+
await updateModuleDependenciesInGraph(filePath);
|
|
607
|
+
}
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
case "unlink":
|
|
611
|
+
if (isJavascriptModule(pathToModified)) {
|
|
612
|
+
removeModuleFromGraph(pathToModified);
|
|
613
|
+
}
|
|
614
|
+
break;
|
|
615
|
+
case "unlinkDir": {
|
|
616
|
+
const filesInsideDeletedDirectory = await readAllFilesInsideDirectory(pathToModified);
|
|
617
|
+
const modulesInsideDeletedDirectory = filesInsideDeletedDirectory.filter(isJavascriptModule);
|
|
618
|
+
for await (const filePath of modulesInsideDeletedDirectory) {
|
|
619
|
+
removeModuleFromGraph(filePath);
|
|
620
|
+
}
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
resolveDependentsOf: function resolveDependentsOf(pathToModule) {
|
|
627
|
+
const moduleEntry = graph[pathToModule];
|
|
628
|
+
const dependentPaths = [];
|
|
629
|
+
if (moduleEntry) {
|
|
630
|
+
for (const dependentPath of moduleEntry.dependentPaths) {
|
|
631
|
+
const dependentsOfDependent = resolveDependentsOf(dependentPath);
|
|
632
|
+
dependentPaths.push(...dependentsOfDependent);
|
|
633
|
+
dependentPaths.push(dependentPath);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return dependentPaths;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
];
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
// src/cli/utils/hot-reload/setup-hot-reloading.ts
|
|
643
|
+
var setupHotreloading = async (devServer2, envDirRelativePath) => {
|
|
644
|
+
let clients = [];
|
|
645
|
+
const io = new SocketServer(devServer2);
|
|
646
|
+
io.on("connection", (client) => {
|
|
647
|
+
clients.push(client);
|
|
648
|
+
client.on("disconnect", () => {
|
|
649
|
+
clients = clients.filter((item) => item !== client);
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
let changes = [];
|
|
653
|
+
const reload = debounce(() => {
|
|
654
|
+
clients.forEach((client) => {
|
|
655
|
+
client.emit(
|
|
656
|
+
"reload",
|
|
657
|
+
changes.filter(
|
|
658
|
+
(change) => (
|
|
659
|
+
// Ensures only changes inside the emails directory are emitted
|
|
660
|
+
path6.resolve(absolutePathToEnvDirectory, change.filename).startsWith(absolutePathToEnvDirectory)
|
|
661
|
+
)
|
|
662
|
+
)
|
|
663
|
+
);
|
|
664
|
+
});
|
|
665
|
+
changes = [];
|
|
666
|
+
}, 150);
|
|
667
|
+
const absolutePathToEnvDirectory = path6.resolve(
|
|
668
|
+
process.cwd(),
|
|
669
|
+
envDirRelativePath
|
|
670
|
+
);
|
|
671
|
+
const [dependencyGraph, updateDependencyGraph, { resolveDependentsOf }] = await createDependencyGraph(absolutePathToEnvDirectory);
|
|
672
|
+
const watcher = watch("", {
|
|
673
|
+
ignoreInitial: true,
|
|
674
|
+
cwd: absolutePathToEnvDirectory
|
|
675
|
+
});
|
|
676
|
+
const getFilesOutsideEnvDirectory = () => Object.keys(dependencyGraph).filter(
|
|
677
|
+
(p) => path6.relative(absolutePathToEnvDirectory, p).startsWith("..")
|
|
678
|
+
);
|
|
679
|
+
let filesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
|
|
680
|
+
for (const p of filesOutsideEnvDirectory) {
|
|
681
|
+
watcher.add(p);
|
|
682
|
+
}
|
|
683
|
+
const exit = async () => {
|
|
684
|
+
await watcher.close();
|
|
685
|
+
};
|
|
686
|
+
process.on("SIGINT", exit);
|
|
687
|
+
process.on("uncaughtException", exit);
|
|
688
|
+
watcher.on("all", async (event, relativePathToChangeTarget) => {
|
|
689
|
+
const file = relativePathToChangeTarget.split(path6.sep);
|
|
690
|
+
if (file.length === 0) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const pathToChangeTarget = path6.resolve(
|
|
694
|
+
absolutePathToEnvDirectory,
|
|
695
|
+
relativePathToChangeTarget
|
|
696
|
+
);
|
|
697
|
+
await updateDependencyGraph(event, pathToChangeTarget);
|
|
698
|
+
const newFilesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
|
|
699
|
+
for (const p of filesOutsideEnvDirectory) {
|
|
700
|
+
if (!newFilesOutsideEnvDirectory.includes(p)) {
|
|
701
|
+
watcher.unwatch(p);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
for (const p of newFilesOutsideEnvDirectory) {
|
|
705
|
+
if (!filesOutsideEnvDirectory.includes(p)) {
|
|
706
|
+
watcher.add(p);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
filesOutsideEnvDirectory = newFilesOutsideEnvDirectory;
|
|
710
|
+
changes.push({
|
|
711
|
+
event,
|
|
712
|
+
filename: relativePathToChangeTarget
|
|
713
|
+
});
|
|
714
|
+
for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
|
|
715
|
+
changes.push({
|
|
716
|
+
event: "change",
|
|
717
|
+
filename: path6.relative(absolutePathToEnvDirectory, dependentPath)
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
reload();
|
|
721
|
+
});
|
|
722
|
+
return watcher;
|
|
723
|
+
};
|
|
724
|
+
|
|
320
725
|
// src/cli/commands/dev.ts
|
|
321
|
-
var dev = async ({ dir:
|
|
726
|
+
var dev = async ({ dir: envDirRelativePath, port }) => {
|
|
322
727
|
try {
|
|
323
|
-
if (!
|
|
324
|
-
console.error(`Missing ${
|
|
728
|
+
if (!fs3.existsSync(envDirRelativePath)) {
|
|
729
|
+
console.error(`Missing ${envDirRelativePath} folder`);
|
|
325
730
|
process.exit(1);
|
|
326
731
|
}
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
// defaults to ./emails/static for the static files that are served to the preview
|
|
732
|
+
const devServer2 = await startDevServer(
|
|
733
|
+
envDirRelativePath,
|
|
734
|
+
envDirRelativePath,
|
|
331
735
|
Number.parseInt(port)
|
|
332
736
|
);
|
|
737
|
+
await setupHotreloading(devServer2, envDirRelativePath);
|
|
333
738
|
} catch (error) {
|
|
334
739
|
console.log(error);
|
|
335
740
|
process.exit(1);
|
|
@@ -341,5 +746,9 @@ var PACKAGE_NAME = "@envin/cli";
|
|
|
341
746
|
program.name(PACKAGE_NAME).description(
|
|
342
747
|
"A live preview of your environment variables right in your browser"
|
|
343
748
|
).version(package_default.version);
|
|
344
|
-
program.command("dev").description("Starts the live preview of your environment variables").option(
|
|
749
|
+
program.command("dev").description("Starts the live preview of your environment variables").option(
|
|
750
|
+
"-d, --dir <path>",
|
|
751
|
+
"Directory with your envin configuration and .env files",
|
|
752
|
+
"./"
|
|
753
|
+
).option("-p --port <port>", "Port to run dev server on", "3000").action(dev);
|
|
345
754
|
program.parse();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
ti02qYR7TtWD2j2orEzoT
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"pages": {
|
|
3
3
|
"/_not-found/page": [
|
|
4
|
-
"static/chunks/webpack-
|
|
4
|
+
"static/chunks/webpack-464ea5083b838c17.js",
|
|
5
5
|
"static/chunks/87c73c54-a773d57d245aca41.js",
|
|
6
6
|
"static/chunks/315-850927f416f0524a.js",
|
|
7
7
|
"static/chunks/main-app-fd962d6f95339794.js",
|
|
8
8
|
"static/chunks/app/_not-found/page-60c07ed561e86dd9.js"
|
|
9
9
|
],
|
|
10
10
|
"/layout": [
|
|
11
|
-
"static/chunks/webpack-
|
|
11
|
+
"static/chunks/webpack-464ea5083b838c17.js",
|
|
12
12
|
"static/chunks/87c73c54-a773d57d245aca41.js",
|
|
13
13
|
"static/chunks/315-850927f416f0524a.js",
|
|
14
14
|
"static/chunks/main-app-fd962d6f95339794.js",
|
|
15
|
-
"static/css/
|
|
15
|
+
"static/css/8b2927e38b2520cf.css",
|
|
16
16
|
"static/chunks/app/layout-199c3536e64e10fd.js"
|
|
17
17
|
],
|
|
18
18
|
"/page": [
|
|
19
|
-
"static/chunks/webpack-
|
|
19
|
+
"static/chunks/webpack-464ea5083b838c17.js",
|
|
20
20
|
"static/chunks/87c73c54-a773d57d245aca41.js",
|
|
21
21
|
"static/chunks/315-850927f416f0524a.js",
|
|
22
22
|
"static/chunks/main-app-fd962d6f95339794.js",
|
|
23
|
-
"static/chunks/
|
|
24
|
-
"static/chunks/app/page-
|
|
23
|
+
"static/chunks/985-f32f025f8cdc74d3.js",
|
|
24
|
+
"static/chunks/app/page-781d5c4076d3b10d.js"
|
|
25
25
|
]
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
"devFiles": [],
|
|
6
6
|
"ampDevFiles": [],
|
|
7
7
|
"lowPriorityFiles": [
|
|
8
|
-
"static/
|
|
9
|
-
"static/
|
|
8
|
+
"static/ti02qYR7TtWD2j2orEzoT/_buildManifest.js",
|
|
9
|
+
"static/ti02qYR7TtWD2j2orEzoT/_ssgManifest.js"
|
|
10
10
|
],
|
|
11
11
|
"rootMainFiles": [
|
|
12
|
-
"static/chunks/webpack-
|
|
12
|
+
"static/chunks/webpack-464ea5083b838c17.js",
|
|
13
13
|
"static/chunks/87c73c54-a773d57d245aca41.js",
|
|
14
14
|
"static/chunks/315-850927f416f0524a.js",
|
|
15
15
|
"static/chunks/main-app-fd962d6f95339794.js"
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
"rootMainFilesTree": {},
|
|
18
18
|
"pages": {
|
|
19
19
|
"/_app": [
|
|
20
|
-
"static/chunks/webpack-
|
|
20
|
+
"static/chunks/webpack-464ea5083b838c17.js",
|
|
21
21
|
"static/chunks/framework-82b0332477a76245.js",
|
|
22
22
|
"static/chunks/main-c9e901861bf9798e.js",
|
|
23
23
|
"static/chunks/pages/_app-a48f070af90c9683.js"
|
|
24
24
|
],
|
|
25
25
|
"/_error": [
|
|
26
|
-
"static/chunks/webpack-
|
|
26
|
+
"static/chunks/webpack-464ea5083b838c17.js",
|
|
27
27
|
"static/chunks/framework-82b0332477a76245.js",
|
|
28
28
|
"static/chunks/main-c9e901861bf9798e.js",
|
|
29
29
|
"static/chunks/pages/_error-b8c2e08355edc3b4.js"
|