next.js: Cannot find module 'react-native' error when trying to use ui-kitten library with react-native-web

Bug report

Describe the bug

A clear and concise description of what the bug is. Apologies if this is not the right place to post this, but I have seen a similar issue posted on the Expo Github, so I figured I would post it on the framework in question. In short, the issue is that I can’t get the UI-Kitten library to work with NextJS using react-native-web (the latter working fine without UI-Kitten). When creating a project based on with-react-native-web, and installing the dependencies, yarn add @ui-kitten/components@next @eva-design/eva@next react-native-svg, I get the following error when trying to use the library:

Error: Cannot find module 'react-native'
Require stack:
- /Users/andersravn/plantjammer/ui-kitten/node_modules/@ui-kitten/components/theme/modal/modalPanel.component.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/@ui-kitten/components/theme/application/applicationProvider.component.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/@ui-kitten/components/theme/index.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/@ui-kitten/components/index.js
- /Users/andersravn/plantjammer/ui-kitten/.next/server/static/development/pages/index.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/next-server/server/require.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/next-server/server/load-components.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/next-server/server/api-utils.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/next-server/server/next-server.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/server/next.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/server/lib/start-server.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/cli/next-dev.js
- /Users/andersravn/plantjammer/ui-kitten/node_modules/next/dist/bin/next
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:625:15)
    at Function.Module._load (internal/modules/cjs/loader.js:527:27)
    at Module.require (internal/modules/cjs/loader.js:683:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at Object.<anonymous> (/Users/andersravn/plantjammer/ui-kitten/node_modules/@ui-kitten/components/theme/modal/modalPanel.component.js:12:24)
    at Module._compile (internal/modules/cjs/loader.js:777:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:788:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:683:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at Object.<anonymous> (/Users/andersravn/plantjammer/ui-kitten/node_modules/@ui-kitten/components/theme/application/applicationProvider.component.js:15:32)
    at Module._compile (internal/modules/cjs/loader.js:777:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:788:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)

To Reproduce

I have made a repo to reproduce the error: https://github.com/andersravn/ui-kitten-nextjs.

Expected behavior

NextJS, with webpack/babel configuration, parses react-native imports as react-native-web in order to use the ui-kitten library.

System information

  • OS: macOS
  • Browser chrome
  • Version of Next.js: latest
  • Version of Node.js: 12.7.0

Additional context

Using the same libraries, react-native-web and ui-kitten, with create-react-app works as expected, so that’s why I’m guessing it’s something to do with the way NextJS parses the library files? I know very little about babel and webpack, but from reading here, it seems to have something to do with this.

Thanks for a great product.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 2
  • Comments: 16 (1 by maintainers)

Most upvoted comments

I found the cause. It’s because ui-kitten hasn’t been transpiled yet. I also found a fix. I don’t know if it’s a workaround or a solution but this appears to be working for me.

  1. Install these deps:

npm i --save next-compose-plugins next-transpile-modules

  1. Update next.config.js
const withPlugins = require('next-compose-plugins');
const withTM = require('next-transpile-modules')(['@ui-kitten/components', 'react-native-svg']);

module.exports = withPlugins([withTM], {
  webpack: config => {
    config.resolve.alias = {
      ...(config.resolve.alias || {}),
      // Transform all direct `react-native` imports to `react-native-web`
      'react-native$': 'react-native-web',
    }
    config.resolve.extensions = [
      '.web.js',
      '.web.ts',
      '.web.tsx',
      ...config.resolve.extensions,
    ]
    return config
  },
});

From what I’ve seen you’ll have to add all modules that need to be transpiled to the array. It gets a bit slower though, but it’s not by a whole lot.

@RWOverdijk yes, it should. We can’t allow js for multiple reasons. Please open an issue in our repo if you still have questions on it

Oh heck yes, I did not know that. 😄

@artyorsh Nice. That definitely sped it up significantly. Down to ~20ms. 😮 Thanks, and also for the great work you guys are doing on UI Kitten. 😄

@andersravn oops. Could you please add an npm script with same code and try using it?

like

"scripts": {
  "bootstrap": "ui-kitten bootstrap @eva-design/eva"
}

and then

yarn bootstrap

# npm?
# npm run bootstrap

I started on expo web, but quickly found the bundle size to be abnormally large. Our website is almost 4MB. On top of that prerendering (which is what you’ll need for unfurling and OG reading) doesn’t work properly (and requires a lot of work to get decent).

Next is the right way I think.

In regards of my approach, it’s still not done but I am looking into exported style objects (just POJO) and then a template file (much like .web.js and .ios.js) for web and mobile. They both use the styles their own way (StyleSheet.create and style modules in next). It does mean I have some work to do in terms of a style system for web, but that’s the cost so far…

@RWOverdijk Wonderful! That worked. Thank you so much for getting back to me after trying out for yourself, and then giving such a thorough answer. I also spent several hours on my own before I decided to make this issue. This helped me out a ton. This should be a starter example. 😄

@andersravn Thought I’d add proof in the shape of a screenshot.

image

Code:

import * as React from 'react'
import Link from 'next/link'
import { StyleSheet, Text, View } from 'react-native'
import { Button } from '@ui-kitten/components'

export default function App(props) {
  return (
    <View style={styles.container}>
      <Text accessibilityRole="header" style={styles.text}>
        React Native for Web & Next.js
      </Text>

      <Link style={styles.link} accessibilityRole="link" href={`/alternate`}>
        A universal link
      </Link>

      <Button status='primary'>PRIMARY</Button>

      <View style={styles.textContainer}>
        <Text accessibilityRole="header" aria-level="2" style={styles.text}>
          Subheader
        </Text>
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    flexGrow: 1,
    justifyContent: 'center',
  },
  link: {
    color: 'blue',
  },
  textContainer: {
    alignItems: 'center',
    marginTop: 16,
  },
  text: {
    alignItems: 'center',
    fontSize: 24,
    marginBottom: 24,
  },
})

Update: At some point I have to stop commenting, so I’ll start editing this message.

I also found that you have to replace the “links” in the example, otherwise the page will do a hard refresh. What works for me is just adding Link. I’ve updated the code snippet to reflect this.

Update 2: In case anyone else ends up here, my statement is a bit misleading. The above snippets aren’t enough to get the button to show up. You have to also add a new file: pages/_app.js with the following contents:

import { ApplicationProvider, Layout, Text } from '@ui-kitten/components';
import { mapping, light as lightTheme } from '@eva-design/eva';

function MyApp({ Component, pageProps }) {
  return (
    <ApplicationProvider mapping={mapping} theme={lightTheme}>
      <Component {...pageProps} />
    </ApplicationProvider>
  )
}

export default MyApp

3 hours later, I’m facing the same issue. Timing is everything.