@savvy-web/github-action-builder 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/github-action-builder.js +1 -1
- package/cli/commands/init.js +1 -1
- package/index.d.ts +26 -0
- package/loaders/webpack-ignore-dynamic-imports.cjs +100 -0
- package/package.json +3 -2
- package/schemas/config.js +14 -2
- package/services/build-live.js +26 -1
- package/services/native-dynamic-imports.js +65 -0
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Build a GitHub Action from TypeScript source without writing build config. The b
|
|
|
11
11
|
- **No build config required** - Picks up entry points from `src/main.ts`, `src/pre.ts`, `src/post.ts` on its own
|
|
12
12
|
- **Node.js 24** - Emits ESM actions that run on the `node24` GitHub Actions runtime
|
|
13
13
|
- **Schema validation** - Validates `action.yml` against GitHub's official metadata specification
|
|
14
|
-
- **Single-file bundles** - All npm dependencies inlined via rsbuild; `node:` builtins externalized; user-configured `externals` and `
|
|
14
|
+
- **Single-file bundles** - All npm dependencies inlined via rsbuild; `node:` builtins externalized; user-configured `externals`, `ignore` and `nativeDynamicImports` options for native modules, optional dependencies and runtime-resolved dynamic imports
|
|
15
15
|
- **Local testing** - Auto-persists build output for testing with [nektos/act](https://github.com/nektos/act)
|
|
16
16
|
- **CI-aware** - Strict validation in CI, warnings-only locally
|
|
17
17
|
|
|
@@ -26,7 +26,7 @@ const rootCommand = Command.make("github-action-builder").pipe(Command.withSubco
|
|
|
26
26
|
*/
|
|
27
27
|
const cli = Command.run(rootCommand, {
|
|
28
28
|
name: "github-action-builder",
|
|
29
|
-
version: "1.0
|
|
29
|
+
version: "1.1.0"
|
|
30
30
|
});
|
|
31
31
|
/**
|
|
32
32
|
* Combined layer: AppLayer + NodeContext for CLI.
|
package/cli/commands/init.js
CHANGED
|
@@ -20,7 +20,7 @@ const forceOption = Options.boolean("force").pipe(Options.withAlias("f"), Option
|
|
|
20
20
|
* Get current package version (replaced at build time).
|
|
21
21
|
*/
|
|
22
22
|
const getPackageVersion = () => {
|
|
23
|
-
return "1.0
|
|
23
|
+
return "1.1.0";
|
|
24
24
|
};
|
|
25
25
|
/**
|
|
26
26
|
* Generate package.json content.
|
package/index.d.ts
CHANGED
|
@@ -51,6 +51,18 @@ declare const BuildOptionsSchema: Schema.Struct<{
|
|
|
51
51
|
ignore: Schema.optionalWith<Schema.Array$<typeof Schema.String>, {
|
|
52
52
|
default: () => never[];
|
|
53
53
|
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Packages whose dynamic `import(...)` calls must stay native `import()` at runtime instead of
|
|
56
|
+
* being compiled into an rspack context module. Use this for packages that resolve a module path
|
|
57
|
+
* at runtime (e.g. from a config value or a computed changelog id) and dynamically import it —
|
|
58
|
+
* rspack cannot statically analyze a fully dynamic `import(expr)`, so it emits an empty-context
|
|
59
|
+
* stub that throws `Cannot find module` at runtime even though the file exists on disk. Listing
|
|
60
|
+
* the package here injects a `webpackIgnore` comment into its dynamic imports so rspack leaves
|
|
61
|
+
* them alone. Defaults to [].
|
|
62
|
+
*/
|
|
63
|
+
nativeDynamicImports: Schema.optionalWith<Schema.Array$<typeof Schema.String>, {
|
|
64
|
+
default: () => never[];
|
|
65
|
+
}>;
|
|
54
66
|
}>;
|
|
55
67
|
/**
|
|
56
68
|
* Build options for the bundler.
|
|
@@ -127,6 +139,7 @@ declare const ConfigInputSchema: Schema.Struct<{
|
|
|
127
139
|
sourceMap: Schema.optional<typeof Schema.Boolean>;
|
|
128
140
|
externals: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
129
141
|
ignore: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
142
|
+
nativeDynamicImports: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
130
143
|
}>>;
|
|
131
144
|
validation: Schema.optional<Schema.Struct<{
|
|
132
145
|
requireActionYml: Schema.optional<typeof Schema.Boolean>;
|
|
@@ -176,6 +189,18 @@ declare const ConfigSchema: Schema.Struct<{
|
|
|
176
189
|
ignore: Schema.optionalWith<Schema.Array$<typeof Schema.String>, {
|
|
177
190
|
default: () => never[];
|
|
178
191
|
}>;
|
|
192
|
+
/**
|
|
193
|
+
* Packages whose dynamic `import(...)` calls must stay native `import()` at runtime instead of
|
|
194
|
+
* being compiled into an rspack context module. Use this for packages that resolve a module path
|
|
195
|
+
* at runtime (e.g. from a config value or a computed changelog id) and dynamically import it —
|
|
196
|
+
* rspack cannot statically analyze a fully dynamic `import(expr)`, so it emits an empty-context
|
|
197
|
+
* stub that throws `Cannot find module` at runtime even though the file exists on disk. Listing
|
|
198
|
+
* the package here injects a `webpackIgnore` comment into its dynamic imports so rspack leaves
|
|
199
|
+
* them alone. Defaults to [].
|
|
200
|
+
*/
|
|
201
|
+
nativeDynamicImports: Schema.optionalWith<Schema.Array$<typeof Schema.String>, {
|
|
202
|
+
default: () => never[];
|
|
203
|
+
}>;
|
|
179
204
|
}>;
|
|
180
205
|
validation: Schema.Struct<{
|
|
181
206
|
/** Require action.yml to exist and be valid. Defaults to true. */requireActionYml: Schema.optionalWith<typeof Schema.Boolean, {
|
|
@@ -247,6 +272,7 @@ type Config = typeof ConfigSchema.Type;
|
|
|
247
272
|
* sourceMap: true,
|
|
248
273
|
* externals: ["@aws-sdk/client-s3"],
|
|
249
274
|
* ignore: ["libxmljs2"],
|
|
275
|
+
* nativeDynamicImports: ["@changesets/apply-release-plan"],
|
|
250
276
|
* },
|
|
251
277
|
* validation: {
|
|
252
278
|
* requireActionYml: true,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* rspack loader that injects the `webpackIgnore` magic comment into dynamic
|
|
5
|
+
* `import(...)` calls whose argument is not a string literal (or is a
|
|
6
|
+
* template literal that isn't fully static).
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* rspack compiles a fully dynamic `import(expr)` (an argument it cannot
|
|
10
|
+
* statically resolve to a literal path) into a "context module" — a stub
|
|
11
|
+
* that globs a directory at build time and throws `Cannot find module` at
|
|
12
|
+
* runtime for any path it didn't see, even when the real file exists on
|
|
13
|
+
* disk. Some third-party packages (e.g. `@changesets/apply-release-plan`)
|
|
14
|
+
* resolve a module path at runtime and dynamically import it; bundling that
|
|
15
|
+
* call as a context module breaks it. The same is true of an *interpolated*
|
|
16
|
+
* template literal — `` import(`./x/${y}.js`) `` compiles to the same
|
|
17
|
+
* context-module stub as a bare identifier, because rspack cannot statically
|
|
18
|
+
* resolve the interpolated segment either.
|
|
19
|
+
*
|
|
20
|
+
* rspack (like webpack) respects a `/* webpackIgnore: true *\/` comment
|
|
21
|
+
* immediately inside the `import(` call — it skips context-module analysis
|
|
22
|
+
* for that call and leaves a plain, native, runtime `import()` in the
|
|
23
|
+
* output. This loader is a pure string transform (no AST parsing, so no
|
|
24
|
+
* source-map chaining — the returned source is treated as a 1:1 replacement
|
|
25
|
+
* and any pre-existing source map for this file is not remapped) that runs
|
|
26
|
+
* in two passes:
|
|
27
|
+
*
|
|
28
|
+
* 1. Inject the comment into any `import(` call whose argument is not a
|
|
29
|
+
* string literal, not a backtick template literal (handled in pass 2),
|
|
30
|
+
* and does not already carry a `webpackIgnore` magic comment. A
|
|
31
|
+
* *different* leading magic comment (e.g. `webpackChunkName`) does not
|
|
32
|
+
* suppress injection — the ignore comment is prepended alongside it, so
|
|
33
|
+
* both survive: `import(/* webpackIgnore: true *\/ /* webpackChunkName:
|
|
34
|
+
* "x" *\/ ident)`.
|
|
35
|
+
* 2. Inject the comment into a backtick template-literal argument, but only
|
|
36
|
+
* when it contains `${` interpolation. A fully static template literal
|
|
37
|
+
* (e.g. `` import(`./static.js`) ``) compiles to a literal path just like
|
|
38
|
+
* a plain string, so it is left untouched. Finding the template
|
|
39
|
+
* literal's closing backtick is a pragmatic linear scan (skipping
|
|
40
|
+
* backslash-escaped characters), not a real parser: it does not track
|
|
41
|
+
* nested template literals inside an interpolation (e.g.
|
|
42
|
+
* `` import(`${`nested`}`) ``) and will stop at the first unescaped
|
|
43
|
+
* backtick it sees, which is a documented limitation of this non-AST
|
|
44
|
+
* heuristic.
|
|
45
|
+
*
|
|
46
|
+
* Deliberately skipped (left untouched):
|
|
47
|
+
* - `import("./static.js")` — a string-literal import; the bundler already
|
|
48
|
+
* resolves and bundles these correctly, no need to touch them.
|
|
49
|
+
* - `` import(`./static.js`) `` — a fully static template literal; same
|
|
50
|
+
* reasoning as a plain string (see pass 2 above).
|
|
51
|
+
* - `import(/* webpackIgnore: true *\/ x)` — already has the comment
|
|
52
|
+
* injected (idempotent: running this loader twice must not double-inject).
|
|
53
|
+
* - `important(x)` — the `\b` word-boundary guard on `import` prevents
|
|
54
|
+
* matching inside a longer identifier.
|
|
55
|
+
*
|
|
56
|
+
* This file is shipped as a genuine on-disk `.cjs` file (not bundled away)
|
|
57
|
+
* because rspack loaders are loaded via `require()` at build time — see
|
|
58
|
+
* `public/` in this package's `package.json`, which is copied verbatim to
|
|
59
|
+
* the package root by the build (so this ships at `<pkg>/loaders/
|
|
60
|
+
* webpack-ignore-dynamic-imports.cjs`, not under a `public/` prefix).
|
|
61
|
+
*
|
|
62
|
+
* @param source - The original module source text.
|
|
63
|
+
* @returns The source text with `webpackIgnore` comments injected into
|
|
64
|
+
* every fully-dynamic `import(` call.
|
|
65
|
+
*/
|
|
66
|
+
module.exports = function webpackIgnoreDynamicImportsLoader(source) {
|
|
67
|
+
// Pass 1: string-literal and backtick arguments are excluded from this
|
|
68
|
+
// pass (the former never needs the comment; the latter is handled by
|
|
69
|
+
// pass 2 below). An optional single leading `/* ... */` magic comment is
|
|
70
|
+
// captured so it can be inspected: if it already contains
|
|
71
|
+
// `webpackIgnore`, the call is left untouched (idempotent); otherwise the
|
|
72
|
+
// new comment is prepended ahead of it.
|
|
73
|
+
let result = source.replace(/\bimport\s*\(\s*(\/\*[\s\S]*?\*\/\s*)?(?!["'`])/g, (match, existingComment) => {
|
|
74
|
+
if (existingComment && /webpackIgnore/.test(existingComment)) {
|
|
75
|
+
return match;
|
|
76
|
+
}
|
|
77
|
+
return match.replace("(", "(/* webpackIgnore: true */ ");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Pass 2: backtick template-literal arguments. Only interpolated
|
|
81
|
+
// template literals (containing `${`) need the comment; a fully static
|
|
82
|
+
// one is left untouched.
|
|
83
|
+
result = result.replace(/\bimport\s*\(\s*`/g, (match, offset, full) => {
|
|
84
|
+
const backtickIndex = offset + match.length - 1;
|
|
85
|
+
let end = backtickIndex + 1;
|
|
86
|
+
while (end < full.length && full[end] !== "`") {
|
|
87
|
+
if (full[end] === "\\") {
|
|
88
|
+
end++;
|
|
89
|
+
}
|
|
90
|
+
end++;
|
|
91
|
+
}
|
|
92
|
+
const literal = full.slice(backtickIndex, end + 1);
|
|
93
|
+
if (!literal.includes("${")) {
|
|
94
|
+
return match;
|
|
95
|
+
}
|
|
96
|
+
return match.replace(/`$/, "/* webpackIgnore: true */ `");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return result;
|
|
100
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@savvy-web/github-action-builder",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A zero-config build tool for creating GitHub Actions from TypeScript. Bundles with rsbuild, validates action.yml against GitHub's schema, and outputs production-ready Node.js 24 actions.",
|
|
6
6
|
"keywords": [
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"import": "./index.js"
|
|
41
41
|
},
|
|
42
42
|
"./tsconfig/action.json": "./tsconfig/action.json",
|
|
43
|
+
"./loaders/webpack-ignore-dynamic-imports.cjs": "./loaders/webpack-ignore-dynamic-imports.cjs",
|
|
43
44
|
"./package.json": "./package.json"
|
|
44
45
|
},
|
|
45
46
|
"bin": {
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
"yaml-effect": "^0.7.0"
|
|
63
64
|
},
|
|
64
65
|
"peerDependencies": {
|
|
65
|
-
"@types/node": "^26.
|
|
66
|
+
"@types/node": "^26.1.0",
|
|
66
67
|
"@typescript/native-preview": "^7.0.0-dev.20260612.1",
|
|
67
68
|
"typescript": "^6.0.0"
|
|
68
69
|
},
|
package/schemas/config.js
CHANGED
|
@@ -54,7 +54,17 @@ const BuildOptionsSchema = Schema.Struct({
|
|
|
54
54
|
/** Packages to exclude from the bundle (in addition to node: builtins). Defaults to []. */
|
|
55
55
|
externals: Schema.optionalWith(Schema.Array(Schema.String), { default: () => [] }),
|
|
56
56
|
/** Packages to exclude from the bundle and replace with a stub that throws if loaded at runtime. Use for optional transitive dependencies the action never exercises (e.g. native modules). Defaults to []. */
|
|
57
|
-
ignore: Schema.optionalWith(Schema.Array(Schema.String), { default: () => [] })
|
|
57
|
+
ignore: Schema.optionalWith(Schema.Array(Schema.String), { default: () => [] }),
|
|
58
|
+
/**
|
|
59
|
+
* Packages whose dynamic `import(...)` calls must stay native `import()` at runtime instead of
|
|
60
|
+
* being compiled into an rspack context module. Use this for packages that resolve a module path
|
|
61
|
+
* at runtime (e.g. from a config value or a computed changelog id) and dynamically import it —
|
|
62
|
+
* rspack cannot statically analyze a fully dynamic `import(expr)`, so it emits an empty-context
|
|
63
|
+
* stub that throws `Cannot find module` at runtime even though the file exists on disk. Listing
|
|
64
|
+
* the package here injects a `webpackIgnore` comment into its dynamic imports so rspack leaves
|
|
65
|
+
* them alone. Defaults to [].
|
|
66
|
+
*/
|
|
67
|
+
nativeDynamicImports: Schema.optionalWith(Schema.Array(Schema.String), { default: () => [] })
|
|
58
68
|
});
|
|
59
69
|
/**
|
|
60
70
|
* Schema for validation options.
|
|
@@ -113,7 +123,8 @@ const ConfigInputSchema = Schema.Struct({
|
|
|
113
123
|
minify: Schema.optional(Schema.Boolean),
|
|
114
124
|
sourceMap: Schema.optional(Schema.Boolean),
|
|
115
125
|
externals: Schema.optional(Schema.Array(Schema.String)),
|
|
116
|
-
ignore: Schema.optional(Schema.Array(Schema.String))
|
|
126
|
+
ignore: Schema.optional(Schema.Array(Schema.String)),
|
|
127
|
+
nativeDynamicImports: Schema.optional(Schema.Array(Schema.String))
|
|
117
128
|
})),
|
|
118
129
|
validation: Schema.optional(Schema.Struct({
|
|
119
130
|
requireActionYml: Schema.optional(Schema.Boolean),
|
|
@@ -178,6 +189,7 @@ const ConfigSchema = Schema.Struct({
|
|
|
178
189
|
* sourceMap: true,
|
|
179
190
|
* externals: ["@aws-sdk/client-s3"],
|
|
180
191
|
* ignore: ["libxmljs2"],
|
|
192
|
+
* nativeDynamicImports: ["@changesets/apply-release-plan"],
|
|
181
193
|
* },
|
|
182
194
|
* validation: {
|
|
183
195
|
* requireActionYml: true,
|
package/services/build-live.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { BundleFailed, CleanError, WriteError } from "../errors.js";
|
|
2
2
|
import { BuildService } from "./build.js";
|
|
3
3
|
import { ConfigService } from "./config.js";
|
|
4
|
+
import { buildNativeDynamicImportRules } from "./native-dynamic-imports.js";
|
|
4
5
|
import { Effect, Layer } from "effect";
|
|
5
6
|
import { existsSync, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
7
|
import { resolve } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
7
9
|
import { createRsbuild } from "@rsbuild/core";
|
|
8
10
|
|
|
9
11
|
//#region src/services/build-live.ts
|
|
@@ -18,6 +20,23 @@ import { createRsbuild } from "@rsbuild/core";
|
|
|
18
20
|
*/
|
|
19
21
|
const IGNORE_STUB_SOURCE = `throw new Error("A module excluded via the build 'ignore' option was loaded at runtime.");\n`;
|
|
20
22
|
/**
|
|
23
|
+
* Self-referencing specifier for the `webpackIgnore`-injecting loader
|
|
24
|
+
* shipped from `public/loaders/webpack-ignore-dynamic-imports.cjs` (see
|
|
25
|
+
* `package.json` `exports`). Resolved through the package's own `exports`
|
|
26
|
+
* map via `import.meta.resolve`, which stays correct whether this module is
|
|
27
|
+
* running from `src` (the map points at `./public/loaders/...`) or from a
|
|
28
|
+
* built `dist` (the map points at the flattened `./loaders/...`, since the
|
|
29
|
+
* `public/` copy step drops the `public/` prefix both on disk and in the
|
|
30
|
+
* built manifest) — no relative-path assumption needed either way.
|
|
31
|
+
*/
|
|
32
|
+
const WEBPACK_IGNORE_LOADER_SPECIFIER = "@savvy-web/github-action-builder/loaders/webpack-ignore-dynamic-imports.cjs";
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the absolute on-disk path to the `webpackIgnore`-injecting loader.
|
|
35
|
+
*/
|
|
36
|
+
function resolveWebpackIgnoreLoaderPath() {
|
|
37
|
+
return fileURLToPath(import.meta.resolve(WEBPACK_IGNORE_LOADER_SPECIFIER));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
21
40
|
* Format bytes as a human-readable string.
|
|
22
41
|
*/
|
|
23
42
|
function formatBytes(bytes) {
|
|
@@ -90,6 +109,8 @@ function bundleEntry(entry, config, cwd) {
|
|
|
90
109
|
const externalsSet = new Set(config.build.externals);
|
|
91
110
|
const ignoreSet = new Set(config.build.ignore);
|
|
92
111
|
const ignoreAlias = {};
|
|
112
|
+
// webpackIgnore-injecting loader below leaves those calls as native
|
|
113
|
+
const nativeDynamicImportRules = config.build.nativeDynamicImports.length > 0 ? buildNativeDynamicImportRules(config.build.nativeDynamicImports, resolveWebpackIgnoreLoaderPath()) : [];
|
|
93
114
|
if (config.build.ignore.length > 0) {
|
|
94
115
|
const stubPath = resolve(cwd, "node_modules", ".cache", "github-action-builder", "ignore-stub.mjs");
|
|
95
116
|
yield* writeFile(stubPath, IGNORE_STUB_SOURCE);
|
|
@@ -122,7 +143,11 @@ function bundleEntry(entry, config, cwd) {
|
|
|
122
143
|
__dirname: "node-module",
|
|
123
144
|
__filename: "node-module"
|
|
124
145
|
},
|
|
125
|
-
module: {
|
|
146
|
+
module: {
|
|
147
|
+
parser: { javascript: { importMeta: false } },
|
|
148
|
+
// webpackIgnore-injecting loader (empty when the option is unset).
|
|
149
|
+
rules: nativeDynamicImportRules
|
|
150
|
+
},
|
|
126
151
|
output: { asyncChunks: false }
|
|
127
152
|
} }
|
|
128
153
|
} }),
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/services/native-dynamic-imports.ts
|
|
2
|
+
/**
|
|
3
|
+
* Helpers for the `build.nativeDynamicImports` option: building the rspack
|
|
4
|
+
* module-rule `test` pattern that matches a package's resolved module path
|
|
5
|
+
* under `node_modules`, and the module rules themselves.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* See {@link ../schemas/config.js#BuildOptionsSchema} for the option this
|
|
9
|
+
* supports, and `webpack-ignore-dynamic-imports.cjs` (shipped from
|
|
10
|
+
* `public/loaders/`, see `package.json` `exports`) for the loader these
|
|
11
|
+
* rules point at.
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Escape a string for literal use inside a `RegExp`, and turn every `/` into
|
|
17
|
+
* a `[\/]` alternation so the result matches both POSIX and Windows path
|
|
18
|
+
* separators.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* Order matters: the regex-metacharacter escape runs first (it never
|
|
22
|
+
* touches `/`, which is not a regex metacharacter), then `/` is expanded to
|
|
23
|
+
* `[\/]` afterward — a scoped package name like `@changesets/apply-release-plan`
|
|
24
|
+
* has a literal `/` that must become a path-separator alternation, not stay
|
|
25
|
+
* a bare `/`.
|
|
26
|
+
*/
|
|
27
|
+
function escapePathSegment(value) {
|
|
28
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\//g, "[\\/]");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build a `RegExp` matching a package's resolved absolute module path under
|
|
32
|
+
* `node_modules`, in both the flat layout (`node_modules/<name>/`) and the
|
|
33
|
+
* pnpm layout (`node_modules/.pnpm/<name>@x.y.z/node_modules/<name>/`).
|
|
34
|
+
*
|
|
35
|
+
* @param packageName - The npm package name to match, as configured in
|
|
36
|
+
* `build.nativeDynamicImports` (e.g. `"@changesets/apply-release-plan"` or
|
|
37
|
+
* `"some-unscoped-pkg"`).
|
|
38
|
+
* @returns A `RegExp` suitable for an rspack module rule's `test`.
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
function buildNativeDynamicImportPathPattern(packageName) {
|
|
43
|
+
const escapedName = escapePathSegment(packageName);
|
|
44
|
+
return new RegExp(`[\\/]node_modules[\\/](\\.pnpm[\\/][^\\/]+[\\/]node_modules[\\/])?${escapedName}[\\/]`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build the rspack `module.rules` entries for `build.nativeDynamicImports`:
|
|
48
|
+
* one rule per configured package name, each pointing at the
|
|
49
|
+
* `webpackIgnore`-injecting loader.
|
|
50
|
+
*
|
|
51
|
+
* @param packageNames - Package names configured in `build.nativeDynamicImports`.
|
|
52
|
+
* @param loaderPath - Absolute, resolved path to `webpack-ignore-dynamic-imports.cjs`.
|
|
53
|
+
* @returns One module rule per package name. Empty when `packageNames` is empty.
|
|
54
|
+
*
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
function buildNativeDynamicImportRules(packageNames, loaderPath) {
|
|
58
|
+
return packageNames.map((packageName) => ({
|
|
59
|
+
test: buildNativeDynamicImportPathPattern(packageName),
|
|
60
|
+
use: [{ loader: loaderPath }]
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
export { buildNativeDynamicImportPathPattern, buildNativeDynamicImportRules };
|