"Could not dynamically require 'binding.node'" when trying to rollup speaker module - node.js

I'm trying to use rollup to bundle the speaker module.
Once it builds and I try to run it, I get the following error:
Error: Could not dynamically require "/path/to/Project/build/binding.node". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of #rollup/plugin-commonjs appropriately for this require call to work.
From the build:
const os = require$$0__default$3["default"];
const debug = src.exports('speaker');
const binding = bindings.exports('binding'); // Error occurs here
I've tried to add the path and version of it to dynamicRequireTargets with no luck. Thing is, there is no Project/build folder, so I'm not sure if it only exists during build time or if it's a fake path.
How can I get this to build and run correctly?
Minimal reproducible example
$ npm init
$ npm i --save speaker
src/index.ts
import * as Speaker from 'speaker';
console.log(Speaker);
rollup.config.ts
import * as fs from 'fs';
import path from 'path';
import executable from 'rollup-plugin-executable';
import commonjs from '#rollup/plugin-commonjs';
import json from '#rollup/plugin-json';
import { nodeResolve } from '#rollup/plugin-node-resolve';
import typescript from '#rollup/plugin-typescript';
const incrementalDependencyLoader = {
input: 'src/index.ts',
output: {
file:
'/dist/' +
require(path.join(process.cwd(), 'package.json')).name,
// cjs translates to CommonJs which is supported by Node
format: 'cjs',
banner: '#!/usr/bin/env node\n',
},
plugins: [
nodeResolve(),
typescript({
tsconfig: fs.existsSync(path.join(process.cwd(), './tsconfig.build.json'))
? './tsconfig.build.json'
: './tsconfig.json',
}),
json(),
commonjs({}),
executable(),
],
external: [],
};
// with using an array, we can create multiple bundled javascript files
export default [incrementalDependencyLoader];
tsconfig.json
{
"compilerOptions": {
"jsx": "preserve",
"module": "esnext",
"moduleResolution": "node",
"target": "esnext",
"lib": ["esnext"],
"baseUrl": ".",
"allowSyntheticDefaultImports": true
}
}

Related

Using TS absolute paths in import statement triggers an error in react-native

I am currently converting relative paths to absolute paths in my React-Native app and it triggers the following error:
Error response to absolute import
And I have set up my tsconfig.json as follows:
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"#buttons/*": ["src/components/buttons/*"]
},
"jsx": "react",
"resolveJsonModule": true
}
}
The following statement is how it looks in the file that I am importing it in:
import {CoreButton} from '#buttons/CoreButton';
Any ideas or suggestions would be amazing :)
The solution to this problem has been found at the following link:
React native Typescript path alias unable to resolve module

Jest Typescript with ES Module in node_modules error - Must use import to load ES Module:

I'm trying to write a simple jest test for a 3rd party package were using that only exports an ES module. It's a wrapper around an http server.
Here is a test repo I setup (just run yarn && yarn jest to reproduce): https://github.com/jamesopti/hocuspocus-testing
No matter what config I experiment with, I still get this error when trying to run it:
Must use import to load ES Module: /Users/j/hocuspocus-testing/node_modules/#hocuspocus/server/dist/hocuspocus-server.esm.js
> 1 | import { Server, Hocuspocus } from '#hocuspocus/server'
| ^
2 | import * as request from 'supertest'
3 |
4 | describe('Server (e2e)', () => {
Things I've tried already:
The Jest instructions on ES modules: https://jestjs.io/docs/ecmascript-modules
In Jest configuration using transformIgnorePatterns
transformIgnorePatterns: ['node_modules/(?!#hocuspocus/)']
Using Babel via babel-jest
modifying transform setup in Jest configuration as '^.+\.jsx?$': 'babel-jest', '^.+\.tsx?$': 'ts-jest'
Ran into the error You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously.
Using .babel.config.js instead of .babelrc.js
Any ideas what I'm missing here? I thought this would be straightforward
[EDIT 1] - Added tsconfig.json and a working src/index.ts file to the example repo.
So for anyone still hitting this, ESM configuration explained in this section of documentation :
https://kulshekhar.github.io/ts-jest/docs/guides/esm-support
{
// [...]
"jest": {
"extensionsToTreatAsEsm": [".ts"],
"globals": {
"ts-jest": {
"useESM": true
}
}
}
}
JAN 2023: ES2022, TypeScript 4.9.4, jest 29.3.1, ts-jest 29.0.3
This is what worked for me, after 2 hours of frustration.
I used this configuration in jest.config.ts:
import type { JestConfigWithTsJest } from 'ts-jest'
const config: JestConfigWithTsJest = {
extensionsToTreatAsEsm: ['.ts'],
verbose: true,
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
transform: {
'^.+\\.(ts|tsx)?$': ['ts-jest', { useESM: true }]
},
testPathIgnorePatterns: ['./dist']
}
export default config
Change the test script in package.json to:
I use pnpm. Change to npx jest with npm,
or yarn exec with yarn
...
"scripts": {
...
"test": "NODE_OPTIONS=--experimental-vm-modules pnpm exec jest",
...
}
...
tsconfig.json:
{
"compilerOptions": {
"rootDirs": ["src"],
"outDir": "dist",
"lib": ["ES2022"],
"target": "ES2022",
"module": "ES2022",
"composite": true,
"moduleResolution": "node",
"declaration": true,
"declarationMap": true,
"incremental": true,
"esModuleInterop": true,
"types": ["jest", "node", "#types/jest"],
"sourceMap": true
},
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node"
},
"include": ["./src/**/*", "./tests/**/*"]
}
See this (rather confusing) documentation for reference:
https://kulshekhar.github.io/ts-jest/docs/guides/esm-support/
You don't have a tsconfig.json file that specifies module. Therefore it uses the default, where it transpiles all your modules to CommonJS syntax, which uses require.
If you actually look at your dist/hocuspocus-server.esm.js, you should see it using require over the ESM import syntax.
I was having the same problem with my svelte app and testing. I ultimately traced it to having a jest.config.js and a jest.config.json in my root folder. It seems that jest does not have automatic config file resolution and was using a default configuration instead of either of my specified configurations.

Three.js with typescript autocomplete

I have a Node.js project that uses Typescript and Three.js. To import modules, I use the commonjs syntax, which I configured via
{
"compilerOptions": {
"module": "commonjs"
}
}
in my tsconfig.json. I downloaded Three.js via NPM have a typescript file like this:
const THREE = require('three');
const scene = new THREE.Scene();
which compiles fine, but I do not get any autocomplete. I don't think this specific to the editor used, as both Visual Studio Code as well as Neovim with YouCompleteMe don't work. Both work if I use the ES6 module syntax:
import * as THREE from 'node_modules/three/src/Three';
const scene = new THREE.Scene();
Here however I cannot get it to work without giving the actual path to the library (which is a problem later on when using webpack). What did I forget to configure to get autocomplete (or the ES6 syntax without explicitly defining the path, at this point I am fine with both solutions)?
EDIT
As mentioned in the comments to accepted answer, I was not able to find my mistake, but found a working solution while trying to create a minimal working project. So I will post this here, in case it might help someone else. If you have the same problem, please still read the answer, as it is correct.
My source file (in src/main.ts):
import * as THREE from 'three';
const scene = new THREE.Scene();
package.json (with webpack to test if the library can be resolved there):
{
"devDependencies": {
"#types/node": "^12.0.4",
"three": "^0.105.2",
"ts-loader": "^6.0.2",
"typescript": "^3.5.1",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2"
}
}
tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"paths": { "*": ["types/*"] },
"target": "es6",
"module": "es6",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"sourceMap": true
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules/"
]
}
webpack.config.js:
const path = require('path');
module.exports = {
entry: './src/main.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
resolve: {
extensions: [ '.ts', '.js' ]
},
module: {
rules : [
{ test: /\.ts$/, use: [ 'ts-loader' ], exclude: /node_modules/ }
]
}
};
What version of three is installed in your package.json file? Make sure it's 0.101 or later, since that's when TypeScript support began. I recommend you use the latest (105 as of this writing), since it gets updated definition files on each release.
Then, in your .ts files, you can import it with:
import * as THREE from "three";
// After importing, THREE is available for auto-complete.
var lala = new THREE.WebGLRenderer();
Edit:
You might need to perform path-mapping in your .tsconfig file to force the compiler to find the correct module address. I've never had to do this, but the Typescript documentation suggests something like this:
{
"compilerOptions": {
"baseUrl": ".", // This must be specified if "paths" is.
"paths": {
"three": ["node_modules/three/src/Three"] // relative to "baseUrl"
}
}
}
Update r126
As of revision r126, Three.js has moved Typescript declaration files to a separate repository. If you're using r126 or later, you'll have to run npm install #types/three as a second step. Make sure you install the version of #types/three that targets your version of Three.js. For example:
"three": "0.129.0",
"#types/three": "^0.129.1",

importing class in Node js with typescript

I would import class in nodejs and use it in app.ts
var nano = require("nano");
import { EnvConfig } from './envConfig.service';
let config = new EnvConfig();
const dbCredentials: any = config.appEnv.getServiceCreds('dataservices');
export const nanodb = nano({
url: dbCredentials.url,
});
export const nanodbCockpitLight = nanodb.use('data');
console.log(dbCredentials);
When I try to compile I get this error.
import { EnvConfig } from './envConfig.service';
^
SyntaxError: Unexpected token {
I have created the tsconfig file :
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": true,
"allowJs": true,
"outDir": "./dist",
//"baseUrl": "src" // Attention !! nécessite l'utilisation d'un loader de module node pour fonctionner sur node
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
I get this warning
No inputs were found in config file 'c:/Users/EHHD05911.COMMUN/Documents/cockpitLight/DB mananger/tsconfig.json'. Specified 'include' paths were '["src//"]' and 'exclude' paths were '["node_modules","/.spec.ts"]'
You cannot run node app.ts file directly that won't work
You need transpiler like babel js or typescript compiler tsc so first transpile to js file and then run node app.js
You're using .js extension, you need .ts extension, e.g.: app.ts instead of app.js.
Make sure you have typescript either in npm global or in dev dependencies.
I suspect whatever you're importing has typescript syntax (strong typing and such), and so running node directly won't work. You need to run tsc first, which will transpile everything to javascript in a dist folder, and then run node dist/app.js.
This is a bit cumbersome though, which is why there is ts-node. It's exactly what it sounds like, a node REPL for typescript. You should be able to run ts-node src/app.ts.
import { something } is a typescript syntax, it won't work in a .js file. That is a separate language. Try using require instead.
Use babel js which is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
package.json
"dependencies": {
"#babel/polyfill": "^7.0.0",
}
"babel": {
"presets": [
"#babel/preset-env"
]
},
"scripts": {
"start": "server.js --exec babel-node",
}
https://babeljs.io/docs
This will enable/resolve your import statements.

How to reference externally defined node modules with string identifiers with typescript

I'm writing a set of node helper modules in typescript. I'm having difficulty getting typescript to interpret type information for external node modules such as "fs" and "path".
Importantly, I want to separate my module into a bunch of Typescript files, with a class/interface per file. They file layout is like this:
ts/ISomeInterface1.ts
ts/ISomeInterface2.ts
ts/SomeClass1.ts
ts/SomeClass2.ts
A class instantiates one or more interfaces, and is written as follows:
///<reference path="IFileSystemHelpers.ts" />
var fs = require("fs");
namespace myNmspace {
export class SomeClass1 implements SomeInterface1 {
public someIFunction() {
//do work
}
}
}
I'm using gulp-typescript to install type declarations for NodeJs. And I use a tsconfig.json file to build and reference these external typings. Here's a snippet:
{
"version": "1.8.9",
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"preserveConstEnums": true,
"declaration": true,
"suppressImplicitAnyIndexErrors": true,
"out": "./outputfile.js"
},
"filesGlob": [
"./**/*.ts",
"!./node_modules/**/*.ts"
],
"files": [
"./typings/main.d.ts",
"./ts/ISomeInterface1.ts",
"./ts/ISomeInterface2.ts",
"./ts/SomeClass1.ts",
"./ts/SomeClass2.ts",
"./ts/exports.ts"
]
}
Then classes are exported in the exports.ts file:
declare var exports: any;
if (exports) {
exports.SomeClass1 = myNmspace.SomeClass1;
exports.SomeClass2 = myNmspace.SomeClass2;
}
Then comes my problem. How do I get type information for the "fs" module?
I can see the following in the node.d.ts file (see here)that typings has installed:
declare module "fs" {
import * as stream from "stream";
import * as events from "events";
...
}
How do I force Typescript to interpret my fs variable in the SomeClass1.ts file as strongly-typed? In other words, what do I write here:
var fs : ??? = require("fs");
Can anyone help?
As an aside, I've noticed that if I replace the var with an import keyword, I get correct type interpretation for the fs variable. However the terms which point to my interfaces break and I get a squiggly line under the implements ISomeInterface1. Changing the pattern to use imports breaks my file separation, and seems valid only if I want to create a single-file node module.
Use ES6 style imports
import * as fs from 'fs'
import * as path from 'path'
This will also import the definitions from the definition file.
The syntax var x = require('x') does not (however import x = require('x') does, to add to the confusion)

Resources