Fixing Plugin Compatibility in React Native Web with Expo: How to Disable Google AdMob and Other Native Modules

React Native has made it incredibly easy to develop cross-platform apps that work on both mobile and web using frameworks like Expo. However, there are times when a native plugin (designed for iOS or Android) isn’t compatible with the web platform. One common example is Google AdMob (react-native-google-mobile-ads), which can cause crashes when trying to build for the web with errors like:

Error: Module not found: Can’t resolve ‘../Utilities/Platform’

This type of error can be frustrating, especially when you’re trying to maintain a shared codebase for both mobile and web. In this guide, I’ll show you how to “mock” or disable incompatible modules for specific platforms using a simple configuration tweak in your metro.config.js file.

The Problem: Incompatible Plugins on Web

When working with React Native apps, you might want to include certain modules, like Google AdMob, to monetize your app. However, plugins like react-native-google-mobile-ads rely on native iOS and Android APIs and will throw errors when included in a web build because the required native code doesn’t exist in the web environment. For example, you might encounter this error during a web build:

Error: Module not found: Can’t resolve ‘../Utilities/Platform’

In this case, the app crashes because it’s trying to resolve native utilities that are unavailable on the web platform.

The goal is to disable the incompatible plugin from the web build so the rest of the app can function properly without issues.

The Solution: Customizing Metro Bundler to Skip Web-Incompatible Modules

Luckily, Metro bundler (the JavaScript bundler used by React Native) provides a way to conditionally exclude or mock modules based on the platform. We can use a clever hack by modifying the metro.config.js file to instruct Metro to skip loading certain modules when building for the web.

Let’s walk through the solution step by step.

Modify metro.config.js :

In your React Native project, locate the metro.config.js file. If it doesn’t exist, create one in the root of your project.

Add the following code to your metro.config.js:


Explanation of the Code:

  1. Get the Default Metro Config:
    We’re first getting the default Metro configuration using getDefaultConfig from expo/metro-config.
  2. Resolver Override:
    The resolver.resolveRequest function allows us to customize how modules are resolved for different platforms. This is the key to our solution.
  3. Platform-Specific Module Exclusion:
    We’re adding a condition to check if the current platform is 'web' and the module name is 'react-native-google-mobile-ads'. If these conditions are true, we return an object with type: 'empty'. This effectively mocks the module, making it appear as an empty module for the web platform, preventing the app from crashing due to missing dependencies.
  4. Fallback to Default Resolver:
    After our custom condition, we ensure the default resolver is called to handle other modules that are not problematic.

Why This Approach Works

React Native modules like react-native-google-mobile-ads are built to interact with native APIs on Android and iOS, but web platforms don’t have access to these APIs. By instructing Metro to return an empty module for web builds, we can safely bypass the need for these plugins without affecting the mobile versions of the app.

This method is:

  • Simple: You only need to modify one file, metro.config.js, to skip incompatible modules.
  • Safe: This approach doesn’t impact mobile builds, so you can continue using native plugins on iOS and Android without issues.
  • Flexible: You can extend this method to handle multiple incompatible plugins or modules across different platforms (e.g., web, desktop).

Additional Use Cases

This technique is not limited to react-native-google-mobile-ads. You can use it for any plugin or module that is incompatible with a specific platform. Here’s an example of how you could apply it to other modules:

config.resolver.resolveRequest = (context, moduleName, platform) => {
  if (platform === 'web' && moduleName === 'react-native-some-other-module') {
    return {
      type: 'empty',
    };
  }

  return context.resolveRequest(context, moduleName, platform);
};

Simply replace 'react-native-some-other-module' with the name of the plugin you want to mock.

Conclusion

If you’re building a cross-platform React Native app that targets both mobile and web, dealing with incompatible plugins can be frustrating. Thankfully, Metro’s resolveRequest functionality allows you to mock incompatible modules like react-native-google-mobile-ads, enabling you to create web builds that work seamlessly alongside mobile ones.

This approach saves time, prevents crashes, and makes your development process smoother. Happy coding! 🎉

Key Takeaways:

  • You can mock or skip incompatible plugins on specific platforms using metro.config.js.
  • This solution works by checking the platform and conditionally returning an empty module.
  • The approach doesn’t affect mobile builds, so your native modules will still work as intended on iOS and Android.

You can now implement this solution and even share it with your developer peers if they face similar issues. It’s a simple yet effective way to ensure your app remains stable across multiple platforms.

Leave a Reply

Your email address will not be published. Required fields are marked *