Skip to content

Commit

Permalink
docs: assets (#605)
Browse files Browse the repository at this point in the history
* docs: assets loader

* docs: add assets related guides

* fix: replace deadlink with placeholder for now
  • Loading branch information
jbroma committed May 8, 2024
1 parent c24c60f commit 6473b47
Show file tree
Hide file tree
Showing 6 changed files with 533 additions and 0 deletions.
10 changes: 10 additions & 0 deletions website/src/4.x/docs/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,19 @@
"type": "section-header",
"label": "Configuration"
},
{
"type": "dir",
"name": "loaders",
"label": "Loaders"
},
{
"type": "dir",
"name": "plugins",
"label": "Plugins"
},
{
"type": "dir",
"name": "guides",
"label": "Guides"
}
]
1 change: 1 addition & 0 deletions website/src/4.x/docs/guides/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["inline-assets", "remote-assets", "svg"]
93 changes: 93 additions & 0 deletions website/src/4.x/docs/guides/inline-assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Inlining Assets

There are some situations when you might want to inline assets into the JavaScript bundle, instead of extracting them into standalone files.

Common examples of such use cases are:

- Out-of-tree platforms that don't support static assets in a similar way as React Native on iOS/Android does or don't support static assets at all.
- [Code splitting](../placeholder) with static assets used by [remote chunks](../placeholder).

:::info

If you're using [Code Splitting](../placeholder) or Module Federation, assets will be inlined into the chunks or containers
importing them and should be properly rendered by the host application.

:::

## Usage

Generally speaking, to inline assets you have to pass `inline: true` option to the [Assets loader](../loaders/assets-loader):

```js
/* ... */

export default (env) => {
/* ... */

return {
/* ... */

module: {
rules: [
/* ... */

{
test: Repack.getAssetExtensionsRegExp(Repack.ASSET_EXTENSIONS),
use: {
loader: '@callstack/repack/assets-loader',
options: {
inline: true,
platform,
devServerEnabled: Boolean(devServer),
/**
* Defines which assets are scalable - which assets can have
* scale suffixes: `@1x`, `@2x` and so on.
* By default all images are scalable.
*/
scalableAssetExtensions: Repack.SCALABLE_ASSETS,
},
},
},
],
},

/* ... */
};
};
```

This will cause all assets processed by Assets loader in the rule to be inlined into the JavaScript bundle.

Inlined assets are imported in the same way as extracted assets:

```jsx
import image from './image.png';
<Image source={image} />
// or
<Image source={require('./image.png')} />
```

The value of `image` in this example would be either an object with `uri`, `width`, `height` and `scale` or an array of such objects, in case there are multiple scales.

:::info

Assets loader supports inlining assets with multiple scales.

:::

Keep in mind, you can provide multiple rules with Re.Pack's Assets loader - one rule would extract the assets and another would inline them. There's no limit how many of these rules you could have.

Make sure you configure those rules not to overlap, so that any single asset is only processed by one rule (by one Asset loader).
Use combination `include`, `exclude` and `test` (for extensions matching) to configure each rule.

:::tip

You can read more about Webpack's loader rules here: https://webpack.js.org/configuration/module/#rule-conditions:

- `test: string | RegExp | Array<string | RegExp>` must match if specified
- `include: string | RegExp | Array<string | RegExp>` must match if specified
- `exclude: string | RegExp | Array<string | RegExp>` must **not** match if specified

:::

You can even use [Webpack's Assets Modules](https://webpack.js.org/guides/asset-modules/) if you prefer (with some differences however).
103 changes: 103 additions & 0 deletions website/src/4.x/docs/guides/remote-assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Remote Assets

RePack provides you with a way to extract and serve your assets externally, such as on a CDN,
instead of bundling them directly into your application. When working with ModuleFederation
this is the recommended approach to handling the assets in federated modules, as inlining
the assets causes your bundle size to increase dramatically.

## Usage

To convert assets to remote assets you have to configure `remote` option to the [Assets loader](../loaders/assets-loader):

```js
/* ... */

export default (env) => {
/* ... */

return {
/* ... */

module: {
rules: [
/* ... */

{
test: Repack.getAssetExtensionsRegExp(
Repack.ASSET_EXTENSIONS.filter((ext) => ext !== 'svg')
),
use: {
loader: '@callstack/repack/assets-loader',
options: {
platform,
devServerEnabled: Boolean(devServer),
scalableAssetExtensions: Repack.SCALABLE_ASSETS,
remote: {
enabled: true,
publicPath: 'http://localhost:9999',
},
},
},
},
],
},

/* ... */
};
};
```

This will cause all assets processed by this Assets Loader to be converted to remote ones.

:::info
For development, it's best to set `enabled: false` and load the assets locally. This will allow you to work with the assets more efficiently. However, when you're ready to move to production, you can switch the flag to `enabled: true` and include the converted assets in the production bundle.
:::

Remote assets are imported in the same way as local assets:

```jsx
import image from './image.png';
<Image source={image} />
// or
<Image source={require('./image.png')} />
```

In both cases shown above, the the value of `source` prop will resolve to an object of shape:

```ts
type source = {
uri: string;
width: number;
height: number;
scale: number;
};
```

The `uri` prop will have a value of an URL that's constructed by joining `publicPath`, 'assets' and local path to the asset together. If `publicPath` is set to https://example.com and the local path to the asset is logo.png, then the resulting `uri` value would be: `https://example.com/assets/images/logo.png`.

:::info

Scaled assets are fully supported. The asset will resolve to proper scale in runtime by constructing a relevant URL with scale suffix at the end of it.

:::

When you create a production bundle, a directory called `remote-assets` will be included in your project's build directory. This directory contains all of the remote assets that are needed for your application.

By default, the remote-assets directory will be located at `build/generated/<platform>/remote-assets`. However, if you want the remote assets to appear in the `OutputPlugin` directory, which is part of the `RepackPlugin`, you will need to configure an additional property called `auxiliaryAssetsPath`:

```ts
new Repack.RepackPlugin({
context,
mode,
platform,
devServer,
output: {
bundleFilename,
sourceMapFilename,
assetsPath,
auxiliaryAssetsPath: path.join('build/output', platform, 'remote'),
},
});
```

The final step is to upload your remote assets to your CDN, which is located at `publicPath`, and then host them from that location, which will make them available to users of your app.

0 comments on commit 6473b47

Please sign in to comment.