Skip to content

Commit

Permalink
🌲 Reduce bundle size on Web by 80% (software-mansion#3278)
Browse files Browse the repository at this point in the history
## Description

<!--
Description and motivation for this PR.

Inlude Fixes #<number> if this is fixing some issue.

Fixes # .
-->

Fixes software-mansion#2843.

Reduces Reanimated's bundle size on Web from `85kb` to `17kb`.

## Changes

Zero user-facing changes are in this PR. It is strictly file organization changes to optimize Reanimated for tree shaking. After extensive testing, this PR reduced Reanimated's bundle size on Web by almost 80%.

In `package.json`, you'll notice that there is a new `sideEffects` array. This is a way to tell Webpack which files need to run global code rather than as standalone modules. I looked through every file that runs on Web which edits `global` at the top-level and found 2 files. Ideally, we could move all side effects into a single file rather than colocating them with other code that may go unused. But for now, this works. (Update: I moved some into their own file)

More on Webpack tree shaking and the `sideEffects` field can be found here: https://webpack.js.org/guides/tree-shaking/

## Screenshots / GIFs

I created a fresh [repo](https://github.com/nandorojo/reanimated-tree-shaking) to fix tree shaking for Reanimated. The playground tests it by building in a Next.js app (the most common framework for Web).

Prior to this PR, this imported _all_ code from Reanimated:

```ts
import Animated from 'react-native-reanimated'
```

This resulted in an absolutely massive impact on the Web bundle size, approximately 85kb, including tons of unused code (such as layout animations).

This PR reduces the Reanimated overhead down to about `17kb`. In the future, I may be able to investigate further improvements by seeing where that size is actually coming from. But this PR is a massive step forward, since it provides no changes to the user.

I wrote about my findings [here](nandorojo/reanimated-tree-shaking#1). There are plenty of detailed screenshots there.

### Before

Massive bundle size on Web, nearly unusable.

### After

It's now very optimized for tree shaking.

## Checklist

- [x] Included code example that can be used to test this change
- [x] Updated TS types
- [ ] Added TS types tests
- [ ] Added unit / integration tests
- [ ] Updated documentation
- [x] Ensured that CI passes
  • Loading branch information
nandorojo authored and fluiddot committed Jun 5, 2023
1 parent 77225f9 commit 270ce09
Show file tree
Hide file tree
Showing 11 changed files with 49 additions and 75 deletions.
13 changes: 13 additions & 0 deletions Example/yarn.lock
Expand Up @@ -858,6 +858,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==

"@babel/helper-plugin-utils@^7.17.12":
version "7.17.12"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96"
integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==

"@babel/helper-plugin-utils@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670"
Expand Down Expand Up @@ -1350,6 +1355,14 @@
"@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-syntax-export-namespace-from" "^7.8.3"

"@babel/plugin-proposal-export-namespace-from@^7.17.12":
version "7.17.12"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz#b22864ccd662db9606edb2287ea5fd1709f05378"
integrity sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==
dependencies:
"@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-export-namespace-from" "^7.8.3"

"@babel/plugin-proposal-json-strings@^7.12.13", "@babel/plugin-proposal-json-strings@^7.14.2":
version "7.14.2"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.2.tgz#830b4e2426a782e8b2878fbfe2cba85b70cbf98c"
Expand Down
1 change: 1 addition & 0 deletions FabricExample/package.json
Expand Up @@ -13,6 +13,7 @@
"postinstall": "patch-package && echo 73fa47c9c033e2f1bf10ebab9ac58f02c94ffff9 > ./node_modules/react-native/sdks/.hermesversion"
},
"dependencies": {
"@babel/plugin-proposal-export-namespace-from": "^7.17.12",
"@react-navigation/native": "^6.0.10",
"@react-navigation/native-stack": "^6.6.2",
"react": "18.0.0",
Expand Down
16 changes: 11 additions & 5 deletions package.json
Expand Up @@ -34,10 +34,10 @@
"clean:deep": "cd android && rm -rf .cxx .gradle build && cd ../Example/android && rm -rf .gradle build app/build && cd ../.. && yarn clean",
"reset:deep": "yarn clean:deep && yarn setup"
},
"main": "lib/Animated.js",
"module": "lib/Animated",
"react-native": "src/Animated",
"source": "src/Animated",
"main": "lib/index.js",
"module": "lib/index",
"react-native": "src/index",
"source": "src/index",
"types": "react-native-reanimated.d.ts",
"files": [
"Common/",
Expand Down Expand Up @@ -76,6 +76,7 @@
},
"homepage": "https://github.com/software-mansion/react-native-reanimated#readme",
"dependencies": {
"@babel/plugin-proposal-export-namespace-from": "^7.17.12",
"@babel/plugin-transform-object-assign": "^7.16.7",
"@babel/preset-typescript": "^7.16.7",
"@types/invariant": "^2.2.35",
Expand Down Expand Up @@ -158,5 +159,10 @@
"commonjs",
"module"
]
}
},
"sideEffects": [
"./lib/reanimated2/core",
"./lib/reanimated2/js-reanimated/global",
"./lib/index"
]
}
18 changes: 0 additions & 18 deletions src/Animated.js

This file was deleted.

2 changes: 0 additions & 2 deletions src/Animated.ts
Expand Up @@ -9,5 +9,3 @@ export { default as View } from './reanimated2/component/View';
export { default as ScrollView } from './reanimated2/component/ScrollView';
export { default as Image } from './reanimated2/component/Image';
export { default as FlatList } from './reanimated2/component/FlatList';
// @ts-ignore backward compatibility with treeshaking
export * from './reanimated1';
2 changes: 0 additions & 2 deletions src/index.ts
@@ -1,7 +1,5 @@
// tree-shaken side effects
import './reanimated2/js-reanimated/global';

// @ts-ignore backward compatibility with treeshaking
export * from './reanimated1';
export * from './reanimated2';
export * as default from './Animated';
8 changes: 3 additions & 5 deletions src/reanimated2/component/FlatList.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { FlatList, FlatListProps, LayoutChangeEvent } from 'react-native';
import WrappedComponents from './WrappedComponents';
import ReanimatedView from './View';
import createAnimatedComponent from '../../createAnimatedComponent';
import { ILayoutAnimationBuilder } from '../layoutReanimation/animationBuilder/commonTypes';

Expand All @@ -15,11 +15,9 @@ interface AnimatedFlatListProps {
const createCellRenderer = (itemLayoutAnimation?: ILayoutAnimationBuilder) => {
const cellRenderer = (props: AnimatedFlatListProps) => {
return (
<WrappedComponents.View
layout={itemLayoutAnimation}
onLayout={props.onLayout}>
<ReanimatedView layout={itemLayoutAnimation} onLayout={props.onLayout}>
{props.children}
</WrappedComponents.View>
</ReanimatedView>
);
};

Expand Down
5 changes: 5 additions & 0 deletions src/reanimated2/js-reanimated/global.ts
Expand Up @@ -25,6 +25,11 @@ if (shouldBeUseWeb()) {
"[Reanimated] You can't use `scrollTo` with Chrome Debugger or with web version"
);
};
global._dispatchCommand = () => {
console.warn(
"[Reanimated] You can't use `scrollTo` or `dispatchCommand` methods with Chrome Debugger or with web version"
);
};
global._setGestureState = () => {
console.warn(
"[Reanimated] You can't use `setGestureState` with Chrome Debugger or with web version"
Expand Down
36 changes: 0 additions & 36 deletions src/reanimated2/js-reanimated/index.ts
@@ -1,5 +1,4 @@
import JSReanimated from './JSReanimated';
import { shouldBeUseWeb } from '../PlatformChecker';
import { AnimatedStyle, StyleProps } from '../commonTypes';

const reanimatedJS = new JSReanimated();
Expand All @@ -13,41 +12,6 @@ interface JSReanimatedComponent {
};
}

if (shouldBeUseWeb()) {
global._frameTimestamp = null;
global._setGlobalConsole = (_val) => {
// noop
};
global._measure = () => {
console.warn(
"[Reanimated] You can't use `measure` with Chrome Debugger or with web version"
);
return {
x: 0,
y: 0,
width: 0,
height: 0,
pageX: 0,
pageY: 0,
};
};
global._scrollTo = () => {
console.warn(
"[Reanimated] You can't use `scrollTo` with Chrome Debugger or with web version"
);
};
global._dispatchCommand = () => {
console.warn(
"[Reanimated] You can't use `scrollTo` or `dispatchCommand` methods with Chrome Debugger or with web version"
);
};
global._setGestureState = () => {
console.warn(
"[Reanimated] You can't use `setGestureState` with Chrome Debugger or with web version"
);
};
}

export const _updatePropsJS = (
updates: StyleProps | AnimatedStyle,
viewRef: { _component?: JSReanimatedComponent }
Expand Down
10 changes: 3 additions & 7 deletions tsconfig.json
Expand Up @@ -4,19 +4,15 @@
"declaration": false,
"preserveSymlinks": true,
"target": "es6",
"module": "es6",
"module": "ESNext",
"jsx": "react-native",
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"lib": ["es6", "dom"],
"esModuleInterop": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"lib/**/*.ts",
"lib/**/*.tsx",
"react-native-reanimated.d.ts"
]
"include": ["lib/**/*.ts", "lib/**/*.tsx", "react-native-reanimated.d.ts"]
}
13 changes: 13 additions & 0 deletions yarn.lock
Expand Up @@ -388,6 +388,11 @@
resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz"
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==

"@babel/helper-plugin-utils@^7.17.12":
version "7.17.12"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96"
integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==

"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.8.3"
resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz"
Expand Down Expand Up @@ -632,6 +637,14 @@
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-export-namespace-from" "^7.8.3"

"@babel/plugin-proposal-export-namespace-from@^7.17.12":
version "7.17.12"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz#b22864ccd662db9606edb2287ea5fd1709f05378"
integrity sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==
dependencies:
"@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-export-namespace-from" "^7.8.3"

"@babel/plugin-proposal-json-strings@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8"
Expand Down

0 comments on commit 270ce09

Please sign in to comment.