Skip to content

[Website] Retry import("main.js") when it fails in Safari#3216

Merged
adamziel merged 3 commits intotrunkfrom
fix-safari-module-import-retry
Jan 28, 2026
Merged

[Website] Retry import("main.js") when it fails in Safari#3216
adamziel merged 3 commits intotrunkfrom
fix-safari-module-import-retry

Conversation

@adamziel
Copy link
Copy Markdown
Collaborator

@adamziel adamziel commented Jan 28, 2026

Summary

Follows up on #3125 in an attempt to finally resolve #3064.

#3125 introduced a fetch("main.js") to bust the Safari cache and load that ES module after a page reload. That solution turned out to be, unfortunately, flaky.

This PR retries to import main.js with a cache buster string, similarly to import("main.js?_ts=178961653"). It seems to have worked for me during testing. Fingers crossed it solves it once and for all!

The Problem

As documented in #3215, Safari sometimes fails with "TypeError: Importing a module script failed" when trying to import the main module after a new deployment. The previous solution (fetch + page reload) worked but was heavy-handed.

Test plan

  1. Open playground.wordpress.net in Safari on iOS
  2. Plug it in to a Mac with a cable
  3. Open devtools for that tab in Desktop Safari
  4. Deploy this PR
  5. Refresh the tab on iOS
  6. Confirm the website reloaded correctly
  7. If you also can see the "Failed to load main module" error in the console, this fix works.
  8. If you can't, we don't know if it fully works yet.

Safari sometimes fails with "TypeError: Importing a module script failed" when trying to import the main module after a new deployment. The error provides no stack trace or useful debugging information.

After extensive debugging, the issue was traced to Safari not even attempting to fetch the module - no network request is made and the service worker fetch handler is not called. The root cause remains unclear, but it appears to be cache-related.

The solution is to catch the import error, fetch the module URL explicitly to prime the cache, then reload the page with a timestamp parameter. This workaround successfully resolves the issue. After a successful retry, the timestamp parameter is removed from the URL using the history API.

The actual module URL is extracted by stringifying a function containing the import statement, allowing Vite to transform it to the correct built chunk URL.
This is a cleaner approach to fixing Safari's module import failures after deployments. Instead of fetching and reloading the entire page, we now catch the import error and retry with a cache-busting query parameter added directly to the module URL.

When the import fails, we extract the actual built chunk URL by stringifying a function that contains the import statement (allowing Vite to transform it), then append a timestamp query parameter to that URL and re-import it. This bypasses Safari's cache without requiring a full page reload.

This approach is simpler and more user-friendly than the previous solution.
@adamziel adamziel changed the title Improve Safari module import fix with cache-busted retry [Website] Retry import("main.js") when it fails in Safari Jan 28, 2026
@adamziel adamziel merged commit c1695ad into trunk Jan 28, 2026
35 checks passed
@adamziel adamziel deleted the fix-safari-module-import-retry branch January 28, 2026 23:35
@adamziel
Copy link
Copy Markdown
Collaborator Author

adamziel commented Jan 28, 2026

Woohoo, this finally did it! See the initial Failed to load main module: - TypeError: Importing a module script failed. error and then the next message already says WordPress was loaded.

CleanShot 2026-01-29 at 00 46 02@2x

And it really loaded as expected:

WordPress Playground

I even spotted the failed network request this time – it never revealed itself until now:

CleanShot 2026-01-29 at 00 46 28@2x

Interestingly, it's a 200 response that still somehow says it's failed, possibly at the service worker level. There's no further details though.

After that initial page load, the subsequent page refreshes continue to fail the initial import and succeed the retry attempt. The devtools don't display the main.js request anymore. After closing and reopening Safari, the very first import starts working again.

This probably means Playground is not cached offline until Safari is restarted, since the "cache buster-less" main.js is never cached by the service worker. I'm not sure what to do with that yet. At least we're a lot better off now and the offline mode auto-heals after a page refresh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Playground won't load in Safari after some website deployments

1 participant