Closed heroic closed 3 years ago
That doesn't seem right. Eva JSON files shouldn't be getting into your assets as far as I know. Even then, it's not as huge. What's the size of the files when you build for release?
For me, using ui-kitten
with react-native-web
renders a 3.5MB bundle - this is including all my packages and code. For Android, I couldn't see any json
files in my /res
folder.
@lesmo This is the analysis on "release" build. I use custom mappings. Do you have any custom mappings in your project?
So when I took a look at your Sample Project section I didn't notice you were talking about the output from:
ls -la node_modules/@eva-design/eva/generated.json
This is the wrong way to think about it. The Metro Bundler does many things behind the scenes, including tree shaking, minifying and more.
I cloned your sample project, and ran react-native-bundle-visualizer to see the actual bundled size and it's components:
As you can see, the bundled JS isn't even close to the size of the generated json
you're talking about. Furthermore, in the actual report you can see that ui-kitten
is taking only 224kb while @eva-design
is taking only 9kb:
The rest of the bundle is mostly React runtime and components.
@lesmo Did you run the size-analyze command on the build release bundle?
Here's the sample output from the example project:
Dynamically delivering large files7.1 MiB
Place large file base/res/raw/node_modules_evadesign_eva_generated.json inside an on demand dynamic-feature to avoid bundling in apk (saves 3.8 MiB)
Place large file base/assets/index.android.bundle inside an on demand dynamic-feature to avoid bundling in apk (saves 2.4 MiB)
Place large file base/res/raw/node_modules_evadesign_eva_mapping.json inside an on demand dynamic-feature to avoid bundling in apk (saves 282.0 kiB)
By default, react-native-bundle-visualizer runs the build process for release bundle.
I noticed your output is for Android build (the bundle analyzer automatically builds for iOS), so I tried running the command with Android as target:
The result is the same, the generated bundle is only 1.3mb in size:
So then I ran:
$ cd android
$ ./gradlew assembleRelease
The React bundle generated during this process is, as expected, the same size as the bundle analyzer command (located under android/app/build/generated/assets/react/release
):
Furthermore, the files referenced in your comments are mere kilobytes in size:
I took one more crack at this. I don't know what size-analyzer
tool is, or where to get it... but I built the file again and listed the files in it with the tools in the Android SDK:
$ apkanalyzer -h files list app-release.aab
The files we're concerned with are:
/base/res/raw/node_modules_evadesign_eva_themes_light.json
/base/res/raw/node_modules_evadesign_eva_themes_dark.json
/base/res/raw/node_modules_evadesign_eva_mapping.json
Which aren't as big as you're reporting (wc -m
returns the char count, which essentially tells us the size in bytes of the file):
$ apkanalyzer -h files cat --file /base/res/raw/node_modules_evadesign_eva_themes_light.json app-release.aab | wc -m
17335
$ apkanalyzer -h files cat --file /base/res/raw/node_modules_evadesign_eva_themes_dark.json app-release.aab | wc -m
17323
$ apkanalyzer -h files cat --file /base/res/raw/node_modules_evadesign_eva_mapping.json app-release.aab | wc -m
288808
So.... I can safely say your reported sizes are wrong. There's something you're doing differently.
About the "updatability" of the mappings through CodePush, I haven't had problems with that so far. The bundled JSONs that are out of reach from CodePush are the Eva design's defaults and are not very frequently updated as far as I know... if you ever need to update a major version of any library, you probably should be looking at uploading a whole new binary anyway.
@lesmo size-analyzer is the tool recommended by google. Here's the link: https://github.com/android/size-analyzer/releases/tag/v0.3.1
You can find google's article on reducing the bundle size where the tool is referenced here: https://developer.android.com/topic/performance/reduce-apk-size
Let me know if you still don't find a similar output as I am getting in the example project.
Cool! You learn something new everyday!
So I did that...
$ ./size-analyzer check-bundle ../app-release.aab -d
Dynamically delivering large files1.8 MiB
Place large file base/assets/index.android.bundle inside an on demand dynamic-feature to avoid bundling in apk (saves 1.3 MiB)
Place large file base/res/raw/node_modules_evadesign_eva_mapping.json inside an on demand dynamic-feature to avoid bundling in apk (saves 282.0 kiB)
Place large file base/res/raw/node_modules_csstree_dist_defaultsyntax.json inside an on demand dynamic-feature to avoid bundling in apk (saves 56.4 kiB)
Place large file base/res/raw/node_modules_entities_lib_maps_entities.json inside an on demand dynamic-feature to avoid bundling in apk (saves 43.8 kiB)
File base/root/okhttp3/internal/publicsuffix/publicsuffixes.gz does not appear to be a needed file. Consider removing this file or placing it in the assets directory. If the file is added through a library dependency, consider using packagingOptions to exclude the file https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html (saves 33.2 kiB)
Place large file base/res/drawable-mdpi-v4/node_modules_reactnative_libraries_newappscreen_components_logo.png inside an on demand dynamic-feature to avoid bundling in apk (saves 23.5 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_light.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_dark.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/mipmap-xxxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 15.2 kiB)
Place large file base/res/mipmap-xxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 10.4 kiB)
Efficiently configuring proguard
It seems that you are not using Proguard/R8, consider enabling it in your application. (saves )
Total size savings of 1.8 MiB found.
As you can see, the Eva JSON files match the size I got with my not-so-sophisticated method. Did you customize Babel config? Metro?
@lesmo, yes I use react native navigation, and have a custom mapping. Sharing relevant parts below:
const MetroConfig = require('@ui-kitten/metro-config')
const evaConfig = {
evaPackage: '@eva-design/eva',
// Optional, but may be useful when using mapping customization feature.
customMappingPath: './src/config/custom-mapping.json',
}
module.exports = MetroConfig.create(evaConfig, {
resolver: {
sourceExts: process.env.RN_SRC_EXT
? process.env.RN_SRC_EXT.split(',').concat(defaultSourceExts)
: defaultSourceExts,
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
serializer: {
processModuleFilter: module => {
return !module.path.endsWith(
'react-native/Libraries/Renderer/implementations/ReactFabric-prod.js',
);
},
},
})
{
"strict": {
"text-font-family": "lato-light",
"title-font-family": "liberation-sans-regular"
},
"components": {
"Card": {
"meta": {
"variantGroups": {
"size": {
"large": {
"default": true
},
"tiny": {
"default": false
}
}
}
},
"appearances": {
"outline": {
"mapping": {
"titleFontFamily": "title-font-family"
},
"variantGroups": {
"size": {
"large": {},
"tiny": {
"headerPaddingHorizontal": 12,
"headerPaddingVertical": 8,
"bodyPaddingHorizontal": 12,
"bodyPaddingVertical": 8,
"footerPaddingHorizontal": 12,
"footerPaddingVertical": 8
}
}
}
},
"filled": {
"mapping": {},
"variantGroups": {
"size": {
"large": {},
"tiny": {
"headerPaddingHorizontal": 12,
"headerPaddingVertical": 8,
"bodyPaddingHorizontal": 12,
"bodyPaddingVertical": 8,
"footerPaddingHorizontal": 12,
"footerPaddingVertical": 8
}
}
}
}
}
},
}
}
Aha! That's probably where the problem lies. I've never toyed with Metro bundler, so I'm not sure what's going on here.
However, talking from my experience with WebPack, I can say that sometimes you could be missing some configs that make the resulting bundle ignore treeshaking for some paths... which can be useful in some scenarios, but maybe not on others.
That's my only suggestion for now. Perhaps updating your sample repo with the Metro config you have so it can be reproducible there can be useful.
@lesmo the sample project already has this config.
Oh, sorry! I didn't read through the code, I just concerned myself with building and sizing it.
It's going to be next to impossible to figure out if the sample project doesn't reproduce your problem. Currently the sample project is building and sizing properly, so... can't help further until the sample reproduces the issue.
@lesmo not sure why you are not seeing the issue in the sample project, as it is happening for me. Did you run yarn start
before building for release? Without it, the generated.json file will not be created.
@lesmo not sure why you are not seeing the issue in the sample project, as it is happening for me. Did you run
yarn start
before building for release? Without it, the generated.json file will not be created.
As you can tell from my comments, I didn't do that. It doesn't sound right to me that the generated files get written to node_modules
. If this is happening, sounds to me like a bug on the eva-design/eva
package.
What would you say are the steps to reproduce this? By doing the steps you mentioned in the issue I don't get the outputs you're getting. I've ran yarn start
, exited the process and ran the steps, but the result is the same:
$ yarn start
^C
$ ./size-analyzer check-bundle ../app-release.aab -d
Dynamically delivering large files1.8 MiB
Place large file base/assets/index.android.bundle inside an on demand dynamic-feature to avoid bundling in apk (saves 1.3 MiB)
Place large file base/res/raw/node_modules_evadesign_eva_mapping.json inside an on demand dynamic-feature to avoid bundling in apk (saves 282.0 kiB)
Place large file base/res/raw/node_modules_csstree_dist_defaultsyntax.json inside an on demand dynamic-feature to avoid bundling in apk (saves 56.4 kiB)
Place large file base/res/raw/node_modules_entities_lib_maps_entities.json inside an on demand dynamic-feature to avoid bundling in apk (saves 43.8 kiB)
File base/root/okhttp3/internal/publicsuffix/publicsuffixes.gz does not appear to be a needed file. Consider removing this file or placing it in the assets directory. If the file is added through a library dependency, consider using packagingOptions to exclude the file https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html (saves 33.2 kiB)
Place large file base/res/drawable-mdpi-v4/node_modules_reactnative_libraries_newappscreen_components_logo.png inside an on demand dynamic-feature to avoid bundling in apk (saves 23.5 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_light.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_dark.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/mipmap-xxxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 15.2 kiB)
Place large file base/res/mipmap-xxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 10.4 kiB)
Efficiently configuring proguard
It seems that you are not using Proguard/R8, consider enabling it in your application. (saves )
Total size savings of 1.8 MiB found.
@lesmo Here are the exact commands I ran:
Here's the output:
Dynamically delivering large files7.9 MiB
Place large file base/res/raw/node_modules_evadesign_eva_generated.json inside an on demand dynamic-feature to avoid bundling in apk (saves 3.8 MiB)
Place large file base/assets/index.android.bundle inside an on demand dynamic-feature to avoid bundling in apk (saves 3.6 MiB)
Place large file base/res/raw/node_modules_evadesign_eva_mapping.json inside an on demand dynamic-feature to avoid bundling in apk (saves 282.0 kiB)
Place large file base/res/raw/node_modules_csstree_dist_defaultsyntax.json inside an on demand dynamic-feature to avoid bundling in apk (saves 56.4 kiB)
Place large file base/res/raw/node_modules_entities_lib_maps_entities.json inside an on demand dynamic-feature to avoid bundling in apk (saves 43.8 kiB)
File base/root/okhttp3/internal/publicsuffix/publicsuffixes.gz does not appear to be a needed file. Consider removing this file or placing it in the assets directory. If the file is added through a library dependency, consider using packagingOptions to exclude the file https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html (saves 33.2 kiB)
Place large file base/res/drawable-mdpi-v4/node_modules_reactnative_libraries_newappscreen_components_logo.png inside an on demand dynamic-feature to avoid bundling in apk (saves 23.5 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_light.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_dark.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/mipmap-xxxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 15.2 kiB)
Place large file base/res/mipmap-xxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 10.4 kiB)
Efficiently configuring proguard
It seems that you are not using Proguard/R8, consider enabling it in your application. (saves )
Total size savings of 7.9 MiB found.
Thanks! That's great! It's exactly what I needed. The yarn start
command is crucial to reproduce this, I thought it kinda could be disregarded. Sorry about that!
I finally got it:
$ ./size-analyzer check-bundle -d app-release.aab
Dynamically delivering large files7.9 MiB
Place large file base/res/raw/node_modules_evadesign_eva_generated.json inside an on demand dynamic-feature to avoid bundling in apk (saves 3.8 MiB)
Place large file base/assets/index.android.bundle inside an on demand dynamic-feature to avoid bundling in apk (saves 3.6 MiB)
Place large file base/res/raw/node_modules_evadesign_eva_mapping.json inside an on demand dynamic-feature to avoid bundling in apk (saves 282.0 kiB)
Place large file base/res/raw/node_modules_csstree_dist_defaultsyntax.json inside an on demand dynamic-feature to avoid bundling in apk (saves 56.4 kiB)
Place large file base/res/raw/node_modules_entities_lib_maps_entities.json inside an on demand dynamic-feature to avoid bundling in apk (saves 43.8 kiB)
File base/root/okhttp3/internal/publicsuffix/publicsuffixes.gz does not appear to be a needed file. Consider removing this file or placing it in the assets directory. If the file is added through a library dependency, consider using packagingOptions to exclude the file https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html (saves 33.2 kiB)
Place large file base/res/drawable-mdpi-v4/node_modules_reactnative_libraries_newappscreen_components_logo.png inside an on demand dynamic-feature to avoid bundling in apk (saves 23.5 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_light.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/raw/node_modules_evadesign_eva_themes_dark.json inside an on demand dynamic-feature to avoid bundling in apk (saves 16.9 kiB)
Place large file base/res/mipmap-xxxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 15.2 kiB)
Place large file base/res/mipmap-xxhdpi-v4/ic_launcher_round.png inside an on demand dynamic-feature to avoid bundling in apk (saves 10.4 kiB)
Efficiently configuring proguard
It seems that you are not using Proguard/R8, consider enabling it in your application. (saves )
Total size savings of 7.9 MiB found.
I suggest we move this over to eva-design/eva. Perhaps @artyorsh can tell us if it should go in eva or here π
@lesmo Iβd prefer leaving it here to keep it alive. Thanks for chipping in :)
@lesmo Iβd prefer leaving it here to keep it alive. Thanks for chipping in :)
Any idea what could be happening? This issue means everybody can save 3mb on their binary by just building on a clean, never yarn start
ed project... which is kinda cool, but at the same time not so cool.
@lesmo yarn start
is crucial as without it, with react native navigation, the mapping are computed on each screen load. It's mentioned in the document here: https://akveo.github.io/react-native-ui-kitten/docs/4.x/guides/improving-performance#improving-performance
I think it's still valid for v5
Just noting that we are running into the same thing on one of our projects. It's 4.1mb, which is far too much for our size budget. (I do have a call scheduled with the UI Kitten folks to talk about paying them to fix this issue.)
Chiming in on behalf of @jamonholmgren above...
We had implemented the optimizations as described in the documentation for metro to preprocess the theme file. This works great for mobile since it speeds up application load time on mobile but on the web it includes a HUGE generated.json
file. Our web build system is separate from our mobile build system.
The key to removing the 4mb+ generated.json
from our final web production build was to remove the yarn command yarn ui-kitten bootstrap @eva-design/eva ./custom-eva-theme.json
and simply import CustomEvaTheme from "custom-eva-theme.json"
in our ApplicationProvider
and pass it to the UIKitten ApplicationProvider component as a customMapping
prop.
Thanks to the UIKitten team @artyorsh, Anton, and @malashkevich for their great support in helping get this figured out!
Thank you for the response @markrickert π
A few words to summarize our call with InfiniteRed team:
We didn't realize that UI Kitten users will use this framework on the web a lot... So we focused more on mobile and that's why this problem occurred. This is not a problem for mobile at all, because the final bundle is downloaded once. However this may affect web platform.
The best way to fix for web without bringing any changes to the framework itself is to make sure that you don't have generated.json
file in node modules in case you build a web project.
To do this:
ui-kitten bootstrap
script calledApplicationProvider
to have mapping, theme, and customMapping (if you have that) instead of spreading imported eva
variable.If you build for both web and mobile:
generated.json
for web, but there is for mobile. Having platform-dependent entry points (different ApplicationProviders) for platforms and building the web before building a mobile is a simplest solution.We definitely need to mention this somewhere in the documentation π€
This is actually pretty cool info! Thanks a lot!
I'm about to start a project where I'll be using React Native, SSR with Razzle and React Native Web, and UI Kitten. One of my main objectives is to be as optimal as possible, knowing this info is going to be super useful.
I will consider this issue as closed.
If you have still issues with the theme file size please refer to @artyorsh's comment above.
I'm curious what performance considerations & benefits factored into building this large style lookup object (either in generated.json
cache or in memory in schemaProcessor.process
call without caching). The Button component alone results in about 44k lines in generated.json
because all styles are repeated for every combination of appearance/variants/states. This probably leads to fast lookups/rerenders at runtime once the style lookup is built (or loaded from cache), but is the performance significantly better than not building a large style lookup object and merging on demand doing something like this?
// pseudo code for fetching styles for Button/filled/primary/medium/active:
const { Button } = mapping.components;
const styles = {
// default appearance styles:
...Button.appearances.filled.mapping,
// defaults can be overridden by variant styles:
...Button.appearances.filled.variantGroups.status.primary,
...Button.appearances.filled.variantGroups.size.medium,
// overridden by state styles which could be on any variant (often status):
...Button.appearances.filled.variantGroups.status.primary.state.active
}
Is that even possible with the mapping structure? I might be missing something about how much knowledge the system can assume about style precedence at runtime without limiting flexibility...
For anybody like me who may have been concerned about initial download size for mobile with generated.json
build time styles, I just realized itβs pretty negligible (~ 100kb added to compressed aab/apk file for android). I created a UI Kitten starter template app and built it with & without generated.json and styles export in @eva-design/eva using: cd android && ./gradlew bundleRelease
. aab files are just compressed files and if you unzip it from terminal, you will see generated.json in base/res/raw folder. The size-analyzer tool with the -d flag suggestions is giving you the size savings in uncompressed, so itβs not actually adding 3.8 MB to bundle/initial download from app store - only adds ~100kb compressed.
π Bug Report
after running
yarn start
, and taking a look at the generated.json file, it seems the file is 3.8MB. This is too huge for a theme file. We should potentially use babel to tree-shake and remove the config for components that are not being used.Also noted that this file is included as res in android. I'd expect this to be in index.bundle.js so that codepush can affect theme changes.
The final bundle also has these two files included, not sure why:
To Reproduce
size-analyzer check-bundle -d app-release.aab
Expected behavior
generated.json should be included in index.bundle.js
Sample project
https://github.com/heroic/uikitten-test
run,
yarn
, and thenyarn start
and thenls -la node_modules/@eva-design/eva/generated.json
The file size is abount 3.8MB
UI Kitten and Eva version
Environment information