Skip to content

feat: public path fallbacks - #358

Merged
DanilaBeseda merged 18 commits into
mainfrom
feat/publicPathFallback
Oct 20, 2026
Merged

DanilaBeseda merged 18 commits into
mainfrom
feat/publicPathFallback

Conversation

@DanilaBeseda

Copy link
Copy Markdown
Contributor

No description provided.

@DanilaBeseda
DanilaBeseda force-pushed the feat/publicPathFallback branch from 1574556 to b0e0d1d Compare October 20, 2026 12:16

@dgaponov dgaponov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The controller/plugin split and the MF runtime plugin are a big step up from the first version, and the late-failure attribution in installChunkFallback is the right call given webpack's in-flight chunk dedup. Three things remain, two of them blocking for the scenario this feature targets (a hung or blocked CDN). Inline below.

Comment thread src/common/webpack/public-path-fallback-plugin.ts Outdated
Comment thread src/common/webpack/config.ts
Comment thread package.json Outdated

@dgaponov dgaponov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concrete suggestions for the two blocking points from my previous review, as GitHub suggestion blocks so they can be applied in one batch:

  • Runtime syntax level: six one-line rewrites in fallback-controller.ts that bring both serialized functions down to ES2017, plus an acorn-based test that fails if anything newer sneaks back in. This is option 1 from the earlier comment; if you prefer the esbuild-at-build-time route instead, ignore these and keep only the test idea.
  • JS chunk timeout: compiler.options.output.chunkLoadTimeout ??= 15000 inside the plugin's apply (the configureOutput block is not part of this diff, so it cannot carry a suggestion).
  • playwright replaced by acorn in devDependencies (lockfile needs pnpm install).

Not included as a suggestion because it is more than a few lines: the CSS chunk timeout. mini-css-extract-plugin never times out on its own, so the controller needs to watch managed <link rel="stylesheet"> elements and dispatch error on them after the same 15 s; the existing retry path then handles CSS_CHUNK_LOAD_FAILED. Happy to send that as a follow-up patch if you want.

Comment thread src/common/webpack/fallback-controller.test.ts
Comment thread src/common/webpack/fallback-controller.test.ts
Comment thread package.json Outdated
Comment thread src/common/webpack/public-path-fallback-plugin.ts
@dgaponov dgaponov changed the title Public path fallback feat: public path fallbacks Oct 20, 2026
@dgaponov

dgaponov commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up on the runtime syntax level: on reflection the six hand-rewrites I suggested above are the wrong tool. They fix today's six lines, but nothing stops the next ?. from landing, and the acorn test only reports it after the fact. I have removed those six suggestions (the chunkLoadTimeout, package.json and acorn-test ones are still there; the test is optional with this approach). Consider this instead: build the runtime module source at package build time with a fixed target, the same way app-layout now ships its loader. app-builder already depends on @swc/core, so no new dependency is needed.

scripts/build-fallback-runtime.mjs:

import {writeFile} from 'node:fs/promises';
import {transformFile} from '@swc/core';

// fallback-controller.ts has no runtime imports, so a plain transform is enough.
const {code} = await transformFile('src/common/webpack/fallback-controller.ts', {
    jsc: {parser: {syntax: 'typescript'}, target: 'es2017'},
    module: {type: 'commonjs'},
    sourceMaps: false,
});

const source = `(function () {\nvar exports = {};\n${code}\nreturn exports;\n})()`;

await writeFile(
    'src/common/webpack/fallback-runtime-source.ts',
    `// Generated by scripts/build-fallback-runtime.mjs. Do not edit.\nexport const fallbackRuntimeSource: string = ${JSON.stringify(source)};\n`,
);

public-path-fallback-plugin.ts:

import {fallbackRuntimeSource} from './fallback-runtime-source.js';

generate() {
    return [
        `var fallback = ${fallbackRuntimeSource};`,
        `var controller = fallback.createFallbackController(${JSON.stringify(runtimeConfig)});`,
        `fallback.installChunkFallback(${RuntimeGlobals.require}, controller);`,
    ].join('\n');
}

package.json / .gitignore:

"build:runtime": "node scripts/build-fallback-runtime.mjs",
"build:compile": "pnpm run build:runtime && tsc -p tsconfig.production.json",
"pretest": "pnpm run build:runtime",
"pretypecheck": "pnpm run build:runtime",
"prepare": "husky && pnpm run build:runtime"
src/common/webpack/fallback-runtime-source.ts

What this gives:

  • fallback-controller.ts stays idiomatic TS and keeps being imported normally by federation-fallback-plugin.ts, where the consumer's own pipeline transpiles it.
  • The RuntimeModule gets a string produced with an explicit target: 'es2017', independent of app-builder's tsconfig target and of whatever the next edit introduces. swc inlines its own helpers (_to_consumable_array for the Set spread etc.), so the output is self-contained.
  • toString() of compiled library code is gone from the webpack path. The acorn test becomes optional; if you keep it, point it at fallbackRuntimeSource instead of the functions.

es2017 is a pragmatic floor rather than "the consumer's browserslist"; reading the real output.environment inside generate() and transpiling per build would be more correct but is not worth the complexity for ~250 lines that change rarely.

@dgaponov dgaponov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All three points from the last round are addressed, and the stylesheet monitor plus the swc-built runtime came out cleaner than what I sketched. CI is green on both bundlers. Two non-blocking leftovers inline.

Comment thread src/common/webpack/fallback-controller.ts
Comment thread src/common/webpack/fallback-controller.ts

@dgaponov dgaponov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions for the two leftovers, verified locally on this branch (tsc --noEmit clean, eslint 0 errors, 47/47 tests in src/common/webpack green, both bundlers):

  • __webpack_require__.p spelling (fallback-controller.ts, 6 blocks + 2 test expectations): absolute URLs remain the key for matching and shared state, a small forms map remembers how each base was configured, and path() writes that spelling. /build/ stays /build/, https://cdn/…/ stays as is. Behaviour for chunk loading is unchanged, consumers reading __webpack_public_path__ see what they saw before this PR.
  • miniCssF coverage (fallback-runtime.test.ts, 3 blocks): a real compile on webpack and rspack with a lazy CSS chunk, asserting the runtime contains .miniCssF and createStylesheetMonitor. No new dependencies: mini-css-extract-plugin and css-loader are already here.

Apply in file order; the controller blocks depend on each other (remember is introduced in the last one).

Comment thread src/common/webpack/fallback-controller.ts
Comment thread src/common/webpack/fallback-controller.ts Outdated
Comment thread src/common/webpack/fallback-controller.ts Outdated
Comment thread src/common/webpack/fallback-controller.ts Outdated
Comment thread src/common/webpack/fallback-controller.ts Outdated
Comment thread src/common/webpack/fallback-controller.test.ts Outdated
Comment thread src/common/webpack/fallback-controller.test.ts Outdated
Comment thread src/common/webpack/fallback-runtime.test.ts
Comment thread src/common/webpack/fallback-runtime.test.ts
Comment thread src/common/webpack/fallback-runtime.test.ts
DanilaBeseda and others added 12 commits October 20, 2026 17:35
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
Co-authored-by: dgaponov <dagaponov@yandex-team.ru>
- add the remember() helper that the applied public-path suggestions call
- drop the stale acorn test in fallback-controller.test.ts (superseded by
  fallback-runtime.test.ts, which checks the generated runtime source)
- remove a stray brace left at the top of fallback-runtime.test.ts by the
  batch apply

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@DanilaBeseda
DanilaBeseda merged commit d2a739e into main Oct 20, 2026
4 checks passed
@DanilaBeseda
DanilaBeseda deleted the feat/publicPathFallback branch October 20, 2026 14:56
@gravity-ui gravity-ui Bot mentioned this pull request Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants