expo/examples

Storybook example broken after webpack 5 upgrade

Alex-McLean opened this issue · 5 comments

Describe the bug
The recent webpack 5 upgrade (expo/expo-cli#3763), shipped with Expo 48, removed the withUnimodules method @expo/webpack-config and provides no alternative.
withUnimodules is still erroneously referenced in the @expo/webpack-config README, and is also used in the with-storybook example in this repo.

To Reproduce
Steps to reproduce the behavior:

  1. Clone this repo
  2. Attempt to run the with-storybook example

Expected behavior
Storybook example works and provides a reference implementation for expo + storybook.

Screenshots

ERR! TypeError: withUnimodules is not a function
ERR!     at module.exports (~/expo-examples/with-storybook/.storybook/webpack.config.js:5:10)

Desktop (please complete the following information):

  • OS: macOS
  • Browser: N/A - fails in CLI

Smartphone (please complete the following information):

  • N/A

Having the same problem, did you find a solution @Alex-McLean?

I just had to do my best to reproduce at least the parts of withUnimodules that I needed for my use case, in a webpack 5 compatible way, ended up with:

const { DefinePlugin } = require("webpack");
const { withAlias } = require("@expo/webpack-config/addons");
const {
  getAliases,
  getConfig,
  validateEnvironment,
  getMode,
  getPaths,
  getPublicPaths,
  getModuleFileExtensions
} = require("@expo/webpack-config/env");
const { createBabelLoader } = require("@expo/webpack-config/loaders");

module.exports = function withUnimodules(baseConfig, projectRoot) {
  const webpackConfig = withAlias(baseConfig, getAliases(projectRoot));
  const env = { projectRoot, mode: webpackConfig.mode };

  const environment = validateEnvironment(env);
  const config = getConfig(environment);
  const mode = getMode(env);
  const locations = getPaths(environment.projectRoot, environment);

  const { platform = "web" } = env;
  const { build: buildConfig = {} } = config.web || {};
  const { babel: babelAppConfig = {} } = buildConfig;
  const babelProjectRoot = babelAppConfig.root || locations.root;

  const babelLoader = createBabelLoader({
    projectRoot: locations.root,
    mode,
    platform,
    babelProjectRoot,
    verbose: babelAppConfig.verbose,
    include: [
      ...(babelAppConfig.include || []),
      ...(env.babel?.dangerouslyAddModulePathsToTranspile || [])
    ],
    use: babelAppConfig.use
  });

  function reuseOrCreatePublicPaths() {
    if (webpackConfig.output && webpackConfig.output.publicPath) {
      const publicPath = webpackConfig.output.publicPath;
      return {
        publicPath,
        publicUrl: publicPath.endsWith("/")
          ? publicPath.slice(0, -1)
          : publicPath
      };
    }
    return getPublicPaths(environment);
  }

  const { publicPath } = reuseOrCreatePublicPaths();

  webpackConfig.mode = mode;

  webpackConfig.output = {
    ...webpackConfig.output,
    publicPath
  };

  webpackConfig.plugins.push(
    new DefinePlugin({
      __DEV__: process.env.NODE_ENV === "development"
    })
  );

  webpackConfig.module = {
    ...webpackConfig.module,
    rules: [...webpackConfig.module.rules, babelLoader]
  };

  webpackConfig.resolve = {
    ...webpackConfig.resolve,
    symlinks: false,
    extensions: getModuleFileExtensions("web")
  };

  return webpackConfig;
};

I liked @Alex-McLean 's fix for webpack, nice! However are looking to move all our bundling to metro, trying out https://github.com/storybookjs/addon-react-native-web but haven't quite gotten to a working state yet....

Any updates here? this has broken my project and is preventing me from migrating to webpack 5.

Also experiencing this! @EvanBacon maybe you have an idea for a possible workaround?