xpost from my personal blog https://alexbh.dev/posts/2021-01-03-nextjs-lerna-common
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.
Links
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.
Discussion (5)
Did you find a workaround for the problem of
That's probably because you're trying to import {} from '../../common/';
If you're using Lerna you need to let it bundle the raw .ts{x} files into your node_modules. Then do
import {} from @project/common
.I actually just did the same last night, happy to see someone covering it. Are you as nervous as I am about
next-transpile-modules
changing and not working in the future?Haha I guess I wasn't nervous because I hadn't thought about that.
I'll have to update this blog post with my current setup because it's not exactly the same as what I described here anymore.
Thank you sir! You saved me a headache.