Skip to content

fix(site-import): report asset references the archive cannot satisfy - #349

Open
mostafasadeghidev wants to merge 1 commit into
CoreBunch:mainfrom
mostafasadeghidev:fix/site-import-unresolved-assets
Open

fix(site-import): report asset references the archive cannot satisfy#349
mostafasadeghidev wants to merge 1 commit into
CoreBunch:mainfrom
mostafasadeghidev:fix/site-import-unresolved-assets

Conversation

@mostafasadeghidev

Copy link
Copy Markdown

What

Site Import now says when an asset reference doesn't resolve, and matches a few more of them that should have resolved all along.

  1. Punctuation-insensitive fallback match. On an exact-key miss, the path is compared against the archive with everything but letters, digits, . and / removed.
  2. unresolved-asset warning for whatever still doesn't resolve — naming the path, once per path however many pages reference it.

Why

An <img src> or a CSS url() pointing at a file the archive doesn't contain resolved to null in resolveAndRecord and was left alone. That's the right rewrite behaviour — dropping the element would be worse — but nothing recorded it. The page imported with a broken image and the import log said the import succeeded. The user finds out by opening the published site.

The fallback exists because exporters don't always agree with themselves about filenames. A real Webflow static export stores:

images/01-Berlin-Office-Space-Us-Coworking_101-&Berlin-Office-Space-Us+ Coworking.webp

and references it from three different pages as:

images/01-Berlin-Office-Space-Us-Coworking_101-Berlin-Office-Space-Us-Coworking.webp

The & is gone and + became -. The bytes are right there in the zip; only the punctuation disagrees. Exact-key matching imports that page with a broken image through no fault of the archive's owner.

How

  • resolveFileMapKey tries the exact key, then a lazily built index of every FileMap key in normalised form. The fallback match must be unique — two files that differ only in punctuation are two different files, and picking one would silently put the wrong image on the page, which is worse than the broken reference. Ambiguity and genuine absence fall through to the same warning.
  • The index is built on the first miss, so an archive whose references all resolve exactly never pays for it.
  • Only media references are reported. isImportUploadableMimeType(guessMimeType(path)) gates the warning, so <a href="/contact"> and a link to a page living outside the archive stay quiet — a wall of warnings about those would bury the images that really are gone.
  • The import log renders the first 12 warnings, and a stylesheet-heavy import produces dozens of cosmetic CSS notes, so the list is now ordered: kinds that name a missing file → kinds needing a manual re-add → CSS interpretation notes.

One refactor came with it

The four URL normalisers (node props, CSS bags, raw CSS text, @font-face) each threaded fileMap + assetMap down to resolveAndRecord, and this change needed two more per-import values in the same places (the warning sink and the lookup index). Rather than grow every signature to four trailing parameters, they now take one AssetResolver. Same call graph, fewer parameters.

User impact

Additive. Every reference that resolved before still resolves to the same key; the fallback only runs where the old code was about to give up. A site with no missing assets sees no new warnings.

Verification

bun test src/__tests__/siteImport/ src/__tests__/fonts/   # 302 pass
bun run build
bun run lint

Five new tests in src/__tests__/siteImport/assetPlan.test.ts, including the exact filename pair above:

  • matches a file whose stored name differs only in punctuation
  • refuses to guess when two files differ only in punctuation
  • warns once per missing image, however many pages reference it
  • reports a missing CSS background image too
  • stays quiet about links, routes, and scripts that are not in the archive

Full-suite note: bun test on this Windows machine reports 302 pre-existing failures on origin/main unmodified (parallel temp-DB / port contention in the server suites). This branch reports the same 302 with 5 additional passing tests.

An `<img src>` or CSS `url()` pointing at a file the archive does not
contain resolved to null and was silently left alone — the page imported
with a broken image and nothing in the import log said so. The user
found out by opening the published site.

Two changes:

- On an exact-key miss, compare the path punctuation-insensitively
  against the archive. Exporters do not always agree with themselves
  about filenames: a Webflow export stores
  `101-&Berlin-Office-Us+ Coworking.webp` and references it from the HTML
  as `101-Berlin-Office-Us-Coworking.webp`. The match must be UNIQUE —
  two files differing only in punctuation are two different files, and
  guessing would put the wrong image on the page.

- Whatever still does not resolve emits an `unresolved-asset` warning
  naming the path, once per path however many pages reference it. Only
  references whose extension maps to an uploadable media MIME are
  reported; anchors to extensionless routes and pages outside the
  archive are normal and would bury the real misses.

The import log shows the first 12 warnings, so it now orders the kinds
that name a missing file ahead of the CSS interpretation notes.

The four URL normalisers all needed the same four things — file map,
asset map, warnings, and the new lookup index — so they take one
resolver instead of passing the pieces around individually.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mostafasadeghidev
mostafasadeghidev marked this pull request as ready for review August 7, 2026 00:03
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.

1 participant