-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tsconfig paths
are not transformed if not bundling
#394
Comments
That said. It appears that |
How about module-alias? I'm going to use it on Koa apps. |
the behavior is not consistent with the most common scenario for this requirement is when creating a lib which should not be published as bundle: import { MyComponent } from '@/components';
|
workaround is to use tsc-alias |
@g00fy- How does it work with |
@evanw is there an official workaround to this? |
Just create a simple loader, e.g. const path = require('path');
/**
* @see https://github.com/evanw/esbuild/issues/394
*/
module.exports = function (content) {
const relativePath = path.relative(
path.dirname(this.resourcePath),
path.resolve(__dirname, '../src')
);
return content.replaceAll(
`from "@/`,
`from "${relativePath ? relativePath + '/' : './'}`
);
}; and then use it to pre-process files: {
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: path.resolve(__dirname, 'src'),
loader: path.resolve(
__dirname,
'./esbuild-loaders/paths-loader.js'
),
} |
wrote https://www.npmjs.com/package/esbuild-ts-paths |
Maybe this is shortsighted of me, having a plugin handle this feels pretty heavy. Below is not the most robust solution, feels like the right amount of effort. // tsc-helpers.js
const path = require('path');
const tsconfig = require('../../tsconfig.json');
module.exports = {
// Workaround for Typescript import paths not being transformed inside onResolve
// @link https://github.com/evanw/esbuild/issues/394
fixBaseUrl: (importPath) =>
importPath.startsWith('./')
? importPath
// Assumption: this is an aliased import
// Read tsconfig directly to avoid any drift
: path.join(tsconfig.compilerOptions.baseUrl, importPath),
};
// some-plugin.js
module.exports = {
name: 'my-plugin',
setup(build) {
build.onResolve({ filter: ... }, async (args) => {
args.path = tscHelper.fixBaseUrl(args.path);
// 🍕 delicious
... |
This seems to work: https://nodejs.org/docs/latest-v16.x/api/packages.html#subpath-exports // tsconfig.json
...
"paths": {
"#Src/*": [
"./src/*"
]
},
...
// package.json
...
"imports": {
"#Src/*": "./dist/*"
}
...
// ./src/index.ts
import { someFunction } from "#Src/util.js"; // <-- the source file name is `util.ts`, but import uses `.js`
someFunction(...); Built using: esbuild --format=esm --platform=node --target=node18 --outbase=src --outdir=dist --sourcemap ./src/*.ts |
Works perfectly. Thanks. Looking forward to esbuild adopting this hint hint. |
Future ref for people looking for solutions that's in similar build scenario. I performed path alias transformations using tsc-alias Conditions:
import { replaceTscAliasPaths } from 'tsc-alias';
import { build } from 'esbuild';
import fg from 'fast-glob';
await build({
entryPoints: await fg(['src/**/*.ts']),
outdir: 'dist',
platform: 'node',
tsconfig: 'tsconfig.json'
});
// Post build paths resolve since ESBuild only natively
// support paths resolution for bundling scenario
await replaceTscAliasPaths({
configFile: 'tsconfig.json',
watch: false,
outDir: 'dist',
declarationDir: 'dist'
}); If your runtime doesn't support top level await yet, you can change it using async/await IIFE
{
"scripts": {
"build": "node build.mjs"
}
} Similar setup can be done only by using CLI instead of defining it programmatically, since |
is it also possible to use this code with tsup? |
@RedStars071 generally yes, the core idea should be the same, assuming |
For Docker builds, we don't want to bundle the config files into the dist/index.js file. By bundling them, we lose the ability to change them without rebuilding the image. Rebuilding the image every time we want to change the config files is not ideal and would prevent us from using the image for other sites. Solving this problem is a bit tricky because we want to use the same build script for both Docker and non-Docker builds, keep the independent core and scripts bundling, and retain the path aliasing functionality. To achieve all of this, I used the following: - tsup's 'external' option to exclude the "@config" modules from the bundle - The tsc-alias package to resolve the "@config" paths to a relative path - The process.env.DOCKER variable to determine whether to use tsup's 'external' option or not (this variable is set in the Dockerfile). By doing all of this, we can now pass the config files into the container as volumes and change them without rebuilding the image. At the same time, we can still use the same build script for local development and retain the simplicity of standalone builds. The use of tsc-alias was discovered in this issue: evanw/esbuild#394 (comment). Without it, "@config/*" paths would remain in the bundle and would cause errors as there is no way for "@config" to be resolved as a local path.
So 4 years later and its still no easier to fix path alias's at transpile time? |
It could be worse, at least there isn't a bot closing these for 30 days of inactivity like every other github project lol |
It might be worth pointing out that if you use
Note that this is only the case with esbuild 0.19+, not with previous versions. |
Esbuild is treating imports like |
i ended up using pnpm workspace for our monorepo. so "external" imports are now aliased from |
^ the import/require is left as-is (as opposed to being transformed to
./lib/logger
), so will fail if run, say in Node.jsWas thinking about whether it's esbuild's responsibility to do the transform, and I feel it is: as a ts-to-js transformer, it should perform any transforms implied in tsconfig.json, including path transforms
The text was updated successfully, but these errors were encountered: