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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support react-native builds #2541

Closed
12 tasks
farcaller opened this issue Mar 18, 2021 · 18 comments
Closed
12 tasks

Support react-native builds #2541

farcaller opened this issue Mar 18, 2021 · 18 comments
Labels
Can Close? We will close this in 30 days if there is no further activity

Comments

@farcaller
Copy link

馃殌 feature request

This is a fork off the #2411 now that I am confident that rn support is possible to a reasonable extent. I want to collect the work on the matter in a more structured way than comments on a PR that says it's not possible :)

Relevant Rules

I expect we will need something akin to a rollup_bundle, probably metro_bundle to incapsulate the complexity of bundling the RN code.

Description

I want to see bazel building react-native projects end to end, delivering an appropriate apk or ipa for the mobile device. Good developer story (i.e. fast reloads and HMR) are useful but aren't subject of the initial effort.

Describe the solution you'd like

There are at least 3 parts to building a RN project:

  • bundle the js code;
  • build the native application for android along with any third-party packages;
  • build the native application for ios along with any third-party packages.

Describe alternatives you've considered

We could focus on bundling the JS code alone and ignore the native host apps which can be built using gradle & xcodebuild as appropriate.

Feasible milestones

  • one can build the RN js bundle using bazel, being able to rely on the ts_project rules for any supporting code;
  • the previous step needs to be as straightforward as calling a metro_bundle rule;
  • one can build the host android app with bazel:
    • this should be either done by incapsulating the gradle build into bazel;
    • or by replacing it with bazel's own adroid support;
    • it needs to support the thrid-party react-native modules;
  • one can build the host iosapp with bazel:
    • it seems that both RN and bazel delegate to xcodebuild (being the only reasonable tool to build the ios projects). Thus it's a matter of having a good level of CocoaPods support to be able to then build the native project and
    • to support the thrid-party react-native modules.
@farcaller farcaller mentioned this issue Mar 18, 2021
9 tasks
@farcaller
Copy link
Author

Field notes on metro bundler

It doesn't seem to matter much if you run react-native bundle or call into the metro bundler directly, the latter is an easier approach, though.

This is (roughly) how you call the bundler:

npm_package_bin(
    name = "metro",
    outs = ["index.android.js"],
    args = [
        "bundle",
        "--entry-file",
        "./src/mobile/index.js",  # must be relative to the WORKSPACE
        "--platform",
        "android",
        "--dev",
        "true",
        "--bundle-output",
        "$@",
        "--config",
        "./metro.config.js",  # the config must be next to the WORKSPACE
    ],
    data = glob([
        # pass in all the sources you want metro to handle. At the very least you need to pass in the index.js
        # (which can then reference from your ts_projects)
        "*/**",  
    ]) + [
        # pass in top-level configuration. Many things RN cares about are resolved against the top-level package.json
        "//:package.json", # react-native needs to see the package.json or it will run in the detached mode
        "//:metro.config.js",  # needs to be at the WORKSPACE
        "//:tsconfig.json",
    ] + [
        "@npm//metro-react-native-babel-preset",
        "@npm//:node_modules",
    ] + [
        # you can pass in all your ts_project deps as usual
        "//src/test",
    ],
    package = "react-native",
    package_bin = "react-native",
)

Here's a sample metro config:

const metroResolver = require('metro-resolver');
const path = require('path');
const rootDirs = [
  ".",
  "./bazel-out/darwin-fastbuild/bin",
  "./bazel-out/k8-fastbuild/bin",
  "./bazel-out/x64_windows-fastbuild/bin",
  "./bazel-out/darwin-dbg/bin",
  "./bazel-out/k8-dbg/bin",
  "./bazel-out/x64_windows-dbg/bin",
];

module.exports = {
  // projectRoot: '',  // TODO: do we actually need this?
  resolver: {
    resolveRequest: (_context, realModuleName, platform, moduleName) => {
      console.log(`[BAZEL] Resolving: ${moduleName}`);

      const { resolveRequest, ...context } = _context;
      try {
        return metroResolver.resolve(context, moduleName, platform);
      } catch (e) {
        console.log(`[BAZEL] Unable to resolve with default Metro resolver: ${moduleName}`);
      }
      try {
        const absOriginalModuleDir = path.dirname(_context.originModulePath);
        const relOriginalModuleDir = absOriginalModuleDir.replace(__dirname, './');
        // NB: it seems that the above ./ doesn't work while the below does, because
        //     path.join actually eats it up and simplifies the path. require.resolve()
        //     needs it though, to do the "local" resolution.
        const relPath = './' + path.join(relOriginalModuleDir, realModuleName);
        console.log(`[BAZEL] Resolving manually: ${relPath}`);
        console.log(`[BAZEL] absOriginalModuleDir=${absOriginalModuleDir})`);
        console.log(`[BAZEL] relOriginalModuleDir=${relOriginalModuleDir})`);
        // NB: we only care about .js files from in here as tsc would have processed them anyways
        const match = require.resolve(relPath, { paths: rootDirs });
        return {
          type: 'sourceFile',
          filePath: match,
        };
      } catch (e) {
        console.log(`[BAZEL] Unable to resolve with require.resolve: ${moduleName}`);
      }
    },
  },
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
  },
};

@farcaller
Copy link
Author

Field notes on android

You need to have react-native.config.js next to your package.json pointing to where your android project lives:

module.exports = {
  project: {
    android: {
      sourceDir: './src/mobile/android',
    },
  },
};

This can be verified via yarn run react-native config. Android section must not be empty.


  • it is not clear to me yet how to package gradle so it could be run within bazel. For now here's how you can build out of bazel. This will taint your source tree as gradle will create a bunch of build/ and .gradle/ directories!
  1. Copy the asset built with bazel to where gradle expects to find it: cp dist/bin/src/mobile/index.android.js ./src/mobile/android/app/build/generated/assets/react/release/index.android.bundle
  2. Chmod it so you can re-run the build: chmod 644 src/mobile/android/app/build/generated/assets/react/release/index.android.bundle
  3. Assemble the app skipping the assets: ./gradlew :app:assembleRelease -x :app:bundleReleaseJsAndAssets

It isn't possible to skip gradle completely as it does some codegen. FB seems to use buck at some point of their pipeline but they still wrap it all up in gradle.

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had any activity for 90 days. It will be closed if no further activity occurs in two weeks. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs!

@github-actions github-actions bot added the Can Close? We will close this in 30 days if there is no further activity label Jun 30, 2021
@fbartho
Copy link

fbartho commented Jun 30, 2021

Hey Stalebot! This is definitely an important issue. This issue is a blocker for me getting into Bazel, as I was looking at it to improve our reproducibility / performance when building a monorepo with multiple react-native apps.

I don't have the active knowledge of how bazel works to implement my own workarounds, and since I'm preparing this project for a team of react-native developers (who also don't know bazel), we don't have the knowledge or spare bandwidth to contribute, and I wouldn't want to ramp up a team to rely on a tool if it's not a primary supported use-case.

Hope that's sufficient justification to continue!

@farcaller
Copy link
Author

A quick update: I'm still on it. I'm trying to teach bazel to run android builds, so far unsuccessful. It works with an external Makefile but I consider that a sub-optimal solution.

@github-actions github-actions bot removed the Can Close? We will close this in 30 days if there is no further activity label Jul 1, 2021
@jahdiel
Copy link

jahdiel commented Aug 15, 2021

Minor comment: The bundling doesn't seem to work with older react and react-native versions. Had to update from { react: 16.13.1, react-native: 0.63.2 } to { react: 17.0.2, react-native: 0.64.2 }

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had any activity for 90 days. It will be closed if no further activity occurs in two weeks. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs!

@github-actions github-actions bot added the Can Close? We will close this in 30 days if there is no further activity label Nov 13, 2021
@mgenov
Copy link

mgenov commented Nov 13, 2021

Ping.

Such support is really important and would be nice to be part of rules_nodejs.

@alexeagle
Copy link
Collaborator

in our 5.0 we are working to reduce scope of rules_nodejs. Maybe someone would like to own a rules_react_native (or maybe it could go with a rules_react)

@farcaller do you still hope to come back to it?

@farcaller
Copy link
Author

Unfortunately I couldn't make it work any reliably and somewhat gave up. I'm ok to close this given the reduced scope.

@zachgrayio
Copy link

So I know this is closed, but I think maybe we might re-open it until we find out what a suitable home for this issue is? any thoughts @alexeagle ?

FWIW I just launched this MNF discussion on the same topic and would love to get some input from folks: MobileNativeFoundation/discussions#145

@zachgrayio
Copy link

@farcaller @mgenov -- we are considering assembling a working group to collaborate on this as there is interest from a few folks in the community in making this happen.

if you have any interest in collaborating in this work and/or your organization has the capability to fund it, please let me know; whether in the MNF discussion item or directly in Bazel slack or flare.build's inbox.

looks like this will likely end up in a separate repo, which is fine by me, but we'll at least keep this issue updated as that progresses, since this is currently where folks are likely to land first.

@alexeagle alexeagle reopened this Nov 22, 2021
@github-actions github-actions bot removed the Can Close? We will close this in 30 days if there is no further activity label Nov 23, 2021
@github-actions
Copy link

This issue has been automatically marked as stale because it has not had any activity for 6 months. It will be closed if no further activity occurs in 30 days. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs!

@github-actions github-actions bot added the Can Close? We will close this in 30 days if there is no further activity label May 25, 2022
@fbartho
Copy link

fbartho commented May 25, 2022

Until this feature is added, I unfortunately can't really use bazel, but I hope this comment is enough to tell stale-bot not to close this ticket!

@github-actions github-actions bot removed the Can Close? We will close this in 30 days if there is no further activity label May 26, 2022
@github-actions
Copy link

This issue has been automatically marked as stale because it has not had any activity for 6 months. It will be closed if no further activity occurs in 30 days. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs!

@github-actions github-actions bot added the Can Close? We will close this in 30 days if there is no further activity label Nov 26, 2022
@fbartho
Copy link

fbartho commented Nov 26, 2022

This is still requested. Cannot use bazel for mobile react-native without this! Thanks!

@github-actions github-actions bot removed the Can Close? We will close this in 30 days if there is no further activity label Nov 27, 2022
@github-actions
Copy link

This issue has been automatically marked as stale because it has not had any activity for 6 months. It will be closed if no further activity occurs in 30 days. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs!

@github-actions github-actions bot added the Can Close? We will close this in 30 days if there is no further activity label May 30, 2023
@github-actions
Copy link

This issue was automatically closed because it went 30 days without any activity since it was labeled "Can Close?"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Can Close? We will close this in 30 days if there is no further activity
Projects
None yet
Development

No branches or pull requests

6 participants