8

In the Next.js 9 tutorial the suggested way to import shared components is by relative paths, like

import Header from '../components/Header';

I want to use absolute imports, like

import Header from 'components/Header';

How do I make this work both locally and when I deploy using the Now CLI?


Using the suggested setup from the tutorial, my project structure is:

my-project
├── components
├── pages
└── package.json
ArneHugo
  • 6,051
  • 1
  • 26
  • 47

3 Answers3

19

Next.js 9.4 and later

If you're using Next.js 9.4 or later, see Black's answer.


Next.js 9.3 and earlier

There are different ways of achieving this, but one way – that requires no additional dependencies and not too much config – is to set the environment variable NODE_PATH to the current directory, i.e. NODE_PATH=..

1. Make it work locally

I think the easiest way to set NODE_PATH=. when running the dev/build scripts in your package.json locally (e.g. $ npm run dev or $ yarn dev), is to add it to each script in package.json:

"scripts": {
  "dev": "NODE_PATH=. next",
  "build": "NODE_PATH=. next build",
  "start": "next start"
},

2. Make it work when you deploy

When you deploy to ZEIT Now, NODE_PATH must be set in a different way.

You can add a Deployment Configuration by adding a now.json file (it should be in the same directory as your package.json). If you don't have a now.json file already, create it and add the following contents:

{
  "version": 2,
  "build": {
    "env": {
      "NODE_PATH": "."
    }
  }
}

This tells Now to use NODE_PATH=. when buildnig your app (see build.env).

(It also tells Now that we use Now platform version 2 which is currently the newest version (see version). Omitting the version will give you a warning when you deploy using $ now.)

ArneHugo
  • 6,051
  • 1
  • 26
  • 47
  • 1
    Thanks for this answer, I haven't seen this documented clearly anyplace else—I found that the [webpack resolver solution](https://whoisryosuke.com/blog/2018/nextjs-tip-relative-es6-modules/) kept failing on Now. One small tweak I made to this answer: since I was already setting some other values in a `.env` file, I included `NODE_PATH="."` there. Then, I use the `dotenv` library and call `require('dotenv').config()` at the top of a root-level `next.config.js` file. This sets the value without modifying the script commands in `package.json`. – allanlasser Feb 21 '20 at 22:21
  • I also added `jsconfig.json`: `{ "compilerOptions": { "allowSyntheticDefaultImports": true, "baseUrl": "./", "paths": { "components": ["./components/"] } }, "exclude": ["node_modules"] }` – Brunno Vodola Martins Apr 12 '20 at 02:53
  • I use this solution but some recent package update created some incompatibility with this solution. I posted here https://stackoverflow.com/q/61857093/2700303. Now every page renders blank and a json parser error appears at the javascript console. – MiguelSlv May 17 '20 at 19:03
4

In Next.js 9.4 it is possible to do it by adding the baseUrl config to jsconfig.json (JS projects) or tsconfig.json (TS projects).

// jsconfig.json or tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "."
  }
}

This will allow imports from the root directory. It also integrates well with IDE such as VS Code. See documentation for more information.

ArneHugo
  • 6,051
  • 1
  • 26
  • 47
Black
  • 9,541
  • 3
  • 54
  • 54
  • 1
    Thanks for the update. I'm using NextJS 9.4. also and still had to add NODE_PATH to my .env.production file to make my gitlab pipeline runner work (docker executor with node12-alpine image). Several different ways of setting the webpack modules-alias in next.config.js did not work. My local build passed without setting NODE_PATH or configuring module resolution in next's-config while having set the baseUrl in tsconfig.json. I would love to know how to set the alias properly through the webpack configuration instead of letting NextJs do its thing. – mowtheone May 15 '20 at 10:44
0

Change web pack configuration:

//next.config.js file
module.exports = {  
    webpack(config) {
      config.resolve.modules.push(__dirname)
      return config;
    },
}

Then use it like this:

import TopBar from 'components/TopBar' // for components
import "public/baseLine.css" // for any public resources
MiguelSlv
  • 14,067
  • 15
  • 102
  • 169