expo: Local Expo CLI: Can't set webpack port anymore (webOnly setting)

Summary

In the old cli, I ran expo web --port=19007 which caused webpack to host on an alternate port, I think this was triggered by webOnly which was set here

The new cli still has this code here for a webOnly setting which sets multiBundlerSettings.webpackPort: https://github.com/expo/expo/blob/83d464dcb2c8b897f0946718bc7365a0efac76d2/packages/%40expo/cli/src/start/resolveOptions.ts#L138-L147

… but from what I can tell it’s impossible to trigger this anymore, since webOnly: false is hardcoded here: https://github.com/expo/expo/blob/83d464dcb2c8b897f0946718bc7365a0efac76d2/packages/%40expo/cli/src/start/index.ts#L87

What platform(s) does this occur on?

Web

SDK Version

47.0.9

Environment

  expo-env-info 1.0.3 environment info:
    System:
      OS: macOS 13.0.1
      Shell: 5.8.1 - /bin/zsh
    Binaries:
      Node: 16.19.0 - /opt/homebrew/opt/node@16/bin/node
      Yarn: 1.22.19 - /opt/homebrew/bin/yarn
      npm: 8.19.3 - /opt/homebrew/opt/node@16/bin/npm
      Watchman: 2022.12.26.00 - /opt/homebrew/bin/watchman
    Managers:
      CocoaPods: 1.11.3 - /Users/gllen/.gem/ruby/2.7.3/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 22.1, iOS 16.1, macOS 13.0, tvOS 16.1, watchOS 9.1
      Android SDK:
        API Levels: 23, 30, 31
        Build Tools: 29.0.2, 30.0.2, 30.0.3, 31.0.0
        System Images: android-30 | Google Play ARM 64 v8a, android-31 | Google APIs ARM 64 v8a, android-Sv2 | Google APIs ARM 64 v8a
    IDEs:
      Android Studio: 2021.2 AI-212.5712.43.2112.8609683
      Xcode: 14.1/14B47b - /usr/bin/xcodebuild
    npmPackages:
      @expo/webpack-config: ^0.17.2 => 0.17.3
      expo: ^47.0.9 => 47.0.9
      react: 18.1.0 => 18.1.0
      react-dom: 18.1.0 => 18.1.0
      react-native: 0.70.5 => 0.70.5
      react-native-web: ~0.18.7 => 0.18.10
    npmGlobalPackages:
      eas-cli: 3.1.1
      expo-cli: 6.0.8
    Expo Workflow: bare

Minimal reproducible example

npx expo start --port 19007 --web
Starting project at (redacted)
Starting Metro Bundler
Starting Webpack on port 19006 in development mode.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 11
  • Comments: 22 (9 by maintainers)

Most upvoted comments

Instead of patching the webOnly option I changed the resolvePortsAsync function:

diff --git a/build/src/start/resolveOptions.js b/build/src/start/resolveOptions.js
index c8a010f7533ea4ef2c7bc226acb2565d289db523..6e13f3356ec29e0d8e32cd3bb76fd6784c7c7ddd 100644
--- a/build/src/start/resolveOptions.js
+++ b/build/src/start/resolveOptions.js
@@ -128,28 +128,31 @@ function resolveHostType(options) {
 }
 async function resolvePortsAsync(projectRoot, options, settings) {
     const multiBundlerSettings = {};
-    if (settings.webOnly) {
-        const webpackPort = await (0, _port).resolvePortAsync(projectRoot, {
-            defaultPort: options.port,
-            // Default web port
-            fallbackPort: 19006
-        });
-        if (!webpackPort) {
-            throw new _errors.AbortCommandError();
-        }
-        multiBundlerSettings.webpackPort = webpackPort;
-    } else {
-        const devClientDefaultPort = process.env.RCT_METRO_PORT ? parseInt(process.env.RCT_METRO_PORT, 10) : 8081;
-        const expoGoDefaultPort = 19000;
-        const metroPort = await (0, _port).resolvePortAsync(projectRoot, {
-            defaultPort: options.port,
-            fallbackPort: options.devClient ? devClientDefaultPort : expoGoDefaultPort
-        });
-        if (!metroPort) {
-            throw new _errors.AbortCommandError();
-        }
-        multiBundlerSettings.metroPort = metroPort;
+
+    const metroDefaultPort = process.env.METRO_PORT ? parseInt(process.env.METRO_PORT, 10) : undefined;
+    const webDefaultPort = process.env.WEB_PORT ? parseInt(process.env.WEB_PORT, 10) : undefined;
+
+    const webpackPort = await (0, _port).resolvePortAsync(projectRoot, {
+        defaultPort: webDefaultPort ?? options.port,
+        // Fallback web port
+        fallbackPort: 19006
+    });
+    if (!webpackPort) {
+        throw new _errors.AbortCommandError();
+    }
+    multiBundlerSettings.webpackPort = webpackPort;
+
+    const devClientFallbackPort = process.env.RCT_METRO_PORT ? parseInt(process.env.RCT_METRO_PORT, 10) : 8081;
+    const expoGoFallbackPort = 19000;
+    const metroPort = await (0, _port).resolvePortAsync(projectRoot, {
+        defaultPort: metroDefaultPort ?? options.port,
+        fallbackPort: options.devClient ? devClientFallbackPort : expoGoFallbackPort
+    });
+    if (!metroPort) {
+        throw new _errors.AbortCommandError();
     }
+    multiBundlerSettings.metroPort = metroPort;
+
     return multiBundlerSettings;
 }

This way we can override both the Metro and Webpack ports through environment variables:

METRO_PORT=19100 WEB_PORT=19200 expo start --web

and it falls back to the --port option for any of the two if the env var is not present. Not sure why the webpack port was only being set when settings.webOnly is true, but since that’s hardcoded to false in expoStart it was never being set. Changing it to webOnly: options.web like was mentioned before is not a solution since then the metro port is the one that can’t be configured when starting the project with --web.

Maybe I’m missing something here and this conflicts with something else but I can open a PR if that would be helpful @brentvatne

Can confirm, we’ve been having this issue for a while now 😄

Running multiple apps in the same monorepo becomes a pain to handle if we can’t specify a different port for each.

The solution for every problem with Expo can’t continuously be “upgrade to the latest X thing because we silently dropped the support for previous thing” 💔

The option is still broken as of SDK 49 and the patch from @cesargdm seems to no longer work (probably because Metro tries to use the same port as web so it fails). And switching to Metro is not a viable solution until it supports bundle splitting and tree shaking.

The --port argument works when using the Metro bundler, so I guess that’s the official solution. Switch to Metro if you’re using Webpack.

The issue prevents me from deploying an app on GCP App Engine using Node.js runtime because I cannot change the Webpack default port to 8080.

The workaround in https://github.com/expo/expo/issues/20629#issuecomment-1418556120 doesn’t work in my case because the node_modules folder is provided by GCP which I don’t know how to bypass (.gcloudignore tweaking doesn’t help) and the staging file system is read-only.

I am able to run it with npx expo web --port=3000