repack icon indicating copy to clipboard operation
repack copied to clipboard

Re.pack Rspack (5.0.0-alpha.0) - Panic occurred at runtime. Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.

Open sahajarora1286 opened this issue 1 year ago • 2 comments

Describe the bug

I am trying to upgrade from @callstack/repack v4 to v5.0.0-alpha.0. I have followed the templates in the repack example as well as the official webpack -> rspack migration documentation to migrate from webpack to rspack.

I have a react-native super-app that leverages module-federation and exists as a monorepo.

Here's what my rspack.config.mjs file looks like for the host:

export default (env) => {
  console.log('using mobile webpack config...');
  const {
    mode = 'development',
    context = Repack.getDirname(import.meta.url),
    entry = './index.js',
    platform = process.env.PLATFORM,
    minimize = mode === 'production',
    devServer = undefined,
    bundleFilename = undefined,
    sourceMapFilename = undefined,
    assetsPath = undefined,
    reactNativePath = new URL('./node_modules/react-native', import.meta.url)
      .pathname,
  } = env;
  const dirname = Repack.getDirname(import.meta.url);

  if (!platform) {
    throw new Error('Missing platform');
  }

  /**
   * Depending on your Babel configuration you might want to keep it.
   * If you don't use `env` in your Babel config, you can remove it.
   *
   * Keep in mind that if you remove it you should set `BABEL_ENV` or `NODE_ENV`
   * to `development` or `production`. Otherwise your production code might be compiled with
   * in development mode by Babel.
   */
  process.env.BABEL_ENV = mode;

  return {
    mode,
    /**
     * This should be always `false`, since the Source Map configuration is done
     * by `SourceMapDevToolPlugin`.
     */
    devtool: false,
    context,
    /**
     * `getInitializationEntries` will return necessary entries with setup and initialization code.
     * If you don't want to use Hot Module Replacement, set `hmr` option to `false`. By default,
     * HMR will be enabled in development mode.
     */
    entry,
    resolve: {
      /**
       * `getResolveOptions` returns additional resolution configuration for React Native.
       * If it's removed, you won't be able to use `<file>.<platform>.<ext>` (eg: `file.ios.js`)
       * convention and some 3rd-party libraries that specify `react-native` field
       * in their `package.json` might not work correctly.
       */
      ...Repack.getResolveOptions(platform),
      tsConfig: './tsconfig.json',
    },
    /**
     * Configures output.
     * It's recommended to leave it as it is unless you know what you're doing.
     * By default Webpack will emit files into the directory specified under `path`. In order for the
     * React Native app use them when bundling the `.ipa`/`.apk`, they need to be copied over with
     * `Repack.OutputPlugin`, which is configured by default inside `Repack.RepackPlugin`.
     */
    output: {
      clean: true,
      hashFunction: 'xxhash64',
      path: path.join(dirname, 'build/generated', platform),
      filename: 'index.bundle',
      chunkFilename: '[name].chunk.bundle',
      publicPath: Repack.getPublicPath({ platform, devServer }),
    },
    /**
     * Configures optimization of the built bundle.
     */
    optimization: {
      /** Enables minification based on values passed from React Native CLI or from fallback. */
      minimize,
      /** Configure minimizer to process the bundle. */
      minimizer: [
        new TerserPlugin({
          test: /\.(js)?bundle(\?.*)?$/i,
          /**
           * Prevents emitting text file with comments, licenses etc.
           * If you want to gather in-file licenses, feel free to remove this line or configure it
           * differently.
           */
          extractComments: false,
          terserOptions: {
            format: {
              comments: false,
            },
          },
        }),
      ],
      chunkIds: 'named',
    },
    module: {
      rules: [
        Repack.REACT_NATIVE_LOADING_RULES,
        Repack.NODE_MODULES_LOADING_RULES,
        /* repack is symlinked to a local workspace */
        {
          test: /\.[jt]sx?$/,
          type: 'javascript/auto',
          include: [/repack[/\\]dist/],
          use: {
            loader: 'builtin:swc-loader',
            options: {
              env: { targets: { 'react-native': '0.74' } },
              jsc: { externalHelpers: true },
            },
          },
        },
        /* codebase rules */
        {
          test: /\.[jt]sx?$/,
          type: 'javascript/auto',
          exclude: [/node_modules/, /repack[/\\]dist/],
          use: {
            loader: 'builtin:swc-loader',
            /** @type {import('@rspack/core').SwcLoaderOptions} */
            options: {
              sourceMaps: true,
              env: {
                targets: { 'react-native': '0.74' },
              },
              jsc: {
                parser: {
                  syntax: 'typescript',
                },
                externalHelpers: true,
                transform: {
                  react: {
                    runtime: 'automatic',
                  },
                },
              },
            },
          },
        },
        {
          test: Repack.getAssetExtensionsRegExp(Repack.ASSET_EXTENSIONS),
          use: {
            loader: '@callstack/repack/assets-loader',
            options: {
              platform,
              devServerEnabled: Boolean(devServer),
            },
          },
        },
      ],
    },
    plugins: [
      new rspack.IgnorePlugin({ resourceRegExp: /@react-native-masked-view/ }),
      /**
       * Configure other required and additional plugins to make the bundle
       * work in React Native and provide good development experience with
       * sensible defaults.
       *
       * `Repack.RepackPlugin` provides some degree of customization, but if you
       * need more control, you can replace `Repack.RepackPlugin` with plugins
       * from `Repack.plugins`.
       */
      new Repack.RepackPlugin({
        context,
        mode,
        platform,
        devServer,
        output: {
          bundleFilename,
          sourceMapFilename,
          assetsPath,
        },
      }),
      new Repack.plugins.ModuleFederationPlugin({
        name: 'host',
        shared: {
          react: {
            ...Repack.Federated.SHARED_REACT,
            requiredVersion: '18.2.0',
            eager: true,
          },
          'react-native': {
            ...Repack.Federated.SHARED_REACT_NATIVE,
            requiredVersion: '0.74',
            eager: true,
          },
          reselect: {
            singleton: true,
            requiredVersion: monorepoDeps['reselect'],
            eager: true,
          },
          'react-redux': {
            singleton: true,
            requiredVersion: monorepoDeps['react-redux'],
            eager: true,
          },
          '@reduxjs/toolkit': {
            singleton: true,
            requiredVersion: monorepoDeps['@reduxjs/toolkit'],
            eager: true,
          },
          '@reduxjs/toolkit/query': {
            singleton: true,
            requiredVersion: monorepoDeps['@reduxjs/toolkit/query'],
            eager: true,
          },
          '@reduxjs/toolkit/query/react': {
            singleton: true,
            requiredVersion: monorepoDeps['@reduxjs/toolkit/query/react'],
            eager: true,
          },
          '@react-navigation/native': {
            singleton: true,
            requiredVersion: monorepoDeps['@react-navigation/native'],
            eager: true,
          },
          '@react-navigation/native-stack': {
            singleton: true,
            requiredVersion: monorepoDeps['@react-navigation/native-stack'],
            eager: true,
          },
          'react-native-screens': {
            singleton: true,
            requiredVersion: monorepoDeps['react-native-screens'],
            eager: true,
          },
          'react-native-safe-area-context': {
            singleton: true,
            requiredVersion: monorepoDeps['react-native-safe-area-context'],
            eager: true,
          },
          'redux-persist': {
            singleton: true,
            requiredVersion: monorepoDeps['redux-persist'],
            eager: true,
          },
          '@react-native-async-storage/async-storage': {
            singleton: true,
            requiredVersion:
              monorepoDeps['@react-native-async-storage/async-storage'],
            eager: true,
          },
        },
      }),
      new rspack.EnvironmentPlugin({ MF_CACHE: null }),
      process.env.RSDOCTOR && new RsdoctorRspackPlugin(),
    ].filter(Boolean),
  };
};

When I try to start the host app using the command: react-native webpack-start --webpackConfig ./rspack.config.mjs --host 127.0.0.1, I get the following error:

Panic occurred at runtime. Please file an issue on GitHub with the backtrace below: https://github.com/web-infra-dev/rspack/issues
Message:  Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.
Location: crates/rspack_binding_options/src/options/raw_devtool.rs:99

My motivation, and need, to get to Rspack from Webpack is to lower the build time it currently takes with webpack. The fact that with callstack/repack v4 we need to use webpack and babel-loader to transpile huge node_module files (for react-native compatibility) is a pain and leads to really slow compilation of the host and other mini-apps that have bare minimal code (2-4 source files). I have learnt that swc is a much faster alternative to babel-loader and hence I'd love to be able to leverage it in my project setup.

Any help with resolving this issue and getting my project to successfully work with @callstack/repack v5.0.0-alpha.0 and rspac + swc-loader would be highly appreciated.

Thanks !

System Info

System:
  OS: macOS 14.5
  CPU: (10) arm64 Apple M1 Max
  Memory: 104.30 MB / 64.00 GB
  Shell:
    version: 3.2.57
    path: /bin/bash
Binaries:
  Node:
    version: 18.18.0
    path: ~/.nvm/versions/node/v18.18.0/bin/node
  Yarn:
    version: 1.19.0
    path: /opt/homebrew/bin/yarn
  npm:
    version: 9.8.1
    path: ~/.nvm/versions/node/v18.18.0/bin/npm
  Watchman: Not Found
Managers:
  CocoaPods:
    version: 1.15.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK: Not Found
  Android SDK: Not Found
IDEs:
  Android Studio: 2021.3 AI-213.7172.25.2113.9123335
  Xcode:
    version: /undefined
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.5
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react: Not Found
  react-native:
    installed: 0.74.5
    wanted: "0.74"
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Re.Pack Version

5.0.0-alpha.0

Reproduction

n/a

Steps to reproduce

Use the following config for rspack.config.js :

import path from 'path';
import TerserPlugin from 'terser-webpack-plugin';
import * as Repack from '@callstack/repack';
import monorepoPackage from '../../package.json' assert { type: 'json' };
import rspack from '@rspack/core';
import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';

const monorepoDeps = monorepoPackage.dependencies;

/**
 * More documentation, installation, usage, motivation and differences with Metro is available at:
 * https://github.com/callstack/repack/blob/main/README.md
 *
 * The API documentation for the functions and plugins used in this file is available at:
 * https://re-pack.netlify.app/
 */

/**
 * Webpack configuration.
 * You can also export a static object or a function returning a Promise.
 *
 * @param env Environment options passed from either Webpack CLI or React Native CLI
 *            when running with `react-native start/bundle`.
 */
export default (env) => {
  console.log('using mobile webpack config...');
  const {
    mode = 'development',
    context = Repack.getDirname(import.meta.url),
    entry = './index.js',
    platform = process.env.PLATFORM,
    minimize = mode === 'production',
    devServer = undefined,
    bundleFilename = undefined,
    sourceMapFilename = undefined,
    assetsPath = undefined,
    reactNativePath = new URL('./node_modules/react-native', import.meta.url)
      .pathname,
  } = env;
  const dirname = Repack.getDirname(import.meta.url);

  if (!platform) {
    throw new Error('Missing platform');
  }

  /**
   * Depending on your Babel configuration you might want to keep it.
   * If you don't use `env` in your Babel config, you can remove it.
   *
   * Keep in mind that if you remove it you should set `BABEL_ENV` or `NODE_ENV`
   * to `development` or `production`. Otherwise your production code might be compiled with
   * in development mode by Babel.
   */
  process.env.BABEL_ENV = mode;

  return {
    mode,
    /**
     * This should be always `false`, since the Source Map configuration is done
     * by `SourceMapDevToolPlugin`.
     */
    devtool: false,
    context,
    /**
     * `getInitializationEntries` will return necessary entries with setup and initialization code.
     * If you don't want to use Hot Module Replacement, set `hmr` option to `false`. By default,
     * HMR will be enabled in development mode.
     */
    entry,
    resolve: {
      /**
       * `getResolveOptions` returns additional resolution configuration for React Native.
       * If it's removed, you won't be able to use `<file>.<platform>.<ext>` (eg: `file.ios.js`)
       * convention and some 3rd-party libraries that specify `react-native` field
       * in their `package.json` might not work correctly.
       */
      ...Repack.getResolveOptions(platform),
      tsConfig: './tsconfig.json',
    },
    /**
     * Configures output.
     * It's recommended to leave it as it is unless you know what you're doing.
     * By default Webpack will emit files into the directory specified under `path`. In order for the
     * React Native app use them when bundling the `.ipa`/`.apk`, they need to be copied over with
     * `Repack.OutputPlugin`, which is configured by default inside `Repack.RepackPlugin`.
     */
    output: {
      clean: true,
      hashFunction: 'xxhash64',
      path: path.join(dirname, 'build/generated', platform),
      filename: 'index.bundle',
      chunkFilename: '[name].chunk.bundle',
      publicPath: Repack.getPublicPath({ platform, devServer }),
    },
    /**
     * Configures optimization of the built bundle.
     */
    optimization: {
      /** Enables minification based on values passed from React Native CLI or from fallback. */
      minimize,
      /** Configure minimizer to process the bundle. */
      minimizer: [
        new TerserPlugin({
          test: /\.(js)?bundle(\?.*)?$/i,
          /**
           * Prevents emitting text file with comments, licenses etc.
           * If you want to gather in-file licenses, feel free to remove this line or configure it
           * differently.
           */
          extractComments: false,
          terserOptions: {
            format: {
              comments: false,
            },
          },
        }),
      ],
      chunkIds: 'named',
    },
    module: {
      rules: [
        Repack.REACT_NATIVE_LOADING_RULES,
        Repack.NODE_MODULES_LOADING_RULES,
        /* repack is symlinked to a local workspace */
        {
          test: /\.[jt]sx?$/,
          type: 'javascript/auto',
          include: [/repack[/\\]dist/],
          use: {
            loader: 'builtin:swc-loader',
            options: {
              env: { targets: { 'react-native': '0.74' } },
              jsc: { externalHelpers: true },
            },
          },
        },
        /* codebase rules */
        {
          test: /\.[jt]sx?$/,
          type: 'javascript/auto',
          exclude: [/node_modules/, /repack[/\\]dist/],
          use: {
            loader: 'builtin:swc-loader',
            /** @type {import('@rspack/core').SwcLoaderOptions} */
            options: {
              sourceMaps: true,
              env: {
                targets: { 'react-native': '0.74' },
              },
              jsc: {
                parser: {
                  syntax: 'typescript',
                },
                externalHelpers: true,
                transform: {
                  react: {
                    runtime: 'automatic',
                  },
                },
              },
            },
          },
        },
        {
          test: Repack.getAssetExtensionsRegExp(Repack.ASSET_EXTENSIONS),
          use: {
            loader: '@callstack/repack/assets-loader',
            options: {
              platform,
              devServerEnabled: Boolean(devServer),
            },
          },
        },
      ],
    },
    plugins: [
      new rspack.IgnorePlugin({ resourceRegExp: /@react-native-masked-view/ }),
      /**
       * Configure other required and additional plugins to make the bundle
       * work in React Native and provide good development experience with
       * sensible defaults.
       *
       * `Repack.RepackPlugin` provides some degree of customization, but if you
       * need more control, you can replace `Repack.RepackPlugin` with plugins
       * from `Repack.plugins`.
       */
      new Repack.RepackPlugin({
        context,
        mode,
        platform,
        devServer,
        output: {
          bundleFilename,
          sourceMapFilename,
          assetsPath,
        },
      }),
      new Repack.plugins.ModuleFederationPlugin({
        name: 'host',
        shared: {
          react: {
            ...Repack.Federated.SHARED_REACT,
            requiredVersion: '18.2.0',
            eager: true,
          },
          'react-native': {
            ...Repack.Federated.SHARED_REACT_NATIVE,
            requiredVersion: '0.74',
            eager: true,
          },
          reselect: {
            singleton: true,
            requiredVersion: monorepoDeps['reselect'],
            eager: true,
          },
          'react-redux': {
            singleton: true,
            requiredVersion: monorepoDeps['react-redux'],
            eager: true,
          },
          '@reduxjs/toolkit': {
            singleton: true,
            requiredVersion: monorepoDeps['@reduxjs/toolkit'],
            eager: true,
          },
          '@reduxjs/toolkit/query': {
            singleton: true,
            requiredVersion: monorepoDeps['@reduxjs/toolkit/query'],
            eager: true,
          },
          '@reduxjs/toolkit/query/react': {
            singleton: true,
            requiredVersion: monorepoDeps['@reduxjs/toolkit/query/react'],
            eager: true,
          },
          '@react-navigation/native': {
            singleton: true,
            requiredVersion: monorepoDeps['@react-navigation/native'],
            eager: true,
          },
          '@react-navigation/native-stack': {
            singleton: true,
            requiredVersion: monorepoDeps['@react-navigation/native-stack'],
            eager: true,
          },
          'react-native-screens': {
            singleton: true,
            requiredVersion: monorepoDeps['react-native-screens'],
            eager: true,
          },
          'react-native-safe-area-context': {
            singleton: true,
            requiredVersion: monorepoDeps['react-native-safe-area-context'],
            eager: true,
          },
          'redux-persist': {
            singleton: true,
            requiredVersion: monorepoDeps['redux-persist'],
            eager: true,
          },
          '@react-native-async-storage/async-storage': {
            singleton: true,
            requiredVersion:
              monorepoDeps['@react-native-async-storage/async-storage'],
            eager: true,
          },
        },
      }),
      new rspack.EnvironmentPlugin({ MF_CACHE: null }),
      process.env.RSDOCTOR && new RsdoctorRspackPlugin(),
    ].filter(Boolean),
  };
};

Try to start the dev server using: react-native webpack-start --webpackConfig ./rspack.config.mjs

sahajarora1286 avatar Sep 12 '24 18:09 sahajarora1286

Hi @sahajarora1286, could you please create a reproduction repository with this issue? It really saves a lot of time and allows us to handle issues more swiftly instead of trying to recreate this on our own, thanks!

jbroma avatar Sep 13 '24 20:09 jbroma

This issue has been marked as stale because it has been inactive for 30 days. Please update this issue or it will be automatically closed in 14 days.

github-actions[bot] avatar Oct 19 '24 00:10 github-actions[bot]

Closing since no repro was provided and the issue is about a non-stable version of Re.Pack. Happy to revisit the issue if it's still a problem in the future.

jbroma avatar Nov 01 '24 17:11 jbroma