expo: Expo vector icons are not loading up and is producing "3000ms timeout exceeded" loops on Brave Browser

Summary

Upon closer investigation, it has to do with node_module/fontfaceobserver not loading or failing to load from multiple requests resulting in Expo Vector Icons not showing up.

Managed or bare workflow? If you have ios/ or android/ directories in your project, the answer is bare!

bare

What platform(s) does this occur on?

Web

SDK Version (managed workflow only)

No response

Environment

Expo CLI 4.3.2 environment info: System: OS: Windows 10 10.0.19042 Binaries: Node: 12.18.3 - C:\Program Files\nodejs\node.EXE npm: 6.14.6 - C:\Program Files\nodejs\npm.CMD IDEs: Android Studio: Version 4.1.0.0 AI-201.8743.12.41.6858069 npmPackages: expo: ~40.0.0 => 40.0.1 react: 16.13.1 => 16.13.1 react-dom: 16.13.1 => 16.13.1 react-native: ^0.64.0 => 0.64.0 react-native-web: ^0.15.0 => 0.15.0 Expo Workflow: bare

Reproducible demo or steps to reproduce from a blank project

Refreshing the web browser will either Load the icon or produce an “Error: 3000ms timeout exceeded” loop with a bunch of requests from bundle.js.map. Most likely it will produce the error.

I think it is the same issue with #5935. I am using Brave Browser in debugging.

all Expo Vector Icon would either show up or not at all.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 41 (6 by maintainers)

Commits related to this issue

Most upvoted comments

Issue still present

My two cents as someone who has faced this and used expo vector icons: if you aren’t deep into using @expo/vector-icons, I recommend not using it if you want to target Web. Instead, use a package that uses react-native-svg-based icons under the hood.

I’ve faced so many issues with this package on Web, so I thought I’d share. It isn’t necessary for an icon set to be a single font. The SVG approach works great and doesn’t have any of the issues with loaders and assets.

If you want to use any of the existing icon sets, you can use SVGr to convert a folder of SVGs into a React Native icon package.

I turned Hero Icons and Iconic into React Native SVG packages with this approach. You can see the script I used in those repos to generate your own icon packs if you’d like. It’s easy to fork and implement.

I know it isn’t a solution to this thread, but figured I’d save someone else the time. (I’m in too deep to remove Expo’s icons, but I get OP’s error everyday on our Sentry on Web, and I wish I could get rid of the package.)

Not stale, still relevant.

Does Expo-Font 11.5.0 have any compatibility issues with Expo 49?

@SleeplessByte

Thanks, great info!

After 3 seconds, it aborts the request.

That’s really it.

Right, the strange thing though is:

The browser (192.168.1.251) sends a request for /fonts/MaterialCommunityIcons.ttf at 03:05:34.986 (frame 1488) and then, about 4 milliseconds later, the browser sends a TLS Close Notify (frame 1489) and then tears down its half of the socket with a FIN/ACK (frame 1490). Meanwhile, the server (143.198.245.8), in parallel, dutifully responds with a successful HTTP 304 about 40 milliseconds later (frame 1500). In the Firefox network inspector, this request shows as “No response” so it seems this request was canceled by the browser for some reason. […] So the font loading started only about 800ms before the request for that font. So I don’t see any reason why the client should have canceled the request. This is well before the 3000ms timeout error which happens about 2.5 seconds later. […] So the first issue is that the font loader seems to be mysteriously canceling its own request for no obvious reason well before the timeout and with the server trying to send a successful response.

At first, I was thinking might be due to scheduling delays, but the seeming canceling of the request well before the timeout seems like a functional issue rather than a timing or scheduling issue.

I’m not a fan of introducing arbitrary delays and retries so I will stick to images until this is fixed. I like the idea of switching to FontFace.load.

Thanks for the icon images link, very useful!

After hours of fruitless investigation, I’ve decided to use a workaround of just extracting out the font icons I need into images and using those instead. It’s cumbersome and inflexible, but I also noticed that MaterialCommunityIcons.ttf was 1.1MB, so I get the side benefit of less network consumption.

  1. Find icon on https://icons.expo.fyi/
  2. Since the font icon isn’t selectable text, inspect it in the browser dev tools and then copy the text
  3. Create the PNG from the command line, pasting the clipboard after label: and changing the color with -fill:
    convert -background none -fill "#007AFF" -font .../MaterialCommunityIcons.ttf -pointsize 24 label:󰈳 filter-outline-blue.png
    

Not stale, still relevant.

@findhumane you can find all the icons (as SVG and PNG) on http://materialdesignicons.com/, because that’s what the Material Community Icons font is.

I also read your investigation. It’s really not that complex, but I can support your findings with source code, as I’ve posted before (in this thread).

The package used is fontfaceobserver, which is imported here:

https://github.com/expo/expo/blob/master/packages/expo-font/src/ExpoFontLoader.web.ts#LL2C27-L2C43

…and called here:

https://github.com/expo/expo/blob/master/packages/expo-font/src/ExpoFontLoader.web.ts#L92

As you can see no arguments are passed. In this case, no timeout is given and it will use the default timeout of 3 seconds, as declared here:

https://github.com/bramstein/fontfaceobserver/blob/master/src/observer.js#LL195C51-L195C51

After 3 seconds, it aborts the request.

That’s really it.

You can find previous explorations of the code base here: https://github.com/expo/expo/issues/12382#issuecomment-812946025

And the fix: https://github.com/expo/expo/issues/12382#issuecomment-829338711


I’ve been using a patch to retry automatically for the past 2 years and that works well. I recommend you do the same.

I just hit this issue where icons intermittently fail to load and it’s much stranger than just a simple server-side or network slow-down. Below is a Wireshark capture from the client. The browser (192.168.1.251) sends a request for /fonts/MaterialCommunityIcons.ttf at 03:05:34.986 (frame 1488) and then, about 4 milliseconds later, the browser sends a TLS Close Notify (frame 1489) and then tears down its half of the socket with a FIN/ACK (frame 1490). Meanwhile, the server (143.198.245.8), in parallel, dutifully responds with a successful HTTP 304 about 40 milliseconds later (frame 1500). In the Firefox network inspector, this request shows as “No response” so it seems this request was canceled by the browser for some reason. Presumably, since the client had already given up on the request, it sends a RST packet for good measure to make sure the server knows it’s not interested in this socket anymore (frame 1502).

1488	2022-12-24 03:05:34.986449191	192.168.1.251	143.198.245.8	HTTP	635	53	GET /fonts/MaterialCommunityIcons.ttf HTTP/1.1 
1489	2022-12-24 03:05:34.990468743	192.168.1.251	143.198.245.8	TLSv1.3	90	53	Alert (Level: Warning, Description: Close Notify)
1490	2022-12-24 03:05:34.990509057	192.168.1.251	143.198.245.8	TCP	66	53	56836 → 443 [FIN, ACK] Seq=2779 Ack=5930 Win=64128 Len=0 TSval=629929637 TSecr=4263784990
1500	2022-12-24 03:05:35.032238954	143.198.245.8	192.168.1.251	HTTP	247	53	HTTP/1.1 304 Not Modified 
1502	2022-12-24 03:05:35.032277292	192.168.1.251	143.198.245.8	TCP	54	53	56836 → 443 [RST] Seq=2755 Win=0 Len=0

All of this happens within dozens of milliseconds.

My code right before the call to Font.loadAsync prints a timestamp:

[2022-12-24T03:05:35.078Z] Loading fonts

So the font loading started only about 800ms before the request for that font. So I don’t see any reason why the client should have canceled the request. This is well before the 3000ms timeout error which happens about 2.5 seconds later:

[2022-12-24T03:05:38.200Z] Error loading fonts AppUtilities.js:50:12
Error: 3000ms timeout exceeded

So the first issue is that the font loader seems to be mysteriously canceling its own request for no obvious reason well before the timeout and with the server trying to send a successful response.

At first, I was thinking might be due to scheduling delays, but the seeming canceling of the request well before the timeout seems like a functional issue rather than a timing or scheduling issue.

Then, there is another request for MaterialCommunityIcons.ttf, although I’m not sure where this is coming from. There are other “Error: 3000ms timeout exceeded” console messages (with characteristically ambiguous stack traces) although from “Uncaught (in promise)” which means it’s not from my direct Font.loadAsync call but must be coming from somewhere else.

In any case, that call doesn’t have the TLS Close or RST and succeeds quickly:

2066	2022-12-24 03:05:36.664555172	192.168.1.251	143.198.245.8	HTTP	635	61	GET /fonts/MaterialCommunityIcons.ttf HTTP/1.1 
2090	2022-12-24 03:05:36.711881821	143.198.245.8	192.168.1.251	HTTP	247	61	HTTP/1.1 304 Not Modified 

I also see the Firefox network panel showing this second request and this time it looks like a healthy response.

On the server-side, everything looks normal for both requests:

[24/Dec/2022:03:05:36.271] 304 163 499 2/2/0/0/0 0/0 "GET /fonts/MaterialCommunityIcons.ttf HTTP/1.1"
[24/Dec/2022:03:05:37.951] 304 163 499 4/4/0/0/0 0/0 "GET /fonts/MaterialCommunityIcons.ttf HTTP/1.1"

Nevertheless, those icons never did load in my app, so the second issue is that a successful loading of the icons may still not show them in the app.

I’ll add some retry loops but I’m worried this will be fruitless because even a successful response didn’t load the icons.

I think this also exposes the long-standing, systemic issue in Expo (and the JS community in general) that these sorts of issues are incredibly hard to create a standalone reproduction for and might depend on various external factors. This might be a good use case to explore alternative diagnostic capabilities of dynamically-enabled debug logging statements that us users of Expo can enable in our apps to help investigate these sorts of issues (e.g. a log statement when the font loader decides to cancel the request, etc.).