Can i exclude files dynamically from ts compiler? - node.js

I'm setting up a node/typescript server to build a real time application. I have my server and my client on the same folder.
What i want to do is to exclude "src/client" from the typescript compiler when i run the "server:dev" script end exclude "src/server" when i run "client:dev".
I already tried to find a way to exclude files from command line, but i didn't find solutions for that.
that's how my tsconfig.json look like
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"lib": ["dom","es2017"],
"sourceMap": true,
"outDir": "dist",
"strict": true,
"noImplicitAny": true,
"moduleResolution": "node",
"esModuleInterop": true,
"resolveJsonModule": true
},
"exclude": [
"src/client"
]
}
but i need to include "src/client" and exclude "src/server" when i run the client.

tsconfig.json support extends field, in your case, you should put the common config in a base tsconfig.json, then create tsconfig with extends for client and server respectively.
// tsconfig.json
{
"compilerOptions": {
...
}
}
// tsconfig.client.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
...
},
"exclude": ["src/server"]
}
// tsconfig.server.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
...
},
"exclude": ["src/client"]
}
For npm scripts:
// package.json
{
"scripts": {
"server:dev": "tsc --build tsconfig.server.json",
"client:dev": "tsc --build tsconfig.client.json",
}
}

The general approach to change the compiler options dynamically:
since fs module can be used in node.js, you could add this util function to your node.j sproject:
const fs = require("fs")
const prettier = require("prettier")
function changeTs(){
// this guarantees that I am on server
if(typeof window === "undefined"){
// process.cwd returns base folder, current working directory
// whatever path is
const tsPath = path.join(process.cwd(), "tsconfig.json")
const tsConfig = require(tsPath)
tsConfig.compilerOptions.exclude = ["src/client"]
fs.writeFileSync(
tsPath,
prettier.format(
JSON.stringify(tsConfig), { parser: "json" }
)
)
}
}
call the above function, top-level when node.js app loads, so it tsconfig.json will be updated. default setting should be "exclude": ["src/server"]. When you are on server, it will be changed to "exclude": ["src/client"]
With this approach, you can even pass an argument to the function, so you can change the ts compiler options based on a specific setting that your app needs.

Related

How do I import from a relative path like "/utils" within my "src" folder in Jest + RTL Tests

I am creating tests with Jest and React Testing Library and I am having difficulties with imports to the util folder that exists within the src folder. I am using TypeScript for this which seems to create its own interesting challenges.
My jest.config.ts file looks like the following:
module.exports = {
'preset': 'ts-jest',
'testEnvironment': 'node',
'testPathIgnorePatterns': [
'<rootDir>/dist'
],
'moduleNameMapper': { 'src/(.*)': '<rootDir>/src/$1' }
};
The test looks like the following:
import React from 'react';
import { render, screen } from '#testing-library/react';
import { Tag } from '/components';
describe('Tabs Component', () => {
it('should render a tab component correctly', () => {
render(<Tag id="test" />);
expect(screen.getAllByTestId('test')).toHaveBeenCalled();
});
});
When I run this I am getting import issues:
Cannot find module '/components' from 'src/components/Tag/Tag.spec.tsx'
Additionally my tsconfig looks like the following:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"/*": [
"*"
]
},
"outDir": "./tested/esm",
"module": "esnext",
"target": "es5",
"lib": [
"es6",
"dom",
"es2016",
"es2017"
],
"jsx": "react",
"declaration": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true
},
"include": [
"src/**/*.spec.{ts,tsx}",
"./jest.config.ts"
],
"exclude": [
"node_modules",
"dist",
"./src/**/*.stories.tsx",
"./*.js"
]
}
I have tried a few of the tricks from Stack Overflow like:
Jest gives `Cannot find module` when importing components with absolute paths
None of these seemed to fix the issue.
I think the problem here is how the import is done. As the jest.config.ts has already specified the moduleNameMapper as { 'src/(.*)': '<rootDir>/src/$1' }, it means if Tag component is imported as below,
import { Tag } from "src/components";
Jest will look into the <rootDir>/src/components/index.ts to import the Tag component.
If you want to import modules in this way,
import { Tag } from "components"; // not "/components"
It's better to replace moduleNameMapper config with moduleDirectories:
module.exports = {
'preset': 'ts-jest',
'testEnvironment': 'node',
'testPathIgnorePatterns': [
'<rootDir>/dist'
],
'moduleDirectories': ['node_modules', 'src']
};
This tells Jest when it sees an import from "components", it will look into both node_modules and src and see if there is the file components/index.ts or components.ts.
PS: tsconfig.json is only used by the editor. Therefore, Jest won't take it into consideration. jest.config.ts is the config file that matters to Jest.

How configure a local package for use in a NestJS app?

I cant import classes from a local package, please see summary below.
NestJS app
I created a NestJS app called exp1 with the cli:
nest new exp1
Then, add my local package
yarn add "file:../core"
Next, I want to import classes from the package. In app.controller I put
import { Feature } from '#me/core'
...
console.log(Feature)
So far so good, no warnings. But the console.log() output is undefined.
Package configuration
package.json
{
"name": "#me/core",
"main": "dist/index.js",
"types": "src/index.d.ts",
"files": [
"/dist",
"/src"
],
...
}
tsconfig.json
{
"compilerOptions": {
"module": "ES6",
"esModuleInterop": true,
"moduleResolution": "node",
"declaration": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"lib": ["es2019",],
"target":"ES6"
},
"include": [
"src/**/*"
]
}
index.ts
export { Feature } from './Feature'
Feature.ts
export class Feature {
public type = 'unknown'
}
webpack.mix.js
const mix = require('laravel-mix');
mix.ts('src/index.ts', 'dist')
Running this successfully outputs dist/index.js, src/index.d.ts, src/Feature.d.ts
Clues
The typing seems to work in NestJS app
(new Feature).type // OK
(new Feature).typo // Warning
However when accessing Feature it is always undefined..
Not sure what I am missing. Is it correct to point package.json main attribute to dist/index.js file or should it point to index.ts?

tsconfig's path parameter and ESLint

I've been setting up the paths option in my tsconfig.json file. So far everything works fine. I can run my tests, and I can execute the program as usual. My only problem is, that ESLint does not find the modules that are accessed with one of the paths defined in tsconfig.json.
Here are all of the files that are related to the problem:
tsconfig.json:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"allowJs": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./",
"strict": true,
"esModuleInterop": true,
"declaration": true,
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"#/*": ["./src/*"]
}
},
"include": ["src/**/*", "test/**/*", "index.ts"]
}
tsconfig.eslint.json:
{
"extends": "./tsconfig.json",
"include": ["src/**/*", "test/**/*", "index.ts", ".eslintrc.js"]
}
.eslintrc.js:
{
root: true,
env: {
browser: true,
es6: true,
node: true
},
extends: ['plugin:#typescript-eslint/recommended', 'plugin:#typescript-eslint/recommended-requiring-type-checking'],
parser: '#typescript-eslint/parser',
parserOptions: {
project: ['tsconfig.eslint.json'],
sourceType: 'module'
},
settings: {
'import/resolver': {
typescript: {}
}
},
plugins: ['#typescript-eslint', 'import', 'prefer-arrow'],
rules: {...}
}
Am am using the package eslint-import-resolver-typescript.
Now, if I try to import the file './src/test.ts' into './index.ts' with the path '#/test', then ESLint will not be able to resolve that import (although TypeScript resolves it just fine).
I've mostly copied my current solution from here, because I thought the person who asked that problem had the same problem that I had, but my setup still does not work.
I am in an NodeJS environment by the way.
EDIT:
I've also tried using the package eslint-import-resolver-alias. This only helped partially. I could get rid of the 'import/no-unresolved' errors, but whenever I call an imported function, I get '#typescript-eslint/no-unsafe-call' because apparently, ESLint does not find the types for the imported files and thusly gives everything the type any.
Could you try adding the tsconfigRootDir to your .eslintrc.js? It has worked for me.
parserOptions: {
tsconfigRootDir: __dirname,
}
For those using Angular and.eslintrc.json, I use this (notice the 2 stars in "Project"
"parserOptions": {
"project": ["**/tsconfig.json"],
"createDefaultProgram": true
},
you need to add eslint plugin https://github.com/benmosher/eslint-plugin-import#typescript
there under the extends you can specify option for typescript
extends:
- plugin:import/typescript
it should do the trick

Nodejs local dependencies its not working when the build it's make

I have an application developed in node and typescript, so to make this application more modular (something like libs in asp.net), I've been created two local packages to be more reusable and add them in my application as local package (npm i 'path-my-module').
But now I'd problems when I build my solution to make a deploy in test because this modules hasn't been included in the build.
I'm new in node and I didn't find much thing about how can I work in this case I would like to know how can I do in this case?
This approach it's right?
How can I use local dependencies and include them in my build to be deployed in test env?
More information:
My Package.json is more or less like this:
"dependencies": {
some imports ...
"my-local-package-a": "file:../LocalPackageA",
"my-local-package-b": "file:../LocalPackageB",
.... more imports,
},
I'm using Gulp.js to automate the pipeline.
My gulp file:
var gulp = require("gulp");
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");
var OUT_DIR = "dist";
var IN_DIR = "../MyAlexaApp";
// compile typescript
gulp.task("compile", function () {
return tsProject.src()
.pipe(tsProject())
.js.pipe(gulp.dest(OUT_DIR));
});
// copy json files (e.g. localization json)
gulp.task("json", function () {
return gulp.src(IN_DIR + "/**/*.json").pipe(gulp.dest(OUT_DIR));
});
gulp.task("default", gulp.parallel(["compile", "json"]));
My ts config:
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"lib": ["es6"],
"moduleResolution": "node",
"rootDir": "../DealerSearchSkill",
"outDir": "dist",
"sourceMap": true,
"allowJs": false,
"noImplicitAny": true,
"noUnusedLocals": true,
"noImplicitThis": true,
"strictNullChecks": true,
"noImplicitReturns": true,
"preserveConstEnums": true,
"suppressImplicitAnyIndexErrors": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"resolveJsonModule": true
},
"exclude": [
".ask",
"coverage",
"skill-package",
"infrasctructure",
"/**/node_modules",
"lambda/local/",
"__tests__",
"**/__mocks__"
]
}

*export ... from* returns undefined in node with typescript

I'm aggregating files in an index.ts. When I try to import from the index.ts the object returns as undefined. When I try to import directly from the file, it works fine. I'm not sure what I'm doing wrong -- it's my impression that export { ... } from '...' should work fine in Node with TypeScript (which is the case for this app).
fileThatUsesTheExportedVariables.ts
import { dates } from '../consts' // Undefined
import { dates } from '../consts/index' // Undefined
import { dates } from '../consts/dates' // Works
consts/index.ts
export { dates } from './dates'
// ...
export { someNamedExport } from './someFile'
consts/dates.ts
const months = {
// some months stuff
}
export const dates = {
months,
// ...
someOtherChildObject
}
I presume I'm doing something silly. VS Code can connect the dots which makes it all the more frustrating.
Thanks in advance for any and all help
UPDATE: #casieber pointed out it might be helpful to know more about the TS compilation process (uses tsc):
Versions:
tsc 2.9.1
typescript 6.1.0
tsconfig.json
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"lib": ["es2018", "dom"],
"declaration": true,
"sourceMap": true,
"outDir": "dist",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"include": [
"app/**/*"
]
}

Resources