Skip to content

How it works

This guide is optional and provides a high-level explanation of how to render a remote component using ReChunk. There are two main parts to this library - the client and the command-line interface (CLI). The CLI is the precursor to actually being able to render a remote component via the client.

Command-line Interface

The CLI has 5 commands currently: dev-server, init, list, publish and unpublish. The commands allow you to actively integrate with a remote ReChunk service to bundle and cache your components. In this guide only 3 commands will be discuused: dev-server init and publish - as this guide is more high-level and explaining how this library works.

Initialization

The ReChunk library relies almost completely on a configuration file to ease the integration process. This configuration is denoted by the rechunk.json file. In the example app of this repo there is already a rechunk.json configuration file generated for anybody to test out this library without a remote ReChunk service. To generate a rechunk.json configuration file utilize the init command - this will generate a new ReChunk project to publish components to.

Terminal window
yarn rechunk init --host http://localhost:3000 --username rechunk --password aC00Lpr0ject

In the above example command usage there are three required options: host, username and password. The host is where the ReChunk service is being hosted, the username and password are the basic authentication credentials that the project creation endpoint abides by. Once the command is complete a rechunk.json configuration file will be generated in the root of your React Native project - it will look similar to the following file.

rechunk.json
{
"$schema": "https://crherman7.github.io/rechunk/schema.json",
"project": "prototypical-pigs-interlay",
"readKey": "read-5456fcad-99bd-4328-bfc4-0cb597ffbc4d",
"writeKey": "write-9bd47fc2-323e-4f74-9082-2abfb86582b4",
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArk92wo3nc7AShy2c860h\nojRACKTnYGbB1NPRezyZ40Lk9p/myZ02ZpmVDGlMtWgqgIOoufUwPTa9LkmjFUgg\nYkhDHZzokiJjZ9PseRXr4+63p8MSvOmQvoQMqSO2mBEuXTks4tTNx/AySWqV9GDC\nMeM+VFKtQULuxgQSNJ1LDIu8ofpeKDB2bivV8phrLzRSM4TWuCu9u9gWxsUbTihR\nLyicJvmx44NBmdr9N0WIOh/15vAYieiY8MsZE7B8St0x5jgDT4taUzTd8R0RyDw/\nOtpCeOIDGwmz7h0Rx2r0Q+WOuRL4MSbGBJuT3TJoWkOPCrhfH3Sc6a61NyoPeiDZ\nXQIDAQAB\n-----END PUBLIC KEY-----\n",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuT3bCjedzsBKH\nLZzzrSGiNEAIpOdgZsHU09F7PJnjQuT2n+bJnTZmmZUMaUy1aCqAg6i59TA9Nr0u\nSaMVSCBiSEMdnOiSImNn0+x5Fevj7renwxK86ZC+hAypI7aYES5dOSzi1M3H8DJJ\napX0YMIx4z5UUq1BQu7GBBI0nUsMi7yh+l4oMHZuK9XymGsvNFIzhNa4K7272BbG\nxRtOKFEvKJwm+bHjg0GZ2v03RYg6H/Xm8BiJ6JjwyxkTsHxK3THmOANPi1pTNN3x\nHRHIPD862kJ44gMbCbPuHRHHavRD5Y65EvgxJsYEm5PdMmhaQ48KuF8fdJzprrU3\nKg96INldAgMBAAECggEAQfVhzAbkYRtsN2ikLnUB+B3raRn1T74ydHVenFJ3LM7g\nUw54xyvNLQ/KnbKuyypKguzPCOblxRQUjBJjOqdbUbVkaC06uCl5Eg3YOo14AH0R\nU9L2ITQEiILxQ4N3EZ3WvIHpIUBDSffzH2LMsXd3pGcH6+KJGtvX/GgH947Zmjoa\nXOiu3hw+E1qZaUTjWgGYmT+ph+8gHW34ner5JS4m8tqkNtP0U2DJIVD7MR5i/jp3\nzv19/foEUew8wvs4R4GcvS3xGETebg4H6DonxJ79HtXe3jzigreOLYybjyw4zRFv\nYHDh9qRCL20Qydq7Ogg963Yur1Ecys2faeehNp8pxQKBgQDUNreN8wMYU4/qyLmi\n7wHQ9rr/pqqcNsLsBRSlwXKsK7ffwSjvx+aUOzucnlHUrLpJtllT551aWw8EY4Rx\nGI7iTwCPCKK7s6laZeXSrSKWgXibTuCn/1FJ8dZbFHKhWaXQW2QFSSNRzqp41FhB\ncZXs9cS0Yf6issvtiP7hAX7N/wKBgQDSRqpdl/eX2t4vMYbdfHvvtzy01MccKrQ2\nhADX/PgVAe/8n1/vxftK5cKAUapq0gpS8/1mRuTeRZ9a7HAZvpNuYEKhlRsSOzNg\nYYqNmq9F33kxRjsdm6RrYMMyk8v8pIuyFTaZY+MdIRDt306a2VK4EAQxS5G+wTr6\nOgOM4fxQowKBgGawZ5gf7PJ7lRu2r+XBJC7bBdgp7UsUULRnLPucpYHc0ehLjySg\npdo643jBP7XbM3Xx8D3iyUjs4VJtWaxkhtfKBOox8pVDtgKRZmnQ7/jGg/cbbyi8\nKrjOdryyI1oiiFNPthG8t4OhruozTtW0QildMCddeBuAy5+Q+E0nLRY/AoGAFxXR\nAGN9uDs8J1w9nTVcee3ZCVVO4sXBcTa+zPel2NCUo1xv8OgAdbGRz/qnRgD3RzIo\nQMFJwSlNnHLWv8zPbM++oPS4uyCqvEsZJgC0e2xUZtd6B/8dZviBlZzqSTtbZtqz\nWtW/imQl8qeQfqmbTj/b5fmQ76tRKUWTPDVXORcCgYEArx0LII/G1luLj/z2bvhz\nA5OXyUL7ka2wJqmpb0XdFP+PPIsud5GXf2uG9GTkhBHnwuakXW8UdB/4pwEtAYRS\nGndITg+KPDwTvuz6P51MQM6wd1922UKjTl3BY+7CzaWCuBGV/yfFjpsWtoSQJvSY\nDCwpHpF7v/6fhQU/Y2ZnI84=\n-----END PRIVATE KEY-----\n",
"entry": {},
"external": [],
"host": "http://localhost:3000"
}

This configuration file contains both public and private information, it’s very important that the writeKey and privateKey are not leaked outside of your repository. The writeKey is responsible for manipulating your cached components and the privateKey is responsible for generating a digital signature.

At this point a component can now be bundled to be cached via the ReChunk service. Update the entry value with a key and path relative to the root of the project.

rechunk.json
{
"$schema": "https://crherman7.github.io/rechunk/schema.json",
"project": "prototypical-pigs-interlay",
"readKey": "read-5456fcad-99bd-4328-bfc4-0cb597ffbc4d",
"writeKey": "write-9bd47fc2-323e-4f74-9082-2abfb86582b4",
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArk92wo3nc7AShy2c860h\nojRACKTnYGbB1NPRezyZ40Lk9p/myZ02ZpmVDGlMtWgqgIOoufUwPTa9LkmjFUgg\nYkhDHZzokiJjZ9PseRXr4+63p8MSvOmQvoQMqSO2mBEuXTks4tTNx/AySWqV9GDC\nMeM+VFKtQULuxgQSNJ1LDIu8ofpeKDB2bivV8phrLzRSM4TWuCu9u9gWxsUbTihR\nLyicJvmx44NBmdr9N0WIOh/15vAYieiY8MsZE7B8St0x5jgDT4taUzTd8R0RyDw/\nOtpCeOIDGwmz7h0Rx2r0Q+WOuRL4MSbGBJuT3TJoWkOPCrhfH3Sc6a61NyoPeiDZ\nXQIDAQAB\n-----END PUBLIC KEY-----\n",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuT3bCjedzsBKH\nLZzzrSGiNEAIpOdgZsHU09F7PJnjQuT2n+bJnTZmmZUMaUy1aCqAg6i59TA9Nr0u\nSaMVSCBiSEMdnOiSImNn0+x5Fevj7renwxK86ZC+hAypI7aYES5dOSzi1M3H8DJJ\napX0YMIx4z5UUq1BQu7GBBI0nUsMi7yh+l4oMHZuK9XymGsvNFIzhNa4K7272BbG\nxRtOKFEvKJwm+bHjg0GZ2v03RYg6H/Xm8BiJ6JjwyxkTsHxK3THmOANPi1pTNN3x\nHRHIPD862kJ44gMbCbPuHRHHavRD5Y65EvgxJsYEm5PdMmhaQ48KuF8fdJzprrU3\nKg96INldAgMBAAECggEAQfVhzAbkYRtsN2ikLnUB+B3raRn1T74ydHVenFJ3LM7g\nUw54xyvNLQ/KnbKuyypKguzPCOblxRQUjBJjOqdbUbVkaC06uCl5Eg3YOo14AH0R\nU9L2ITQEiILxQ4N3EZ3WvIHpIUBDSffzH2LMsXd3pGcH6+KJGtvX/GgH947Zmjoa\nXOiu3hw+E1qZaUTjWgGYmT+ph+8gHW34ner5JS4m8tqkNtP0U2DJIVD7MR5i/jp3\nzv19/foEUew8wvs4R4GcvS3xGETebg4H6DonxJ79HtXe3jzigreOLYybjyw4zRFv\nYHDh9qRCL20Qydq7Ogg963Yur1Ecys2faeehNp8pxQKBgQDUNreN8wMYU4/qyLmi\n7wHQ9rr/pqqcNsLsBRSlwXKsK7ffwSjvx+aUOzucnlHUrLpJtllT551aWw8EY4Rx\nGI7iTwCPCKK7s6laZeXSrSKWgXibTuCn/1FJ8dZbFHKhWaXQW2QFSSNRzqp41FhB\ncZXs9cS0Yf6issvtiP7hAX7N/wKBgQDSRqpdl/eX2t4vMYbdfHvvtzy01MccKrQ2\nhADX/PgVAe/8n1/vxftK5cKAUapq0gpS8/1mRuTeRZ9a7HAZvpNuYEKhlRsSOzNg\nYYqNmq9F33kxRjsdm6RrYMMyk8v8pIuyFTaZY+MdIRDt306a2VK4EAQxS5G+wTr6\nOgOM4fxQowKBgGawZ5gf7PJ7lRu2r+XBJC7bBdgp7UsUULRnLPucpYHc0ehLjySg\npdo643jBP7XbM3Xx8D3iyUjs4VJtWaxkhtfKBOox8pVDtgKRZmnQ7/jGg/cbbyi8\nKrjOdryyI1oiiFNPthG8t4OhruozTtW0QildMCddeBuAy5+Q+E0nLRY/AoGAFxXR\nAGN9uDs8J1w9nTVcee3ZCVVO4sXBcTa+zPel2NCUo1xv8OgAdbGRz/qnRgD3RzIo\nQMFJwSlNnHLWv8zPbM++oPS4uyCqvEsZJgC0e2xUZtd6B/8dZviBlZzqSTtbZtqz\nWtW/imQl8qeQfqmbTj/b5fmQ76tRKUWTPDVXORcCgYEArx0LII/G1luLj/z2bvhz\nA5OXyUL7ka2wJqmpb0XdFP+PPIsud5GXf2uG9GTkhBHnwuakXW8UdB/4pwEtAYRS\nGndITg+KPDwTvuz6P51MQM6wd1922UKjTl3BY+7CzaWCuBGV/yfFjpsWtoSQJvSY\nDCwpHpF7v/6fhQU/Y2ZnI84=\n-----END PRIVATE KEY-----\n",
"entry": {"foo": "./src/shared/remote-ui/Remote.tsx"},
"external": [],
"host": "http://localhost:3000"
}

The publish command can now be utilized to bundle this component to the ReChunk service.

Terminal window
yarn rechunk publish --chunk foo

Once the command has finished the bundle is ready to be consumed by the client. If you are developing bundles and need to test them out before publishing them, that can be done via the dev-server command.

Terminal window
yarn rechunk dev-server

Once you start the React Native app, the client will now connect to the development server instead of the ReChunk service. Components will be bundled on the fly from the file-system when the client attempts to consume a bundle.

Client

The client library handles the process of consuming a bundled component, verifying data integrity and converting the bundle into a renderable component.

Bundle Consumption

After installing, configuration babel, generating a ReChunk project and publishing a component - the published component can now be consumed by the client. The out-of-the-box experience provided by the client does not require any runtime configuration (not to be mistaken by compile time configuration via the rechunk.json). The only reason to need a runtime configuration is if there is a necessity to override the resolver, global require function, public key or verification conditions. Otherwise, the babel configuration takes care of all code-generation to run the client without runtime configuration.

In order to consume the ReChunk bundle the default resolver will fetch the bundle from the host denoted in the rechunk.json configuration.

index.ts
export async function(chunkId: string) {
try {
const response = await fetch(
`${process.env.RECHUNK_HOST}/chunk/${chunkId}`,
{
method: 'GET',
headers: {
Authorization: `Basic ${btoa(
`${process.env.RECHUNK_PROJECT}:${process.env.RECHUNK_READ_KEY}`,
)}`,
},
},
);
if (!response.ok) {
throw new Error(`Failed to fetch chunk with ID ${chunkId}`);
}
return response.json();
} catch (error: any) {
throw new Error(`Failed to fetch chunk: ${error.message}`);
}
}

Once the bundle is consumed the client will then attempt to verify the data and render the component. If there are any errors, they will be hoisted to the application and will need to be handled - the recommended approache for this is via an error boundary.

Data Verification

Ensuring data integrity is crucial because this library executes JavaScript; when fetching a chunk, there’s a risk of tampering to execute malicious code, underscoring the need for data integrity verification. This library employs digital signature verification for this purpose.

Digital signatures are mathematical tools used to confirm the authenticity of digital messages or documents. A valid digital signature assures the recipient that the sender is trusted. This library uses encoded data, hashed data, and a public key to verify authenticity. If verification succeeds, the component is rendered; otherwise, an error occurs.

Since there are very limited, if any, JavaScript libraries that provide digital signature verification - the verification occurs on the native iOS and Android platforms via a React Native bridge. Verification is enabled by default - if for some reason you choose to disable verification, highly unrecommended, this can be done via the ReChunk runtime configuration.

index.ts
import ReChunk from '@crherman7/rechunk';
ReChunk.addConfiguration({verify: false});

Component Rendering

To render a component from a string, we leverage the new Function JavaScript instance. This approach involves passing in a custom require function, which is generated using Babel during compile time. The custom require function is designed to inject all necessary dependencies.

The string component and custom require function are then combined within the new Function instance and returned as the default object. This technique enables efficient lazy loading of components.

App.tsx
import {importChunk} from '@crherman7/rechunk';
const Foo = React.lazy(() => importChunk('foo'));
export function App(): React.JSX.Element {
return (
<ErrorBoundary FallbackComponent={Error404}>
<Suspense fallback={<ActivityIndicator style={styles.container} />}>
<Foo />
</Suspense>
</ErrorBoundary>
);
}

The importChunk method is the consumption, verification and component generation occurs. The importChunk method is meant to work the same way i.e. function signature, as import works with React.lazy.