Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] Add Assets guide to Home #28331

Merged
merged 8 commits into from May 10, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/common/error-utilities.ts
Expand Up @@ -356,6 +356,7 @@ const RENAMED_PAGES: Record<string, string> = {
'/versions/latest/sdk/in-app-purchases/': '/guides/in-app-purchases/',
'/versions/v50.0.0/sdk/in-app-purchases/': '/guides/in-app-purchases/',
'/guides/web-performance/': '/guides/analyzing-bundles/',
'/guides/assets/': '/develop/user-interface/assets/',

// Classic updates moved to archive
'/guides/configuring-ota-updates/': '/archive/classic-updates/getting-started/',
Expand Down
1 change: 1 addition & 0 deletions docs/constants/navigation.js
Expand Up @@ -65,6 +65,7 @@ const home = [
makePage('develop/user-interface/app-icons.mdx'),
makePage('develop/user-interface/safe-areas.mdx'),
makePage('develop/user-interface/fonts.mdx'),
makePage('develop/user-interface/assets.mdx'),
makePage('develop/user-interface/color-themes.mdx'),
makePage('develop/user-interface/animation.mdx'),
makePage('develop/user-interface/store-data.mdx'),
Expand Down
1 change: 1 addition & 0 deletions docs/deploy.sh
Expand Up @@ -170,6 +170,7 @@ redirects[get-started/errors]=debugging/errors-and-warnings
redirects[develop/development-builds/parallel-installation]=build-reference/variants
redirects[home/develop/user-interface/safe-areas]=develop/user-interface/safe-areas
redirects[home/develop/development-builds/introduction]=develop/development-builds/introduction
redirects[guides/assets]=develop/user-interface/assets

# Redirects after Guides organization
redirects[guides]=guides/overview
Expand Down
125 changes: 125 additions & 0 deletions docs/pages/develop/user-interface/assets.mdx
@@ -0,0 +1,125 @@
---
title: Assets
description: Learn about using local and remote assets.
---

Files such as images, videos, sounds, database files for SQLite, or fonts are considered **assets**. They are not part of your project's JavaScript but are part of your app.
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

Your project can use two types of assets: **Local** and **Remote**. This guide will explain how to use both types of assets.

## Local assets
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

These assets are stored on your file system and can be imported like JavaScript modules using `require` or `import` statements.

For example, to render an image called **example.png** in **App.js**, you can directly use `require` to import the image from the project's **assets/images** directory and pass it to the `<Image>` component:

```jsx App.js
<Image source={require('./assets/images/example.png')} />
```

The bundler automatically provides a width and height for the images imported, as shown in the above example. For more information, see [Static Image Resources](https://reactnative.dev/docs/images#static-image-resources).

Libraries such as `expo-image` and `expo-file-system` work similarly to the `<Image>` component with local assets.

### How are local assets served

Local assets used this way are served over HTTP in development. They are automatically bundled into your app binary at the build time for production apps and served from disk on a device.

### Load a local asset at build time

> **Note:** The `expo-asset` config plugin is only available for SDK 51 and above. If you are using an older SDK, you can load a [using the `useAssets` hook](/versions/unversioned/sdk/asset/#useassetsmoduleids).
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

Install the `expo-asset` library and add the config plugin to the app config file. This plugin will embed the asset file in your native project.

```json app.json
{
"expo": {
"plugins": [
[
"expo-asset",

{
"assets": ["./assets/images/example.png"]
}
]
]
}
}
```

The `assets` option takes an array of one or more asset files or directory names to link the file to the native project. The path to each file is relative to the project's root.

When you [create a new native build](/develop/development-builds/create-a-build/), you can import and use the asset in your project without using a `require` or an `import` statement.

For example, the **example.png** is linked by the above config plugin. You can directly import it into your component:

```jsx App.js
import { Image } from 'expo-image';
/* @hide ... */ /* @end */

function App() {
return <Image source="example" />;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might want to mention that this isn't particularly useful, but if some native api expects a resource name then this makes integration with that api easier

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the following explanation below the example.

CleanShot 2024-05-07 at 04 55 46@2x

}
```

> **info** For more information on supported file formats used with the config plugin, see [Assets API reference](/versions/unversioned/sdk/asset/#configurable-properties).
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

### Load a local asset at runtime

Install the `expo-asset` library in your project. Once the installation step is complete, import the `useAssets` hook from the `expo-asset` library. The hook downloads and stores an asset locally, and after the asset is loaded, it returns a list of that asset's instances.

```jsx App.js
import { useAssets } from 'expo-asset';

export default function App() {
const [assets, error] = useAssets([
require('path/to/example-1.jpg'),
require('path/to/example-2.png'),
]);

return assets ? <Image source={assets[0]} /> : null;
}
```

## Remote assets

Remote assets are not bundled into binaries at build time. You can use the URL of the asset resource in your project if it is hosted remotely. For example, pass the URL to the `<Image>` component to render a remote image.

```jsx App.js
import { Image } from 'expo-image';
/* @hide ... */ /* @end */

function App() {
return (
<Image source={{ uri: 'https://example.com/logo.png' }} style={{ width: 50, height: 50 }} />
);
}
```

There is no guarantee about the availability of images served remotely using a web URL because an internet connection may not be available, or the asset might be removed.

Additionally, loading assets remotely also requires you to pass the metadata. In this example, the bundler cannot retrieve the image's metadata (width and height), and you have to pass it explicitly to the `<Image>` component. If you don't, the image will default to 0x0.
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

## Manual optimization methods

### Images

You can also compress images using any other online service or a tool such as:
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

- [`guetzli`](https://github.com/google/guetzli)
- [`pngcrush`](https://pmt.sourceforge.io/pngcrush/)
- [`optipng`](http://optipng.sourceforge.net/)

Some image optimizers are lossless. They re-encode your image to be smaller without any change or loss in the pixels displayed. When you need each pixel to be untouched from the original image, a lossless optimizer and a lossless image format like PNG are a good choice.

Other image optimizers are lossy. The optimized image differs from the original image. Often, lossy optimizers are more efficient because they discard visual information that reduces file size while making the image look nearly identical to humans. Tools like `imagemagick` can use comparison algorithms like [SSIM](https://en.wikipedia.org/wiki/Structural_similarity) to show how similar two images look. It's quite common for an optimized image that is over 95% similar to the original image to be far less than 95% of the original file size.

### Fonts

See [Wait for fonts to load in the Fonts guide](/develop/user-interface/fonts/#wait-for-fonts-to-load) for more information.

### Other assets

For assets like GIFs or movies, or non-code and non-image assets, it's up to the developer to optimize and minify those assets.
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

> **Note**: GIFs are a very inefficient format. Modern video codecs can produce smaller file sizes by over an order of magnitude.
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved
25 changes: 14 additions & 11 deletions docs/pages/develop/user-interface/fonts.mdx
Expand Up @@ -258,9 +258,7 @@ export default function App() {

return (
<View style={styles.container}>
<Text style={{ fontFamily: 'Inter_900Black', fontSize: 40 }}>
Inter Black
</Text>
<Text style={{ fontFamily: 'Inter_900Black', fontSize: 40 }}>Inter Black</Text>
</View>
);
}
Expand All @@ -278,21 +276,29 @@ const styles = StyleSheet.create({

## Wait for fonts to load

If you [embed your fonts in your native project](#embed-the-font-in-your-native-project), they will be available immediately without any additional code outside the config plugin. However, if you load your fonts at runtime, they will not be available immediately. So, it is generally a good practice not to render anything until the font is ready. Instead, you can continue to display the Splash Screen of your app until all fonts have loaded (or an error has been returned). It is done using [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) package. See the [minimal example](#minimal-example) section on how to use it.
If you [embed your fonts in your native project](#embed-font-in-a-native-project), they will be available immediately without any additional code outside the config plugin. However, if you load your fonts at runtime, they will not be available immediately. So, it is generally a good practice not to render anything until the font is ready. Instead, you can continue to display the Splash Screen of your app until all fonts have loaded (or an error has been returned). It is done using [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) package. See the [minimal example](#minimal-example) section on how to use it.
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

### Load fonts on the web

Sometimes, particularly on the web people choose to render their content in a platform default font while their custom font is loading. Alternatively, to render the rest of their content, that doesn't depend on the custom font while the font is loading. These approaches are called FOUT and FOIT and you can read a lot more about them on the web.
Sometimes, particularly on the web people choose to render their content in a platform default font while their custom font is loading. Alternatively, to render the rest of their content, that doesn't depend on the custom font while the font is loading. These approaches are called [Flash of Unstyled Text (FOUT), Flash of Invisible Text (FOIT), and Flash of Faux Text (FOFT)](https://css-tricks.com/fout-foit-foft/).
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

In general, these strategies are not recommended for native apps. If you include your fonts in your project, the fonts will always be delivered to the user by the time your code is running. The one exception to this is that you may prefer to do this on the web.

### Handle `@expo/vector-icons` initial load

The default behavior of `@expo/vector-icons` icons is a FOIT on the first load. On subsequent loads, the font will be automatically cached. You can preload fonts during the initial loading screen with [`useFonts`](/versions/latest/sdk/font/#usefontsmap). For example:
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

```jsx App.js
useFonts([require('./assets/fonts/ComicSans.ttf', FontAwesome.font)]);
```

## Additional information

You probably don't need to know anything beyond this point to use custom fonts effectively in your app. If you are curious or your use case has not been addressed by the above information, please continue reading.
You probably don't need to know anything beyond this point to use custom fonts effectively in your app. If you are curious or your use case has not been addressed by the above information, continue reading.
amandeepmittal marked this conversation as resolved.
Show resolved Hide resolved

### Loading a remote font directly from the web

In general, it's best and safest to load fonts from your local assets. If you submit to app stores, they will be bundled with the download and available immediately. You don't have to worry about CORS or other potential issues.
In general, it's best and safest to load fonts from your local assets. If you submit your app to app stores, the fonts will be bundled with the download and available immediately. You don't have to worry about CORS or other potential issues.

However, if you to load a remote font file directly from the web rather than from your project's assets, you can do it by replacing the `require('./assets/fonts/MyFont.otf')` with the URL of your font. See the below example:

Expand All @@ -319,15 +325,14 @@ export default function App() {
</View>
);
}
/* @hide const styles = StyleSheet.create({ ... }); */

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
/* @end */
```

</SnackInline>
Expand Down Expand Up @@ -383,15 +388,13 @@ export default class App extends React.Component {
}
}

/* @hide const styles = StyleSheet.create({ ... }); */
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
/* @end */
```

</SnackInline>
16 changes: 1 addition & 15 deletions docs/pages/eas-update/optimize-assets.mdx
Expand Up @@ -39,21 +39,7 @@ After running the command, all image assets are compressed except the ones that

### Other manual optimization methods

You can also compress images using any other online service or a tool such as:

- [`guetzli`](https://github.com/google/guetzli)
- [`pngcrush`](https://pmt.sourceforge.io/pngcrush/)
- [`optipng`](http://optipng.sourceforge.net/)

Some image optimizers are lossless. They re-encode your image to be smaller without any change or loss in the pixels displayed. When you need each pixel to be untouched from the original image, a lossless optimizer and a lossless image format like PNG are a good choice.

Other image optimizers are lossy. The optimized image differs from the original image. Often, lossy optimizers are more efficient because they discard visual information that reduces file size while making the image look nearly identical to humans. Tools like `imagemagick` can use comparison algorithms like [SSIM](https://en.wikipedia.org/wiki/Structural_similarity) to show how similar two images look. It's quite common for an optimized image that is over 95% similar to the original image to be far less than 95% of the original file size.

## Other assets

For assets like GIFs or movies, or non-code and non-image assets, it's up to the developer to optimize and minify those assets.

> **Note**: GIFs are a very inefficient format. Modern video codecs can produce smaller file sizes by over an order of magnitude.
To optimize images and videos manually, see [Assets](/develop/user-interface/assets/#manual-optimization-methods) for more information.

## Ensuring assets are included in updates

Expand Down
60 changes: 0 additions & 60 deletions docs/pages/guides/assets.mdx

This file was deleted.