expo / examples

Example projects that demonstrate how to use Expo APIs and integrate Expo with other popular tools
2.24k stars 868 forks source link

Expo yarn workspaces setup doesn't work for web #264

Open tuncaulubilge opened 3 years ago

tuncaulubilge commented 3 years ago

Describe the bug The support for expo web in with-yarn-workspaces example is limited. Noticed two main issues:

To Reproduce

  1. Install expo with template with-yarn-workspaces
  2. Run expo web inside one of the apps
  3. Make a change in one of the packages inside packages/
  4. Observe the change not reflected.
  5. Kill expo and restart to observe the change.

Expected behavior Expo web should work just like the expo android and ios on the monorepo, where any change gets reflected without the need to kill expo

Desktop (please complete the following information):

ajsmth commented 3 years ago

Hi there! Thanks so much for this. I think there are a couple things here we can improve for expo yarn workspaces.

While we fix this stuff - can you try pasting this webpack config (in your app directory e.g first-app/webpack.config.js) and let me know if it works for you?

The config.resolve.symlinks = true seems to get the reload behaviour you are looking for, I suspect you've figured out the rest already

const createExpoWebpackConfigAsync = require("@expo/webpack-config");

// Expo CLI will await this method so you can optionally return a promise.
module.exports = async function (env, argv) {
  const config = await createExpoWebpackConfigAsync({
    ...env,
    babel: {
      dangerouslyAddModulePathsToTranspile: [
        "first-package",
        "second-package",
      ]
    }
  }, argv);

  config.resolve.symlinks = true;

  return config;
};
tuncaulubilge commented 3 years ago

Hi Andy, thanks for the quick reply.

What if I need those symlinked packages to be transpiled as well? (which is probably the case for most monorepos). I'm building a shared component package to be used in multiple expo apps.

Transpilation of the shared package works with dangerouslyAddModulePathsToTranspile configuration, but once I add the symlink config, I get You may need an appropriate loader to handle this file type, error again. I guess I can run a separate babel watcher in my component package and re-transpile it whenever there is a change, but that kinda defeats the purpose of a monorepo. Do you know any suggestions on how to resolve this?

ajsmth commented 3 years ago

Hello again - thanks for bringing this up! It took some digging but you're absolutely right, this is not quite the right configuration. As a workaround, I believe you can specify the symlinked package folder name instead of whatever alias you are using for your package:

const createExpoWebpackConfigAsync = require("@expo/webpack-config");

// Expo CLI will await this method so you can optionally return a promise.
module.exports = async function (env, argv) {
  const config = await createExpoWebpackConfigAsync(
    {
      ...env,
      babel: {
        dangerouslyAddModulePathsToTranspile: [
          // "@yew/first-package", // remove this package alias 
          "first-package" // <- points to the actual folder packages/first-package
        ],
      },
    },
    argv
  );

  config.resolve.symlinks = true;

  return config;
};

In your apps you should still import these under their configured package names like this:

import { StatusBar } from "expo-status-bar";
import React from "react";
import { StyleSheet, Text, View } from "react-native";

// import using configured package name:
import MyCoolView from "@yew/first-package";

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Hello from the first application</Text>
      <MyCoolView text="Hi there" />
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});

I'm still looking around to see if there's a better option, but I hope this works for you for now. Also, let me know if that makes sense!

tuncaulubilge commented 3 years ago

That worked, thanks Andy! This is how my webpack.config.js looks like now:

const path = require("path");
const fs = require("fs");
const createExpoWebpackConfigAsync = require("@expo/webpack-config");

const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);

module.exports = async function (env, argv) {
  const config = await createExpoWebpackConfigAsync(
    {
      ...env,
      babel: {
        dangerouslyAddModulePathsToTranspile: [
          // Ensure the shared packages are transpiled.
          resolveApp("../../packages/core"),
        ],
      },
    },
    argv
  );
  config.resolve.symlinks = true;

  return config;
};
ajsmth commented 3 years ago

Awesome, glad to hear! Thanks for bringing this up, we'll try and iron this out for others who might want to use this example repo in the future!

ajsmth commented 3 years ago

Following up on this - as of v1.5.1 you can use the webpack config export from expo-yarn-workspaces to take care of this configuration for you:

https://github.com/expo/expo/tree/master/packages/expo-yarn-workspaces#usage-with-expo-web

SushiWaUmai commented 2 years ago

Seems like running yarn on windows doesn't work:

C:\Users\eugen\Coding\Webdev\Learning\rn-yarn-workspaces>yarn
yarn install v1.22.11
[1/4] Resolving packages...
success Already up-to-date.
$ expo-yarn-workspaces check-workspace-dependencies && yarn workspaces run build
✅  Verified that all workspace dependencies are symlinked.
yarn workspaces v1.22.11

> mobile
yarn run v1.22.11
$ echo 'Nothing to build'
'Nothing to build'
Done in 0.12s.

> expo-custom
yarn run v1.22.11
$ expo-module build
C:\Users\eugen\Coding\Webdev\Learning\rn-yarn-workspaces\node_modules\expo-module-scripts\bin\expo-module-build:3
set -eo pipefail
        ^^^^^^^^

SyntaxError: Unexpected identifier
    at wrapSafe (internal/modules/cjs/loader.js:988:16)
    at Module._compile (internal/modules/cjs/loader.js:1036:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
    at Module.load (internal/modules/cjs/loader.js:937:32)
    at Function.Module._load (internal/modules/cjs/loader.js:778:12)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
    at internal/main/run_main_module.js:17:47
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed.
Exit code: 1
Command: C:\Program Files\nodejs\node.exe
Arguments: C:\Users\eugen\AppData\Roaming\npm\node_modules\yarn\lib\cli.js run build
Directory: C:\Users\eugen\Coding\Webdev\Learning\rn-yarn-workspaces\packages\expo-custom
Output:

info Visit https://yarnpkg.com/en/docs/cli/workspaces for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
chriscoomber commented 1 year ago

@ajsmth According to the expo monorepos guide we shouldn't be using expo-yarn-workspaces. Do you know if that guidance is correct?

I actually came to this issue by following that guide and still having issues with expo web - your advice with dangerouslyAddModulePathsToTranspile helped me out.

seanadkinson commented 11 months ago

Same as @chriscoomber above, I found this post looking for hot-reload support for web. The dangerouslyAddModulePathsToTranspile solution works for me, but I wonder if this support can be added to @expo/webpack-config, since that is the recommended approach now, and usage of expo-yarn-workspaces is explicitly discouraged.

Here is the config that I'm using now:

const createExpoWebpackConfigAsync = require('@expo/webpack-config');
const path = require('path');

module.exports = async function (env, argv) {
    const config = await createExpoWebpackConfigAsync(
        {
            ...env,
            babel: {
                dangerouslyAddModulePathsToTranspile: [
                    '../my-local-package'
                ]
            }
        },
        argv,
    );

    config.resolve.symlinks = true;

    return config;
};
JM-CF commented 10 months ago

Using Metro bundler (instead of webpack) as described in a related issue worked for me.