typescriptwebpacknext.jstsconfig-paths

Next.js 13 project references path aliases throwing webpack error


I'm migrating a small and old react project (and its nestjs server) to Next.js 13. I'm doing that by scaffolding from a CLI called Create T3 App. I use project references a lot, in all projects I work on and I'm trying to do that here like this:

tsconfig.json:

{
  "compilerOptions": {
    "target": "es2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "noUncheckedIndexedAccess": true,

    "baseUrl": ".",
    "paths": {
      "@core/*": ["../../../../libs/core/src/*"]
    }
  },
  "references": [
    { "path": "../../../../libs/core/" }
  ],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.cjs", "**/*.mjs"],
  "exclude": ["node_modules"]
}

But it keeps throwing this webpack loader error:

error - ../../../../libs/core/src/path/to/file.ts Module parse failed: Unexpected token (4:12) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

There are no errors marked red on the file, vscode's intellisense works fine.

I have tried adding the aliases to webpack, like so:

next.config.mjs:

// @ts-check
/**
 * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
 * This is especially useful for Docker builds.
 */
!process.env.SKIP_ENV_VALIDATION && (await import("./src/env/server.mjs"));
import path from 'path';

/** @type {import("next").NextConfig} */
const config = {
  reactStrictMode: true,
  swcMinify: true,
  i18n: {
    locales: ["en"],
    defaultLocale: "en",
  },
  webpack: (config, { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }) => {
    return {
      ...config, 
      resolve: { 
        ...config.resolve,
        alias: {
          ...config.resolve.alias,
          '@core': path.resolve('../../../../libs/core/src'),
        }
      }
    }
  },
};
export default config;

This yielded no changes to the error message.

I have tried adding ts-loader to webpack but it throws errors in other parts of the app. I'd like to solve this without using babel if at all possible.

Does anyone know how to make paths aliases for external projects work on Next.js 13?


ANSWER BREAKDOWN:

Using the package that @Yilmaz suggested, called next-transpile-modules I was able to make the project references and their aliases work. This solution requires "baseUrl" and "paths" fields to be correctly set on tsconfig.json and these additions to next.config.mjs:

import transpile from 'next-transpile-modules';

const withModules = transpile([
  '../../../../libs/core'
]);

/** @type {import("next").NextConfig} */
const config = {
  ...
};

export default withModules(config);

Solution

  • your tsconfig.json does not meet default next13 typescript configuration. I created a next app with --typescript and this is the default tsconfig.json. I did not touch it

    {
      "compilerOptions": {
        "target": "es5",
        "lib": [
          "dom",
          "dom.iterable",
          "esnext"
        ],
        "allowJs": true,
        "skipLibCheck": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "noEmit": true,
        "esModuleInterop": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "jsx": "preserve",
        "incremental": true,
        "plugins": [
          {
            "name": "next"
          }
        ]
      },
      "include": [
        "next-env.d.ts",
        "**/*.ts",
        "**/*.tsx",
        ".next/types/**/*.ts"
      ],
      "exclude": [
        "node_modules"
      ]
    }
    

    If you follow next-transpile-modules npm package and set it next.config.js

    import transpile from 'next-transpile-modules';
    
    const withModules = transpile([
      '../../../../libs/core'
    ]);
    
    /** @type {import("next").NextConfig} */
    const config = {
      ...
    };
    
    export default withModules(config);