Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

[RFC] esbuild support #3659

Closed
wants to merge 15 commits into from
Closed

[RFC] esbuild support #3659

wants to merge 15 commits into from

Conversation

EvanBacon
Copy link
Contributor

@EvanBacon EvanBacon commented Jul 14, 2021

Why

esbuild is a bundler written with native code, react-native is almost exclusively used with Metro bundler. This PR demonstrates how esbuild could be implemented at scale for cross platform React apps. Based on some work I did in mid-2020 -- tweet.

This is a side project and not official Expo work. Expo is a small team without the bandwidth to pursue every project.

How

Initially I built the system using a fork of React Native that had flow stripped out. Since then, esbuild has added a plugin system which can manually strip flow (suboptimal as every project must do this).

Most of the plugin system was assembled by @dalcib in his project exbuild, symbolication is based on re.pack.

The purpose of this PR is to show users how modular the bundler system is in Expo CLI, and how a new bundler can be added.

Planned

  • Native support
  • Expo Go / Dev Client support
  • Asset support
  • Websocket controls (press R and M to interact with the client)
  • Symbolication (error stack traces)
    • Open to code
    • Code preview
  • Hot module reloading
  • Flipper
    • React Dev Utils inspector
    • Logs
  • Hermes (maybe done)
  • Bare support -- EXPO_BUNDLER=esbuild expo start --dev-client
  • Fast Refresh
  • Production builds
  • Web support
  • Hidden file output
  • Monorepo support (should be able to start expo/apps/native-component-list)
  • Integrated Expo logging

Test Plan

Run the following in an Expo project:

EXPO_BUNDLER=esbuild expo start

And open the project in the Expo Go app on iOS. Use EXPO_PLATFORM=android to bundle for Android (should improve this long term).

  • Make some changes and save the project to see HMR.
  • Press r, m, shift+m in the terminal to interact with the client.

Stack Traces

Throw an error in the project to test symbolication, similar traces should be collapsed in esbuild. There is a known bug right now where the LogBox doesn't format the symbols unless you tap to the next error/warning.

@EvanBacon EvanBacon force-pushed the @evanbacon/expo-cli/esbuild branch 2 times, most recently from 4dbdbdc to 741e231 Compare July 14, 2021 04:27
added exbuild stuff

refactor

Update EsbuildConfig.ts

Update utils.ts

Added logging middleware

Added symbolicator

remove legacy

added license

Clean up extras

clean up more

split out logging plugin

Unify platform extensions

Refactor

refactor

refactor

Update EsbuildDevServer.ts
@EvanBacon EvanBacon force-pushed the @evanbacon/expo-cli/esbuild branch from 741e231 to f70e2f2 Compare July 14, 2021 04:37
})
.filter(Boolean) as string[];

const packagesRemoveFlow = new RegExp(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Split out of function and test

const patchPlugin: Plugin = {
name: 'patches',
setup(build) {
build.onLoad({ filter: /views[\\|/]GestureHandlerNative\.js$/ }, args => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Upstream fix

build.onEnd((result: any) => {
if (result.errors.length) {
logger.info(
{ tag: 'metro' },
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Create a new tag “bundler” which can be used for general events

name: 'expoLogging',
setup(build) {
build.onStart(() => {
logger.info(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add progress support if possible. Also figure out why progress loader isn’t showing in-app.
Possibly related to the issue where logs don’t show up in flipper

const { registerAsset } = require('react-native/Libraries/Image/AssetRegistry.js')
${asset.files
.map(
file => `const ${camelize(path.parse(file).name)} = require('${file.replace(/\\/g, '/')}')`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test multi resolution handling

watch: {
onRebuild(error, result) {
if (error) {
options.logger.error({ tag: 'esbuild' }, `watch build failed: ${error}`);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use “bundler” tag or maybe “devServer”

import { replaceMiddlewareWith } from '../middleware/replaceMiddlewareWith';
import getBuildOptions from './EsbuildConfig';

const nativeMiddleware = (port: number, _platform: string) => (
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Clean up, focus on JS, maps, assets, and move into a generic function. In theory, this would need to be so good that we could use it across metro and esbuild.

@@ -39,7 +39,12 @@
"@expo/metro-config": "0.1.78",
"@react-native-community/cli-server-api": "^5.0.1",
"body-parser": "1.19.0",
"deepmerge": "^4.2.2",
"deno-importmap": "^0.1.6",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe drop this one

Use generic logger tag

Simplify symbolicator

fix config

Remove deepmerge

fixup config
@EvanBacon EvanBacon force-pushed the @evanbacon/expo-cli/esbuild branch from 9875773 to 36f7bef Compare July 14, 2021 19:39
@EvanBacon EvanBacon closed this Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant