Skip to content

Commit 0ebb28e

Browse files
authored
fix(egg-bundler): copy app runtime assets (#5931)
## Summary - Copy non-source runtime assets under app into the bundle output with the same baseDir-relative paths. - Preserve source-module exclusion while copying static asset directories such as app/public verbatim. - Cover app/port/*.html assets and document bundle/non-bundle readFile behavior. ## Tests - pnpm --filter @eggjs/egg-bundler test -- integration.test.ts - pnpm --filter @eggjs/egg-bundler typecheck - pnpm --filter @eggjs/egg-bundler lint - pnpm exec oxfmt --check tools/egg-bundler/src/lib/Bundler.ts tools/egg-bundler/test/integration.test.ts tools/egg-bundler/docs/output-structure.md - git diff --check <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Runtime assets are copied into the bundle output and listed in the final manifest; a new runtimeAssets config (with roots and forceCopyDirs) controls which app files are preserved. * **Documentation** * README and docs updated with a "Runtime assets" section, examples, and option descriptions for runtimeAssets.roots and runtimeAssets.forceCopyDirs. * **Tests** * Added integration and validation tests for asset copying, manifest inclusion, content preservation, and invalid runtimeAssets config errors. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent f6c7b7c commit 0ebb28e

6 files changed

Lines changed: 482 additions & 23 deletions

File tree

tools/egg-bundler/README.md

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ Applications can also provide stable bundle configuration in
3333

3434
```yaml
3535
bundle:
36+
runtimeAssets:
37+
# Optional. When omitted, defaults to app.
38+
# When present, this list replaces the default runtime asset scan roots.
39+
roots:
40+
- app
41+
# Optional. When omitted, defaults to app/public, app/assets, and app/static.
42+
# When present, this list replaces the default force-copy directories.
43+
forceCopyDirs:
44+
- app/public
45+
- app/assets
46+
- app/static
3647
pack:
3748
resolve:
3849
alias:
@@ -42,7 +53,11 @@ bundle:
4253
Dot-relative alias targets are resolved from `baseDir`; package-style and
4354
absolute targets are passed through. Aliases supplied directly through the
4455
programmatic `pack.resolve.alias` option override aliases with the same key from
45-
`module.yml`.
56+
`module.yml`. `runtimeAssets.forceCopyDirs` entries are bundle-output relative
57+
paths that are copied even when their files use source-like extensions such as
58+
`.js` or `.ts`. `runtimeAssets.roots` entries are baseDir-relative directories
59+
that are scanned for runtime assets and preserve that same relative path in the
60+
bundle output.
4661

4762
If the startup manifest is missing, the bundler generates it by starting the app
4863
with `metadataOnly: true`. In that mode Egg skips the agent and normal boot
@@ -52,19 +67,21 @@ not run.
5267

5368
## Options
5469

55-
| Option | Description |
56-
| -------------------- | ------------------------------------------------------------------------------- |
57-
| `baseDir` | Application root directory. Required. |
58-
| `outputDir` | Output directory for the bundled artifact. Required. |
59-
| `manifestPath` | Path to `manifest.json`. Defaults to `<baseDir>/.egg/manifest.json`. |
60-
| `framework` | Framework package specifier. Defaults to `egg`; absolute paths are unsupported. |
61-
| `mode` | Build mode, `production` or `development`. Defaults to `production`. |
62-
| `tegg` | Accepted by `BundlerConfig`, but not applied by the current implementation yet. |
63-
| `externals.force` | Package names to always keep external. |
64-
| `externals.inline` | Package names to force inline even if auto-detected as external. |
65-
| `pack.buildFunc` | Test hook for replacing the real `@utoo/pack` build entry. |
66-
| `pack.rootPath` | Override the monorepo workspace root used by `@utoo/pack`. |
67-
| `pack.resolve.alias` | Application-supplied `@utoo/pack` resolve aliases; overrides `module.yml`. |
70+
| Option | Description |
71+
| ----------------------------- | ------------------------------------------------------------------------------- |
72+
| `baseDir` | Application root directory. Required. |
73+
| `outputDir` | Output directory for the bundled artifact. Required. |
74+
| `manifestPath` | Path to `manifest.json`. Defaults to `<baseDir>/.egg/manifest.json`. |
75+
| `framework` | Framework package specifier. Defaults to `egg`; absolute paths are unsupported. |
76+
| `mode` | Build mode, `production` or `development`. Defaults to `production`. |
77+
| `tegg` | Accepted by `BundlerConfig`, but not applied by the current implementation yet. |
78+
| `externals.force` | Package names to always keep external. |
79+
| `externals.inline` | Package names to force inline even if auto-detected as external. |
80+
| `runtimeAssets.roots` | BaseDir-relative runtime asset scan roots; overrides `module.yml`. |
81+
| `runtimeAssets.forceCopyDirs` | Relative dirs copied even for source-like files; overrides `module.yml`. |
82+
| `pack.buildFunc` | Test hook for replacing the real `@utoo/pack` build entry. |
83+
| `pack.rootPath` | Override the monorepo workspace root used by `@utoo/pack`. |
84+
| `pack.resolve.alias` | Application-supplied `@utoo/pack` resolve aliases; overrides `module.yml`. |
6885

6986
## Result
7087

tools/egg-bundler/docs/output-structure.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ the chunks.
1414
├── _root-of-the-server___<hash>.js.map
1515
├── _turbopack__runtime.js # @utoo/pack runtime shim
1616
├── _turbopack__runtime.js.map
17+
├── app/port/binary.html # app runtime asset copied from <baseDir>/app/port/binary.html
18+
├── app/port/login.html # app runtime asset copied from <baseDir>/app/port/login.html
1719
├── tsconfig.json # written by PackRunner; SWC reads decorator options from here
1820
├── package.json # written by PackRunner; `{ "type": "commonjs" }` so node parses *.js as CJS
1921
└── bundle-manifest.json # written by Bundler; reference / debug metadata
@@ -40,6 +42,36 @@ is keyed by relKey, output-dir absolute paths, precomputed original app absolute
4042
paths, and manifest `resolveCache` request aliases. Application code and plugins
4143
may still use `fs` for resources such as config, views, or assets.
4244

45+
## Runtime assets
46+
47+
The bundler copies application runtime assets from `<baseDir>/app` by default
48+
into the same relative path under `outputDir`, excluding manifest-known module
49+
files and source-like files such as `.js`, `.ts`, `.mjs`, and `.cjs` outside
50+
static asset directories. For example, `<baseDir>/app/port/binary.html` is
51+
emitted as `<outputDir>/app/port/binary.html`. Since bundled workers start Egg with
52+
`baseDir: outputDir`, existing reads such as
53+
`fs.readFile(path.join(app.config.baseDir, 'app/port/binary.html'))` resolve to
54+
the copied file in bundle mode and continue to resolve to the original file in
55+
non-bundle mode. Static asset directories such as `app/public`, `app/assets`,
56+
and `app/static` are copied verbatim so frontend `.js` and `.css` files remain
57+
servable from the bundled app. Applications may replace those force-copy
58+
directories with `bundle.runtimeAssets.forceCopyDirs` in `module.yml`, for
59+
example:
60+
61+
```yaml
62+
bundle:
63+
runtimeAssets:
64+
roots:
65+
- app
66+
forceCopyDirs:
67+
- app/port
68+
- app/public
69+
```
70+
71+
Applications may also replace the scanned roots with
72+
`bundle.runtimeAssets.roots`. Root entries are baseDir-relative directories, and
73+
the output keeps the same baseDir-relative path.
74+
4375
## `bundle-manifest.json`
4476

4577
A reference file produced by `Bundler` (not consumed at runtime). Shape:

tools/egg-bundler/src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ export interface BundlerPackConfig {
3030
readonly resolve?: PackRunnerResolveConfig;
3131
}
3232

33+
export interface BundlerRuntimeAssetsConfig {
34+
/** BaseDir-relative directories scanned for runtime assets. Defaults to `['app']`. */
35+
readonly roots?: readonly string[];
36+
/** Relative directories whose files should be copied even when they use source-like extensions. */
37+
readonly forceCopyDirs?: readonly string[];
38+
}
39+
3340
export interface BundlerConfig {
3441
/** Application root directory. Required. */
3542
readonly baseDir: string;
@@ -45,6 +52,8 @@ export interface BundlerConfig {
4552
readonly externals?: BundlerExternalsConfig;
4653
/** @utoo/pack tuning. */
4754
readonly pack?: BundlerPackConfig;
55+
/** Runtime asset copy tuning. */
56+
readonly runtimeAssets?: BundlerRuntimeAssetsConfig;
4857
/** Enable tegg decoratedFile collection. Defaults to `true`. */
4958
readonly tegg?: boolean;
5059
}

0 commit comments

Comments
 (0)