Skip to content

Commit

Permalink
chore: release 3.0 (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
kirillzyusko committed Jul 19, 2024
1 parent 7fe1680 commit c1fb504
Show file tree
Hide file tree
Showing 23 changed files with 1,003 additions and 1 deletion.
3 changes: 3 additions & 0 deletions docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const config = {
'2.x': {
label: '2.x',
},
'3.x': {
label: '3.x',
},
},
},
blog: {
Expand Down
7 changes: 7 additions & 0 deletions docs/versioned_docs/version-3.x/api/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"label": "API reference",
"position": 4,
"link": {
"type": "generated-index"
}
}
13 changes: 13 additions & 0 deletions docs/versioned_docs/version-3.x/api/is-cached.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
sidebar_position: 3
---

# isCached

### `isCached` - check if screen/component was already preloaded

Call this function if you need to check whether the component was already loaded or not:

`isCached(componentName: string)` => `boolean`

- `componentName` - name of the component/screen that was registered in `register` function
16 changes: 16 additions & 0 deletions docs/versioned_docs/version-3.x/api/preload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
sidebar_position: 2
---

# preload

### `preload` - as an optimization, you can also decide to preload a component before it gets rendered.

You can select what you'd like to load:
- `preload().component(componentName: string)` => `Promise`

- `componentName` - name of your component, that was registered via `register` function

- `preload().group(groupName: string)` => `Promise`

- `groupName` - name of your group, that was specified in `register` function
18 changes: 18 additions & 0 deletions docs/versioned_docs/version-3.x/api/register.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
sidebar_position: 1
---

# register

### `register` - allow you wrap your component/screen into separate bundle

`register<P>(params: Object)` - return react component (`P` - component props type, use only in TypeScript projects).

Params:
- `name` (optional) - you need to specify this param only if you will call `preload` function for this screen
- `require` - function, that return your presentation component. Example: `() => require('./Presentational.js')` (**DEPRECATED - will be removed in future releases. Use `loader` instead**)
- `loader` - function, that return your presentation component. Example: `() => import('./View')`
- `group` (optional) - You need specify it, only if you need to `preload` entire group of screens
- `static` (optional) - all static members from your presentational component.
- `cached` (optional) - Default: `true`. Set to `false` if you don't need cache your screens. _**Warning:**_ it may decrease performance of your application.
- `placeholder` (optional) - React component which will display during screen loading. Should specify if you don't use `preload` for this screen.
7 changes: 7 additions & 0 deletions docs/versioned_docs/version-3.x/fundamentals/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"label": "Fundamentals",
"position": 1,
"link": {
"type": "generated-index"
}
}
68 changes: 68 additions & 0 deletions docs/versioned_docs/version-3.x/fundamentals/basic-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
sidebar_position: 3
---

# Basic usage

This library contains pretty minimalistic API. And we will look on this a little bit later.
Let's assume we have next folder structure

.
├── ...
├── Login # Folder with your screen
│ ├── View.jsx # Your presentational component
│ ├── styles.ts # Your styles for the component
│ └── index.ts # Your entry point to the screen
└── ...

And your `index.ts` file looks like this:

```js
import View from './View';

export default View;
```

You can easily rewrite it with this library!

```js
import { register } from 'react-native-bundle-splitter';

export default register({ loader: () => import('./View') });
```

That's all! You can reload your application to see the results and guarantee this changes will not break anything.

:::tip
If you are using TypeScript in your project, then you may want to specify `Props` for your lazily loaded component. You can do it in this way:

```ts
import { register } from 'react-native-bundle-splitter';
import type {Props} from './types';

export default register<Props>({ loader: () => import('./View') });
```
:::

:::caution Avoid direct references to lazy-loaded file
Please, be sure, that you have such `index.ts` file. This library works only in case if you don't have any `import` statements which refers to your file. In other words: be sure that you do **NOT** import this file (`View`) from anywhere in your code.
:::

To assure, that you are doing everything in correct way this library provides a way for checking the performance.

In order to capture your metrics you should change your `App.js` file:

```diff
import React, { Fragment, PureComponent } from 'react';
...
+import { investigate } from 'react-native-bundle-splitter/dist/utils';

+console.log('Bundle Info: ', investigate());

class App extends PureComponent {
...
}
```

Usually your output from log will look like `Bundle Info: { loaded: 2731, waiting: 141 }`. Such way allows to understand is your changes make sense or not. After adding new screen to this library count of loaded files should be decreasing. Of course, ideal way is when you load as minimum modules as you can. For example only one page with login. In this case your startup time will be almost the same as just created application. And splash screen will not take a lot of time.
But it depends absolutely on you and yours architecture solutions. Feel free to play around this library and find suitable way for separating your files.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
sidebar_position: 2
---

# Enabling Ram Bundle

## RAM... What is it? About RAM Bundle format

### RAM Bundle format

[Metro](https://facebook.github.io/metro/) bundler for react-native offers special format - RAM (Random Access Memory). RAM bundle is a new format of React Native application packaging that helps to optimize load times of your app.

You can read [more](https://facebook.github.io/metro/docs/bundling) about this bundle format.

### Context and motivation

React Native is a still JS application. In the browser all your JavaScript and modules have to be bundled (combined, minified, and maybe even uglified) before deploying. As a result, you drastically reduce the number of files (usually down to one) along with the total size of the code you’re serving by removing all information not necessary for production, i.e., mercilessly rewriting function and variables names, deleting code comments, and so on.

The whole procedure stays pretty much the same when you’re developing a React Native app. It’s still (React-flavored) JavaScript you write there, right?

But here’s a problem: when your app grows, so does the bundle size, and let’s just say that React Native apps are usually more than a few kilobytes in size. The heavier your app bundle is, the more time it needs to be fully loaded into memory, parsed, and executed, before even showing you a splash screen!

However, the difference is that a React Native app is executed in a different environment — on your mobile device running Android or iOS (coming soon on Windows devices) rather than in your browser. This allows React Native to be smarter about what it loads to memory and when. And this is when RAM bundles come into play: they define a new bundling format that enables on-demand loading of individual app modules, resulting in a smoother user experience.

### Formats

The official way to bundle your React Native apps at the moment is using Metro Bundler, which currently supports the following bundling formats:

- **Plain**: Good old, pure JavaScript bundle. This is the default type that doesn’t offer any optimizations.

- **Indexed RAM Bundle**: This format defines a binary file with a header that can be used for quickly finding a specific module. For example, the header can tell us that module number 23 (all JavaScript modules in React Native apps are given numerical identifiers) can be found at offset 320 in the RAM bundle file, and has a length of 430 bytes. How does this help us? React Native runtime now doesn’t need to read the entire bundle file into memory, and can load specific modules only when they are needed (e.g., via inline requires).

- **File RAM Bundle**: With this approach, every module is stored in a separate file with the name `js-modules/${id}.js`, where `${id}` is the module’s ID. This format is used by default on Android devices but has the same purpose: to have fast access to individual modules in your bundle.

## Enabling RAM Bundle feature in your application

For enabling this format in your application you need to do pretty simple steps for each platform.

:::tip Enable per platform
Although enabling RAM Bundle format is recommended for both platforms, you can only enable it for one if necessary.
:::

### Android

Open `android/app/build.gradle` and edit your file in the following way.

```diff
project.ext.react = [
entryFile : "index.js",
+ bundleCommand : "ram-bundle",
+ extraPackagerArgs : ["--indexed-ram-bundle"]
...
```

:::info
You can choose between formats, since Android support both format (indexed and file). But since iOS support only `indexed` format, would be reasonable to keep both platform in consistent and use `indexed` format. But if you decided for some reasons to use `file` format, you don't need to add `extraPackagerArgs: ["--indexed-ram-bundle"]` line. By default android uses `file` format.
:::

:::caution Hermes enabled
If you are trying to enable this feature with Hermes engine, you may faced with application crash. It's a known [issue](https://github.com/facebook/react-native/issues/25730). As a temporary solution you can don't activate this bundle format for Android, since Hermes is using similar [mechanism](https://github.com/facebook/react-native/issues/25730#issuecomment-514115115).
:::

### iOS

For enabling RAM format for iOS you need to open XCode, select the project, go to `Build Phases`, and edit phase `Bundle React Native code and images`. Before `../node_modules/react-native/scripts/react-native-xcode.sh` you need to add `BUNDLE_COMMAND="ram-bundle"`:

```diff
+export BUNDLE_COMMAND="ram-bundle"
export NODE_BINARY=node
../node_modules/react-native/scripts/react-native-xcode.sh
```

### macOS

Enabling `RAM Bundles` on macOS should be done exactly in the same way as for `iOS`

Just open macOS specific project and repeat the same steps.

### web

No extra steps for `web` as there is no such term as "RAM bundles". Webpack itself will be able to split your JS bundle into small parts and will load them as soon as they are needed.

## Summary

Basically you have completed native set up and now you are ready for using this library!

:::tip
To be sure, that your application isn't broken after all manipulations you can rebuild your application and see, that it works correctly.
:::
53 changes: 53 additions & 0 deletions docs/versioned_docs/version-3.x/fundamentals/getting-started.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
sidebar_position: 1
---

# Getting started

## What to expect

Splitting your bundle into small pieces allows you reduce size of main bundle, which is loaded on application startup. It means, that you can load only necessary things, such as login pages, which user inevitably will see if open an application. And only "necessary" things will be in main bundle. Thus, this means that **the time of initial launch of the application will be minimized** and **memory consumption will be decreased**, since often in applications is a lot of code (components and screens) that the user may simply not see.

import BundleSplittingImageUrl from "@site/static/img/bundle-splitting.png";

<p style={{ textAlign: "center" }}>
<img src={BundleSplittingImageUrl}></img>
<i>
On green part of this picture, you can see that all components/screens are
divided into different groups. It allows you to load the application much
faster, because instead of loading the entire bundle (red picture), you can
load only the parts that you need.
</i>
</p>

## What does this package do?

This package is built on top of **RAM** bundles. In addition to the base functionality provided by React Native, it allows you to:

- avoid boilerplate code (you don't need to write code as per react-native docs - you can simply wrap your component into `register` function);
- use `preload` API (when you can load screens in advance and the transition to them will be as if the entire bundle was loaded at once);
- and has web support.

## Features

This library is add-on on react-native API. But this library has some features, and here is list of them:

- **Enhanced cache management**. This library provide a way for caching yours components. This mechanism allows you to improve performance of your application and help to avoid unnecessary reloading yours components, which were already loaded.
- **Ability to preload component**. You can preload components in background, which user may see in the nearest future. It allows to make UI experience more smooth and use your components from cache without any intermittentions.
- **Supporting all navigation libraries**. This library is compatible with all most known navigation libraries, such as [react-navigation](https://reactnavigation.org/), [react-native-navigation](https://wix.github.io/react-native-navigation/#/) and more others.

## Installation

Install the react-native-bundle-splitter package in your React Native project.

```bash
yarn add react-native-bundle-splitter
# or with npm
# npm install react-native-bundle-splitter --save
```

This module does not use any native (platform) dependencies and does not need to be linked. So installation process basically is finished. But you also need to enable `RAM bundles` feature in your application. To see how to do it, please read [the guide](./enabling-ram-bundle).

:::tip Minimal react-native version
You need to use react-native 0.60 or higher, since feature with inline requires is available out-of-box only from this version.
:::
7 changes: 7 additions & 0 deletions docs/versioned_docs/version-3.x/guides/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"label": "Guides",
"position": 2,
"link": {
"type": "generated-index"
}
}
Loading

0 comments on commit c1fb504

Please sign in to comment.