Unclear nicknames within the Vite monorepository

An issue has surfaced in the Vite monorepo setup where TypeScript respects @ aliases due to separate tsconfig files (visible in IDE), but Vite does not differentiate them among workspaces during build.

The project utilizes Yarn 1.x with workspaces, TypeScript 4.9, Vite 3.2, Lerna 6.4 (which should not impact the current problem).

The structure of the project adheres to a standard monorepo setup:

packages/
  foo-bar/
    src/
      index.ts
    package.json
    tsconfig.json
    vite.config.ts
    yarn.lock
  foo-baz/
    (same as above)
  foo-shared/
    src/
      qux.ts
      quux.ts
    package.json
    tsconfig.json
    yarn.lock
lerna.json
package.json
tsconfig.json
yarn.lock

When one package (foo-bar) imports a module from another (foo-shared):

packages/foo-bar/src/index.ts:

import qux from `@foo/shared/qux';

During build, another package incorrectly resolves local aliased imports to the wrong package because Vite is unaware of tsconfig aliases:

packages/foo-shared/src/qux.ts:

import quux from `@/quux'; // resolves to packages/foo-bar/src/quux.ts and errors

The error message reads like this:

[vite:load-fallback] Could not load ...\packages\foo-bar\src/quux (imported by ../foo-shared/src/qux.ts): ENOENT: no such file or directory, open '...\packages\foo-bar\src\stores\quux' error during build:

foo-shared currently serves as a dummy package that is not built independently; it is only aliased and used in other packages.

packages/foo-bar/vite.config.ts:

  // ...
  export default defineConfig({
    resolve: {
      alias: {
        '@': path.join(__dirname, './src'),
        '@foo/shared': path.join(__dirname, '../foo-shared/src'),
      },
    },
    / * some irrelevant options */
  });

packages/foo-bar/tsconfig.json and packages/foo-shared/tsconfig.json are similar:

{
  "extends": "@vue/tsconfig/tsconfig.web.json",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@foo/shared/*": ["../foo-shared/src/*"]
    },
    "typeRoots": [
      "./node_modules/@types",
      "../../node_modules/@types"
    ]
  },
  "include": [
     "src/**/*.ts",
     "src/**/*.d.ts",
     "src/**/*.vue"
   ],
  "exclude": [
    "node_modules"
  ],
}

I attempted to switch resolve.alias with the vite-tsconfig-paths plugin without success. The plugin did not alter the aliases as expected, and its compatibility for this scenario remains uncertain.

Is there a way to configure Vite to correctly resolve paths starting with "@" based on the parent module's path?

Answer №1

According to the Vite documentation about the resolve.alias option:

The entries option in @rollup/plugin-alias can be passed as an object or an array of

{ find, replacement, customResolver }
pairs.

However, the readme for rollup's resolve-alias plugin is currently lacking details:

Type: Function | Object
Default: null

This setting instructs the plugin to use a different resolving algorithm instead of Rollup's resolver. For more information on the resolveId hook, please refer to the Rollup documentation. To see an example, check: Custom Resolvers.

If you need more information than provided by the example, especially regarding writing your own custom resolver, you can consult the type declaration file at: https://github.com/rollup/plugins/blob/master/packages/alias/types/index.d.ts, which includes:

// Type declarations explaining how to define aliases and custom resolvers

Furthermore, it might be helpful to reorder your resolve.alias entries in your vite.config.js file to address certain issues, prioritizing accordingly.

alias: {
  '@foo/shared': path.join(__dirname, '../foo-shared/src'), // repositioned to topmost entry
  '@': path.join(__dirname, './src'),
}

In case rearranging entries does not yield the desired results, or if future scenarios call for additional handling beyond standard aliasing, consider creating a custom resolver (note the customResolver field in the Alias type). This should help with questions like: "How can Vite resolve paths starting with '@' differently based on parent module paths?"

For detailed guidance on this topic, refer to the council within the rollup/plugin-alias documentation: . The excerpt below highlights key points, notably emphasizing the importer parameter:

Type: ResolveIdHook
Kind: async, first
Details: Explanation of ResolveIdHook usage
Important: Focus on the importer parameter
type ResolveIdHook = (
  source: string,
  importer: string | undefined,
  options: {
      assertions: Record<string, string>;
      custom?: { [plugin: string]: any };
      isEntry: boolean;
  }
) => ResolveIdResult;

// Additional related definitions ...

Further insights are highlighted in the document, including the usage of the importer parameter to provide context when resolving modules.

Answer №2

Consider using the vite-tsconfig-paths plugin as an alternative to the alias method.

For example:

import vue from '@vitejs/plugin-vue';
import tsconfigPaths from 'vite-tsconfig-paths';
import { defineConfig } from 'vite';

// Vite configuration
export default defineConfig({
  plugins: [tsconfigPaths(), vue()],
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What about combining a fat arrow function with a nested decorator?

Trying to implement a fat arrow function with a nestjs decorator in a controller. Can it be done in the following way : @Controller() export class AppController { @Get() findAll = (): string => 'This is coming from a fat arrow !'; } Wh ...

A generalized function that provides IEntity[E][S] as its return type, delving into two levels of

I've encountered a compilation/type error while attempting to implement something similar to the code snippet below. interface IEntityLookup { [Entity.PERSON]: IPersonLookup [Entity.COMPANY]: ICompanyLookup } interface ISubEntity { [Entit ...

The custom form input in Angular2 is throwing an error because it is trying to access the property 'name' of an

Upon switching to the latest Angular version 2 final, I encountered the following error Uncaught TypeError: Cannot read property 'name' of undefined This is my customized input import { Component, EventEmitter, Provider, forwardRef } from &a ...

Rejecting the request by clicking a button

While switching to a menu, I retrieve data from the API. As the pending data is still loading in DevTools, I click on the Filter button to search for additional data. The data I am searching for appears in my table. However, once the pending data finishes ...

Mapbox GL JS stops displaying layers once a specific zoom level or distance threshold is reached

My map is using mapbox-gl and consists of only two layers: a marker and a circle that is centered on a specific point. The distance is dynamic, based on a predefined distance in meters. The issue I'm facing is that as I zoom in and move away from the ...

Angular 5: Utilizing distinct router-outlets in separate modules for optimized lazy loading experience

Having two modules with routing module files and router-outlets in their html, I aim to load components based on the current module. The file tree structure is as follows: project |-- module2 |-- -- profil |-- -- - profil.component.html |-- -- - profil. ...

How can you prevent specific dates from being selected in an Angular Datepicker?

Is there a way to exclude Monday from the "mat-datepicker" component? I've tried implementing the following code in my class component: dateFilter = (_date: any) =>{ let day = _date.getDay(); console.log(day); return day != 1; ...

Ways to trigger an Angular function once and persist it even after the component is reloaded

Currently, I am learning Angular and have come across a particular issue. As far as I understand, everything placed within the `ngOnInit` method gets executed every time the component reloads. I have a timer function that needs to continue running even aft ...

How to implement a collapsible tree view component in Angular 2

I am currently working on creating my own collapsible tree view in order to gain a better understanding of Angular 2. I have made some progress with it, but I am facing an issue with applying the hidden property to the specific <li> item that is clic ...

Configuring Stylelint in a NextJS project using Emotionjs

I recently encountered an issue while trying to integrate Stylelint into a new NextJS Typescript project with EmotionJS. Many rules were not working in my styles files, and the only error I could identify was Unknown word CssSyntaxError. This particular U ...

Utilizing Optional Generics in TypeScript

I have created a wrapper for making API calls to a Strapi server. export const api = { post: async<T extends unknown, K>(url: string, body: Partial<T>, jwt?: string): Promise<K> => { try { const result = await ...

The regular expression in Vite / Vue is causing a SyntaxError

I've encountered an error in my new Vuejs project when I run the npm run dev command. Can anyone help me resolve this issue? I believe it may be an internal bug from Vite in the node_modules. My operating system is macOS Ventura 13.3.1. https://i.sst ...

What is the reason why the swiper feature is malfunctioning in my React-Vite-TS application?

I encountered an issue when trying to implement Swiper in my React-TS project. The error message reads as follows: SyntaxError: The requested module '/node_modules/.vite/deps/swiper.js?t=1708357087313&v=044557b7' does not provide an export na ...

How to Implement the Play/Pause Button in an Angular Application

I'm working on adding a show/hide feature to the play and pause buttons for a list of tracks in Angular 7. I had some success with Angular animation initially, but encountered an issue where all buttons in my list would change state instead of just on ...

Create a chronological timeline based on data from a JSON object

Here is a JSON object generated by the backend: { "step1": { "approved": true, "approvalTime": "10-11-2021", "title": "title 1", "description": "description 1" ...

JavaScript function variable encountering syntax error

My current node version is 12.22.6. I'm struggling to understand why this code isn't working correctly. It seems like I must be missing an important basic concept, but I can't quite pinpoint it. const changeVars = (variable) => { c ...

How can Multer library be effectively utilized to manage exceptions in NestJS controllers?

While working on creating a service to upload specific files from a Post multipart/form-data request, I came across an easy way to validate the fields count and name sent using the FileInterceptor decorator from @nestjs/platform-express. However, I'm ...

insert information into a fixed-size array using JavaScript

I am attempting to use array.push within a for loop in my TypeScript code: var rows = [ { id: '1', category: 'Snow', value: 'Jon', cheapSource: '35', cheapPrice: '35', amazonSource ...

Exploring how Jasmine tests the checkbox change handler function in the latest version of Angular (12)

I'm attempting to create a basic test function for a checkbox change event, but I'm encountering some issues running it. The error message states "Spec has no expectations," and the handler function is not included in code coverage. Template: &l ...

Angular function implementing a promise with a return statement and using the then method

I have a function in which I need to return an empty string twice (see return ''. When I use catch error, it is functioning properly. However, I am struggling to modify the function so that the catch error is no longer needed. This is my current ...