How to set up import aliases for Gatsby.js
A step-by-step guide to use import aliases with Webpack, ESlint, and VS Code
Don't you just hate when you have to import a component from deep within your import tree?
import Component from "../../../../components/Component";
All I want is to be able to directly import from my project's local directory's alias from anywhere:
import Component from "~components/Component";
On top of the Gatsby understanding this, I want to keep all the benefits of my current setup—ESlint's import
linting and VS Code's import
autocomplete.
Import alias naming
Let's begin by figuring out what we want to call our alias. I've considered several different options:
import Component from "components/Component";
You see this one quite often in people's setups. While technically not an alias, my biggest issue with this naming is that it reads as if components
were a library from NPM—which it's not. Nope.
import Component from "@components/Component";
This is the direction many libraries are going (think @babel
, @types
, etc.), however, it carries the same issue as above—components
is not an NPM library. Nope.
import Component from "~/components/Component";
Now were getting somewhere, ~
is generally understood to signify local things. Yet, ~/
would read as if I'm importing from the root of the machine, not the root of the project. Nope.
import Component from "~components/Component";
This is my sweet spot. Similar to @
meaning a scoped package, a ~
tells me it's a local folder within the project. Yup.
Gatsby import alias
Gatsby uses Webpack. Aliases in Webpack can be set up through a resolve alias. Gatsby doesn't expose its Webpack config for us to change. Dang it.
At the same time, Gatsby does expose an onCreateWebpackConfig
hook. Yessir. Let's add this to gatsby-node.js
:
const path = require("path");exports.onCreateWebpackConfig = ({ actions }) => {actions.setWebpackConfig({resolve: {alias: {"~components": path.resolve(__dirname, "src/components"),},},});};
actions.setWebpackConfig
merges (shouldn't it be called mergeWebpackConfig?) whatever we define in its argument into Gatsby's Webpack config whenever it's run. Easy and done.
ESlint import plugin
While Gatsby is now happy, a few things broke. ESlint's import plugin is screaming left-and-right that it cannot resolve these paths (even though everything works):
// [eslint] Unable to resolve path to module '~components/Component'. [import/no-unresolved]import Component from "~components/Component";
We need to tell ESlint to resolve these paths, just like we told Gatsby. And we're going to need a little library for that. Let's run:
yarn add -D eslint-import-resolver-alias
And then add the following to our .eslintrc
(or any other way you control your ESlint):
{[...]"settings": {"import/resolver": {"alias": [["~components", "./src/components"]]}}}
The alias
field defines an array in which each item defines one alias—the first item is the name, the second is the path to resolve it to. Smooth and done.
VS Code import autocomplete
Lastly, VS Code stopped suggesting subfolders when typing the alises. Unsurprisingly, VS Code needs to be told about the aliases too.
Let's add the following to our jsconfig.json
(or create this file at the root of your project):
{[...]"compilerOptions": {"baseUrl": ".","paths": {"~components": ["src/components"]}}}
Same thing as above, this time with glob patterns—key being the name, value being an array of routes to resolve. All done.
All done
That's it. Generally, I'd prefer to keep the information about my aliases in one place—single source of truth etc. Then again, it's understandable as the tools we need to orchestrate work completely independently.
You're going to save a lot of typing with this. Let me know on Twitter what you think!