'tsconfig problems with test and compiling
This is my tsconfig.json
{
"compilerOptions": {
"noImplicitAny": true,
"declaration": false,
"strict": true,
"strictNullChecks": false,
"target": "ES2019",
"module": "commonjs",
"resolveJsonModule": true,
"allowJs": true,
"checkJs": false,
"outDir": "dist",
"esModuleInterop": true,
"inlineSourceMap": true,
"rootDir": "./",
"baseUrl": "./",
"typeRoots": [
"./node_modules/@types"
],
"paths": {
"@/*": [
"src/*"
]
}
},
"include": [
"src/**/*.ts",
"src/**/*.js",
"src/**/*.json",
"tests/**/*.ts"
],
}
My architecture is as follows:
├── tests
├── src
├── eslint.yml
├── tsconfig.json
├── package.json
The problem with this structure is that in the dist folder it looks like this:
dist
├── tests
├── src
So I could change rootDir to src, problem that the tests folder cannot be outside of src.
What I want is to be able to use typescript in both the tests folder and the src folder. What would be the solution in that case. I've searched in several places and haven't found a solution to my problem.
Maybe some changes might affect eslint, because it imports tsconfig.json
My eslintrc.yml:
env:
es2017: true
node: true
jest: true
extends:
- airbnb-base
- "eslint:recommended"
- "plugin:import/typescript"
parser: "@typescript-eslint/parser"
parserOptions:
ecmaVersion: 2020
sourceType: module
project: "./tsconfig.json"
plugins:
- "@typescript-eslint"
settings:
"import/resolver":
typescript: {}
ignorePatterns:
- "dist/*"
Any idea how to solve this problem?
Solution 1:[1]
Following @fast-reflexes answer and after a lot of research I arrived at the following answer:
- On
package.jsonkeep using only tsc command to compile:
{ ... "scripts": { ... "build": "tsc", ... }, ... }
- My
tsconfig.jsonchange a little bit.
{ "compilerOptions": { "noImplicitAny": true, "declaration": false, "strict": true, "strictNullChecks": false, "target": "ES2019", "module": "commonjs", "resolveJsonModule": true, "allowJs": true, "checkJs": false, "outDir": "dist", "esModuleInterop": true, "inlineSourceMap": true, "rootDir": "./src", // this line changed "baseUrl": "./src", // this line changed "typeRoots": [ "./node_modules/@types" ], "paths": { "@/*": [ "*" // this line changed ] } }, "include": [ "src/**/*.ts", "src/**/*.js", "src/**/*.json" // remove line related to tests ], }
- Created
tsconfig.eslint.json.
{ "extends": "./tsconfig.json", "compilerOptions": { "rootDir": "./", "baseUrl": "./", "paths": { "@/*": [ "src/*" ] } }, "include": [ "src/**/*.ts", "src/**/*.js", "src/**/*.json", "tests/**/*.spec.ts" // line related to tests ] }
- My
eslintrc.ymlchanged:
env: es2017: true node: true jest: true extends: - airbnb-base - "eslint:recommended" - "plugin:import/typescript" parser: "@typescript-eslint/parser" parserOptions: ecmaVersion: 2020 sourceType: module project: - "./tsconfig.json" - "./tsconfig.eslint.json" <-- added this file plugins: - "@typescript-eslint" settings: "import/resolver": typescript: {} ignorePatterns: - ".eslintrc.yml" <-- added this file - "dist/*"
- My architecture is as follows:
??? dist ??? subfolders_without_tests ??? tests ??? tsconfig.json <-- added this file ??? src ??? eslintrc.yml ??? jest.config.js ??? tsconfig.json ??? tsconfig.eslint.json <-- added this file ??? package.json
- My
jest.config.js:
const { pathsToModuleNameMapper } = require('ts-jest/utils'); const { compilerOptions } = require('./tsconfig.json'); module.exports = { preset: 'ts-jest', testEnvironment: 'node', testMatch: ['**/?(*.)+(spec|test).ts'], moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/src/' }), modulePathIgnorePatterns: ['<rootDir>/dist'], coveragePathIgnorePatterns: [ '<rootDir>/dist', ], coverageReporters: ['json', 'lcov', 'text', 'cobertura', 'text-summary'], moduleDirectories: ['node_modules', 'src'], collectCoverage: false, collectCoverageFrom: ['src/**/*.{ts,js,jsx}'], };
Other related links:
Solution 2:[2]
I would advise you to follow the pattern where tests are put in the same folder as the source files they're testing but with an infix test. It will make your life easier in the long run.
Buuut... given your current needs:
1. Post-process output folder
The simplest solution is to replace your (presumed) build script, in package.json:
{
...
"scripts": {
...
"build": "tsc",
...
},
...
}
with the following, updating the output folder as desired
{
...
"scripts": {
...
"build": "tsc && rm -rf ./dist/tests && mv ./dist/src/* ./dist && rmdir ./dist/src",
...
},
...
}
2. Extend Typescript config
You can also add an extra Typescript config only used by Lint. Set rootDir to ./src and remove the include that involves the tests folder in tsconfig.json and then add the following tsconfig.eslint.json Typescript config:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "./"
},
"include": [
"src/**/*.ts",
"src/**/*.js",
"src/**/*.json",
"tests/**/*.ts"
],
}
Now use this config in your .eslintrc.yml only and it should work since it overrides both the rootDir and the include array.
I would have wished for some other solutions as well but even though you can add a temporary rootDir as a command line option to tsc, it will complain about includes that are outside of the root dir and there is no smooth way to replace the include array on the command line (except for literally lining up all the files to compile which is not an option).
In some project I was really motivated to keep a separate tests folder as you do here, but I remember that in the end, I just fell back to the tests-in-sources pattern instead because of the number of ridiculous configuration problems that I got with this other approach.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Cava |
| Solution 2 | fast-reflexes |
