Search code examples
angularvisual-studio-codewebstormtslintnrwl

Disallow barrel file imports within the same library in Nrwl Nx


Suppose we have an app and a library in Nrwl Nx.

/apps
  /myApp

/libs
  /myLib
    /components
       /my.component.ts
       /other.component.ts
    /index.ts

I have already set tags in nx.json and nx-enforce-module-boundaries rule to block importing the app inside the lib. It works and this part is fine.

Another thing I wanted to do is enforcing using barrel files within libraries. So I created a path in tsconfig.ts

"paths": {
   "@myNs/my-lib": ["libs/myLib/index.ts"]
}

I faced the problem. Suppose we have something exported from index.ts.

// index.ts
export { MyComponent } from './components/my.component';

Now if we use some autoimporting IDE feature (e.g. from WebStorm or VS Code). They will be importing MyComponent using the path @myNs/my-lib - and this is expected, because I have just configured it like so.

A real problem appears when I want to autoimport something inside myLib (these imports should be relative, not @myNs/my-lib) - according to logic and this article ([Interesting article here]):

Never let a lib import from its own Barrel file

The TypeScript modules within a particular lib should not care what functionality that lib exposes, so it shouldn’t use its own barrel file at any point.

If a module imports something from its own barrel file, it almost always results in circular reference errors. Therefore, imports from inside of the module should use relative path imports.

So I found a workaround to block TS path-like imports inside lib. I have added a rule inside libs/myLib/tslint.json:

"rules": {
   "import-blacklist": [true, "@myNs/my-lib"]
}

Anyway, it doesn't fix autoimporting feature, just disallows to use wrong imports inside the lib.

Another problem is there are still wrong imports allowed. Suppose OtherComponent wants to import MyComponent Then there are three possibilities:

import { MyComponent } from './my.component'; // the correct way
import { MyComponent } from '.'; // not the best, but also the correct way
import { MyComponent } from '..'; // using barrel file - not correct (look at the citation above), but still successfuly validated by TSLint

Questions:

  1. How to disallow barrel file imports inside the same lib?
  2. How to configure IDEs to have relative paths inside lib and TypeScript paths outside (@myNs/my-lib)?

Solution

  • No one answered, so I decided to create a simple TSLint rule to handle this case: import-blacklist-extended

    Rule works fine in Nrwl monorepo, but it could be optimized and some mechanisms could be resolved better. Feel free to create issues and PRs on Github if any changes are needed for you.