@webiny/build-tools 6.4.11 → 6.6.0-alpha.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/bundling/admin/createRsbuildConfig.js +9 -2
- package/bundling/function/createRsbuildConfig.js +58 -7
- package/bundling/importValidatorPlugin.js +1 -0
- package/package.json +16 -14
- package/packages/buildPackage/rslibCompile.js +5 -3
- package/packages/buildPackage/tsCompile.js +59 -78
- package/packages/buildPackage/typescript/getTscBinaryPath.js +47 -0
- package/packages/buildPackage/typescript/readTsConfig.js +8 -0
- package/packages/buildPackage/typescript/runTsc.js +15 -0
- package/packages/buildPackage/typescript/writeTempTsConfig.js +10 -0
- package/packages/buildPackage.js +1 -1
- package/packages/watchPackage.js +10 -0
- package/testing/presets.d.ts +6 -0
- package/testing/presets.js +162 -0
- package/workspaces/index.js +5 -2
- package/workspaces/linkWorkspaces.js +8 -4
|
@@ -45,7 +45,12 @@ export const createRsbuildConfig = ({ cwd }) => {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
|
-
|
|
48
|
+
// Port precedence matches the served admin app (`webiny serve admin`): an explicit
|
|
49
|
+
// WEBINY_ADMIN_PORT wins, then a PORT injected by the environment, then the 3001 default.
|
|
50
|
+
server: {
|
|
51
|
+
port: process.env.WEBINY_ADMIN_PORT || process.env.PORT || 3001,
|
|
52
|
+
host: "0.0.0.0"
|
|
53
|
+
},
|
|
49
54
|
html: {
|
|
50
55
|
template: paths.projectRootFolder + "/public/index.html"
|
|
51
56
|
},
|
|
@@ -159,7 +164,9 @@ const getEnvVars = () => {
|
|
|
159
164
|
// Provide values one by one, not as a single process.env object,
|
|
160
165
|
// because otherwise plugin will put a big JSON object every time process.env is used in code.
|
|
161
166
|
// This way minifier also removes redundant code on prod (like if(process.env.NODE_ENV === 'development')).
|
|
162
|
-
const envVarsAsStrings = {
|
|
167
|
+
const envVarsAsStrings = {
|
|
168
|
+
"process.env": "{}"
|
|
169
|
+
};
|
|
163
170
|
for (const key of Object.keys(raw)) {
|
|
164
171
|
envVarsAsStrings[`process.env.${key}`] = JSON.stringify(raw[key]);
|
|
165
172
|
}
|
|
@@ -2,7 +2,7 @@ import path from "path";
|
|
|
2
2
|
import { pluginTypeCheck } from "@rsbuild/plugin-type-check";
|
|
3
3
|
import { createImportValidatorPlugin } from "../importValidatorPlugin.js";
|
|
4
4
|
|
|
5
|
-
const DEFAULT_WEBINY_INFRA_API_MAX_BUNDLE_SIZE =
|
|
5
|
+
const DEFAULT_WEBINY_INFRA_API_MAX_BUNDLE_SIZE = 6_291_456; // 6 MB
|
|
6
6
|
|
|
7
7
|
export const createRsbuildConfig = async ({ cwd, enforceMaxBundleSize }) => {
|
|
8
8
|
// Must be a dynamic import — see rslibCompile.js for the reason.
|
|
@@ -10,6 +10,11 @@ export const createRsbuildConfig = async ({ cwd, enforceMaxBundleSize }) => {
|
|
|
10
10
|
const paths = getPaths(cwd);
|
|
11
11
|
const mode = getMode();
|
|
12
12
|
const isDebugEnabled = process.env.DEBUG === "true";
|
|
13
|
+
// NOTE: dirty for now — sniffing the hosting type off an env var here. Ideally the build config
|
|
14
|
+
// wouldn't know about hosting types at all: the caller (createBuildFunction, or the flavour's own
|
|
15
|
+
// build layer) would pass in the externals policy + assetPrefix as options, keeping this file
|
|
16
|
+
// hosting-agnostic. Good enough while the server hosting type is ALPHA; revisit when it settles.
|
|
17
|
+
const isServer = process.env.WEBINY_HOSTING_TYPE === "server";
|
|
13
18
|
|
|
14
19
|
// Configurable via WEBINY_INFRA_API_MAX_BUNDLE_SIZE (bytes).
|
|
15
20
|
// Only enforced during build — watch mode skips size checks.
|
|
@@ -19,12 +24,23 @@ export const createRsbuildConfig = async ({ cwd, enforceMaxBundleSize }) => {
|
|
|
19
24
|
|
|
20
25
|
return /** @type {import("@rsbuild/core").RsbuildConfig} */ ({
|
|
21
26
|
source: { entry: { index: paths.fn.entryFile } },
|
|
27
|
+
// Resolve chunk/asset URLs relative to the running module, not from an absolute root. The
|
|
28
|
+
// server's bg-tasks worker chunk is spawned via `new Worker(new URL("...", import.meta.url))`
|
|
29
|
+
// and rsbuild's default publicPath "/" turns that into an ABSOLUTE url ("/xyz.mjs"), which
|
|
30
|
+
// resolves to the filesystem root and can't be found. "auto" resolves it relative to the module
|
|
31
|
+
// (handler.mjs) instead, so the chunk loads from build/. publicPath comes from
|
|
32
|
+
// `output.assetPrefix` in production and `dev.assetPrefix` in development (watch runs
|
|
33
|
+
// `rsbuild.build({ watch: true })` under NODE_ENV=development), so set BOTH. Not gated to the
|
|
34
|
+
// server hosting type: AWS has no worker chunks so it's a no-op there, and for any other
|
|
35
|
+
// (async import) chunks "auto" is at least as correct as "/" (Lambda runs from its own dir too).
|
|
36
|
+
dev: { assetPrefix: "auto" },
|
|
22
37
|
output: {
|
|
23
38
|
module: true,
|
|
24
39
|
target: "node",
|
|
40
|
+
assetPrefix: "auto",
|
|
25
41
|
minify: true,
|
|
26
42
|
sourceMap: {
|
|
27
|
-
js: isDebugEnabled ? "source-map" : false
|
|
43
|
+
js: isDebugEnabled || mode === "development" ? "source-map" : false
|
|
28
44
|
},
|
|
29
45
|
filename: {
|
|
30
46
|
js: pathData => {
|
|
@@ -41,6 +57,21 @@ export const createRsbuildConfig = async ({ cwd, enforceMaxBundleSize }) => {
|
|
|
41
57
|
},
|
|
42
58
|
tools: {
|
|
43
59
|
rspack: {
|
|
60
|
+
output: {
|
|
61
|
+
// Declares the entry's exports as the bundle's public API, so ALL of them survive.
|
|
62
|
+
//
|
|
63
|
+
// Nothing imports an entry's exports, so without this rspack treats any unused one
|
|
64
|
+
// as dead: it dropped `streamHandler` AND every module reachable only from it. The
|
|
65
|
+
// api bundle then exported just `handler` and contained zero streaming code, so the
|
|
66
|
+
// response-streaming Lambda (`handler.streamHandler`) had no handler to load and
|
|
67
|
+
// failed at cold start. `handler` survived only by accident of being first.
|
|
68
|
+
//
|
|
69
|
+
// To verify after changing anything here, grep the built bundle:
|
|
70
|
+
// .webiny/workspace/apps/api/graphql/build/_handler.mjs
|
|
71
|
+
// It must export BOTH `handler` and `streamHandler`. Removing this line takes the
|
|
72
|
+
// export count back to one — silently, with a green build.
|
|
73
|
+
library: { type: "module" }
|
|
74
|
+
},
|
|
44
75
|
...(enforceMaxBundleSize && {
|
|
45
76
|
performance: {
|
|
46
77
|
hints: "error",
|
|
@@ -48,13 +79,21 @@ export const createRsbuildConfig = async ({ cwd, enforceMaxBundleSize }) => {
|
|
|
48
79
|
maxAssetSize: maxBundleSize
|
|
49
80
|
}
|
|
50
81
|
}),
|
|
51
|
-
|
|
82
|
+
// Both hosting types bundle; externalize only what genuinely can't be bundled.
|
|
83
|
+
// sharp is a native .node binary; knex statically require()s a driver for every SQL
|
|
84
|
+
// dialect (bundling pulls in uninstalled ones) and lazily loads only the configured
|
|
85
|
+
// one at runtime (e.g. better-sqlite3). AWS additionally externalizes aws-sdk (the
|
|
86
|
+
// Lambda runtime provides it). Server ships these in build/node_modules — the build's
|
|
87
|
+
// packaging step (CI/Linux) copies them, natives included.
|
|
88
|
+
externals: isServer
|
|
89
|
+
? [/^sharp$/, /^knex(\/|$)/]
|
|
90
|
+
: [/^@aws-sdk/, /^aws-sdk$/, /^sharp$/, /^knex(\/|$)/],
|
|
52
91
|
plugins: [
|
|
53
|
-
//
|
|
92
|
+
// Ignore optional `canvas` native module required by jsdom.
|
|
54
93
|
// https://rspack.dev/plugins/webpack/ignore-plugin
|
|
55
94
|
new rspack.IgnorePlugin({
|
|
56
|
-
resourceRegExp:
|
|
57
|
-
contextRegExp: /jsdom
|
|
95
|
+
resourceRegExp: /^canvas$/,
|
|
96
|
+
contextRegExp: /jsdom/
|
|
58
97
|
})
|
|
59
98
|
],
|
|
60
99
|
resolve: {
|
|
@@ -63,7 +102,19 @@ export const createRsbuildConfig = async ({ cwd, enforceMaxBundleSize }) => {
|
|
|
63
102
|
// Not needed in Lambda environment and can cause bundling/deployment issues.
|
|
64
103
|
bufferutil: false
|
|
65
104
|
}
|
|
66
|
-
}
|
|
105
|
+
},
|
|
106
|
+
// bree's root-jobs loader does `await import(importUrl)` on a path it builds at runtime,
|
|
107
|
+
// which rspack can't resolve statically, so it reports a critical dependency. That import
|
|
108
|
+
// sits behind `if (this.config.root && ...)` (node_modules/bree/src/index.js), and
|
|
109
|
+
// BreeSchedulerService constructs Bree with `root: false` — the branch never runs, and
|
|
110
|
+
// nothing is missing from the bundle. Matched narrowly so a genuine expression-based
|
|
111
|
+
// import anywhere else still gets reported.
|
|
112
|
+
ignoreWarnings: [
|
|
113
|
+
{
|
|
114
|
+
module: /node_modules[\\/]bree[\\/]/,
|
|
115
|
+
message: /Critical dependency: the request of a dependency is an expression/
|
|
116
|
+
}
|
|
117
|
+
]
|
|
67
118
|
}
|
|
68
119
|
},
|
|
69
120
|
mode,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/build-tools",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -17,22 +17,22 @@
|
|
|
17
17
|
"Adrian Smijulj <adrian@webiny.com>"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@rsbuild/core": "2.1.
|
|
20
|
+
"@rsbuild/core": "2.1.13",
|
|
21
21
|
"@rsbuild/plugin-react": "2.1.0",
|
|
22
22
|
"@rsbuild/plugin-sass": "2.0.1",
|
|
23
23
|
"@rsbuild/plugin-svgr": "2.0.5",
|
|
24
|
-
"@rsbuild/plugin-type-check": "1.
|
|
25
|
-
"@rsdoctor/rspack-plugin": "1.
|
|
24
|
+
"@rsbuild/plugin-type-check": "1.6.0",
|
|
25
|
+
"@rsdoctor/rspack-plugin": "1.6.2",
|
|
26
26
|
"@rslib/core": "0.23.2",
|
|
27
|
-
"@rspack/core": "2.1.
|
|
28
|
-
"@swc/plugin-emotion": "
|
|
29
|
-
"@tailwindcss/postcss": "4.3.
|
|
30
|
-
"
|
|
27
|
+
"@rspack/core": "2.1.10",
|
|
28
|
+
"@swc/plugin-emotion": "15.0.0",
|
|
29
|
+
"@tailwindcss/postcss": "4.3.3",
|
|
30
|
+
"@webiny/stdlib": "0.0.17",
|
|
31
|
+
"chalk": "6.0.0",
|
|
31
32
|
"css-loader": "7.1.4",
|
|
32
33
|
"fast-glob": "3.3.3",
|
|
33
34
|
"find-up": "8.0.0",
|
|
34
|
-
"fs-extra": "11.
|
|
35
|
-
"get-yarn-workspaces": "1.0.2",
|
|
35
|
+
"fs-extra": "11.4.0",
|
|
36
36
|
"load-json-file": "7.0.1",
|
|
37
37
|
"lodash": "4.18.1",
|
|
38
38
|
"postcss-loader": "8.2.1",
|
|
@@ -40,14 +40,16 @@
|
|
|
40
40
|
"react-dom": "18.3.1",
|
|
41
41
|
"react-refresh": "0.18.0",
|
|
42
42
|
"rimraf": "6.1.3",
|
|
43
|
-
"sass": "1.
|
|
43
|
+
"sass": "1.103.1",
|
|
44
44
|
"sass-loader": "17.0.0",
|
|
45
|
+
"strip-json-comments": "5.0.3",
|
|
45
46
|
"style-loader": "4.0.0",
|
|
46
47
|
"ts-morph": "28.0.0",
|
|
47
|
-
"tsx": "4.23.
|
|
48
|
-
"typescript": "
|
|
48
|
+
"tsx": "4.23.12",
|
|
49
|
+
"typescript": "7.0.2",
|
|
49
50
|
"url-loader": "4.1.1",
|
|
50
|
-
"utf-8-validate": "6.0.6"
|
|
51
|
+
"utf-8-validate": "6.0.6",
|
|
52
|
+
"yargs": "18.1.0"
|
|
51
53
|
},
|
|
52
54
|
"license": "MIT",
|
|
53
55
|
"adio": {
|
|
@@ -6,7 +6,9 @@ import glob from "fast-glob";
|
|
|
6
6
|
const COMPILE_EXTENSIONS = [".js", ".jsx", ".ts", ".tsx"];
|
|
7
7
|
const SKIP_EXTENSIONS = [".d.ts"];
|
|
8
8
|
|
|
9
|
-
export const rslibCompile = async ({ cwd }) => {
|
|
9
|
+
export const rslibCompile = async ({ cwd, outputDir }) => {
|
|
10
|
+
const distRoot = outputDir || path.join(cwd, "dist");
|
|
11
|
+
|
|
10
12
|
// Copy non-compilable files (assets, json, graphql, etc.) as-is.
|
|
11
13
|
const pattern = path.join(cwd, "src/**/*.*").replace(/\\/g, "/");
|
|
12
14
|
const allFiles = glob.sync(pattern, { onlyFiles: true, dot: true });
|
|
@@ -16,7 +18,7 @@ export const rslibCompile = async ({ cwd }) => {
|
|
|
16
18
|
const shouldSkip = SKIP_EXTENSIONS.some(ext => file.endsWith(ext));
|
|
17
19
|
|
|
18
20
|
if (!shouldCompile || shouldSkip) {
|
|
19
|
-
const destPath = file.replace(path.join(cwd, "src"),
|
|
21
|
+
const destPath = file.replace(path.join(cwd, "src"), distRoot);
|
|
20
22
|
fs.mkdirSync(dirname(destPath), { recursive: true });
|
|
21
23
|
fs.copyFileSync(file, destPath);
|
|
22
24
|
}
|
|
@@ -44,7 +46,7 @@ export const rslibCompile = async ({ cwd }) => {
|
|
|
44
46
|
},
|
|
45
47
|
output: {
|
|
46
48
|
target: "web",
|
|
47
|
-
distPath: { root: "
|
|
49
|
+
distPath: { root: path.relative(cwd, distRoot) || "." },
|
|
48
50
|
cleanDistPath: false,
|
|
49
51
|
sourceMap: { js: "source-map" },
|
|
50
52
|
// mixedImport emits each SVG as a static asset for the default URL
|
|
@@ -1,99 +1,80 @@
|
|
|
1
|
-
import { join } from "path";
|
|
2
|
-
import
|
|
1
|
+
import { join, resolve } from "path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
3
|
import merge from "lodash/merge.js";
|
|
4
4
|
import { replaceTscAliases } from "./tsAliasReplacer.js";
|
|
5
|
+
import { getTscBinaryPath } from "./typescript/getTscBinaryPath.js";
|
|
6
|
+
import { readTsConfig } from "./typescript/readTsConfig.js";
|
|
7
|
+
import { runTsc } from "./typescript/runTsc.js";
|
|
8
|
+
import { writeTempTsConfig } from "./typescript/writeTempTsConfig.js";
|
|
5
9
|
|
|
6
10
|
export const tsCompile = async ({ cwd = "", overrides, debug, outputDir, checkOnly = false }) => {
|
|
7
|
-
|
|
8
|
-
const
|
|
11
|
+
const normalizedCwd = cwd || process.cwd();
|
|
12
|
+
const tscPath = getTscBinaryPath();
|
|
9
13
|
|
|
10
|
-
const
|
|
14
|
+
const originalConfigPath = join(normalizedCwd, "tsconfig.build.json");
|
|
15
|
+
let tsConfigPath = originalConfigPath;
|
|
16
|
+
let tempConfigPath = null;
|
|
17
|
+
let resolvedOutDir = null;
|
|
11
18
|
|
|
12
|
-
|
|
19
|
+
const hasOverrides = overrides?.tsConfig || outputDir;
|
|
13
20
|
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
readTsConfig = overrides.tsConfig(readTsConfig);
|
|
17
|
-
} else {
|
|
18
|
-
merge(readTsConfig, overrides.tsConfig);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (debug) {
|
|
22
|
-
console.log(`"tsconfig.build.json" overridden. New config:`);
|
|
23
|
-
console.log(readTsConfig);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (outputDir) {
|
|
27
|
-
readTsConfig.compilerOptions = readTsConfig.compilerOptions || {};
|
|
28
|
-
readTsConfig.compilerOptions.outDir = outputDir;
|
|
29
|
-
readTsConfig.compilerOptions.declarationDir = outputDir;
|
|
30
|
-
}
|
|
21
|
+
if (hasOverrides) {
|
|
22
|
+
let config = readTsConfig(originalConfigPath);
|
|
31
23
|
|
|
32
|
-
|
|
24
|
+
if (overrides?.tsConfig) {
|
|
25
|
+
if (typeof overrides.tsConfig === "function") {
|
|
26
|
+
config = overrides.tsConfig(config);
|
|
27
|
+
} else {
|
|
28
|
+
merge(config, overrides.tsConfig);
|
|
29
|
+
}
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
if (debug) {
|
|
32
|
+
console.log(`"tsconfig.build.json" overridden. New config:`);
|
|
33
|
+
console.log(config);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
if (outputDir) {
|
|
38
|
+
config.compilerOptions = config.compilerOptions || {};
|
|
39
|
+
config.compilerOptions.outDir = outputDir;
|
|
40
|
+
config.compilerOptions.declarationDir = outputDir;
|
|
41
|
+
}
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
resolvedOutDir = config.compilerOptions?.outDir;
|
|
44
|
+
tempConfigPath = writeTempTsConfig(normalizedCwd, config);
|
|
45
|
+
tsConfigPath = tempConfigPath;
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
rootNames: filteredFileNames,
|
|
46
|
-
configFileParsingDiagnostics: errors
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
if (checkOnly) {
|
|
50
|
-
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(errors);
|
|
48
|
+
try {
|
|
49
|
+
const args = ["-p", tsConfigPath];
|
|
50
|
+
args.push("--tsBuildInfoFile", join(normalizedCwd, "tsconfig.build.tsbuildinfo"));
|
|
51
51
|
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
getCanonicalFileName: path => path,
|
|
55
|
-
getCurrentDirectory: () => normalizedCwd,
|
|
56
|
-
getNewLine: () => ts.sys.newLine
|
|
57
|
-
};
|
|
58
|
-
const message = ts.formatDiagnostics(allDiagnostics, formatHost);
|
|
59
|
-
if (message) {
|
|
60
|
-
throw { message };
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const { diagnostics, emitSkipped } = program.emit(
|
|
67
|
-
undefined, // targetSourceFile
|
|
68
|
-
(fileName, data, writeByteOrderMark) => {
|
|
69
|
-
// Only emit files within the current package directory.
|
|
70
|
-
// Normalize path separators to handle Windows backslashes vs forward slashes.
|
|
71
|
-
const normalizedFileName = fileName.replace(/\\/g, "/");
|
|
72
|
-
const relativePath = normalizedFileName.replace(normalizedCwd, "");
|
|
73
|
-
if (normalizedFileName.startsWith(normalizedCwd) && !relativePath.includes("../")) {
|
|
74
|
-
ts.sys.writeFile(fileName, data, writeByteOrderMark);
|
|
75
|
-
}
|
|
52
|
+
if (checkOnly) {
|
|
53
|
+
args.push("--noEmit");
|
|
76
54
|
}
|
|
77
|
-
);
|
|
78
55
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
getCanonicalFileName: path => path,
|
|
84
|
-
getCurrentDirectory: () => normalizedCwd,
|
|
85
|
-
getNewLine: () => ts.sys.newLine
|
|
86
|
-
};
|
|
87
|
-
const message = ts.formatDiagnostics(allDiagnostics, formatHost);
|
|
88
|
-
if (message) {
|
|
89
|
-
throw { message };
|
|
56
|
+
runTsc(tscPath, args, normalizedCwd);
|
|
57
|
+
} finally {
|
|
58
|
+
if (tempConfigPath) {
|
|
59
|
+
fs.rmSync(tempConfigPath, { force: true });
|
|
90
60
|
}
|
|
91
61
|
}
|
|
92
62
|
|
|
93
|
-
if (
|
|
94
|
-
|
|
63
|
+
if (!checkOnly) {
|
|
64
|
+
const distDir =
|
|
65
|
+
outputDir || resolveDistDir(normalizedCwd, originalConfigPath, resolvedOutDir);
|
|
66
|
+
await replaceTscAliases({ distDir, cwd: normalizedCwd, debug });
|
|
95
67
|
}
|
|
96
|
-
|
|
97
|
-
const distDir = outputDir || options.outDir || join(normalizedCwd, "dist");
|
|
98
|
-
await replaceTscAliases({ distDir, cwd: normalizedCwd, debug });
|
|
99
68
|
};
|
|
69
|
+
|
|
70
|
+
function resolveDistDir(cwd, configPath, overriddenOutDir) {
|
|
71
|
+
if (overriddenOutDir) {
|
|
72
|
+
return resolve(cwd, overriddenOutDir);
|
|
73
|
+
}
|
|
74
|
+
const config = readTsConfig(configPath);
|
|
75
|
+
const outDir = config.compilerOptions?.outDir;
|
|
76
|
+
if (outDir) {
|
|
77
|
+
return resolve(cwd, outDir);
|
|
78
|
+
}
|
|
79
|
+
return join(cwd, "dist");
|
|
80
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
|
|
5
|
+
let cachedPath = null;
|
|
6
|
+
|
|
7
|
+
export function getTscBinaryPath() {
|
|
8
|
+
if (cachedPath) {
|
|
9
|
+
return cachedPath;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const tsPackageJsonPath = require.resolve("typescript/package.json");
|
|
14
|
+
const tsDir = dirname(tsPackageJsonPath);
|
|
15
|
+
|
|
16
|
+
const platformPackage = "@typescript/typescript-" + process.platform + "-" + process.arch;
|
|
17
|
+
|
|
18
|
+
let platformPkgPath;
|
|
19
|
+
try {
|
|
20
|
+
const platformRequire = createRequire(join(tsDir, "package.json"));
|
|
21
|
+
platformPkgPath = platformRequire.resolve(platformPackage + "/package.json");
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error(
|
|
24
|
+
"Unable to resolve " +
|
|
25
|
+
platformPackage +
|
|
26
|
+
". " +
|
|
27
|
+
"Either your platform is unsupported, or you are missing the package on disk."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const libDir = join(dirname(platformPkgPath), "lib");
|
|
32
|
+
|
|
33
|
+
let exe = join(libDir, "tsc");
|
|
34
|
+
if (process.platform === "win32") {
|
|
35
|
+
exe += ".exe";
|
|
36
|
+
if (exe.length >= 248) {
|
|
37
|
+
exe = "\\\\?\\" + exe;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(exe)) {
|
|
42
|
+
throw new Error("TypeScript native binary not found: " + exe);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
cachedPath = exe;
|
|
46
|
+
return cachedPath;
|
|
47
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import stripJsonComments from "strip-json-comments";
|
|
3
|
+
|
|
4
|
+
export function readTsConfig(configPath) {
|
|
5
|
+
const content = fs.readFileSync(configPath, "utf8");
|
|
6
|
+
const stripped = stripJsonComments(content, { trailingCommas: true });
|
|
7
|
+
return JSON.parse(stripped);
|
|
8
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
export function runTsc(tscPath, args, cwd) {
|
|
4
|
+
try {
|
|
5
|
+
execFileSync(tscPath, args, {
|
|
6
|
+
cwd,
|
|
7
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
8
|
+
encoding: "utf8",
|
|
9
|
+
maxBuffer: 10 * 1024 * 1024
|
|
10
|
+
});
|
|
11
|
+
} catch (error) {
|
|
12
|
+
const output = [error.stdout, error.stderr].filter(Boolean).join("\n").trim();
|
|
13
|
+
throw { message: output || error.message || "TypeScript compilation failed." };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
|
|
5
|
+
export function writeTempTsConfig(cwd, config) {
|
|
6
|
+
const suffix = randomBytes(4).toString("hex");
|
|
7
|
+
const tempPath = join(cwd, `tsconfig.build.tmp-${suffix}.json`);
|
|
8
|
+
fs.writeFileSync(tempPath, JSON.stringify(config, null, 2), "utf8");
|
|
9
|
+
return tempPath;
|
|
10
|
+
}
|
package/packages/buildPackage.js
CHANGED
|
@@ -69,7 +69,7 @@ async function buildWithSafeReplace(options, distDir) {
|
|
|
69
69
|
|
|
70
70
|
const stagingOptions = { ...options, outputDir: stagingDir };
|
|
71
71
|
|
|
72
|
-
await
|
|
72
|
+
await rslibCompile(stagingOptions);
|
|
73
73
|
await tsCompile(stagingOptions);
|
|
74
74
|
|
|
75
75
|
stagingOptions.logs !== false && console.log("Copying meta files...");
|
package/packages/watchPackage.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
1
4
|
export default async options => {
|
|
2
5
|
const { cwd } = options;
|
|
3
6
|
|
|
7
|
+
// Invalidate the build-cache freshness marker (see scripts/buildPackages
|
|
8
|
+
// distBuildHash.ts, ".webiny-build-hash"). Watch writes into dist without
|
|
9
|
+
// updating that marker, so its contents no longer match the last full
|
|
10
|
+
// build — a later `yarn build` must restore/rebuild instead of trusting the
|
|
11
|
+
// marker and skipping the cache→dist copy.
|
|
12
|
+
fs.rmSync(join(cwd, "dist", ".webiny-build-hash"), { force: true });
|
|
13
|
+
|
|
4
14
|
// Must be a dynamic import — see rslibCompile.js for the reason.
|
|
5
15
|
const [{ createRslib }, { pluginSvgr }] = await Promise.all([
|
|
6
16
|
import("@rslib/core"),
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { listWorkspaces } from "@webiny/stdlib/node";
|
|
4
|
+
import yargs from "yargs";
|
|
5
|
+
import { hideBin } from "yargs/helpers";
|
|
6
|
+
import { PackageJson } from "@webiny/build-tools/utils/PackageJson.js";
|
|
7
|
+
|
|
8
|
+
const MIN_STORAGE_LENGTH = 1;
|
|
9
|
+
const DEFAULT_STORAGE = "ddb";
|
|
10
|
+
/**
|
|
11
|
+
* @param argv {string[]}
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
14
|
+
const getStorage = argv => {
|
|
15
|
+
/**
|
|
16
|
+
* Storage is available in process.env?
|
|
17
|
+
*/
|
|
18
|
+
const envValue = process.env.WEBINY_STORAGE;
|
|
19
|
+
if (typeof envValue === "string" && envValue.length > 2) {
|
|
20
|
+
return envValue;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This is if storage is available in args.
|
|
24
|
+
*/
|
|
25
|
+
const args = yargs(argv);
|
|
26
|
+
const argsValue = args.storage;
|
|
27
|
+
if (typeof argsValue === "string" && argsValue.length > 2) {
|
|
28
|
+
return argsValue;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Then we try to get --storage=([a-z])
|
|
32
|
+
*/
|
|
33
|
+
const matched = argv
|
|
34
|
+
.map(item => {
|
|
35
|
+
const matched = item.match(/^--storage=([^\s]+)$/);
|
|
36
|
+
return matched ? matched[1] : null;
|
|
37
|
+
})
|
|
38
|
+
.find(item => {
|
|
39
|
+
return !!item;
|
|
40
|
+
});
|
|
41
|
+
if (typeof matched === "string" && matched.length > MIN_STORAGE_LENGTH) {
|
|
42
|
+
return matched;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Last attempt is to find --storage and then take next index.
|
|
46
|
+
*/
|
|
47
|
+
const index = argv.findIndex(item => {
|
|
48
|
+
return item === "--storage";
|
|
49
|
+
});
|
|
50
|
+
if (index === -1) {
|
|
51
|
+
return DEFAULT_STORAGE;
|
|
52
|
+
}
|
|
53
|
+
const value = argv[index + 1];
|
|
54
|
+
if (typeof value === "string" && value.length > MIN_STORAGE_LENGTH) {
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
return DEFAULT_STORAGE;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const getAllPackages = targetKeywords => {
|
|
61
|
+
const storage = getStorage(hideBin(process.argv));
|
|
62
|
+
|
|
63
|
+
if (!storage) {
|
|
64
|
+
throw Error(`Missing required --storage parameter!`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Set the storage type as an environment variable.
|
|
68
|
+
process.env.WEBINY_STORAGE_OPS = storage;
|
|
69
|
+
|
|
70
|
+
const storagePriority = storage.split(",");
|
|
71
|
+
|
|
72
|
+
const packages = listWorkspaces({
|
|
73
|
+
cwd: process.cwd()
|
|
74
|
+
})
|
|
75
|
+
.map(pkg => {
|
|
76
|
+
return pkg.path.replace(/\\/g, "/");
|
|
77
|
+
})
|
|
78
|
+
.filter(pkg => pkg.match(/\/packages\//) !== null);
|
|
79
|
+
|
|
80
|
+
// Find packages that match the given sets of tags.
|
|
81
|
+
const packageJsons = [];
|
|
82
|
+
for (const pkg of packages) {
|
|
83
|
+
const pkgJson = PackageJson.fromFile(pkg + "/package.json");
|
|
84
|
+
const { name, keywords = [] } = pkgJson.getJson();
|
|
85
|
+
|
|
86
|
+
for (const set of targetKeywords) {
|
|
87
|
+
if (set.every(tag => keywords.includes(tag))) {
|
|
88
|
+
packageJsons.push({
|
|
89
|
+
path: pkg,
|
|
90
|
+
name,
|
|
91
|
+
keywords
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Now we need to filter based on the required storage type, but also use fallback, if possible.
|
|
97
|
+
const results = [];
|
|
98
|
+
|
|
99
|
+
for (const set of targetKeywords) {
|
|
100
|
+
for (const storage of storagePriority) {
|
|
101
|
+
const matchingPackage = packageJsons.find(pkg => {
|
|
102
|
+
return [...set, storage].every(tag => pkg.keywords.includes(tag));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (matchingPackage) {
|
|
106
|
+
results.push(matchingPackage);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return results;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const removeEmptyPreset = preset => {
|
|
116
|
+
if (!preset || Object.keys(preset).length === 0) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const getPackagesPresets = async targetKeywords => {
|
|
123
|
+
if (!targetKeywords || targetKeywords.length === 0) {
|
|
124
|
+
throw new Error(`You must pass keywords to search for in the packages.`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!Array.isArray(targetKeywords[0])) {
|
|
128
|
+
targetKeywords = [targetKeywords];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const packages = getAllPackages(targetKeywords);
|
|
132
|
+
if (packages.length === 0) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
const items = [];
|
|
136
|
+
/**
|
|
137
|
+
* We go through all available packages to build presets for them.
|
|
138
|
+
*/
|
|
139
|
+
for (const pkg of packages) {
|
|
140
|
+
const presetsPath = path.join(pkg.path, "__tests__/__api__/presets.js");
|
|
141
|
+
if (!fs.existsSync(presetsPath)) {
|
|
142
|
+
throw new Error(`Missing presets.js of the "${pkg.name}" package: ${presetsPath}`);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* We expect presets file to contain an array of presets.
|
|
146
|
+
* We do not check for the actual contents of the presets arrays since they can be quite different per package.
|
|
147
|
+
*/
|
|
148
|
+
const presets = await import(presetsPath).then(m => m.default ?? m);
|
|
149
|
+
if (Array.isArray(presets) === false) {
|
|
150
|
+
throw new Error(`Presets in package "${pkg.name}" must be defined as an array.`);
|
|
151
|
+
} else if (presets.length === 0) {
|
|
152
|
+
throw new Error(`There are no presets in the file "${presetsPath}".`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
items.push(...presets.filter(removeEmptyPreset));
|
|
156
|
+
}
|
|
157
|
+
return items;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const getPresets = async (...targetKeywords) => {
|
|
161
|
+
return getPackagesPresets(targetKeywords);
|
|
162
|
+
};
|
package/workspaces/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import
|
|
3
|
+
import { listWorkspaces } from "@webiny/stdlib/node";
|
|
4
4
|
export { linkWorkspaces } from "./linkWorkspaces";
|
|
5
5
|
|
|
6
6
|
const hasPackageJson = p => fs.existsSync(p + "/package.json");
|
|
7
7
|
|
|
8
8
|
export const allWorkspaces = () => {
|
|
9
|
-
return
|
|
9
|
+
return listWorkspaces()
|
|
10
|
+
.map(pkg => {
|
|
11
|
+
return pkg.path;
|
|
12
|
+
})
|
|
10
13
|
.filter(hasPackageJson)
|
|
11
14
|
.map(pkg => pkg.replace(/\//g, path.sep));
|
|
12
15
|
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import "tsx";
|
|
8
|
-
|
|
8
|
+
import { listWorkspaces } from "@webiny/stdlib/node";
|
|
9
9
|
import path from "path";
|
|
10
10
|
import get from "lodash/get.js";
|
|
11
11
|
import fs from "fs-extra";
|
|
@@ -56,9 +56,13 @@ export const linkWorkspaces = async ({ whitelist, blacklist } = defaults) => {
|
|
|
56
56
|
whitelist = (whitelist || []).map(p => path.resolve(p));
|
|
57
57
|
blacklist = (blacklist || []).map(p => path.resolve(p));
|
|
58
58
|
// Filter packages to only those in the whitelisted folders
|
|
59
|
-
|
|
60
|
-
const packages =
|
|
61
|
-
|
|
59
|
+
|
|
60
|
+
const packages = listWorkspaces({
|
|
61
|
+
cwd: process.cwd()
|
|
62
|
+
})
|
|
63
|
+
.map(pkg => {
|
|
64
|
+
return pkg.path.replace(/\//g, path.sep);
|
|
65
|
+
})
|
|
62
66
|
.filter(pkg => {
|
|
63
67
|
const isBlacklisted = blacklist.some(b => pkg.startsWith(b));
|
|
64
68
|
if (isBlacklisted) {
|