oblador / react-native-vector-icons

Customizable Icons for React Native with support for image source and full styling.
https://oblador.github.io/react-native-vector-icons/
MIT License
17.46k stars 2.13k forks source link

New Major Version feedback #1638

Closed vonovak closed 1 month ago

vonovak commented 4 months ago

Hi! Let me start by saying thanks for maintaining the library! :) I'm reaching out with regard to #1612 to provide some feedback for the new major version rewrite. I figured it'd be easier to open a new issue to keep discussion more focused.

Firstly, a clarifying question about "Package per font - Only install the fonts you need for smaller bundle sizes" which is listed as one of the benefits of the rewrite.

Does this concern the JS bundle size or the native binary size (because the "default" installation instructions result into copying all icon files into the binary)?

In terms of JS bundle size, I believe there shouldn't be a difference, because metro will bundle only the JS file that are imported in the JS code, so if I import import Icon from 'react-native-vector-icons/Ionicons', then only the JS code backing Ionicons will be bundled.

Secondly, I'd like to provide some feedback on the implementation. Please correct me if I'm wrong somewhere.

To render custom fonts, on both platforms, the font files need to be copied into the native app. This is all that needs to happen on Android, afaik. Then on iOS, the fonts also need to be added to Info.plist.

How font setup happens now ### iOS The copying of font files is currently done by [this line in the podspec](https://github.com/oblador/react-native-vector-icons/blob/e3e7ba7cf27ca38152e8994eeffd9afec7a1b97b/RNVectorIcons.podspec#L16). The iOS installation instructions currently say that a [manual step is needed](https://github.com/oblador/react-native-vector-icons?tab=readme-ov-file#ios-setup), but I haven't found it to be necessary. In fact, when I follow the "iOS Setup" I get an error `Multiple commands produce '.../iconsdemo.app/FontAwesome6_Regular.ttf'`. I tried to improve the installation instructions in #1636. Then, `UIAppFonts` need to be added to `Info.plist`. ### Android The [`fonts.gradle`](https://github.com/oblador/react-native-vector-icons/blob/master/fonts.gradle) copies the font files. That's it.
How font setup happens in the new monorepo branch ### iOS The font file copying part is no longer taken care of by Cocoapods but by a custom bash script [here](https://github.com/oblador/react-native-vector-icons/blob/5c2d2427f8cd798fb11a1a9afed5a2d8b67e3a68/packages/common/react-native-vector-icons.podspec#L24). Note that because the font files are copied into a `react-native-vector-icons` subfolder in the application bundle, the icon fonts won't render correctly even if they are added in the `UIAppFonts` entry in `Info.plist`. This I find unexpected and at odds with how [apple covers](https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app) adding custom fonts. Icon rendering works in the end thanks to this [`loadFont()`](https://github.com/oblador/react-native-vector-icons/blob/5c2d2427f8cd798fb11a1a9afed5a2d8b67e3a68/packages/common/src/create-icon-set.tsx#L171) call. However, if standard setup was followed this call wouldn't be necessary. The implementation is necessary for dynamic font loading but for static fonts, the call doesn't need to happen. Let me also note that the promise returned by the call is not awaited so race conditions could happen when icon is rendered before the font is loaded. The aforementioned bash script calls the `getFonts.js` node script which reads `package.json` and looks for all `react-native-vector-icons` subpackages and collects the font files from them. It appears it should work okay with monorepos πŸ‘ . ### Android The `getFonts.js` script is called by [`build.gradle`](https://github.com/oblador/react-native-vector-icons/blob/5c2d2427f8cd798fb11a1a9afed5a2d8b67e3a68/packages/common/android/build.gradle#L116)

Question for Android: With the new implementation, are the font files copied to the location documented here?

Summary

johnf commented 3 months ago

Hi @vonovak.

Thanks for the feedback, apologies for the delay, I've been travelling.

Does this concern the JS bundle size or the native binary size (because the "default" installation instructions result into copying all icon files into the binary)?

That's a terminology misstep on my part. I do mean the native binary size. I'll update that everywhere.

NOTE: Those are the old installation instructions you linked to. See the new branch: https://github.com/oblador/react-native-vector-icons/tree/monorepo?#installation. In the new version, there is a script that copies only the fonts for installed packages into the bundle.

iOS

The key goal was to simplify installation and make it zero-touch. The majority of the project's user issues are caused by installation problems.

Based on some of the documentation you've shared, I think I might be overreaching here.

The script on iOS is mainly to avoid needing the podspec in every module, the fonts are auto generated though so this is not a biggy and we could include one.

Do you think it would be possible to either make use of some expo-font code or use it directly in some way as part of this library to not require users to edit Info.plist

Thanks for the gist, I'll definitely look at improving my hack :)

Android

Question for Android: With the new implementation, are the font files copied to the location documented here?

It doesn't copy them into the directory mentioned there, as that would mean they need to be git ignored or committed. The scripts place them in android/app/build/intermediates/assets/debug/fonts/, the same place they would end up if you added an assets entry to react-native-config.js.

Thanks for the feedback!

vonovak commented 3 months ago

Hi @johnf! I purposely linked to the current installation instructions - at the moment all font files are included in the binary. That changes with the new major version, so that's good.

You mentioned that most issues people have on iOS are around installing - I believe the installation instructions can be much simpler. I made a PR for that: #1636

The script on iOS is mainly to avoid needing the podspec in every module, the fonts are auto generated though so this is not a biggy and we could include one.

If the script that does the copying is solid, then I agree there's no need for podspec (again, just for completeness: how cocoapods do it).

Do you think it would be possible to either make use of some expo-font code or use it directly in some way as part of this library to not require users to edit Info.plist

It'd be nice to not have to change info.plist but given that it's the officially instructed way to add custom fonts, I think the package should stick with it for static fonts (= fonts that are present at build time, which covers the vast majority of how the fonts are used). Expo has a config plugin that adds the font entries to info.plist so no manual step is needed but I don't see an easy way to bring that into this package. But again, if the the docs are better I'm hopeful that the situation will improve.

why rely on changed in `info.plist` With the current `monorepo` branch, [`loadFontWithFileName`](https://github.com/oblador/react-native-vector-icons/blob/f0670f89592f1c64f5e2aecc3b6d26bb3e424cff/packages/common/ios/VectorIcons.mm#L132) needs to be called and do some work before the icons can render (and we should [await the result here](https://github.com/oblador/react-native-vector-icons/blob/f0670f89592f1c64f5e2aecc3b6d26bb3e424cff/packages/common/src/create-icon-set.tsx#L171) before proceeding - otherwise there's potential for race conditions.). But if we take the path of changing plist file, there's no need to run this extra code and await its result / block the JS thread. I understand the desire to make the library "just work" after installing but it feel it's at the expense of what is right.

There are cases when users might want to load a font family dynamically (without changes to info.plist) - e.g. with OTA updates this can be the case. For that purpose I'm planning to contribute dynamic font loading from this branch. It relies on the presence of Expo, namely expo-font to determine if a font is loaded or not, and loading it. Because the font file can be served by metro bundler when developing locally, there's also some work around that. This still requires some changes inside expo but I'll try to contribute this soon.

Hope this makes sense, and thank you for explaining everything.

johnf commented 3 months ago

@vonovak I've just rolled a new release that moves back to a more static treatment of fonts on iOS I did try a couple of techniques to try and dynamically edit Info.plist during the build process, but I couldn't quite find the right hook, so it didn't get overridden. I have provided a script, though so that users can update their Info.plist with a single command which adds any missing fonts.

vonovak commented 3 months ago

Thank you for making that change; that sounds like a good way to handle it!

johnf commented 2 months ago

@vonovak Are there any more pull requests coming? I's like to cut a new alpha release soon

vonovak commented 2 months ago

Hi @johnf yes I'll open 1 PR tomorrow.

johnf commented 2 months ago

@vonovak Thanks for all the help with the dynamic font loading and other improvements. I'll clean up a couple of things and then push another alpha release this week.

vonovak commented 2 months ago

hey @johnf I was wondering if you have a timeline for releasing stuff from the monorepo branch and making it the default?

Are there todo items / tasks that need resolving and would move us closer to that goal?

Also regarding https://github.com/oblador/react-native-vector-icons/commit/82b4fdabe6be38069487a9efb804f1dea19aa256 I just wanted to point out that the naming of postscriptName and fontFilename seems inconsistent: it seems that the name part should be Name in both cases.

Thank you! πŸ™‚

johnf commented 1 month ago

@vonovak I'm hoping to release a beta this weekend and then a full version in a couple of weeks. My main focus is getting the tests working - I'm going to try switching from detox to owl (I've had all sorts of issues with detox, e.g. it just seems to crash the app on ios)

Regarding the naming, you are right. I'm going to switch it back. I think it's the leftover rubyisms in my brain that preferred filename, but FileName seems more correct in JS/TS land

vonovak commented 1 month ago

@johnf great to hear that! With tests - I believe there are better options than Detox for what you're trying to achieve. Detox's advantage is that it's "grey box" - it understands what's going on inside of the app which is useful for real apps. However, if you're trying to just boot a simple "icons gallery app" and take a few screenshots, it's not a real benefit.

Rather, the issue with it is that Detox supports specific React Native versions and doesn't officially work with the new architecture so it might block you from testing the most recent releases.

I'm not too familiar with react native owl so I cannot comment on it but Appium (as much as I don't like it because to me it seems it's trying to do a lot of things but only few work really properly) or Maestro (which I don't have experience with but heard positive comments on) would seems better choices for this purpose compared to Detox.

jbrodriguez commented 1 month ago

hi, quick comment

these instructions didn't work for me (with the new per-package approach) https://github.com/oblador/react-native-vector-icons/blob/monorepo/docs/SETUP-REACT-NATIVE.md#ios

it can't find rnvi-update-plist

i manually added the fonts i installed to info.plist

johnf commented 1 month ago

@jbrodriguez I just shipped a new release with updated docs which I think should fix this