← ALL POSTS

Shared components in a Lerna / TypeScript / Next.js project

2021-01-03

As you may have seen from my last post I’m migrating things to Next.js and keep running into little issues, so I’ve decided to blog about them here. The newest issue I’ve run into has been sharing common TypeScript components between apps in a Lerna monorepo. My setup looks like this:

packages/
  frontend/
  landing/
  ui/
  common/
  backend/

What I’ve been trying to do it share a ui component between the frontend and landing projects. It’s as simple as it sounds so I expected it to just work but there are some tricky gotchas. My landing page in this case is https://portabella.io and my frontend is https://app.portabella.io.

Issues

Cannot import outside of base directory

This error message looking familiar?

You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.

The issue stems from the face that Next.js cannot import anything from outside its root, there are ways to change your tsconfig.json baseUrl but I couldn’t get that way to work with Lerna.

Multiple React versions

Having issues with multiple versions of React? If this error is present in your application continue reading.

hooks can only be called inside the body of a function component

Having to compile .tsx files before importing

The last issue I’ve been having is I needing to compile any .ts or .tsx files I want to import, however in a monorepo that’s what I’m looking to do.

If you’ve run into the problems above you may have found the following links:

  • https://github.com/martpie/next-transpile-modules
  • https://stackoverflow.com/questions/63668508/how-do-you-share-uncompiled-typescript-between-react-native-and-next-js-in-a-mon
  • https://github.com/vercel/next.js/issues/9474
  • https://www.grouparoo.com/blog/nextjs-plugins

If any of these sound familiar you’re in luck! I’ve managed to cobble together enough things to make it work.

Solution

Pin React version

The first step is to settle on a React version you want to use in your monorepo. If you’re using the latest Next.js it probably installed React 17, however my application is still on 16. Decide on one to use and update your package.json files accordingly.

Transpile .ts and .tsx files

Add this to your next.config.js to force Next.js to transpile your components:

config.module.rules.push({
  test: /\.tsx?|\.ts?$/,
  use: [options.defaultLoaders.babel],
});

Resolve the correct React implementation

Additionally to the above Webpack config, add this to your next.config.js file:

config.resolve.alias['react'] = path.join(
  __dirname,
  '..',
  '..',
  'node_modules',
  'react'
);
config.resolve.alias['react-dom'] = path.resolve(
  __dirname,
  '..',
  '..',
  'node_modules',
  'react-dom'
);

We’re going up two directories in this case because we want our root node_modules/ directory and my folder structure has everything under packages/.

Hopefully that clears up any issues you were having! Next.js has some great features and generally works well but doing things like this is a bit finnicky, hopefully support is ironed out soon.