Bun Fails To Resolve HTML With Tsconfig Paths: A Bug Report
Hey guys! Today, we're diving deep into a quirky issue encountered while trying to integrate Bun into a complex Vue-based application. Specifically, Bun seems to be ignoring the tsconfig.json
paths when resolving *.html
files. This can be a real headache, especially when you're dealing with aliased paths that point outside the root directory. Let's break down the problem, explore the expected behavior, and see what's actually happening.
The Issue: Bun's tsconfig.json Blind Spot
So, what's the buzz? The core problem is that Bun doesn't seem to be honoring the path aliases defined in tsconfig.json
when it comes to resolving *.html
files. Imagine you've set up your tsconfig.json
to make your imports cleaner and more manageable. You've got aliases pointing to different parts of your project, maybe even outside the root directory. Everything looks neat and tidy, right? Well, when you try to run your application with Bun, it throws a tantrum, complaining that it can't resolve those *.html
files. It's like Bun is wearing blinders, completely ignoring the roadmap you've meticulously laid out in your tsconfig.json
.
Diving into the Details
Let's get a bit more specific. The issue arises particularly when you're using an aliased path in an import
statement, especially one that ventures outside the project's root directory. You see, tsconfig.json
is supposed to act like a friendly guide, telling Bun (and other tools) where to find these aliased modules. Inside tsconfig.json
, the compilerOptions.paths
section is where the magic happens. You define your aliases here, mapping them to their actual locations. For instance, you might have an alias like @components
pointing to a directory containing your Vue components. This keeps your import statements clean and readable, like this: import MyComponent from '@components/MyComponent.vue';
However, when Bun encounters such an import, instead of following the alias defined in tsconfig.json
, it throws its hands up in the air and cries, "Cannot resolve module!" It even suggests that you might need to install a package, which is totally misleading. It's like asking for directions, having someone point you in the right direction, and then ignoring them completely. This behavior is not only frustrating but also a significant roadblock in migrating existing projects to Bun. For those of us who rely on tsconfig.json
for path resolution (and let's be honest, that's most of us), this issue is a deal-breaker.
An Example to Illustrate
To paint a clearer picture, consider a scenario where you have a Vue application with a structure like this:
my-app/
├── src/
│ ├── components/
│ │ └── MyComponent.vue
│ └── App.vue
├── tsconfig.json
└── bun.config.ts
In your tsconfig.json
, you've defined a path alias:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"]
}
}
}
Now, in your App.vue
, you import MyComponent
using the alias:
<template>
<MyComponent />
</template>
<script setup>
import MyComponent from '@components/MyComponent.vue';
</script>
When you try to run this with Bun, you'd expect it to happily resolve @components/MyComponent.vue
using the path defined in tsconfig.json
. But instead, Bun throws an error, complaining that it can't find the module. This is precisely the issue we're tackling here. It's as if Bun has decided to play hide-and-seek with our modules, and it's not very good at seeking.
Expected Behavior: Bun Should Obey tsconfig.json
Okay, so we've established the problem. But what's the right way for Bun to behave? The expected behavior is crystal clear: Bun should absolutely respect the tsconfig.json
file and use the compilerOptions.paths.*
definitions for alias resolution. This is not just a nice-to-have feature; it's a fundamental aspect of modern JavaScript and TypeScript development. Tools like Webpack, Parcel, and Vite have long supported tsconfig.json
paths, making it a standard practice for managing module imports. Bun, aiming to be a top-tier JavaScript runtime and bundler, should follow suit.
Why is tsconfig.json Support Crucial?
Think about it. tsconfig.json
is more than just a configuration file; it's a contract between the developer and the tooling. It lays out the rules for how the project should be compiled, type-checked, and, crucially, how modules should be resolved. By adhering to tsconfig.json
, Bun ensures consistency across the development workflow. Developers can use the same path aliases in their code, regardless of whether they're running tests, building for production, or just tinkering in the development environment.
Furthermore, tsconfig.json
support is vital for project maintainability. Imagine a large codebase without consistent path aliases. Import statements would be littered with relative paths, making it difficult to refactor and move files around. With tsconfig.json
aliases, you can change the underlying directory structure without breaking a sweat. Just update the paths in tsconfig.json
, and everything else falls into place. It's like having a GPS for your project, guiding the bundler through the maze of modules.
The Bigger Picture: Ecosystem Compatibility
Beyond individual projects, tsconfig.json
support is essential for ecosystem compatibility. Many libraries and frameworks assume that tools will respect tsconfig.json
paths. If Bun deviates from this expectation, it risks creating friction for developers who want to use these libraries. This can lead to a fragmented ecosystem, where developers have to jump through hoops to make things work with Bun. For Bun to truly thrive, it needs to play well with others, and that means embracing tsconfig.json
as a first-class citizen.
What We See Instead: A Resolution Breakdown
So, if Bun should be using tsconfig.json
for path resolution, what's it actually doing? Unfortunately, what we see instead is a rather frustrating inability to resolve modules using the defined aliases. Bun throws a "cannot resolve" error, leaving developers scratching their heads and wondering if they've missed a crucial step. It's like Bun is speaking a different language, ignoring the carefully crafted instructions in tsconfig.json
.
The Error Message in Detail
The error message itself is quite telling. It typically looks something like this: error: Cannot resolve module "@components/MyComponent.vue"
. The key phrase here is "Cannot resolve module." This indicates that Bun has failed to locate the module using its standard resolution mechanisms. What's particularly misleading is that Bun often suggests that you might need to install a package, which is completely irrelevant in this case. The issue isn't a missing dependency; it's Bun's failure to follow the path alias defined in tsconfig.json
.
Why This is Problematic
This behavior is problematic for several reasons. First, it creates a confusing developer experience. Developers who are accustomed to using tsconfig.json
for path resolution will naturally expect Bun to behave accordingly. When it doesn't, it leads to frustration and wasted time as they try to debug the issue. Second, it hinders the adoption of Bun in existing projects. Many projects rely heavily on tsconfig.json
paths, and migrating to Bun becomes significantly more challenging if this feature is not supported. It's like trying to fit a square peg into a round hole; you can force it, but it's not going to be pretty.
A Deeper Dive into the Resolution Process
To understand why this is happening, let's delve a bit deeper into how module resolution typically works. When a bundler encounters an import statement, it goes through a series of steps to locate the module. These steps might include:
- Checking the
node_modules
directory. - Looking for relative paths.
- Consulting the
tsconfig.json
file for path aliases. - Using other configuration files (like
webpack.config.js
) for custom resolution rules.
It appears that Bun is either skipping step 3 or not implementing it correctly. It's as if the tsconfig.json
file is invisible to Bun's module resolution engine. This is a critical oversight, as tsconfig.json
is the standard way to define path aliases in TypeScript projects. Without proper tsconfig.json
support, Bun's module resolution becomes incomplete and unreliable.
Additional Information: A Real-World Scenario
To drive the point home, let's consider a real-world scenario. Imagine you're working on a large Vue.js application with a complex directory structure. You've meticulously organized your components, services, and utilities into separate directories, and you've defined path aliases in tsconfig.json
to keep your import statements clean and maintainable. You've got aliases like @components
, @services
, and @utils
pointing to their respective directories.
Now, you decide to give Bun a try, hoping to leverage its speed and performance. You install Bun, configure your project, and run the build command. To your dismay, Bun starts throwing errors left and right, complaining that it can't resolve your modules. You dig into the error messages and realize that Bun is ignoring your tsconfig.json
paths. It's like you've entered a parallel universe where your carefully crafted aliases mean nothing.
The Impact on Migration
This scenario highlights the significant impact of the tsconfig.json
issue on project migration. For many developers, migrating to Bun is not just a matter of switching a few commands; it's a comprehensive process that involves adapting the build pipeline, updating dependencies, and ensuring that everything works seamlessly. If Bun doesn't support tsconfig.json
paths, it adds a major hurdle to this process. Developers may have to refactor their code, replace aliases with relative paths, or resort to other workarounds. This not only increases the migration effort but also introduces the risk of errors and inconsistencies.
The Excitingly Fast Failure
The original bug report mentioned that Bun was