@webtypen/webframez-core 0.3.93 → 0.3.95
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/README.md +27 -0
- package/dist/BuildApplication.d.ts +7 -0
- package/dist/BuildApplication.js +70 -29
- package/dist/BuildCompiler.d.ts +1 -0
- package/dist/BuildCompiler.js +70 -0
- package/dist/BuildDependencies.d.ts +2 -0
- package/dist/BuildDependencies.js +89 -0
- package/dist/Cli.js +42 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -997,3 +997,30 @@ Metro consumers can call
|
|
|
997
997
|
It applies `WEBFRAMEZ_BUILD_MAX_WORKERS` and `WEBFRAMEZ_METRO_CACHE_DIRECTORY`,
|
|
998
998
|
preserving Expo's FileStore implementation and supporting old/new file-map option
|
|
999
999
|
names. Do not pass Expo `--clear` on normal cached builds.
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
### Reusable build workspaces
|
|
1003
|
+
|
|
1004
|
+
`webframez compile --project tsconfig.json --dir build` compiles TypeScript without loading
|
|
1005
|
+
application configuration, console services or build plugins. It preserves incremental
|
|
1006
|
+
compiler output under `WEBFRAMEZ_BUILD_CACHE_DIRECTORY` (default `.webframez-cache`),
|
|
1007
|
+
invalidates deleted/renamed source files and promotes a successful output atomically.
|
|
1008
|
+
A failed compilation leaves the previous build intact. Include the compiler cache in
|
|
1009
|
+
persistent CI storage; remove it for a force-clear build.
|
|
1010
|
+
|
|
1011
|
+
`webframez dependencies --dir build` prepares an independent, frozen production pnpm
|
|
1012
|
+
installation, then copies its dependencies into `build/node_modules`. Development
|
|
1013
|
+
modules remain untouched. A pinned pnpm version and an independent lockfile are
|
|
1014
|
+
required; monorepos should use `pnpm deploy`. Registry settings are read from
|
|
1015
|
+
`NPM_CONFIG_USERCONFIG` or the source `.npmrc`, never copied into the artifact.
|
|
1016
|
+
Dependency install scripts follow the package's pnpm policy; `--ignore-scripts` disables
|
|
1017
|
+
them. Root lifecycle scripts are excluded from the separate production installation.
|
|
1018
|
+
|
|
1019
|
+
Full `webframez build` supports `build.productionDependencies: true` and
|
|
1020
|
+
`build.dependencyInstallScripts: false` for the same behavior. Runtime-required packages
|
|
1021
|
+
must be declared under dependencies, including browser or compiler packages.
|
|
1022
|
+
|
|
1023
|
+
Asset builds use a stable staging directory so bundler caches can reuse module paths.
|
|
1024
|
+
An exclusive per-output lock prevents concurrent builds overwriting that directory.
|
|
1025
|
+
After a killed local build, remove its `.webframez-build/.building-*.lock` directory
|
|
1026
|
+
only after confirming that no previous build is running. WSM Force Clear removes it.
|
|
@@ -22,6 +22,8 @@ export type WebframezBuildConfig = {
|
|
|
22
22
|
dir?: string;
|
|
23
23
|
tsconfig?: string;
|
|
24
24
|
cacheDirectory?: string;
|
|
25
|
+
productionDependencies?: boolean;
|
|
26
|
+
dependencyInstallScripts?: boolean;
|
|
25
27
|
entry?: string;
|
|
26
28
|
runtimeFiles?: WebframezBuildRuntimeFile[];
|
|
27
29
|
prunePaths?: string[];
|
|
@@ -54,7 +56,12 @@ export declare class BuildApplication {
|
|
|
54
56
|
private readonly stagingDir;
|
|
55
57
|
private readonly buildId;
|
|
56
58
|
constructor(projectRoot: string, config: WebframezAppConfig, options: BuildApplicationOptions);
|
|
59
|
+
/** Compile without booting application configuration or running asset/runtime plugins. */
|
|
60
|
+
compile(): Promise<void>;
|
|
61
|
+
private withBuildLock;
|
|
62
|
+
private compileOnly;
|
|
57
63
|
run(): Promise<void>;
|
|
64
|
+
private execute;
|
|
58
65
|
private logBuildStep;
|
|
59
66
|
private runStep;
|
|
60
67
|
private createContext;
|
package/dist/BuildApplication.js
CHANGED
|
@@ -19,6 +19,7 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
19
19
|
const node_child_process_1 = require("node:child_process");
|
|
20
20
|
const node_util_1 = require("node:util");
|
|
21
21
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
22
|
+
const BuildDependencies_1 = require("./BuildDependencies");
|
|
22
23
|
const exec = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
23
24
|
function timestamp() {
|
|
24
25
|
return new Date().toISOString().replace(/[-:TZ.]/g, "");
|
|
@@ -52,9 +53,55 @@ class BuildApplication {
|
|
|
52
53
|
this.outDir = node_path_1.default.resolve(projectRoot, options.outDir || ((_a = config.build) === null || _a === void 0 ? void 0 : _a.dir) || "build");
|
|
53
54
|
this.buildId = timestamp();
|
|
54
55
|
this.buildRoot = node_path_1.default.resolve(projectRoot, ".webframez-build");
|
|
55
|
-
this.stagingDir = node_path_1.default.join(this.buildRoot, `.building-${this.
|
|
56
|
+
this.stagingDir = node_path_1.default.join(this.buildRoot, `.building-${node_crypto_1.default.createHash("sha256").update(this.outDir).digest("hex").slice(0, 24)}`);
|
|
57
|
+
}
|
|
58
|
+
/** Compile without booting application configuration or running asset/runtime plugins. */
|
|
59
|
+
compile() {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
return this.withBuildLock(() => this.compileOnly());
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
withBuildLock(callback) {
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
const lock = this.stagingDir + ".lock";
|
|
67
|
+
yield promises_1.default.mkdir(this.buildRoot, { recursive: true });
|
|
68
|
+
try {
|
|
69
|
+
yield promises_1.default.mkdir(lock);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error.code === "EEXIST")
|
|
73
|
+
throw new Error(`Build output is locked: ${lock}. Remove the lock only after the previous build has stopped.`);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return yield callback();
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
yield promises_1.default.rm(lock, { recursive: true, force: true });
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
compileOnly() {
|
|
85
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
const context = this.createContext();
|
|
87
|
+
yield promises_1.default.rm(this.stagingDir, { recursive: true, force: true });
|
|
88
|
+
yield promises_1.default.mkdir(this.stagingDir, { recursive: true });
|
|
89
|
+
try {
|
|
90
|
+
yield this.runStep("typescript", () => this.runTypescriptBuild(context));
|
|
91
|
+
yield this.promoteBuild();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
yield promises_1.default.rm(this.stagingDir, { recursive: true, force: true });
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
56
98
|
}
|
|
57
99
|
run() {
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
return this.withBuildLock(() => this.execute());
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
execute() {
|
|
58
105
|
return __awaiter(this, void 0, void 0, function* () {
|
|
59
106
|
const context = this.createContext();
|
|
60
107
|
const plugins = this.loadPlugins();
|
|
@@ -119,34 +166,24 @@ class BuildApplication {
|
|
|
119
166
|
}
|
|
120
167
|
});
|
|
121
168
|
}
|
|
122
|
-
runTypescriptBuild(
|
|
169
|
+
runTypescriptBuild(_context) {
|
|
123
170
|
var _a, _b;
|
|
124
171
|
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
yield promises_1.default.mkdir(output, { recursive: true });
|
|
141
|
-
try {
|
|
142
|
-
yield this.runOrFail(context, "tsc", ["-p", tsconfig, "--outDir", output, "--incremental", "--tsBuildInfoFile", node_path_1.default.join(cache, "build.tsbuildinfo")]);
|
|
143
|
-
yield this.copyTree(output, this.stagingDir);
|
|
144
|
-
yield promises_1.default.writeFile(node_path_1.default.join(cache, "key"), key);
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
yield promises_1.default.rm(cache, { recursive: true, force: true });
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
172
|
+
const options = {
|
|
173
|
+
projectRoot: this.projectRoot,
|
|
174
|
+
tsconfig: node_path_1.default.resolve(this.projectRoot, ((_a = this.config.build) === null || _a === void 0 ? void 0 : _a.tsconfig) || "tsconfig.json"),
|
|
175
|
+
outDir: this.outDir,
|
|
176
|
+
buildRoot: this.buildRoot,
|
|
177
|
+
root: node_path_1.default.resolve(this.projectRoot, ((_b = this.config.build) === null || _b === void 0 ? void 0 : _b.cacheDirectory) || process.env.WEBFRAMEZ_BUILD_CACHE_DIRECTORY || node_path_1.default.join(this.buildRoot, "cache")),
|
|
178
|
+
stagingDir: this.stagingDir,
|
|
179
|
+
};
|
|
180
|
+
yield new Promise((resolve, reject) => {
|
|
181
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [node_path_1.default.join(__dirname, "BuildCompiler.js"), JSON.stringify(options)], {
|
|
182
|
+
cwd: this.projectRoot, stdio: "inherit", env: process.env,
|
|
183
|
+
});
|
|
184
|
+
child.once("error", reject);
|
|
185
|
+
child.once("exit", (code, signal) => code === 0 ? resolve() : reject(new Error(`tsc exited with code ${code}${signal ? ` (${signal})` : ""}`)));
|
|
186
|
+
});
|
|
150
187
|
});
|
|
151
188
|
}
|
|
152
189
|
copyTree(source, target) {
|
|
@@ -162,7 +199,7 @@ class BuildApplication {
|
|
|
162
199
|
});
|
|
163
200
|
}
|
|
164
201
|
copyRuntimeFiles() {
|
|
165
|
-
var _a, _b;
|
|
202
|
+
var _a, _b, _c;
|
|
166
203
|
return __awaiter(this, void 0, void 0, function* () {
|
|
167
204
|
const runtimeFiles = ((_a = this.config.build) === null || _a === void 0 ? void 0 : _a.runtimeFiles) || [
|
|
168
205
|
{ from: ".env", optional: true },
|
|
@@ -181,6 +218,10 @@ class BuildApplication {
|
|
|
181
218
|
}
|
|
182
219
|
throw new Error(`Runtime file does not exist: ${from}`);
|
|
183
220
|
}
|
|
221
|
+
if (from === "node_modules" && to === "node_modules" && ((_b = this.config.build) === null || _b === void 0 ? void 0 : _b.productionDependencies)) {
|
|
222
|
+
yield (0, BuildDependencies_1.buildProductionDependencies)(this.projectRoot, this.stagingDir, this.config.build.dependencyInstallScripts === false);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
184
225
|
yield promises_1.default.rm(targetPath, { recursive: true, force: true });
|
|
185
226
|
yield promises_1.default.mkdir(node_path_1.default.dirname(targetPath), { recursive: true });
|
|
186
227
|
if ((yield promises_1.default.lstat(sourcePath)).isDirectory())
|
|
@@ -188,7 +229,7 @@ class BuildApplication {
|
|
|
188
229
|
else
|
|
189
230
|
yield promises_1.default.cp(sourcePath, targetPath, { dereference: false, mode: node_fs_1.default.constants.COPYFILE_FICLONE });
|
|
190
231
|
}
|
|
191
|
-
for (const prunePath of ((
|
|
232
|
+
for (const prunePath of ((_c = this.config.build) === null || _c === void 0 ? void 0 : _c.prunePaths) || []) {
|
|
192
233
|
yield promises_1.default.rm(node_path_1.default.resolve(this.stagingDir, prunePath), { recursive: true, force: true });
|
|
193
234
|
}
|
|
194
235
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
16
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
17
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
19
|
+
/** A separate process releases the compiler AST before runtime copies and bundling. */
|
|
20
|
+
function compile({ projectRoot, tsconfig, outDir, buildRoot, root, stagingDir }) {
|
|
21
|
+
var _a;
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
const ts = require(require.resolve("typescript", { paths: [projectRoot, __dirname] }));
|
|
24
|
+
const scope = node_crypto_1.default.createHash("sha256").update(tsconfig).digest("hex").slice(0, 24);
|
|
25
|
+
const cache = node_path_1.default.join(root, "typescript", scope), output = node_path_1.default.join(cache, "output");
|
|
26
|
+
const loaded = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
27
|
+
const parsed = ts.parseJsonConfigFileContent(loaded.config || {}, ts.sys, node_path_1.default.dirname(tsconfig), undefined, tsconfig);
|
|
28
|
+
if (parsed.options.noEmit)
|
|
29
|
+
throw new Error("Build compilation requires emitted output; remove noEmit from the build configuration.");
|
|
30
|
+
// Resolve the original project before redirecting output. Otherwise allowJs
|
|
31
|
+
// projects accidentally compile their previous build into build/build/.
|
|
32
|
+
const generated = [outDir, buildRoot, root, parsed.options.outDir].filter(Boolean);
|
|
33
|
+
const inside = (parent, file) => file === parent || file.startsWith(parent + node_path_1.default.sep);
|
|
34
|
+
const files = parsed.fileNames.filter((file) => !generated.some(directory => inside(directory, file)));
|
|
35
|
+
const key = node_crypto_1.default.createHash("sha256").update(JSON.stringify([files, parsed.options, ts.version])).digest("hex");
|
|
36
|
+
const previous = yield promises_1.default.readFile(node_path_1.default.join(cache, "key"), "utf8").catch(() => "");
|
|
37
|
+
if (previous !== key)
|
|
38
|
+
yield promises_1.default.rm(cache, { recursive: true, force: true });
|
|
39
|
+
yield promises_1.default.mkdir(output, { recursive: true });
|
|
40
|
+
console.log(`[webframez] TypeScript cache: ${previous === key ? "reuse" : "cold"} (${files.length} source files)`);
|
|
41
|
+
try {
|
|
42
|
+
const builder = ts.createIncrementalProgram({ rootNames: files, options: Object.assign(Object.assign({}, parsed.options), { outDir: output, incremental: true, tsBuildInfoFile: node_path_1.default.join(cache, "build.tsbuildinfo") }), projectReferences: parsed.projectReferences });
|
|
43
|
+
const diagnostics = [...(loaded.error ? [loaded.error] : []), ...parsed.errors, ...builder.getOptionsDiagnostics(), ...builder.getGlobalDiagnostics(), ...builder.getSyntacticDiagnostics(), ...builder.getSemanticDiagnostics()];
|
|
44
|
+
if (diagnostics.length)
|
|
45
|
+
console.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, { getCanonicalFileName: (name) => name, getCurrentDirectory: () => projectRoot, getNewLine: () => "\n" }));
|
|
46
|
+
if (diagnostics.some((entry) => entry.category === ts.DiagnosticCategory.Error))
|
|
47
|
+
throw new Error("tsc exited with code 1");
|
|
48
|
+
const emitted = builder.emit();
|
|
49
|
+
if ((_a = emitted.diagnostics) === null || _a === void 0 ? void 0 : _a.length) {
|
|
50
|
+
console.error(ts.formatDiagnosticsWithColorAndContext(emitted.diagnostics, { getCanonicalFileName: (name) => name, getCurrentDirectory: () => projectRoot, getNewLine: () => "\n" }));
|
|
51
|
+
if (emitted.diagnostics.some((entry) => entry.category === ts.DiagnosticCategory.Error))
|
|
52
|
+
throw new Error("tsc exited with code 1");
|
|
53
|
+
}
|
|
54
|
+
if (emitted.emitSkipped)
|
|
55
|
+
throw new Error("tsc exited without emitting output");
|
|
56
|
+
yield promises_1.default.cp(output, stagingDir, { recursive: true, mode: node_fs_1.default.constants.COPYFILE_FICLONE });
|
|
57
|
+
yield promises_1.default.writeFile(node_path_1.default.join(cache, "key"), key);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
yield promises_1.default.rm(cache, { recursive: true, force: true });
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (require.main === module) {
|
|
66
|
+
compile(JSON.parse(process.argv[2])).catch(error => {
|
|
67
|
+
console.error((error === null || error === void 0 ? void 0 : error.stack) || error);
|
|
68
|
+
process.exitCode = 1;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.buildProductionDependencies = void 0;
|
|
16
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
17
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
19
|
+
const node_child_process_1 = require("node:child_process");
|
|
20
|
+
const node_util_1 = require("node:util");
|
|
21
|
+
/** Prepare an independent production install without pruning the development tree. */
|
|
22
|
+
function buildProductionDependencies(projectRoot, outDir, ignoreScripts = false) {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const manifest = JSON.parse(yield promises_1.default.readFile(node_path_1.default.join(projectRoot, "package.json"), "utf8"));
|
|
25
|
+
if (!/^pnpm@\d+\.\d+\.\d+(?:\+sha\d+\.[a-f0-9]+)?$/.test(manifest.packageManager || "")) {
|
|
26
|
+
throw new Error("Production dependencies require a pinned pnpm packageManager.");
|
|
27
|
+
}
|
|
28
|
+
if (manifest.workspaces || Object.values(Object.assign(Object.assign(Object.assign({}, manifest.dependencies), manifest.devDependencies), manifest.optionalDependencies)).some(value => /^(file:|link:|workspace:|\.\.?\/)/.test(String(value)))) {
|
|
29
|
+
throw new Error("Workspace/local dependencies require pnpm deploy instead.");
|
|
30
|
+
}
|
|
31
|
+
const output = node_path_1.default.resolve(projectRoot, outDir);
|
|
32
|
+
const relative = node_path_1.default.relative(projectRoot, output);
|
|
33
|
+
if (!relative || relative.startsWith("..") || node_path_1.default.isAbsolute(relative) || relative.split(node_path_1.default.sep).some(part => [".git", "node_modules", ".webframez-cache"].includes(part))) {
|
|
34
|
+
throw new Error("Production output must be a separate directory inside the project.");
|
|
35
|
+
}
|
|
36
|
+
const metadata = { "package.json": JSON.stringify(Object.assign(Object.assign({}, manifest), { scripts: undefined })) };
|
|
37
|
+
metadata["pnpm-lock.yaml"] = yield promises_1.default.readFile(node_path_1.default.join(projectRoot, "pnpm-lock.yaml"), "utf8");
|
|
38
|
+
for (const name of ["pnpm-workspace.yaml"]) {
|
|
39
|
+
const content = yield promises_1.default.readFile(node_path_1.default.join(projectRoot, name), "utf8").catch(() => "");
|
|
40
|
+
if (content)
|
|
41
|
+
metadata[name] = content;
|
|
42
|
+
}
|
|
43
|
+
if (/^\s*packages\s*:/m.test(metadata["pnpm-workspace.yaml"] || "") || /(?:^|[\s\x22\x27@])(?:file|link|workspace):/m.test(metadata["pnpm-lock.yaml"])) {
|
|
44
|
+
throw new Error("Workspace/local dependencies require pnpm deploy instead.");
|
|
45
|
+
}
|
|
46
|
+
const userconfig = process.env.NPM_CONFIG_USERCONFIG || process.env.npm_config_userconfig || node_path_1.default.join(projectRoot, ".npmrc");
|
|
47
|
+
const registry = yield promises_1.default.readFile(userconfig, "utf8").catch(() => "");
|
|
48
|
+
const scope = node_crypto_1.default.createHash("sha256").update(projectRoot).digest("hex").slice(0, 24);
|
|
49
|
+
const cache = node_path_1.default.join(node_path_1.default.resolve(projectRoot, process.env.WEBFRAMEZ_BUILD_CACHE_DIRECTORY || ".webframez-cache"), "production", scope);
|
|
50
|
+
const key = node_crypto_1.default.createHash("sha256").update(JSON.stringify([metadata, registry, ignoreScripts, process.version, process.platform, process.arch])).digest("hex");
|
|
51
|
+
const previous = yield promises_1.default.readFile(node_path_1.default.join(cache, "fingerprint"), "utf8").catch(() => "");
|
|
52
|
+
if (previous !== key)
|
|
53
|
+
yield promises_1.default.rm(cache, { recursive: true, force: true });
|
|
54
|
+
yield promises_1.default.mkdir(cache, { recursive: true });
|
|
55
|
+
for (const [name, content] of Object.entries(metadata))
|
|
56
|
+
yield promises_1.default.writeFile(node_path_1.default.join(cache, name), content);
|
|
57
|
+
const started = Date.now();
|
|
58
|
+
console.log(`[webframez] production dependencies: ${previous === key ? "reuse" : "cold"}`);
|
|
59
|
+
try {
|
|
60
|
+
const expected = manifest.packageManager.split("@")[1].split("+")[0];
|
|
61
|
+
const { stdout } = yield (0, node_util_1.promisify)(node_child_process_1.execFile)("pnpm", ["--version"], { cwd: projectRoot });
|
|
62
|
+
if (stdout.trim() !== expected)
|
|
63
|
+
throw new Error(`Expected pnpm ${expected}, got ${stdout.trim()}`);
|
|
64
|
+
yield new Promise((resolve, reject) => {
|
|
65
|
+
const child = (0, node_child_process_1.spawn)("pnpm", ["install", "--frozen-lockfile", "--prod", ...(ignoreScripts ? ["--ignore-scripts"] : [])], {
|
|
66
|
+
cwd: cache, stdio: "inherit", env: Object.assign(Object.assign({}, process.env), { NODE_ENV: "production", NPM_CONFIG_USERCONFIG: userconfig }),
|
|
67
|
+
});
|
|
68
|
+
child.once("error", reject);
|
|
69
|
+
child.once("exit", code => code === 0 ? resolve() : reject(new Error(`pnpm production install exited with code ${code}`)));
|
|
70
|
+
});
|
|
71
|
+
const modules = node_path_1.default.join(cache, "node_modules"), destination = node_path_1.default.join(output, "node_modules");
|
|
72
|
+
yield promises_1.default.mkdir(output, { recursive: true });
|
|
73
|
+
yield promises_1.default.rm(destination, { recursive: true, force: true });
|
|
74
|
+
if (yield promises_1.default.stat(modules).catch(() => null)) {
|
|
75
|
+
if (process.platform === "linux")
|
|
76
|
+
yield (0, node_util_1.promisify)(node_child_process_1.execFile)("cp", ["-a", "--reflink=auto", "--", modules, destination]);
|
|
77
|
+
else
|
|
78
|
+
yield promises_1.default.cp(modules, destination, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
yield promises_1.default.writeFile(node_path_1.default.join(cache, "fingerprint"), key);
|
|
81
|
+
console.log(`[webframez] production dependencies: ready (${((Date.now() - started) / 1000).toFixed(2)}s)`);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
yield promises_1.default.rm(cache, { recursive: true, force: true });
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
exports.buildProductionDependencies = buildProductionDependencies;
|
package/dist/Cli.js
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -15,7 +38,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
38
|
exports.runWebframezCli = void 0;
|
|
16
39
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
17
40
|
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
-
const
|
|
41
|
+
const BuildDependencies_1 = require("./BuildDependencies");
|
|
19
42
|
const BuildApplication_1 = require("./BuildApplication");
|
|
20
43
|
function printHelp() {
|
|
21
44
|
console.log([
|
|
@@ -73,7 +96,8 @@ function runConsole(projectRoot, cliArgs) {
|
|
|
73
96
|
if (config.setup) {
|
|
74
97
|
yield config.setup({ mode: "console", projectRoot });
|
|
75
98
|
}
|
|
76
|
-
const
|
|
99
|
+
const { ConsoleApplication } = yield Promise.resolve().then(() => __importStar(require("./ConsoleApplication")));
|
|
100
|
+
const app = new ConsoleApplication();
|
|
77
101
|
const originalArgv = process.argv;
|
|
78
102
|
process.argv = [process.argv[0], "webframez", ...cliArgs];
|
|
79
103
|
try {
|
|
@@ -115,6 +139,22 @@ function runWebframezCli(argv = process.argv.slice(2), projectRoot = process.cwd
|
|
|
115
139
|
yield runConsole(projectRoot, argv.slice(1));
|
|
116
140
|
return;
|
|
117
141
|
}
|
|
142
|
+
if (command === "compile") {
|
|
143
|
+
const tsconfig = readOption(argv, "project") || "tsconfig.json";
|
|
144
|
+
const outDir = readOption(argv, "dir") || "build";
|
|
145
|
+
const relative = node_path_1.default.relative(projectRoot, node_path_1.default.resolve(projectRoot, outDir));
|
|
146
|
+
if (!relative || relative.startsWith("..") || node_path_1.default.isAbsolute(relative) || relative.split(node_path_1.default.sep).some(part => [".git", "node_modules", ".webframez-cache"].includes(part)))
|
|
147
|
+
throw new Error("Compile output must be a separate project directory.");
|
|
148
|
+
yield new BuildApplication_1.BuildApplication(projectRoot, { build: { tsconfig, cacheDirectory: process.env.WEBFRAMEZ_BUILD_CACHE_DIRECTORY || ".webframez-cache" } }, { outDir }).compile();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (command === "dependencies") {
|
|
152
|
+
const outDir = readOption(argv, "dir");
|
|
153
|
+
if (!outDir)
|
|
154
|
+
throw new Error("Production dependencies require --dir.");
|
|
155
|
+
yield (0, BuildDependencies_1.buildProductionDependencies)(projectRoot, outDir, argv.includes("--ignore-scripts"));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
118
158
|
if (command === "build" || command === "buid") {
|
|
119
159
|
yield runBuild(projectRoot, argv.slice(1));
|
|
120
160
|
return;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from "./Database/Model";
|
|
|
12
12
|
export * from "./Database/DBConnection";
|
|
13
13
|
export * from "./ConsoleApplication";
|
|
14
14
|
export * from "./BuildApplication";
|
|
15
|
+
export * from "./BuildDependencies";
|
|
15
16
|
export * from "./LambdaApplication";
|
|
16
17
|
export * from "./WebApplication";
|
|
17
18
|
export * from "./Router/Route";
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,7 @@ __exportStar(require("./Database/Model"), exports);
|
|
|
29
29
|
__exportStar(require("./Database/DBConnection"), exports);
|
|
30
30
|
__exportStar(require("./ConsoleApplication"), exports);
|
|
31
31
|
__exportStar(require("./BuildApplication"), exports);
|
|
32
|
+
__exportStar(require("./BuildDependencies"), exports);
|
|
32
33
|
__exportStar(require("./LambdaApplication"), exports);
|
|
33
34
|
__exportStar(require("./WebApplication"), exports);
|
|
34
35
|
__exportStar(require("./Router/Route"), exports);
|
package/package.json
CHANGED