4

I'm trying to bundle a React components library for my Next.js app but I can't figure out what's the cause of the following error. I've spent the last couple of days trying out different configurations of Rollup, TS compiler and package.json but I feel like I just lack some experience and some crucial piece of knowledge here, because I don't really understand what the error log is trying to tell me.

Server Error
Error: Cannot find module '/home/ola/Projects/lifeitself/flowershow/node_modules/.pnpm/file+packages+core+flowershow-core-0.0.4.tgz_wwvq4sry3mrfcince3djb3idna/node_modules/next/link' imported from /home/ola/Projects/lifeitself/flowershow/node_modules/.pnpm/file+packages+core+flowershow-core-0.0.4.tgz_wwvq4sry3mrfcince3djb3idna/node_modules/@flowershow/core/dist/index2.js
Did you mean to import next@13.0.6_biqbaboplfbrettd7655fr4n2y/node_modules/next/link.js?

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Call Stack
new NodeError
node:internal/errors (387:5)
finalizeResolution
node:internal/modules/esm/resolve (330:11)
moduleResolve
node:internal/modules/esm/resolve (907:10)
defaultResolve
node:internal/modules/esm/resolve (1115:11)
nextResolve
node:internal/modules/esm/loader (163:28)
ESMLoader.resolve
node:internal/modules/esm/loader (837:30)
ESMLoader.getModuleJob
node:internal/modules/esm/loader (424:18)
ModuleWrap.<anonymous>
node:internal/modules/esm/module_job (76:40)
link
node:internal/modules/esm/module_job (75:36)

Context:

  • @flowershow/core is the components library package written in TS
  • @flowershow/core is a dependency of`@flowershow/template
  • the whole repository is a monorepo built with Nx (https://github.com/flowershow/flowershow), and it includes both the core and the template package, with the following structure (simplified):
flowershow
├── packages
│   ├── ...
│   ├── core
|   |   ├── src
|   |   ├── project.json (Nx file)
|   |   ├── tsconfig.json
|   |   └── package.json
│   └── template
|       ├── ... pretty standard Next.js app contents
|       ├── project.json (Nx file)
|       └── package.json
├── nx.json
├── package.json
├── pnpm-workspace.yaml
└── tsconfig.base.json

Relevant cofig files of @flowershow/core

package.json:

{
  "name": "@flowershow/core",
  "version": "0.0.4",
  "description": "Core Flowershow components, configs and utils.",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/flowershow/flowershow.git",
    "directory": "packages/core"
  },
  "author": "Rufus Pollock",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/flowershow/flowershow/issues"
  },
  "homepage": "https://github.com/flowershow/flowershow#readme",
  "publishConfig": {
    "access": "public"
  },
  "type": "module",
  "main": "./dist/index.js",
  "dependencies": {
    "@docsearch/react": "^3.3.0",
    "@headlessui/react": "^1.7.6",
    "clsx": "^1.2.1",
    "kbar": "0.1.0-beta.39",
    "mdx-mermaid": "^1.3.2",
    "mermaid": "^9.3.0"
  },
  "peerDependencies": {
    "next": "^13.0.0",
    "next-contentlayer": "^0.2.9",
    "next-themes": "^0.2.1",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}

project.json (Nx's config file):

{
  "name": "core",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "packages/core/src",
  "projectType": "library",
  "tags": [],
  "targets": {
    "build": {
      "executor": "@nrwl/web:rollup",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "packages/core/dist",
        "tsConfig": "packages/core/tsconfig.lib.json",
        "project": "packages/core/package.json",
        "entryFile": "packages/core/src/index.ts",
        "format": ["esm", "cjs"],
        "external": [
          "react/jsx-runtime",
          "react",
          "next",
          "next-contentlayer",
          "next-themes"
        ],
        "generateExportsField": true,
        "rollupConfig": "@nrwl/react/plugins/bundle-rollup",
        "compiler": "babel",
        "assets": [
          {
            "glob": "packages/core/README.md",
            "input": ".",
            "output": "."
          }
        ]
      }
    },
    ...
  }
}

tsconfig.json:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "module": "es2020",
    "moduleResolution": "node",
    "allowJs": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitAny": false,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  },
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ]
}

tsconfig.lib.json:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "dist",
    "types": ["node"]
  },
  "files": [
    "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
    "../../node_modules/@nrwl/react/typings/image.d.ts"
  ],
  "exclude": [
    "jest.config.ts",
    "**/*.spec.ts",
    "**/*.test.ts",
    "**/*.spec.tsx",
    "**/*.test.tsx",
    "**/*.spec.js",
    "**/*.test.js",
    "**/*.spec.jsx",
    "**/*.test.jsx"
  ],
  "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}

Output dist/index.js file, with the import Next complains about:

export { e as BlogLayout, B as BlogsList, C as CustomLink, D as DocsLayout, L as Layout, N as Nav, P as Pre, S as SearchProvider, d as SimpleLayout, U as UnstyledLayout, g as collectHeadings, p as pageview } from './index2.js';
import 'react/jsx-runtime';
import 'react';
import 'next/link';
import 'next-themes';
import 'next/dynamic';
import '@headlessui/react';
import 'next/router';
import 'next/head';
import 'mdx-mermaid/lib/Mermaid';
import 'clsx';

How am I testing this:

To test this I'm packing the core package and installing it using the output tgz file in the template, using "file:" protocol as follows:

(packages/template/package.json)

  "dependencies": {
    "@flowershow/core": "file:../core/flowershow-core-0.0.4.tgz",

Other info

I have tried manually changing the import statement from import 'next/link' to import 'next/link.js' and it seemed to work (except that then the error was thrown for other imported library).

I'm also not really sure why Rollup produces all of there import statements below the export one, so I'd be extremely grateful for some hint here as well. I'm fairly new to this and this is the first time I'm using Rollup or any other bundler to bundle my own library.

Here is the full code base: https://github.com/flowershow/flowershow

I have found this issue with a similar problem someone faced: Error [ERR_MODULE_NOT_FOUND]: Cannot find module

I've tried tinkering with TS compiler config, Rollup config and different package.jsonfields values (e.g. adding/removing type: module in the core package) but with no luck.

And adding file extensions to import statements is not an option here as these are produced automatically by Rollup.

olayway
  • 41
  • 1
  • 1

1 Answers1

0

I've been in the rabbit hole on this lately too. I think this pain is a result of a misconfiguration in Next.js itself when it comes to exporting proper types for ESModules. See this GitHub issue which links to 3 more GitHub issues that explain the story a bit: https://github.com/vercel/next.js/issues/46676#issuecomment-1451731653

From what I understand, the Next.js compiler can take your imported modules and bundles them for you. There used to be a next-transpile-modules plugin for the next.config which now comes built in: https://nextjs.org/blog/next-13-1#built-in-module-transpilation-stable. When I added my package to this array in the config I was able to get things to run in dev mode, but build mode failed no matter what I tried.

So, hopefully this issue will be fixed upstream soon, and if it isn't an issue there will be some guidance on how to bundle a component library for Next.js because I have a similar experience where things don't seem to be working as intended.

edit: After some more messing around, it seems the culprit is the "type: module" in the package.json of the component library. Maybe there is a way to get it working, but when you build your next app it transpiles everything down to commonjs anyway, so maybe there is not much point in putting effort into bundling of the component library and just publish one entrypoint and let Next.js do the rest? Not a satisfying answer but this has been the only way I've been able to run in build and dev mode.

Pear
  • 46
  • 4