mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Network failure of the editor runtime is no longer terminal: the loader
re-arms to idle and the next explicit press starts a fresh cycle, while a
fingerprint mismatch on either attempt stays terminal. The toast now says
what actually helps — retry advice for the network, refresh advice for a
foreign build — via one shared lazyLoadFailureMessage helper (new i18n key
editor.retry_advice in en/ru/de).
The field smoke caught a second, deeper bug on the way: Chromium records a
FAILED module in the page module map permanently, so retrying the same URL
(even the cache-busted one) never touched the network again. Every retry
now carries a per-cycle nonce and becomes a genuinely new module request.
A proxy-cached stale entry no longer kills the card silently: the entry
facade is rewritten at build time from a static re-export into a top-level
`try{await import(...)}catch{...}` — importers keep the happy-path
guarantee (await import(entry) still resolves only after
customElements.define), and the catch defines a fallback element with a
localized "reload the page" panel. Content-hashed chunks are served with
`public, max-age=31536000, immutable`, and verifyBundleTree now fails on
orphan chunks that the manifest does not name.
Proofs: loader units for re-arm/terminality/toast wording + an AST check
that both loaders forward the terminality flag; smoke_entry_stale (en/ru)
against a tree without the main chunk; smoke_lazy_editor_chunk extended —
second press after network failure now really opens the editor; pytest for
the immutable header; orphan-tree unit; five new registry mutants.
TESTING.md budget line updated to the #352 ceiling alongside.
Issue: #353
User-Visible: yes
43 lines
1.4 KiB
JavaScript
Executable File
43 lines
1.4 KiB
JavaScript
Executable File
import typescript from '@rollup/plugin-typescript';
|
|
import json from '@rollup/plugin-json';
|
|
import resolve from '@rollup/plugin-node-resolve';
|
|
import terser from '@rollup/plugin-terser';
|
|
import { sourceFingerprint } from './scripts/source-fingerprint.mjs';
|
|
import { cssTemplateMinifier } from './scripts/css-template-minifier.mjs';
|
|
import {
|
|
buildFingerprintPlugin,
|
|
bundleManifestPlugin,
|
|
cleanBundleOutputPlugin,
|
|
editorRuntimeRetryUrlPlugin,
|
|
entryFallbackPlugin,
|
|
} from './scripts/bundle-manifest.mjs';
|
|
|
|
const SOURCE_FINGERPRINT = sourceFingerprint();
|
|
|
|
export default {
|
|
input: 'src/houseplan-card.ts',
|
|
output: {
|
|
dir: 'dist',
|
|
entryFileNames: 'houseplan-card.js',
|
|
chunkFileNames: 'houseplan-assets/[name]-[hash].js',
|
|
format: 'es',
|
|
sourcemap: false,
|
|
// Tooling reads this before recording screenshots/performance. A committed
|
|
// demo bundle built from older sources must fail closed, never produce a
|
|
// plausible-looking but invalid baseline.
|
|
intro: `globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__=${JSON.stringify(SOURCE_FINGERPRINT)};`,
|
|
},
|
|
plugins: [
|
|
cleanBundleOutputPlugin(),
|
|
buildFingerprintPlugin(SOURCE_FINGERPRINT),
|
|
cssTemplateMinifier(),
|
|
resolve(),
|
|
json(),
|
|
typescript({ compilerOptions: { outDir: 'dist/.ts' } }),
|
|
terser({ format: { comments: false } }),
|
|
editorRuntimeRetryUrlPlugin(),
|
|
entryFallbackPlugin(),
|
|
bundleManifestPlugin(SOURCE_FINGERPRINT),
|
|
],
|
|
};
|