0

I have a NextJs (host) app and a separate utility package published to Github's registry. I want to be able to debug and iterate on the utility package locally when running the logic from my NextJs app.

The utility package compiles typescript to a dist/index.js folder, and index.js exports a class. I run npm run build and ensure the dist assets are present.

I configure the host app to use the file system to import the package locally:

  "dependencies": {
    ...
    "@my-company/utils": "file:../utility-package"
  },

I run npm i. I can see node_modules/@my-company/utils and the dist folder.

In the host app import the utility class, and VSCode sees the import/package just fine.

import { TestService } from "@my-company/utils"; console.log(TestService.helloWorld());

In the browser I get Module not found: Can't resolve '@my-company/utils'.

I suspect something is not quite right with my utility library package.json (or perhaps the compiled index.js file).

Utility library package.json

{
  "name": "@my-company/utils",
  "version": "1.0.3",
  "description": "",
  "type": "module",
  "main": "dist/index.js",
  "module": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": [
    "dist"
  ],
  "exports": {
    ".": {
      "import": "./dist/index.js"
    }
  },
  "scripts": {
    "build": "tsc",
    "prepublishOnly": "npm run build"
  },
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/my-company/utils.git"
  },
  "devDependencies": {
    ...
  },
  "dependencies": {
    ...
  }
}

Utility library tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ES2020",
    "moduleResolution": "bundler",
    "declaration": true,
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

Utility library compiled dist/index.js

export { TestService } from "./services/TestService";

I also have a Github repo demonstrating this here.

I've tried every alternative chatGPT has to offer but this is the simplest reproduction case.

1 Answer 1

1

The issue here is that Turbopack has limitaion with local package resolution. So I used webpack instead of Turbopack.

I switched from ES modules to CommonJS.

Remove "type": "module" from package.json.

// utility-package/package.json
"name": "@my-company/utils",
  "version": "1.0.3",
  "description": "",
  "type": "module", // remove this
  "main": "dist/index.js",
  "module": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": [
    "dist"
  ],

Update tsconfig.json to use CommonJS:

// utility-package/tsconfig.json
{
    "compilerOptions": {
      "target": "ES2020",
      "module": "CommonJS",
      "moduleResolution": "node10",
      "declaration": true,
      "outDir": "dist",
      "strict": true,
      "esModuleInterop": true,
      "allowSyntheticDefaultImports": true,
      "skipLibCheck": true
    },
    "include": ["src"]
  }

Remove the "import" from export configuration because it only works for ES modules

// utility-package/package.json
"exports": {
    ".": {
      "import": "./dist/index.js" // remove this
    }
  },

Then update exports for CommonJS which need "require" instead

// utility-package/package.json
"exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "require": "./dist/index.js",
      "default": "./dist/index.js"
    }
  }

Next update the next.config.ts to handle the local package

// my-app/next.config.ts
import type { NextConfig } from "next";
import path from "path";

const nextConfig: NextConfig = {
  transpilePackages: ["@my-company/utils"],
  webpack: (config, { isServer }) => {
    config.resolve.alias["@my-company/utils"] = path.resolve(__dirname, "../utility-package/dist");
    return config;
  },
};

export default nextConfig;

Finally remove --turbopack from scripts in my-app package.json

// my-app/package.json
"scripts": {
      "dev": "next dev",
      "build": "next build",
      "start": "next start"
    }

Now rebuilt the Utility Package npm run build Then run the Next.js app npm run dev

Now it works: Browser console Terminal Logs

Sign up to request clarification or add additional context in comments.

3 Comments

Wow, that got it working. Is there no way to import without the custom configurations to next.config.js, as it stands it adds complexity to configure that for any developers, and I would not want those configurations in production (which would use the npm registry version of the package and already works).
After some testing I notice that just removing --turbopack was effective enough to get this working. I really appreciate the insights and investigation here. And I also discovered this issue relating to turbopack and "outside" dependencies github.com/vercel/next.js/issues/65125
Thank you for the update. I should have removed the --turbopack in the firstplace

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.