In esbuild, you usually import other files using relative paths:
import './some-related-module'
import `../../utils/some-utility-module`
import `../../../css/some-css.sass`
This is totally fine if you import closely related files, but a bit clunky when you're trying to import some "global" module, like a utility module. When moving a file, your imports also need to change.
To get around this, esbuild support a mechanism first introduced in TypeScript called "path aliases". It works like this:
First, you create a file called jsconfig.json
(or tsconfig.json
if you do use TypeScript):
{
"compilerOptions": {
"baseUrl": "./app/assets",
"paths": {
"@/*": ["js/*"],
"@images/*": ["images/*"],
"@css/*": ["css/*"],
"@spec/*": ["../../spec/js/*"]
}
},
"include": []
}
(The include: []
only makes sense if you do not use Typescript. If you leave it out, hq-alias
will search all js
files in the directory, which could be expensive.)
Then, change your imports to
import './some-related-module'
import '@/utils/some-utility-module'
import '@css/some-css.sass'
That's mostly it. Unfortunately, some parts of the ecosystem will do their own resolving, and you'll have to teach them to use your path aliases.
The alias-hq
npm package
The
alias-hq
Show archive.org snapshot
npm package aims to simplify configuring tools that are unaware of your path aliases.
For example, you would configure webpack using
import hq from 'alias-hq'
module.exports = {
...
resolve: {
alias: hq.get('webpack'),
},
}
or jest using
// jest.config.js
import hq from 'alias-hq'
module.exports = {
...
moduleNameMapper: hq.get('jest'),
}
Support for SASS
In Sass, your @import
statements also use their own resolving. To bring your path aliases to Sass, add this to your esbuild.config.js
:
First, a function that rewrites paths, itself using alias-hq
:
const path = require('path')
const hq = require('alias-hq')
function escapeStringRegexp(string) {
return string
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
.replace(/-/g, '\\x2d')
}
const mapAliasedPath = hq.get(({ rootUrl, baseUrl, paths }) => {
return (importPath) => {
if (!importPath.includes('@')) {
return importPath
}
const basePath = path.join(rootUrl, baseUrl)
for (const [aliasedPath, replacements] of Object.entries(paths)) {
const regexp = new RegExp('(^|.*/)' + escapeStringRegexp(aliasedPath).replace('\\*', '(.*)'))
importPath = importPath.replace(regexp, path.join(basePath, replacements[0]).replace('*', '$2'))
}
return importPath
}
})
Then add it to your esbuild-sass-plugin
config with
require('esbuild').build({
// ...
plugins: [
// ...
sassPlugin({
// ...
importMapper: mapAliasedPath,
}),
],
})
Support for esbuild-plugin-import-glob
Unfortunately,
esbuild-plugin-import-glob
Show archive.org snapshot
does not support external path resolving at all.
Instead, use the attached variant of the plugin, and then set it up via
const importGlob = require('./lib/esbuild/esbuild-plugin-import-glob') // copy the attached plugin here
require('esbuild').build({
// ...
plugins: [
// ...
importGlob({
importMapper: mapAliasedPath,
}),
],
})