@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/backend-federation-build/codegen.js +267 -0
- package/dist/cjs/backend-federation-build/config.js +239 -0
- package/dist/cjs/backend-federation-build/emit.js +154 -0
- package/dist/cjs/backend-federation-build/index.js +53 -0
- package/dist/cjs/build-config/build-environment.js +129 -0
- package/dist/cjs/build-config/precompress/plugin.js +124 -0
- package/dist/cjs/build-config/precompress/types.js +18 -0
- package/dist/cjs/build-config/public.js +43 -0
- package/dist/cjs/build-config/remote-address.js +58 -0
- package/dist/cjs/cloudflare/artifacts.js +8 -19
- package/dist/cjs/cloudflare/constants.js +1 -1
- package/dist/cjs/cloudflare/delivery-unit.js +23 -42
- package/dist/cjs/cloudflare/index.js +10 -2
- package/dist/cjs/cloudflare/worker-manifest.js +13 -4
- package/dist/cjs/cloudflare/wrangler-config.js +35 -7
- package/dist/cjs/cloudflare-builder.js +252 -75
- package/dist/cjs/cloudflare-output-contract.js +69 -3
- package/dist/cjs/cloudflare-output-verifier/identity.js +29 -27
- package/dist/cjs/cloudflare-output-verifier/index.js +10 -0
- package/dist/cjs/cloudflare-output-verifier/manifest.js +46 -0
- package/dist/cjs/cloudflare-output-verifier/mutation-policy.js +7 -1
- package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +14 -6
- package/dist/cjs/config.js +34 -1
- package/dist/cjs/deploy-output/npmAliases.js +251 -0
- package/dist/cjs/deploy-output/plugin.js +97 -0
- package/dist/cjs/deploy-output/public-assets.js +146 -0
- package/dist/cjs/deploy-output/target.js +104 -0
- package/dist/cjs/deploy-output/trace-files.js +90 -0
- package/dist/cjs/native-type-checker.js +193 -0
- package/dist/cjs/policy-defaults.js +101 -0
- package/dist/cjs/release-envelope/framework-output.js +153 -79
- package/dist/cjs/release-envelope/index.js +10 -4
- package/dist/cjs/release-envelope/plugin.js +18 -13
- package/dist/cjs/release-identity.js +5 -6
- package/dist/cjs/runtime-package-resolution.js +118 -0
- package/dist/cjs/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
- package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
- package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
- package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
- package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
- package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/esm/backend-federation-build/codegen.mjs +216 -0
- package/dist/esm/backend-federation-build/config.mjs +163 -0
- package/dist/esm/backend-federation-build/emit.mjs +103 -0
- package/dist/esm/backend-federation-build/index.mjs +1 -0
- package/dist/esm/build-config/build-environment.mjs +88 -0
- package/dist/esm/build-config/precompress/plugin.mjs +76 -0
- package/dist/esm/build-config/precompress/types.mjs +0 -0
- package/dist/esm/build-config/public.mjs +1 -0
- package/dist/esm/build-config/remote-address.mjs +20 -0
- package/dist/esm/cloudflare/artifacts.mjs +8 -19
- package/dist/esm/cloudflare/constants.mjs +1 -1
- package/dist/esm/cloudflare/delivery-unit.mjs +17 -36
- package/dist/esm/cloudflare/index.mjs +10 -2
- package/dist/esm/cloudflare/worker-manifest.mjs +13 -4
- package/dist/esm/cloudflare/wrangler-config.mjs +35 -7
- package/dist/esm/cloudflare-builder.mjs +246 -75
- package/dist/esm/cloudflare-output-contract.mjs +59 -2
- package/dist/esm/cloudflare-output-verifier/identity.mjs +27 -25
- package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
- package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
- package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
- package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +15 -7
- package/dist/esm/config.mjs +3 -0
- package/dist/esm/deploy-output/npmAliases.mjs +199 -0
- package/dist/esm/deploy-output/plugin.mjs +46 -0
- package/dist/esm/deploy-output/public-assets.mjs +82 -0
- package/dist/esm/deploy-output/target.mjs +57 -0
- package/dist/esm/deploy-output/trace-files.mjs +38 -0
- package/dist/esm/native-type-checker.mjs +142 -0
- package/dist/esm/policy-defaults.mjs +45 -0
- package/dist/esm/release-envelope/framework-output.mjs +130 -56
- package/dist/esm/release-envelope/index.mjs +10 -4
- package/dist/esm/release-envelope/plugin.mjs +18 -13
- package/dist/esm/release-identity.mjs +5 -6
- package/dist/esm/runtime-package-resolution.mjs +60 -0
- package/dist/esm/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
- package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
- package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
- package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
- package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
- package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/esm-node/backend-federation-build/codegen.mjs +217 -0
- package/dist/esm-node/backend-federation-build/config.mjs +164 -0
- package/dist/esm-node/backend-federation-build/emit.mjs +104 -0
- package/dist/esm-node/backend-federation-build/index.mjs +2 -0
- package/dist/esm-node/build-config/build-environment.mjs +89 -0
- package/dist/esm-node/build-config/precompress/plugin.mjs +77 -0
- package/dist/esm-node/build-config/precompress/types.mjs +1 -0
- package/dist/esm-node/build-config/public.mjs +2 -0
- package/dist/esm-node/build-config/remote-address.mjs +21 -0
- package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
- package/dist/esm-node/cloudflare/constants.mjs +1 -1
- package/dist/esm-node/cloudflare/delivery-unit.mjs +17 -36
- package/dist/esm-node/cloudflare/index.mjs +10 -2
- package/dist/esm-node/cloudflare/worker-manifest.mjs +13 -4
- package/dist/esm-node/cloudflare/wrangler-config.mjs +35 -7
- package/dist/esm-node/cloudflare-builder.mjs +246 -75
- package/dist/esm-node/cloudflare-output-contract.mjs +59 -2
- package/dist/esm-node/cloudflare-output-verifier/identity.mjs +27 -25
- package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
- package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
- package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
- package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +15 -7
- package/dist/esm-node/config.mjs +3 -0
- package/dist/esm-node/deploy-output/npmAliases.mjs +200 -0
- package/dist/esm-node/deploy-output/plugin.mjs +49 -0
- package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
- package/dist/esm-node/deploy-output/target.mjs +58 -0
- package/dist/esm-node/deploy-output/trace-files.mjs +39 -0
- package/dist/esm-node/native-type-checker.mjs +143 -0
- package/dist/esm-node/policy-defaults.mjs +46 -0
- package/dist/esm-node/release-envelope/framework-output.mjs +130 -56
- package/dist/esm-node/release-envelope/index.mjs +10 -4
- package/dist/esm-node/release-envelope/plugin.mjs +18 -13
- package/dist/esm-node/release-identity.mjs +5 -6
- package/dist/esm-node/runtime-package-resolution.mjs +61 -0
- package/dist/esm-node/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
- package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
- package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
- package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
- package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
- package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/types/backend-federation-build/codegen.d.ts +116 -0
- package/dist/types/backend-federation-build/config.d.ts +121 -0
- package/dist/types/backend-federation-build/emit.d.ts +21 -0
- package/dist/types/backend-federation-build/index.d.ts +2 -0
- package/dist/types/build-config/build-environment.d.ts +14 -0
- package/dist/types/build-config/precompress/plugin.d.ts +4 -0
- package/dist/types/build-config/precompress/types.d.ts +19 -0
- package/dist/types/build-config/public.d.ts +2 -0
- package/dist/types/build-config/remote-address.d.ts +3 -0
- package/dist/types/cloudflare/artifacts.d.ts +7 -6
- package/dist/types/cloudflare/constants.d.ts +1 -1
- package/dist/types/cloudflare/delivery-unit.d.ts +3 -3
- package/dist/types/cloudflare/worker-manifest.d.ts +2 -2
- package/dist/types/cloudflare/wrangler-config.d.ts +6 -0
- package/dist/types/cloudflare-builder.d.ts +49 -9
- package/dist/types/cloudflare-output-contract.d.ts +4 -1
- package/dist/types/cloudflare-output-verifier/identity.d.ts +1 -1
- package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
- package/dist/types/config.d.ts +29 -1
- package/dist/types/deploy-output/npmAliases.d.ts +14 -0
- package/dist/types/deploy-output/plugin.d.ts +35 -0
- package/dist/types/deploy-output/public-assets.d.ts +51 -0
- package/dist/types/deploy-output/target.d.ts +29 -0
- package/dist/types/deploy-output/trace-files.d.ts +17 -0
- package/dist/types/native-type-checker.d.ts +15 -0
- package/dist/types/policy-defaults.d.ts +46 -0
- package/dist/types/precompress/LICENSE +20 -0
- package/dist/types/precompress/index.d.ts +76 -0
- package/dist/types/release-envelope/framework-output.d.ts +8 -3
- package/dist/types/release-envelope/plugin.d.ts +7 -7
- package/dist/types/runtime-package-resolution.d.ts +28 -0
- package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
- package/package.json +97 -15
- package/src/backend-federation-build/codegen.ts +254 -0
- package/src/backend-federation-build/config.ts +492 -0
- package/src/backend-federation-build/emit.ts +213 -0
- package/src/backend-federation-build/index.ts +2 -0
- package/src/build-config/build-environment.ts +160 -0
- package/src/build-config/precompress/plugin.ts +140 -0
- package/src/build-config/precompress/types.ts +26 -0
- package/src/build-config/public.ts +5 -0
- package/src/build-config/remote-address.ts +33 -0
- package/src/cloudflare/artifacts.ts +22 -43
- package/src/cloudflare/constants.ts +1 -1
- package/src/cloudflare/delivery-unit.ts +42 -53
- package/src/cloudflare/index.ts +24 -11
- package/src/cloudflare/worker-manifest.ts +20 -3
- package/src/cloudflare/wrangler-config.ts +86 -10
- package/src/cloudflare-builder.ts +475 -151
- package/src/cloudflare-output-contract.ts +70 -0
- package/src/cloudflare-output-verifier/identity.ts +5 -1
- package/src/cloudflare-output-verifier/index.ts +20 -0
- package/src/cloudflare-output-verifier/manifest.ts +77 -0
- package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
- package/src/cloudflare-output-verifier/worker-bundles.ts +32 -14
- package/src/config.ts +34 -6
- package/src/deploy-output/npmAliases.ts +382 -0
- package/src/deploy-output/plugin.ts +86 -0
- package/src/deploy-output/public-assets.ts +224 -0
- package/src/deploy-output/target.ts +106 -0
- package/src/deploy-output/trace-files.ts +67 -0
- package/src/native-type-checker.ts +183 -0
- package/src/policy-defaults.ts +127 -0
- package/src/release-envelope/framework-output.ts +346 -94
- package/src/release-envelope/index.ts +26 -5
- package/src/release-envelope/plugin.ts +43 -40
- package/src/release-identity.ts +13 -2
- package/src/runtime-package-resolution.ts +115 -0
- package/src/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
- package/src/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
- package/src/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
- package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
- package/src/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
- package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
- package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
- package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
- package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
- package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/src/templates/cloudflare-worker-path.mjs +0 -98
|
@@ -5,9 +5,9 @@ import { pathToFileURL } from "node:url";
|
|
|
5
5
|
import { isDeepStrictEqual } from "node:util";
|
|
6
6
|
import { parse } from "@babel/parser";
|
|
7
7
|
import traverse from "@babel/traverse";
|
|
8
|
-
import { CLOUDFLARE_WORKER_BUNDLE_DIRECTORY, CLOUDFLARE_WORKER_NODE_BUILTINS } from "../cloudflare-output-contract.mjs";
|
|
8
|
+
import { CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT, CLOUDFLARE_WORKER_BUNDLE_DIRECTORY, CLOUDFLARE_WORKER_NODE_BUILTINS, CLOUDFLARE_WORKER_PLATFORM_MODULES } from "../cloudflare-output-contract.mjs";
|
|
9
9
|
import { addIssue } from "./issues.mjs";
|
|
10
|
-
const getReferencedRouteWorkers = (manifest)=>Array.isArray(manifest?.routeSpec?.routes) ? manifest.routeSpec.routes.map((route)=>'string' == typeof route?.
|
|
10
|
+
const getReferencedRouteWorkers = (manifest, field)=>Array.isArray(manifest?.routeSpec?.routes) ? manifest.routeSpec.routes.map((route)=>'string' == typeof route?.[field] && route[field].length > 0 ? route[field] : void 0).filter((worker)=>'string' == typeof worker) : [];
|
|
11
11
|
const getEffectBffWorker = (manifest)=>manifest?.bff?.runtimeFramework === 'effect' && 'string' == typeof manifest.bff.worker ? manifest.bff.worker : void 0;
|
|
12
12
|
const getWorkerBundleReferences = (manifest)=>{
|
|
13
13
|
const effectBffWorker = getEffectBffWorker(manifest);
|
|
@@ -19,9 +19,14 @@ const getWorkerBundleReferences = (manifest)=>{
|
|
|
19
19
|
reference: effectBffWorker
|
|
20
20
|
}
|
|
21
21
|
] : [],
|
|
22
|
-
...getReferencedRouteWorkers(manifest).map((reference)=>({
|
|
22
|
+
...getReferencedRouteWorkers(manifest, 'worker').map((reference)=>({
|
|
23
23
|
kind: 'route',
|
|
24
24
|
reference
|
|
25
|
+
})),
|
|
26
|
+
...getReferencedRouteWorkers(manifest, 'routeDataWorker').map((reference)=>({
|
|
27
|
+
dispatcherExport: CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT,
|
|
28
|
+
kind: 'route-data',
|
|
29
|
+
reference
|
|
25
30
|
}))
|
|
26
31
|
];
|
|
27
32
|
};
|
|
@@ -42,7 +47,7 @@ const resolveWorkerBundleReference = (issues, outputDirectory, reference, manife
|
|
|
42
47
|
path: workerPath
|
|
43
48
|
};
|
|
44
49
|
};
|
|
45
|
-
const missingWorkerBundleMessage = (reference)=>'effect-bff' === reference.kind ? 'Cloudflare Effect BFF manifest points to a missing worker bundle.' : 'Cloudflare route worker manifest points to a missing worker bundle.';
|
|
50
|
+
const missingWorkerBundleMessage = (reference)=>'effect-bff' === reference.kind ? 'Cloudflare Effect BFF manifest points to a missing worker bundle.' : 'route-data' === reference.kind ? 'Cloudflare route data worker manifest points to a missing worker bundle.' : 'Cloudflare route worker manifest points to a missing worker bundle.';
|
|
46
51
|
const isAstNode = (value)=>null !== value && 'object' == typeof value && 'type' in value && 'string' == typeof value.type;
|
|
47
52
|
const getNodeName = (node)=>{
|
|
48
53
|
if (!isAstNode(node)) return;
|
|
@@ -175,7 +180,10 @@ const analyzeWorkerModule = (source)=>{
|
|
|
175
180
|
};
|
|
176
181
|
};
|
|
177
182
|
const getPackageName = (specifier)=>specifier.startsWith('@') ? specifier.split('/').slice(0, 2).join('/') : specifier.split('/')[0];
|
|
178
|
-
const CLOUDFLARE_WORKER_NODE_BUILTIN_SPECIFIERS = new Set(
|
|
183
|
+
const CLOUDFLARE_WORKER_NODE_BUILTIN_SPECIFIERS = new Set([
|
|
184
|
+
...CLOUDFLARE_WORKER_NODE_BUILTINS.map((builtin)=>`node:${builtin}`),
|
|
185
|
+
...CLOUDFLARE_WORKER_PLATFORM_MODULES
|
|
186
|
+
]);
|
|
179
187
|
const isInsideDirectory = (directory, filePath)=>{
|
|
180
188
|
const relative = node_path.relative(directory, filePath);
|
|
181
189
|
return 0 === relative.length || !relative.startsWith('..') && !node_path.isAbsolute(relative);
|
|
@@ -283,9 +291,9 @@ const verifyWorkerModuleClosure = async (issues, entryPath, entrySource, contrac
|
|
|
283
291
|
};
|
|
284
292
|
const verifyWorkerBundleReferences = async (issues, worker, source, contract)=>{
|
|
285
293
|
const entryAnalysis = await verifyWorkerModuleClosure(issues, worker.path, source, contract);
|
|
286
|
-
if ('
|
|
294
|
+
if ('string' == typeof worker.dispatcherExport && !entryAnalysis?.exports.has(worker.dispatcherExport)) addIssue(issues, {
|
|
287
295
|
code: 'invalid-worker-bundle',
|
|
288
|
-
message: 'Cloudflare Effect BFF worker bundle must expose its manifest dispatcherExport.',
|
|
296
|
+
message: 'route-data' === worker.kind ? `Cloudflare route data worker bundle must expose ${worker.dispatcherExport}.` : 'Cloudflare Effect BFF worker bundle must expose its manifest dispatcherExport.',
|
|
289
297
|
path: worker.path
|
|
290
298
|
});
|
|
291
299
|
};
|
package/dist/esm-node/config.mjs
CHANGED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import promises from "node:fs/promises";
|
|
3
|
+
import node_path from "node:path";
|
|
4
|
+
const dependencyKeys = [
|
|
5
|
+
'dependencies',
|
|
6
|
+
'optionalDependencies'
|
|
7
|
+
];
|
|
8
|
+
const rootDependencyKeys = [
|
|
9
|
+
...dependencyKeys,
|
|
10
|
+
'devDependencies'
|
|
11
|
+
];
|
|
12
|
+
const exactVersionPattern = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u;
|
|
13
|
+
async function readPackageJson(filePath) {
|
|
14
|
+
return JSON.parse(await promises.readFile(filePath, 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
function parseNpmAlias(aliasName, specifier) {
|
|
17
|
+
if (!specifier.startsWith('npm:')) return;
|
|
18
|
+
const target = specifier.slice(4);
|
|
19
|
+
const versionSeparator = target.lastIndexOf('@');
|
|
20
|
+
if (versionSeparator <= 0 || versionSeparator === target.length - 1) throw new Error(`Invalid npm alias specifier for ${aliasName}: ${specifier}`);
|
|
21
|
+
return {
|
|
22
|
+
aliasName,
|
|
23
|
+
targetName: target.slice(0, versionSeparator),
|
|
24
|
+
targetVersion: target.slice(versionSeparator + 1)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function aliasesFromPackageJson(packageJson, keys = dependencyKeys) {
|
|
28
|
+
const aliases = [];
|
|
29
|
+
for (const dependencyKey of keys)for (const [aliasName, specifier] of Object.entries(packageJson[dependencyKey] ?? {})){
|
|
30
|
+
const alias = parseNpmAlias(aliasName, specifier);
|
|
31
|
+
if (alias) aliases.push(alias);
|
|
32
|
+
}
|
|
33
|
+
return aliases;
|
|
34
|
+
}
|
|
35
|
+
async function catalogAliasesFromInstalledPackages(appDirectory, packageJson) {
|
|
36
|
+
const aliases = [];
|
|
37
|
+
for (const dependencyKey of rootDependencyKeys)for (const [aliasName, specifier] of Object.entries(packageJson[dependencyKey] ?? {})){
|
|
38
|
+
if (!specifier.startsWith('catalog:')) continue;
|
|
39
|
+
let installedPackage;
|
|
40
|
+
try {
|
|
41
|
+
installedPackage = await readPackageJson(node_path.join(appDirectory, 'node_modules', aliasName, 'package.json'));
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if ('ENOENT' === error.code) continue;
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
if (!installedPackage.name || !installedPackage.version) throw new Error(`Installed catalog package ${aliasName} has no identity`);
|
|
47
|
+
if (installedPackage.name !== aliasName) aliases.push({
|
|
48
|
+
aliasName,
|
|
49
|
+
targetName: installedPackage.name,
|
|
50
|
+
targetVersion: installedPackage.version
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return aliases;
|
|
54
|
+
}
|
|
55
|
+
async function collectPackageRecords(nodeModulesDirectory) {
|
|
56
|
+
const records = [];
|
|
57
|
+
const visitedNodeModules = new Set();
|
|
58
|
+
const visitPackage = async (directory)=>{
|
|
59
|
+
const packageJsonPath = node_path.join(directory, 'package.json');
|
|
60
|
+
try {
|
|
61
|
+
const packageJson = await readPackageJson(packageJsonPath);
|
|
62
|
+
if (packageJson.name && packageJson.version) records.push({
|
|
63
|
+
directory,
|
|
64
|
+
packageJson
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if ('ENOENT' !== error.code) throw error;
|
|
68
|
+
}
|
|
69
|
+
await visitNodeModules(node_path.join(directory, 'node_modules'));
|
|
70
|
+
};
|
|
71
|
+
const visitScope = async (scopeDirectory)=>{
|
|
72
|
+
const entries = await promises.readdir(scopeDirectory, {
|
|
73
|
+
withFileTypes: true
|
|
74
|
+
});
|
|
75
|
+
for (const entry of entries)if (entry.isDirectory()) await visitPackage(node_path.join(scopeDirectory, entry.name));
|
|
76
|
+
};
|
|
77
|
+
const visitNdepeStore = async (storeDirectory)=>{
|
|
78
|
+
const entries = await promises.readdir(storeDirectory, {
|
|
79
|
+
withFileTypes: true
|
|
80
|
+
});
|
|
81
|
+
for (const entry of entries)if (entry.isDirectory()) {
|
|
82
|
+
const entryPath = node_path.join(storeDirectory, entry.name);
|
|
83
|
+
if (entry.name.startsWith('@')) await visitScope(entryPath);
|
|
84
|
+
else await visitNodeModules(node_path.join(entryPath, 'node_modules'));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const visitNodeModules = async (directory)=>{
|
|
88
|
+
const resolvedDirectory = node_path.resolve(directory);
|
|
89
|
+
if (visitedNodeModules.has(resolvedDirectory)) return;
|
|
90
|
+
visitedNodeModules.add(resolvedDirectory);
|
|
91
|
+
let entries;
|
|
92
|
+
try {
|
|
93
|
+
entries = await promises.readdir(directory, {
|
|
94
|
+
withFileTypes: true
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if ('ENOENT' === error.code) return;
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
for (const entry of entries){
|
|
101
|
+
if (!entry.isDirectory()) continue;
|
|
102
|
+
const entryPath = node_path.join(directory, entry.name);
|
|
103
|
+
if ('.ndepe' === entry.name) await visitNdepeStore(entryPath);
|
|
104
|
+
else if (entry.name.startsWith('@')) await visitScope(entryPath);
|
|
105
|
+
else await visitPackage(entryPath);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
await visitNodeModules(nodeModulesDirectory);
|
|
109
|
+
return records;
|
|
110
|
+
}
|
|
111
|
+
async function resolveAliasTarget(ownerDirectory, alias, outputDirectory) {
|
|
112
|
+
let directory = ownerDirectory;
|
|
113
|
+
const outputRoot = node_path.resolve(outputDirectory);
|
|
114
|
+
const resolvedOutputRoot = await promises.realpath(outputRoot);
|
|
115
|
+
while(directory === outputRoot || directory.startsWith(`${outputRoot}${node_path.sep}`)){
|
|
116
|
+
const candidate = node_path.join(directory, 'node_modules', alias.targetName);
|
|
117
|
+
try {
|
|
118
|
+
const resolvedCandidate = await promises.realpath(candidate);
|
|
119
|
+
if (resolvedCandidate !== resolvedOutputRoot && !resolvedCandidate.startsWith(`${resolvedOutputRoot}${node_path.sep}`)) throw new Error(`Cannot preserve npm alias ${alias.aliasName}: emitted target ${candidate} resolves outside deployment output to ${resolvedCandidate}`);
|
|
120
|
+
const packageJson = await readPackageJson(node_path.join(candidate, 'package.json'));
|
|
121
|
+
if (packageJson.name !== alias.targetName || !packageJson.version) throw new Error(`npm alias ${alias.aliasName} resolved ${candidate} to unexpected package ${String(packageJson.name)}`);
|
|
122
|
+
if (exactVersionPattern.test(alias.targetVersion) && packageJson.version !== alias.targetVersion) return;
|
|
123
|
+
return {
|
|
124
|
+
directory: candidate,
|
|
125
|
+
packageJson
|
|
126
|
+
};
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if ('ENOENT' !== error.code) throw error;
|
|
129
|
+
}
|
|
130
|
+
if (directory === outputRoot) break;
|
|
131
|
+
directory = node_path.dirname(directory);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function ensureAliasLink(ownerDirectory, alias, target) {
|
|
135
|
+
const aliasPath = node_path.join(ownerDirectory, 'node_modules', alias.aliasName);
|
|
136
|
+
await promises.mkdir(node_path.dirname(aliasPath), {
|
|
137
|
+
recursive: true
|
|
138
|
+
});
|
|
139
|
+
try {
|
|
140
|
+
const [existing, expected] = await Promise.all([
|
|
141
|
+
promises.realpath(aliasPath),
|
|
142
|
+
promises.realpath(target.directory)
|
|
143
|
+
]);
|
|
144
|
+
if (existing === expected) return;
|
|
145
|
+
throw new Error(`Cannot preserve npm alias ${alias.aliasName}: ${aliasPath} already resolves to ${existing}, expected ${expected}`);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if ('ENOENT' !== error.code) throw error;
|
|
148
|
+
}
|
|
149
|
+
const linkTarget = node_path.relative(node_path.dirname(aliasPath), target.directory);
|
|
150
|
+
await promises.symlink(linkTarget, aliasPath, 'dir');
|
|
151
|
+
}
|
|
152
|
+
function aliasSpecifier(alias) {
|
|
153
|
+
return `npm:${alias.targetName}@${alias.targetVersion}`;
|
|
154
|
+
}
|
|
155
|
+
async function readPackageIdentity(entryPath) {
|
|
156
|
+
let directory = node_path.dirname(entryPath);
|
|
157
|
+
const root = node_path.parse(directory).root;
|
|
158
|
+
while(directory !== root){
|
|
159
|
+
try {
|
|
160
|
+
const packageJson = await readPackageJson(node_path.join(directory, 'package.json'));
|
|
161
|
+
if (packageJson.name && packageJson.version) return {
|
|
162
|
+
name: packageJson.name,
|
|
163
|
+
version: packageJson.version
|
|
164
|
+
};
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if ('ENOENT' !== error.code) throw error;
|
|
167
|
+
}
|
|
168
|
+
directory = node_path.dirname(directory);
|
|
169
|
+
}
|
|
170
|
+
throw new Error(`Cannot find owning package for deployment entry ${entryPath}`);
|
|
171
|
+
}
|
|
172
|
+
async function preserveNpmAliases({ appDirectory, outputDirectory, implicitAliases = [] }) {
|
|
173
|
+
const records = await collectPackageRecords(node_path.join(outputDirectory, 'node_modules'));
|
|
174
|
+
const appPackageJson = await readPackageJson(node_path.join(appDirectory, 'package.json'));
|
|
175
|
+
const rootAliases = [
|
|
176
|
+
...aliasesFromPackageJson(appPackageJson, rootDependencyKeys),
|
|
177
|
+
...await catalogAliasesFromInstalledPackages(appDirectory, appPackageJson),
|
|
178
|
+
...implicitAliases
|
|
179
|
+
].filter((alias)=>alias.aliasName !== alias.targetName);
|
|
180
|
+
const emittedRootAliases = [];
|
|
181
|
+
for (const alias of rootAliases){
|
|
182
|
+
const target = await resolveAliasTarget(outputDirectory, alias, outputDirectory);
|
|
183
|
+
if (!target) {
|
|
184
|
+
if (implicitAliases.includes(alias)) throw new Error(`Cannot preserve implicit npm alias ${alias.aliasName}: emitted target ${alias.targetName}@${alias.targetVersion} is missing`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
await ensureAliasLink(outputDirectory, alias, target);
|
|
188
|
+
emittedRootAliases.push(alias);
|
|
189
|
+
}
|
|
190
|
+
for (const record of records)for (const alias of aliasesFromPackageJson(record.packageJson).filter((candidate)=>candidate.aliasName !== candidate.targetName)){
|
|
191
|
+
const target = await resolveAliasTarget(record.directory, alias, outputDirectory);
|
|
192
|
+
if (target) await ensureAliasLink(record.directory, alias, target);
|
|
193
|
+
}
|
|
194
|
+
const outputPackageJsonPath = node_path.join(outputDirectory, 'package.json');
|
|
195
|
+
const outputPackageJson = await readPackageJson(outputPackageJsonPath);
|
|
196
|
+
outputPackageJson.dependencies ??= {};
|
|
197
|
+
for (const alias of emittedRootAliases)outputPackageJson.dependencies[alias.aliasName] = aliasSpecifier(alias);
|
|
198
|
+
await promises.writeFile(outputPackageJsonPath, `${JSON.stringify(outputPackageJson, null, 2)}\n`);
|
|
199
|
+
}
|
|
200
|
+
export { preserveNpmAliases, readPackageIdentity };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import node_path from "node:path";
|
|
4
|
+
import { preserveNpmAliases, readPackageIdentity } from "./npmAliases.mjs";
|
|
5
|
+
import { NODE_PUBLIC_ASSET_SCOPE, normalizeDeclaredPublicAssets, stageDeclaredPublicAssets } from "./public-assets.mjs";
|
|
6
|
+
import { getDeployingTarget } from "./target.mjs";
|
|
7
|
+
import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
|
|
8
|
+
var __rspack_import_meta_filename__ = __rspack_fileURLToPath(import.meta.url);
|
|
9
|
+
const createDeployOutputAliasesPlugin = ()=>({
|
|
10
|
+
name: '@modern-js/deploy-output-aliases',
|
|
11
|
+
setup (api) {
|
|
12
|
+
api.onAfterDeploy(async ()=>{
|
|
13
|
+
const appContext = api.getAppContext();
|
|
14
|
+
if ('node' !== getDeployingTarget(appContext)) return;
|
|
15
|
+
const { appDirectory } = appContext;
|
|
16
|
+
const entry = createRequire(__rspack_import_meta_filename__).resolve('@modern-js/prod-server');
|
|
17
|
+
const identity = await readPackageIdentity(entry);
|
|
18
|
+
await preserveNpmAliases({
|
|
19
|
+
appDirectory,
|
|
20
|
+
outputDirectory: node_path.join(appDirectory, '.output'),
|
|
21
|
+
implicitAliases: [
|
|
22
|
+
{
|
|
23
|
+
aliasName: '@modern-js/prod-server',
|
|
24
|
+
targetName: identity.name,
|
|
25
|
+
targetVersion: identity.version
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const createDeployOutputPublicAssetsPlugin = ()=>({
|
|
33
|
+
name: '@modern-js/deploy-output-public-assets',
|
|
34
|
+
setup (api) {
|
|
35
|
+
api.onAfterDeploy(async ()=>{
|
|
36
|
+
const appContext = api.getAppContext();
|
|
37
|
+
if ('node' !== getDeployingTarget(appContext)) return;
|
|
38
|
+
const { appDirectory } = appContext;
|
|
39
|
+
const config = api.getNormalizedConfig();
|
|
40
|
+
await stageDeclaredPublicAssets({
|
|
41
|
+
appDirectory,
|
|
42
|
+
outputDirectory: node_path.join(appDirectory, '.output'),
|
|
43
|
+
assets: normalizeDeclaredPublicAssets(config.deploy?.node?.publicAssets, NODE_PUBLIC_ASSET_SCOPE),
|
|
44
|
+
scope: NODE_PUBLIC_ASSET_SCOPE
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
export { createDeployOutputAliasesPlugin, createDeployOutputPublicAssetsPlugin };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import promises from "node:fs/promises";
|
|
3
|
+
import node_path from "node:path";
|
|
4
|
+
import { normalizeRelativePath } from "../cloudflare/utils.mjs";
|
|
5
|
+
const DECLARED_PUBLIC_ASSET_DIRECTORY = 'public';
|
|
6
|
+
const CLOUDFLARE_PUBLIC_ASSET_SCOPE = {
|
|
7
|
+
label: 'deploy.worker.publicAssets',
|
|
8
|
+
output: 'Cloudflare public output'
|
|
9
|
+
};
|
|
10
|
+
const NODE_PUBLIC_ASSET_SCOPE = {
|
|
11
|
+
label: 'deploy.node.publicAssets',
|
|
12
|
+
output: 'Node public output'
|
|
13
|
+
};
|
|
14
|
+
const normalizeDeclaredPublicAssets = (assets, scope)=>(assets ?? []).map((asset, index)=>({
|
|
15
|
+
from: normalizeRelativePath(asset?.from, `${scope.label}[${index}].from`, 'app root'),
|
|
16
|
+
to: normalizeRelativePath(asset?.to, `${scope.label}[${index}].to`, scope.output, {
|
|
17
|
+
allowRoot: true
|
|
18
|
+
}),
|
|
19
|
+
index
|
|
20
|
+
}));
|
|
21
|
+
const isMissingPathError = (error)=>error instanceof Error && 'code' in error && 'ENOENT' === error.code;
|
|
22
|
+
const pathExists = async (filePath)=>{
|
|
23
|
+
try {
|
|
24
|
+
await promises.lstat(filePath);
|
|
25
|
+
return true;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (isMissingPathError(error)) return false;
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const listDeclaredPublicAssetFiles = async (appDirectory, assets, scope)=>{
|
|
32
|
+
const files = [];
|
|
33
|
+
const owners = new Map();
|
|
34
|
+
const add = (index, logicalPath)=>{
|
|
35
|
+
const owner = owners.get(logicalPath);
|
|
36
|
+
if (void 0 !== owner) throw new Error(`${scope.label}[${index}] and ${scope.label}[${owner}] both stage ${JSON.stringify(logicalPath)}.`);
|
|
37
|
+
owners.set(logicalPath, index);
|
|
38
|
+
files.push({
|
|
39
|
+
index,
|
|
40
|
+
logicalPath
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const visit = async (asset, sourcePath, destination)=>{
|
|
44
|
+
const stat = await promises.lstat(sourcePath);
|
|
45
|
+
if (stat.isSymbolicLink()) throw new Error(`${scope.label}[${asset.index}].from must not contain symbolic links: ${node_path.relative(appDirectory, sourcePath).replace(/\\/gu, '/')}`);
|
|
46
|
+
if (stat.isFile()) {
|
|
47
|
+
if (destination === DECLARED_PUBLIC_ASSET_DIRECTORY) throw new Error(`${scope.label}[${asset.index}].to must name a file when ${scope.label}[${asset.index}].from is a file.`);
|
|
48
|
+
add(asset.index, destination);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!stat.isDirectory()) throw new Error(`${scope.label}[${asset.index}].from must contain only files and directories: ${node_path.relative(appDirectory, sourcePath).replace(/\\/gu, '/')}`);
|
|
52
|
+
const entries = (await promises.readdir(sourcePath)).sort();
|
|
53
|
+
for (const entry of entries)await visit(asset, node_path.join(sourcePath, entry), node_path.posix.join(destination, entry));
|
|
54
|
+
};
|
|
55
|
+
for (const asset of assets){
|
|
56
|
+
const sourcePath = node_path.join(appDirectory, asset.from);
|
|
57
|
+
if (!await pathExists(sourcePath)) throw new Error(`${scope.label}[${asset.index}].from does not exist: ${asset.from}`);
|
|
58
|
+
await visit(asset, sourcePath, node_path.posix.join(DECLARED_PUBLIC_ASSET_DIRECTORY, asset.to));
|
|
59
|
+
}
|
|
60
|
+
return files;
|
|
61
|
+
};
|
|
62
|
+
const resolveAddedDeclaredPublicAssetPaths = async ({ appDirectory, assets, generatedRoot, scope })=>{
|
|
63
|
+
const added = [];
|
|
64
|
+
for (const file of (await listDeclaredPublicAssetFiles(appDirectory, assets, scope)))if (!await pathExists(node_path.join(generatedRoot, file.logicalPath))) added.push(file.logicalPath);
|
|
65
|
+
return added.sort();
|
|
66
|
+
};
|
|
67
|
+
const stageDeclaredPublicAssets = async ({ appDirectory, outputDirectory, assets, scope })=>{
|
|
68
|
+
const files = await listDeclaredPublicAssetFiles(appDirectory, assets, scope);
|
|
69
|
+
const added = [];
|
|
70
|
+
for (const file of files){
|
|
71
|
+
const asset = assets.find((candidate)=>candidate.index === file.index);
|
|
72
|
+
const relativePath = node_path.posix.relative(node_path.posix.join(DECLARED_PUBLIC_ASSET_DIRECTORY, asset.to), file.logicalPath);
|
|
73
|
+
const destination = node_path.join(outputDirectory, file.logicalPath);
|
|
74
|
+
const replacesGeneratedFile = await pathExists(destination);
|
|
75
|
+
await promises.mkdir(node_path.dirname(destination), {
|
|
76
|
+
recursive: true
|
|
77
|
+
});
|
|
78
|
+
await promises.copyFile(node_path.join(appDirectory, asset.from, relativePath), destination);
|
|
79
|
+
if (!replacesGeneratedFile) added.push(file.logicalPath);
|
|
80
|
+
}
|
|
81
|
+
return added.sort();
|
|
82
|
+
};
|
|
83
|
+
export { CLOUDFLARE_PUBLIC_ASSET_SCOPE, DECLARED_PUBLIC_ASSET_DIRECTORY, NODE_PUBLIC_ASSET_SCOPE, normalizeDeclaredPublicAssets, resolveAddedDeclaredPublicAssetPaths, stageDeclaredPublicAssets };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { getArgv } from "@modern-js/utils";
|
|
3
|
+
import { provider as external_std_env_provider } from "std-env";
|
|
4
|
+
const DEPLOY_TARGETS = [
|
|
5
|
+
'node',
|
|
6
|
+
'vercel',
|
|
7
|
+
'netlify',
|
|
8
|
+
'ghPages',
|
|
9
|
+
'cloudflare'
|
|
10
|
+
];
|
|
11
|
+
const DEPLOY_TARGET_FLAG = '--deploy-target';
|
|
12
|
+
const providerDeployTargets = {
|
|
13
|
+
vercel: 'vercel',
|
|
14
|
+
netlify: 'netlify',
|
|
15
|
+
cloudflare: 'cloudflare',
|
|
16
|
+
cloudflare_pages: 'cloudflare',
|
|
17
|
+
cloudflare_workers: 'cloudflare'
|
|
18
|
+
};
|
|
19
|
+
const readDeployTargetFlag = (argv)=>{
|
|
20
|
+
for (const [index, arg] of argv.entries()){
|
|
21
|
+
if (arg === DEPLOY_TARGET_FLAG) {
|
|
22
|
+
const value = argv[index + 1];
|
|
23
|
+
if (void 0 === value || value.startsWith('-')) throw new Error(`${DEPLOY_TARGET_FLAG} needs a value.`);
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
if (arg.startsWith(`${DEPLOY_TARGET_FLAG}=`)) return arg.slice(DEPLOY_TARGET_FLAG.length + 1);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const assertDeployTarget = (target, source)=>{
|
|
30
|
+
if (!DEPLOY_TARGETS.includes(target)) throw new Error(`Unknown deploy target '${target}' from ${source}. Use one of: ${DEPLOY_TARGETS.join(', ')}.`);
|
|
31
|
+
return target;
|
|
32
|
+
};
|
|
33
|
+
const resolveDeployTarget = ({ argv = getArgv(), configTarget, env = process.env.MODERNJS_DEPLOY, provider = external_std_env_provider } = {})=>{
|
|
34
|
+
const explicit = [
|
|
35
|
+
[
|
|
36
|
+
readDeployTargetFlag(argv),
|
|
37
|
+
DEPLOY_TARGET_FLAG
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
configTarget,
|
|
41
|
+
'deploy.target'
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
env,
|
|
45
|
+
'MODERNJS_DEPLOY'
|
|
46
|
+
]
|
|
47
|
+
].find(([target])=>target);
|
|
48
|
+
if (explicit?.[0]) return {
|
|
49
|
+
target: assertDeployTarget(explicit[0], explicit[1]),
|
|
50
|
+
explicit: true
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
target: provider && providerDeployTargets[provider] || 'node',
|
|
54
|
+
explicit: false
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const getDeployingTarget = ({ deployTarget, metaName })=>deployTarget && ('modern-js' === metaName || deployTarget.explicit) ? deployTarget.target : void 0;
|
|
58
|
+
export { DEPLOY_TARGETS, DEPLOY_TARGET_FLAG, getDeployingTarget, resolveDeployTarget };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import node_os from "node:os";
|
|
3
|
+
import node_path from "node:path";
|
|
4
|
+
import { nodeFileTrace } from "@vercel/nft";
|
|
5
|
+
const SYSTEM_ROOTS = 'win32' === process.platform ? [] : [
|
|
6
|
+
'/dev',
|
|
7
|
+
'/etc',
|
|
8
|
+
'/proc',
|
|
9
|
+
'/run',
|
|
10
|
+
'/sys',
|
|
11
|
+
'/var/run'
|
|
12
|
+
];
|
|
13
|
+
const GLOB_SEGMENT = /[*?[{]/;
|
|
14
|
+
const isInside = (parent, child)=>child === parent || child.startsWith(`${parent}${node_path.sep}`);
|
|
15
|
+
const globRoot = (absolutePattern)=>{
|
|
16
|
+
const { root } = node_path.parse(absolutePattern);
|
|
17
|
+
const segments = absolutePattern.slice(root.length).split(node_path.sep);
|
|
18
|
+
const index = segments.findIndex((segment)=>GLOB_SEGMENT.test(segment));
|
|
19
|
+
return -1 === index ? void 0 : node_path.join(root, ...segments.slice(0, index));
|
|
20
|
+
};
|
|
21
|
+
const createBuildHostIgnore = (base)=>{
|
|
22
|
+
const wholeDirectories = new Set([
|
|
23
|
+
node_path.parse(node_path.resolve(base)).root,
|
|
24
|
+
node_path.resolve(node_os.homedir()),
|
|
25
|
+
node_path.resolve(node_os.tmpdir())
|
|
26
|
+
]);
|
|
27
|
+
return (relativePath)=>{
|
|
28
|
+
const absolutePath = node_path.resolve(base, relativePath);
|
|
29
|
+
if (SYSTEM_ROOTS.some((root)=>isInside(root, absolutePath))) return true;
|
|
30
|
+
const root = globRoot(absolutePath);
|
|
31
|
+
return void 0 !== root && wholeDirectories.has(root);
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const traceDeployFiles = ({ entryFiles, sourceDir, base = '/' })=>nodeFileTrace(entryFiles, {
|
|
35
|
+
base,
|
|
36
|
+
processCwd: sourceDir,
|
|
37
|
+
ignore: createBuildHostIgnore(base)
|
|
38
|
+
});
|
|
39
|
+
export { createBuildHostIgnore, traceDeployFiles };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
4
|
+
import node_path from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { refreshTsgoCheckerConfig } from "@modern-js/builder";
|
|
7
|
+
const execute = promisify(execFile);
|
|
8
|
+
const native_type_checker_name = 'UltramodernNativeTypeChecker';
|
|
9
|
+
const watchDependencyPath = (file)=>{
|
|
10
|
+
if ('win32' !== process.platform) return file;
|
|
11
|
+
try {
|
|
12
|
+
return realpathSync.native(file);
|
|
13
|
+
} catch {
|
|
14
|
+
return file;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
class UltramodernNativeTypeChecker {
|
|
18
|
+
async check() {
|
|
19
|
+
const { configFile, build } = this.options;
|
|
20
|
+
if (!build) {
|
|
21
|
+
const config = JSON.parse(await this.run([
|
|
22
|
+
'--showConfig',
|
|
23
|
+
'--project',
|
|
24
|
+
configFile
|
|
25
|
+
]));
|
|
26
|
+
if (config.references?.length) await this.run([
|
|
27
|
+
'--build',
|
|
28
|
+
...config.references.map((reference)=>node_path.resolve(node_path.dirname(configFile), reference.path)),
|
|
29
|
+
'--stopBuildOnErrors',
|
|
30
|
+
'--pretty',
|
|
31
|
+
'false'
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
const args = build ? [
|
|
35
|
+
'--build',
|
|
36
|
+
configFile,
|
|
37
|
+
'--stopBuildOnErrors'
|
|
38
|
+
] : [
|
|
39
|
+
'--project',
|
|
40
|
+
configFile,
|
|
41
|
+
'--noEmit'
|
|
42
|
+
];
|
|
43
|
+
await this.run([
|
|
44
|
+
...args,
|
|
45
|
+
'--pretty',
|
|
46
|
+
'false'
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
async run(args) {
|
|
50
|
+
try {
|
|
51
|
+
const result = await execute(this.options.compiler(), args, {
|
|
52
|
+
cwd: node_path.dirname(this.options.configFile),
|
|
53
|
+
maxBuffer: 16777216
|
|
54
|
+
});
|
|
55
|
+
return result.stdout;
|
|
56
|
+
} catch (cause) {
|
|
57
|
+
const output = cause;
|
|
58
|
+
const diagnostics = `${output.stdout ?? ''}${output.stderr ?? ''}`;
|
|
59
|
+
throw new Error(`${native_type_checker_name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}`, {
|
|
60
|
+
cause
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async watchInputs() {
|
|
65
|
+
const inputs = new Set();
|
|
66
|
+
const missing = new Set();
|
|
67
|
+
const projects = [
|
|
68
|
+
this.options.configFile
|
|
69
|
+
];
|
|
70
|
+
const visited = new Set();
|
|
71
|
+
for (const configFile of projects){
|
|
72
|
+
if (visited.has(configFile)) continue;
|
|
73
|
+
visited.add(configFile);
|
|
74
|
+
inputs.add(configFile);
|
|
75
|
+
if (!existsSync(configFile)) {
|
|
76
|
+
missing.add(configFile);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
let config;
|
|
80
|
+
try {
|
|
81
|
+
config = JSON.parse(await this.run([
|
|
82
|
+
'--showConfig',
|
|
83
|
+
'--project',
|
|
84
|
+
configFile
|
|
85
|
+
]));
|
|
86
|
+
} catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const directory = node_path.dirname(configFile);
|
|
90
|
+
for (const file of config.files ?? [])inputs.add(node_path.resolve(directory, file));
|
|
91
|
+
for (const reference of config.references ?? []){
|
|
92
|
+
const target = node_path.resolve(directory, reference.path);
|
|
93
|
+
projects.push('.json' === node_path.extname(target) ? target : node_path.join(target, 'tsconfig.json'));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
inputs,
|
|
98
|
+
missing
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
apply(compiler) {
|
|
102
|
+
compiler.hooks.thisCompilation.tap(native_type_checker_name, (compilation)=>{
|
|
103
|
+
compilation.hooks.processAssets.tapPromise(native_type_checker_name, async ()=>{
|
|
104
|
+
try {
|
|
105
|
+
compilation.fileDependencies.add(watchDependencyPath(this.options.configFile));
|
|
106
|
+
const projectConfigFile = refreshTsgoCheckerConfig(this.options.configFile);
|
|
107
|
+
if (projectConfigFile) {
|
|
108
|
+
const watched = watchDependencyPath(projectConfigFile);
|
|
109
|
+
compilation.fileDependencies.add(watched);
|
|
110
|
+
if (!existsSync(projectConfigFile)) compilation.missingDependencies.add(watched);
|
|
111
|
+
}
|
|
112
|
+
const { inputs, missing } = await this.watchInputs();
|
|
113
|
+
for (const file of inputs)compilation.fileDependencies.add(watchDependencyPath(file));
|
|
114
|
+
for (const file of missing)compilation.missingDependencies.add(watchDependencyPath(file));
|
|
115
|
+
await this.check();
|
|
116
|
+
} catch (cause) {
|
|
117
|
+
compilation.errors.push(new Error(cause instanceof Error ? cause.message : String(cause), {
|
|
118
|
+
cause
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
constructor(options){
|
|
125
|
+
this.options = options;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function configureUltramodernTypeChecker(chain, pluginId, resolveCompiler) {
|
|
129
|
+
if (!chain.plugins.has(pluginId)) return;
|
|
130
|
+
const options = chain.plugin(pluginId).get('args')?.[0];
|
|
131
|
+
const typescript = options?.typescript;
|
|
132
|
+
if (typescript?.tsgo === false) return;
|
|
133
|
+
if (!typescript?.configFile) throw new Error(`${native_type_checker_name} requires the configured TypeScript project.`);
|
|
134
|
+
const configFile = node_path.resolve(typescript.configFile);
|
|
135
|
+
chain.plugin(pluginId).use(UltramodernNativeTypeChecker, [
|
|
136
|
+
{
|
|
137
|
+
build: true === typescript.build,
|
|
138
|
+
compiler: ()=>resolveCompiler(configFile),
|
|
139
|
+
configFile
|
|
140
|
+
}
|
|
141
|
+
]);
|
|
142
|
+
}
|
|
143
|
+
export { UltramodernNativeTypeChecker, configureUltramodernTypeChecker };
|