Typescript error Cannot find module 'typescript-Collections' when changing the module to "umd" or "amd" in tsconfig.json - node.js

I am using VS17 Enterprise. I can easily import "typescript-collections" (as instructed on this page) if I had set my module option to commonjs in my tsconfig.json.
However, as soon as I change it to "umd" or "amd", I get error (see the screenshot please) saying that Cannot find module 'typescript-collections' and therefore, the two variables queue and queue1 will be of type any. I have also attached my tsconfig.json.
Any help will be greatly appreciated.

As of today this problem with this package remains and my solution was to use es6 as my module
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": [],
"module":"es6"
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}
and then import the classes using the notation below -
import * as Collections from 'typescript-collections/src/lib';
It seems there is an issue with this dependency packaging.

I fixed a similar problem by explicitly specifying the moduleResolution compiler option.
{
"compilerOptions":
{
"moduleResolution": "node"
}
}
Apparently the moduleResolution is set to "node" automatically, if module is set to "commonjs". The Typescript compiler seems to use another resolution strategy otherwise.
A post in a GitHub issue thread led me to this idea.

Related

NPM Package: Conflicts between ES libraries

I am currently trying to split a monorepo which includes the API and all the front-end stuff into different repo (at least have the API appart).
To achieve this, I had to first split the common and angular core libraries into two privates NPM packages. I manage to handle this easily for the angular core library using the CLI.
For the API (express 4.17.2/NodeJS 14.16/TypeScript 4.6), I'm not able to compile properly because of some ES conflicts. It's been two days I've been searching everywhere and the ES configuration seems to be very obscure because I don't find any related documentation.
I tried to follow this example to compile with pure ESM package without success. The first commend explain well the struggle.
Here is my problem:
I did a library named common-lib, it contains mainly services, interfaces and constants...
This library is exported from api/node_modules/#project/project-common-lib/dist/#project/project-common-lib/index.js
export * as constants from './constants/index.js';
export * as enums from './enums/index.js';
export * as interfaces from './interfaces/index.js';
export * as services from './services/index.js';
and installed into the api as an NPM package.
The package.json of the library contains this related information
"exports": "./dist/#project/project-common-lib/index.js",
"types": "./dist/#project/project-common-lib/index.d.ts",
"engines": {
"node": ">=14.16"
},
"type": "module",
And finally, this is my tsconfig.json:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"allowJs": true,
"removeComments": true,
"resolveJsonModule": true,
"typeRoots": [
"./node_modules/#types"
],
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": [
"esnext"
],
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "Node",
"skipLibCheck": true,
},
"include": [
"src/**/*"
],
"exclude": ["node_modules"],
}
Once I run npx ts-node-esm src/main.ts I get this error:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/project/project-api/node_modules/#project/project-common-lib/dist/#project/project-common-lib/index.js
require() of ES modules is not supported.
require() of /home/project/project-api/node_modules/#project/project-common-lib/dist/#project/project-common-lib/index.js from /home/project/project-api/dist/app/models/adminUser.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/project/project-api/node_modules/#project/project-common-lib/package.json.
I tried to remove the "type": "module" and to rename the index.js to .csj without any success.
I've come to a frustrating point where I can't make it work trying different configuration not documented so not really knowing what I'm doing.
For example I tried to change the ts compiler options to es5, es6... the "type" to "commonjs"... I have tried many things and I always end up with an error.
One way I get the above error, the other way removing the "type": "module" I get this error:
export * as constants from '#project/project-common-lib/dist/#project/project-common-lib/constants/index.js';
^^^^^^
SyntaxError: Unexpected token 'export'
Can someone clarify me how is it supposed to work ?
I don't use any es5 import const ... require (''). All the API use ES6 syntax with import ... from ...
How can it be so difficult to export/import some basic constants, services and interfaces ?

Typescript Establishing Absolute Imports Node

I built a project in node using TS, and I'm trying to implement absolute path for imports.
However, when I run the project it begins failing saying.
[1] Error: Cannot find module 'src/common/logger'
[1] Require stack:
[1] - C:\...xyz\Workspaces\PROJECT\dist\index.js
When I switch 'src/common/logger' to './common/logger' it proceeds to point to other ones that absolute path imports.
I figure its obviously something wrong with my TS config, but I can't seem to see where I am messing up.
Ultimately I want the imports to become 'common/xyz' and 'db/xyz'
My project directory follows this flow:
├───tsconfig.json
├───node_modules
├───dist // output location
└───src
|───common
|───db
└───index.ts
{
"compilerOptions": {
/* Language and Environment */
"target": "es2021",
/* Modules */
"module": "commonjs",
"rootDir": "./src",
"moduleResolution": "node",
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"],
"/*": [ "./src/*" ],
},
"outDir": "./dist"
}
}
My thought is that the issue is how I set up the tsconfig.
I tried looking through the documentation, but I clearly am not understanding the paths section. I've tried several changes to the paths, but still can't seem to get it work.
Any help would be greatly appreciated.
Leaving this bread trail for people who come across this issue.
TLDR; There is no way with tsconfig only to do it. You would need to use packages such as Webpack, Gulp, or other npm packages to help resolve the absolute imports.
My advice:
If you are working on just getting the project up and running, stick with relative imports for now. Then you can look into the 3rd party tools to implement the absolute pathing.

How to specify the distributable directory visible for both NPM and TypeScript? (Multiple files case)

The library written in TypeScript includes three main files for distribution:
NodeJS.js - for, obviously, Node.js runtime.
BroswerJS.js - for, obviously, browser runtime.
index.js - common functionality for both browser and Node.js
There no "main" file in this library so I has not specified this property in package.json.
Planning usage:
import { isUndefined, isNull } from "package-name;
import { delegateClickEventHandling } from "package-name/BrowserJS;
import { NodeJS_Timer } from "package-name/NodeJS;
Currently, the TypeScript with below config compiles files below Source directory to Distributable directory:
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"moduleResolution": "Node",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"removeComments": true,
"outDir": "Distributable/",
"declaration": true
},
"include": [ "Source/**/*" ]
}
If to publish the library such as, TypeScript even will not see it:
import { isUndefined } from "package-name";
TS2307: Cannot find module 'package-name' or its corresponding type declarations.
Because as default TypeScript expecting that .d.ts files will be in root directory of the library. But the distributables are in Distributable directory!
And of course, isUndefined will not be found. I know about "main" property in package.json, but it is for one file case, but what about directory?
I know that multiple distributable files exporting is the supported scenario. For example the mysql2 exporting promise.ts besides index.js:
import MySQL from "mysql2";
import MySQL_Promise from "mysql2/promise";
Update
The NPM part solved - modern solution is exports filed in package.json:
"exports": {
".": "./Distributable/index.js",
"./NodeJS": "./Distributable/NodeJS.js",
"./BrowserJS": "./Distributable/BrowserJS.js"
},
But distribution files are still invisible for TypeScript.
TS2307: Cannot find module 'package-name' or its corresponding type declarations.
I learned about "types" field of package.json. Unfortunately, it could be only a string. It means currently it's impossible to specify multiple files. The issue about making in to array has been declined.
But how to make visible all of "./Distributable/index.js", "./Distributable/NodeJS.js", "./Distributable/BrowserJS.js" for TypeScript?
Please don't suggest me again to make all imports to single entry point. In this question we considering the multiple entry points case.
I am not entirely sure what you are trying to achive, in TS generally when you have single project with 1 configuration file, and you emit multiple files from it, you would not use package name within the same project, use path instead './someFileName'.
If you have multiple projects (tsconfig files) to manage different directories - sort of monorepo thing going on.
Your best options is project references: https://www.typescriptlang.org/docs/handbook/project-references.html
Or if you are doing something else then this may help altho I'd do this as last resort :-)
https://www.typescriptlang.org/tsconfig#paths

How to use node --experimental-modules with Typescript output

Might be the stupidest question ever, but I have a Node project that is using ES modules with --experimental-modules and Node 12.
Now I'm adding an inner package to the monorepo that's written in Typescript that's consumed by the main node app. I'm struggling with my Typescript build settings that produce something that will work with --experimental-modules.
Currently tsconfig.json:
{
"include": [
"src/**/*ts"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
],
"compilerOptions": {
"module": "esnext",
"esModuleInterop": true,
"target": "esnext",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist"
},
"lib": ["es2015"]
}
If I have index.ts that imports from a neighbour ts file:
import { schema } from './schema'
The built import statements is without any .js and this makes my node app choke:
(node:78972) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/esm/default_resolve.js:79
let url = moduleWrapResolve(specifier, parentURL);
^
Error: Cannot find module /Users/viktor/dev/projects/kb-frontend/packages/graph/dist/schema imported from /Users/viktor/dev/projects/kb-frontend/packages/graph/dist/index.js
The reason is that the import is without .js - patching that in my dist directory of the ts build it works.
I cannot simply change my ts module to commonjs since this will also change the way my main exports are working with my esm based main giving me other errors:
import { server as graphMiddleware } from '#kb-front/graph'
^^^^^^
SyntaxError: The requested module '#kb-front/graph' does not provide an export named 'server'
I would not want to add a lot of .default here and there since the entire setup I have is to avoid commonjs alltogether and just use js and typescript with esm. Hey, I want the new shiny stuff.
What am I missing?
Two issues on using native module support in browser with Typescript:
https://github.com/microsoft/TypeScript/issues/13422
https://github.com/microsoft/TypeScript/issues/16577
From them I got the hack to just import with .js extension. Super weird, but works for my case.

Publish Typescript classes as npm package

I have written a set of Typescript classes that I am publishing as an NPM module to our internal package server. My other projects are able to retrieve this dependency using NPM.
I'd like to publish the classes in such a way that I can import them by referencing the package itself, similar to some other packages that I am using like Angular.
import { SomeClass } from 'mylibrary'
This is my current setup:
I've written a ./mylibrary.d.ts file:
export * from './dist/foldera/folderb'
//etc
./package.json:
"name": "mylibrary",
"main": "mylibrary.d.ts",
"files": [
"mylibrary.d.ts",
"dist/"
],
"types": "mylibrary.d.ts",
//ommitted other settings
src/tsconfig.json:
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "../dist/",
"baseUrl": "src",
"sourceMap": true,
"declaration": true,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/#types"
],
"lib": [
"es2016",
"dom"
]
}
}
When I try to import the package using the desired syntax, MS VS Code says everything is ok, but running my project results in a rather cryptic error message:
Module build failed: Error: Debug Failure. False expression: Output generation failed
I'm feeling lost in the jargon of modules, namespaces and packages. Any help is greatly appreciated.
If you place an index.ts file in the root folder of your package (same level as package.json), so that it re-exports all the functionality from your src/ folder, than you can publish it without building to js, keeping in mind that it will only be used in TS projects.
The negative side of this approach is that, your package will be compiled with your project every time, and possible changes in TS environment may lead to inability to compile the whole project (I have problems compiling one of my packages on versions < 2.4.2, for example).
// index.ts
export { Class1 } from 'src/Class1'
export { Class2 } from 'src/Class2'

Resources