Nuxt.js: Server-side rendering with shared vue components in yarn workspace results in "Cannot find module"

Created on 30 Jan 2020  Â·  14Comments  Â·  Source: nuxt/nuxt.js

Version

v2.11.0

Reproduction link

http://n.a

Steps to reproduce

This is all inside one folder, to reproduce the exact error message it would live at /home/myuser/repos/core

  1. Create a folder structure like common/vue/components/atoms/ with box.vue at the top and a package.json at common/vue defining the name as common-vue
  2. Create a folder structure like example/test containing a nuxt project
  3. Add both as yarn workspaces
  4. In the nuxt project, import the common vue component with import EBox from 'common-vue/components/atoms/box';
  5. Run nuxt dev or build/run commands

What is expected ?

The site works as expected, showing the shared vue component

What is actually happening?

You see a page with a NuxtServerError stating:
Cannot find module 'common-vue/components/atoms/box' from '/home/myuser/repos/core/example/test'

Additional comments?

We tried quite a few things:

  1. Replacing the yarn created symlinks in node_modules with an actual copy of the respective folder
  2. Setting rootDir, modulesDir and webpack's nodeExternals to various combinations, sometimes managing to change the error to Cannot find module 'common-vue/components/atoms/box' from '/home/myuser/repos/core/' (i.e. pointing to where the root level node_modules are)
  3. Setting the bundleRenderer's baseDir

My best guess right now is that it is tied to vue-ssr's externals config that only whitelists css by default as documented here. I sadly can't find whether/where nuxt sets this value and didn't find a way to override it.

Most helpful comment

Having the same issue, also using Nuxt TypeScript, but seems to be an issue even without it.
@pi0 did you share a demo repository anywhere, or would you like me to create one?

All 14 comments

Got the same problem (and gave up) when tried to separate our project to multiple packages (mono repository) (with multiple nuxt instances and balancer between them)

Tried to move main dependencies in packages/common and import them from packages/project1 | packages/project2 - and got same error:

Cannot find module 'vue' from '...\packages\project1'

UPD: fails only in universal mode, spa works fine

Thanks for your contribution to Nuxt.js!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of nuxt-edge
  2. Comment the steps to reproduce it

Issues that are labeled as pending will not be automatically marked as stale.

same

same

Hi! I will share a demo repository soon :)

Having the same issue, also using Nuxt TypeScript, but seems to be an issue even without it.
@pi0 did you share a demo repository anywhere, or would you like me to create one?

Here's an example repository (it's using TypeScript & Lerna thought, but I'm pretty sure it's the same underlying issue)

https://github.com/RobinBertilsson/nuxt-lerna-6929

Steps to reproduce

  1. Clone the repository
  2. Run yarn && yarn lerna bootstrap
  3. Open it in your browser
  4. The error should appear
  5. Switch mode inside nuxt.config.ts from universal to spa
  6. The error should NOT appear

Can also confirm that it's still an issue on the latest release, sadly 😢

same issue here, did anyone get any fix for TypeScript & Lerna

Alright, I've made some progress on this issue.
I created a super simple structure following the original reproduce steps.

Folder structure

   components/Box.vue
   index.js
   package.json
web
   pages/index.vue
   nuxt.config.js
   package.json
package.json

My initial idea was to export my shared components from the index.js inside the common project, just like this.

import Box from './components/Box.vue'

export {
   Box,
}

And then just import it with import { Box } from 'common'.

But that doesn't quite work, getting another issue with that using JS, and when using TS the compiler complains about not being able to compile TypeScript, even though it's valid...

Anyhow, I found a solution that actually works, simply provide the full path to your "shared" Vue component.
For example:

import Box from 'common-vue/components/Box.vue'

Note, adding ".vue" is the key here, works for both TypeScript and JavaScript.

Not the most perfect solution, but it does work, and will let you use the universal mode.

Last update, because this is probably the solution i'll end up using.
Since Nuxt 2.13 they introduced component autodisovery, meaning you can just reference your package directly.

nuxt.config.js

components: [
   '~/components',
   'common-vue'
]

Just ran into this issue today and spent that last 3-4 hours trying to fix it! 😞

None of the workarounds are remotely ideal. The one I've decided to go with is to define common-vue as an alias that points directly to the project folder:

build: {
  extend(config, ctx) {
    config.resolve.alias = {
      ...config.resolve.alias,
      'common-vue': path.resolve(__dirname, '../common-vue'),
    };

Also, need a similar path mapping in tsconfig.json for TypeScript projects:

{
  "compilerOptions": {
    ...
    "paths": {
      ...

      "common-vue/*": ["../common-vue/*"]
    },

It's important that common-vue isn't symlinked into node_modules. In my case, I actually defined my alias with a different name (e.g. common-vue-alias) so that I don't forget to fix it properly once there's a better solution. Speaking of which…

Anyone know a better solution? Like I said, none of the workarounds are ideal, and having a shared component library in a monorepo must be a common use case. Is it not?

@Merott, I totally agree with you, it's far from an ideal solution.
But in our case, the component discovery works fine meaning we'll go for that one until we have another option.

And thanks for sharing your solution, I just find it a bit more hacky than using the component discovery, which is a feature Nuxt actually serves & maintains. That's basically the only reason I went with that solution.

Component discovery reduce imports is quite nice, they're taking up quite a lot of space in your Vue files, surprises me how well it's actually working.

Any update?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

msudgh picture msudgh  Â·  3Comments

surmon-china picture surmon-china  Â·  3Comments

nassimbenkirane picture nassimbenkirane  Â·  3Comments

bimohxh picture bimohxh  Â·  3Comments

mikekidder picture mikekidder  Â·  3Comments