@webiny/build-tools 0.0.0-unstable.7be00a75a9 → 0.0.0-unstable.9f53ea597d

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.
@@ -8,7 +8,7 @@ export const createBuildFunction =
8
8
 
9
9
  // Must be a dynamic import — see rslibCompile.js for the reason.
10
10
  const { createRsbuild } = await import("@rsbuild/core");
11
- const rsbuildConfig = await createRsbuildConfig({ cwd });
11
+ const rsbuildConfig = await createRsbuildConfig({ cwd, enforceMaxBundleSize: true });
12
12
 
13
13
  const rsbuild = await createRsbuild({ rsbuildConfig });
14
14
 
@@ -4,7 +4,7 @@ import { createImportValidatorPlugin } from "../importValidatorPlugin.js";
4
4
 
5
5
  const DEFAULT_WEBINY_INFRA_API_MAX_BUNDLE_SIZE = 4_718_592; // 4.5 MB
6
6
 
7
- export const createRsbuildConfig = async ({ cwd }) => {
7
+ export const createRsbuildConfig = async ({ cwd, enforceMaxBundleSize }) => {
8
8
  // Must be a dynamic import — see rslibCompile.js for the reason.
9
9
  const { default: rspack } = await import("@rspack/core");
10
10
  const paths = getPaths(cwd);
@@ -12,6 +12,7 @@ export const createRsbuildConfig = async ({ cwd }) => {
12
12
  const isDebugEnabled = process.env.DEBUG === "true";
13
13
 
14
14
  // Configurable via WEBINY_INFRA_API_MAX_BUNDLE_SIZE (bytes).
15
+ // Only enforced during build — watch mode skips size checks.
15
16
  const maxBundleSize =
16
17
  parseInt(process.env.WEBINY_INFRA_API_MAX_BUNDLE_SIZE) ||
17
18
  DEFAULT_WEBINY_INFRA_API_MAX_BUNDLE_SIZE;
@@ -23,7 +24,7 @@ export const createRsbuildConfig = async ({ cwd }) => {
23
24
  target: "node",
24
25
  minify: true,
25
26
  sourceMap: {
26
- js: isDebugEnabled ? "source-map" : false
27
+ js: isDebugEnabled || mode === "development" ? "source-map" : false
27
28
  },
28
29
  filename: {
29
30
  js: pathData => {
@@ -40,18 +41,33 @@ export const createRsbuildConfig = async ({ cwd }) => {
40
41
  },
41
42
  tools: {
42
43
  rspack: {
43
- performance: {
44
- hints: "error",
45
- maxEntrypointSize: maxBundleSize,
46
- maxAssetSize: maxBundleSize
47
- },
48
- externals: [/^@aws-sdk/, /^aws-sdk$/, /^sharp$/],
44
+ ...(enforceMaxBundleSize && {
45
+ performance: {
46
+ hints: "error",
47
+ maxEntrypointSize: maxBundleSize,
48
+ maxAssetSize: maxBundleSize
49
+ }
50
+ }),
51
+ externals: [
52
+ /^@aws-sdk/,
53
+ /^aws-sdk$/,
54
+ /^sharp$/,
55
+ // knex is a runtime-polymorphic package: its source statically require()s a
56
+ // driver for EVERY SQL dialect (pg, mysql, mariadb, mssql, sqlite, ...) and
57
+ // picks one at runtime from the configured `client`. Bundling it forces the
58
+ // bundler to resolve drivers that aren't installed (the mariadb/tedious/pg
59
+ // "Module not found" errors). The server flavour runs as a Node process with
60
+ // node_modules present, so we externalize knex and let Node load it — knex then
61
+ // lazily require()s ONLY the configured dialect's driver (e.g. better-sqlite3),
62
+ // never the others.
63
+ /^knex(\/|$)/
64
+ ],
49
65
  plugins: [
50
- // This is necessary to enable JSDOM usage in Lambda.
66
+ // Ignore optional `canvas` native module required by jsdom.
51
67
  // https://rspack.dev/plugins/webpack/ignore-plugin
52
68
  new rspack.IgnorePlugin({
53
- resourceRegExp: /canvas/,
54
- contextRegExp: /jsdom$/
69
+ resourceRegExp: /^canvas$/,
70
+ contextRegExp: /jsdom/
55
71
  })
56
72
  ],
57
73
  resolve: {
@@ -7,7 +7,7 @@ export const createWatchFunction =
7
7
 
8
8
  // Must be a dynamic import — see rslibCompile.js for the reason.
9
9
  const { createRsbuild } = await import("@rsbuild/core");
10
- const rsbuildConfig = await createRsbuildConfig({ cwd });
10
+ const rsbuildConfig = await createRsbuildConfig({ cwd, enforceMaxBundleSize: false });
11
11
 
12
12
  const rsbuild = await createRsbuild({ rsbuildConfig });
13
13
 
@@ -5,7 +5,17 @@ const cyan = "\x1b[36m";
5
5
  const reset = "\x1b[0m";
6
6
  const bold = "\x1b[1m";
7
7
 
8
- const whitelist = ["@webiny/cognito", "@webiny/auth0", "@webiny/okta", "@webiny/plugins"];
8
+ const whitelist = [
9
+ "@webiny/cognito",
10
+ "@webiny/auth0",
11
+ "@webiny/okta",
12
+ "@webiny/plugins",
13
+ "@webiny/sdk",
14
+ "@webiny/stdlib",
15
+ "@webiny/lexical-converter",
16
+ "@webiny/lexical-nodes",
17
+ "@webiny/lexical-theme"
18
+ ];
9
19
 
10
20
  export const createImportValidatorPlugin = () => {
11
21
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/build-tools",
3
- "version": "0.0.0-unstable.7be00a75a9",
3
+ "version": "0.0.0-unstable.9f53ea597d",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -17,20 +17,21 @@
17
17
  "Adrian Smijulj <adrian@webiny.com>"
18
18
  ],
19
19
  "dependencies": {
20
- "@rsbuild/core": "2.0.6",
21
- "@rsbuild/plugin-react": "2.0.0",
22
- "@rsbuild/plugin-sass": "1.5.2",
23
- "@rsbuild/plugin-svgr": "2.0.2",
24
- "@rsbuild/plugin-type-check": "1.3.4",
25
- "@rslib/core": "0.21.5",
26
- "@rspack/core": "2.0.3",
27
- "@swc/plugin-emotion": "14.9.0",
28
- "@tailwindcss/postcss": "4.3.0",
20
+ "@rsbuild/core": "2.1.7",
21
+ "@rsbuild/plugin-react": "2.1.0",
22
+ "@rsbuild/plugin-sass": "2.0.1",
23
+ "@rsbuild/plugin-svgr": "2.0.5",
24
+ "@rsbuild/plugin-type-check": "1.5.0",
25
+ "@rsdoctor/rspack-plugin": "1.6.1",
26
+ "@rslib/core": "0.23.2",
27
+ "@rspack/core": "2.1.5",
28
+ "@swc/plugin-emotion": "14.15.0",
29
+ "@tailwindcss/postcss": "4.3.3",
29
30
  "chalk": "5.6.2",
30
31
  "css-loader": "7.1.4",
31
32
  "fast-glob": "3.3.3",
32
33
  "find-up": "8.0.0",
33
- "fs-extra": "11.3.5",
34
+ "fs-extra": "11.3.6",
34
35
  "get-yarn-workspaces": "1.0.2",
35
36
  "load-json-file": "7.0.1",
36
37
  "lodash": "4.18.1",
@@ -39,12 +40,13 @@
39
40
  "react-dom": "18.3.1",
40
41
  "react-refresh": "0.18.0",
41
42
  "rimraf": "6.1.3",
42
- "sass": "1.99.0",
43
+ "sass": "1.101.3",
43
44
  "sass-loader": "17.0.0",
45
+ "strip-json-comments": "5.0.3",
44
46
  "style-loader": "4.0.0",
45
47
  "ts-morph": "28.0.0",
46
- "tsx": "4.21.0",
47
- "typescript": "6.0.3",
48
+ "tsx": "4.23.1",
49
+ "typescript": "7.0.2",
48
50
  "url-loader": "4.1.1",
49
51
  "utf-8-validate": "6.0.6"
50
52
  },
@@ -68,7 +70,8 @@
68
70
  "bufferutil",
69
71
  "utf-8-validate",
70
72
  "css-loader",
71
- "url-loader"
73
+ "url-loader",
74
+ "@rsdoctor/rspack-plugin"
72
75
  ]
73
76
  }
74
77
  },
@@ -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"), path.join(cwd, "dist"));
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: "./dist" },
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 ts from "typescript";
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
- // Normalize path separators to forward slashes for consistent behavior on Windows.
8
- const normalizedCwd = cwd.replace(/\\/g, "/");
11
+ const normalizedCwd = cwd || process.cwd();
12
+ const tscPath = getTscBinaryPath();
9
13
 
10
- const tsConfigPath = join(normalizedCwd, "tsconfig.build.json");
14
+ const originalConfigPath = join(normalizedCwd, "tsconfig.build.json");
15
+ let tsConfigPath = originalConfigPath;
16
+ let tempConfigPath = null;
17
+ let resolvedOutDir = null;
11
18
 
12
- let { config: readTsConfig } = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
19
+ const hasOverrides = overrides?.tsConfig || outputDir;
13
20
 
14
- if (overrides.tsConfig) {
15
- if (typeof overrides.tsConfig === "function") {
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
- const parsedJsonConfigFile = ts.parseJsonConfigFileContent(readTsConfig, ts.sys, normalizedCwd);
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
- const { projectReferences, options, fileNames, errors } = parsedJsonConfigFile;
31
+ if (debug) {
32
+ console.log(`"tsconfig.build.json" overridden. New config:`);
33
+ console.log(config);
34
+ }
35
+ }
35
36
 
36
- const filteredFileNames = fileNames.filter(fileName => !fileName.endsWith(".d.ts"));
37
+ if (outputDir) {
38
+ config.compilerOptions = config.compilerOptions || {};
39
+ config.compilerOptions.outDir = outputDir;
40
+ config.compilerOptions.declarationDir = outputDir;
41
+ }
37
42
 
38
- if (checkOnly) {
39
- options.noEmit = true;
43
+ resolvedOutDir = config.compilerOptions?.outDir;
44
+ tempConfigPath = writeTempTsConfig(normalizedCwd, config);
45
+ tsConfigPath = tempConfigPath;
40
46
  }
41
47
 
42
- const program = ts.createProgram({
43
- projectReferences,
44
- options,
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 (allDiagnostics.length) {
53
- const formatHost = {
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
- const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(diagnostics, errors);
80
-
81
- if (allDiagnostics.length) {
82
- const formatHost = {
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 (emitSkipped) {
94
- throw { message: "TypeScript compilation failed." };
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
+ }
@@ -69,7 +69,7 @@ async function buildWithSafeReplace(options, distDir) {
69
69
 
70
70
  const stagingOptions = { ...options, outputDir: stagingDir };
71
71
 
72
- await babelCompile(stagingOptions);
72
+ await rslibCompile(stagingOptions);
73
73
  await tsCompile(stagingOptions);
74
74
 
75
75
  stagingOptions.logs !== false && console.log("Copying meta files...");