define is not defined, amd-loader vs CommonJs - node.js

I am working on first part of this answer
When I compile main.ts to js
require("amd-loader");
import someModule = require('../mymodule')
var someClass = new someModule.MyNamespace.MyClass();
it becomes:
define(["require", "exports", '../mymodule'], function (require, exports, someModule) {
require("amd-loader");
var someClass = new someModule.MyNamespace.MyClass();
});
then it gives me define is not defined error
When I modify it as below, error goes away.
require("amd-loader");
define(["require", "exports", '../mymodule'], function (require, exports, someModule) {
var someClass = new someModule.MyNamespace.MyClass();
});
Then I get Cannot read property 'MyClass' of undefined error
How can I get fix these error and get it work as expected as mentioned in that Q&A?
My environment is Visual Studio 2015 and I compile with AMD options as module system(obviously I tried each options). I am doing angular protractor e2e tests

As said by basarat at this answer, CommonJS should be used in this case.
In Visual Studio 2015 version 14.0.23.107.0, it seems TypeScript Module System options does not work, and it compiles always with whatever any one selected
So following this post CommonJS can be selected.
And voila it compile in with CommonJS and works as expected

Related

Force TypeScript to generate export/imports with the ".js" extension; running Node 16?

Have a TS 4.7 library using ESM modules.
tsconfig.json:
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020"],
"moduleResolution": "node",
package.json
"type": "module",
I have a main file with only a one silly export:
index.ts
export { Spig } from './spig';
which is compiled to:
index.js
export { Spig } from './spig';
//# sourceMappingURL=index.js.map
Problem
When I use this library from a Node CLI program (with ESM modules enabled as well), I get the following error:
Cannot find module <path>/lib/spig imported from <path>/lib/index.js
When I manually add .js in the generated index.js, the issue is gone:
export { Spig } from './spig.js';
How can I force TypeScript compiler to generate the extension, too? What am I missing here?
You cannot omit the file extension anymore in ESM module imports. The extension should be always .js/.jsx, not .ts/.tsx for a typescript file. So, in the index.ts you should add the extension to spig export like the following and every other file imported/exported if using ESM modules.:
index.ts
export { Spig } from './spig.js';
Also, moduleResolution should be set to Node16 or NodeNext so ESM modules work as expected.
As stated in the docs (enphasis by me):
Relative import paths need full extensions (e.g we have to write import "./foo.js" instead of import "./foo").
When a .ts file is compiled as an ES module, ECMAScript import/export syntax is left alone in the .js output; when it’s compiled as a CommonJS module, it will produce the same output you get today under module: commonjs.
This also means paths resolve differently between .ts files that are ES modules and ones that are CJS modules. For example, let’s say you have the following code today:
// ./foo.ts
export function helper() {
// ...
}
// ./bar.ts
import { helper } from "./foo"; // only works in CJS
helper();
This code works in CommonJS modules, but will fail in ES modules because relative import paths need to use extensions. As a result, it will have to be rewritten to use the extension of the output of foo.ts - so bar.ts will instead have to import from ./foo.js.
// ./bar.ts
import { helper } from "./foo.js"; // works in ESM & CJS
helper();
This might feel a bit cumbersome at first, but TypeScript tooling like auto-imports and path completion will typically just do this for you.

Cannot find module '.' or its corresponding type declarations

when I use cheerio in my project with typescript, and try to compile it by tsc.
The compiler throws an exception described below:
error TS2307: Cannot find module '.' or its corresponding type declarations.
2 import type { CheerioAPI, Cheerio } from '.';
Found 1 error in node_modules/cheerio/lib/esm/static.d.ts:2
This seems to be a bug in the package itself. How should I solve this problem? Thanks.
And I only use cheerio in my project like this:
import * as cheerio from "cheerio";
cheerio.load(content) // The type of content is string.
"cheerio": "^1.0.0-rc.12"
"#types/cheerio": "^0.22.31" node v16.16.0 npm v8.16.0
Lock your cheerio version to 1.0.0-rc.10, it worked for me, or, in your package.json file change the "type" to "commonjs".

Problem requiring native c++ addon from electron

Error when I require a Native Addon C++ from electron that works fin from Node.js
Recently I developed my first native C++ Addon for node that works fine with my node project (node version 10.15.0)
The Addon has been built using XCode, which project has been generating using CMake.
I´m having the following error when I use the same native C++ addon from my Electron app.
dyld: lazy symbol binding failed: Symbol not found: __ZN2v816FunctionTemplate3NewEPNS_7IsolateEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEENS_5LocalIS4_EENSA_INS_9SignatureEEEiNS_19ConstructorBehaviorENS_14SideEffectTypeE
Referenced from: /Users/vicentvidal/Documents/Desarrollo/DASNet2/dasaudio/build/DASNetAddon.node
Expected in: flat namespace
dyld: Symbol not found: __ZN2v816FunctionTemplate3NewEPNS_7IsolateEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEENS_5LocalIS4_EENSA_INS_9SignatureEEEiNS_19ConstructorBehaviorENS_14SideEffectTypeE
Referenced from: /Users/vicentvidal/Documents/Desarrollo/DASNet2/dasaudio/build/DASNetAddon.node
Expected in: flat namespace
As I can see the problem appears just when I call from my Electron App
const addon = require('bindings')('DASNetAddon');
which call the following C++ code
static NAN_MODULE_INIT(Init) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("StreamingWorker").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(2);
SetPrototypeMethod(tpl, "sendToAddon", sendToAddon);
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
Nan::Set(target, Nan::New("StreamingWorker").ToLocalChecked(),
Nan::GetFunction(tpl).ToLocalChecked());
}
My Electron version is 3.0.10
My Nan version 2.12.1
My bindings version 1.3.1
Does anybody has any suggestion?
I'm not positive that this is the problem but it is possible that, because the function template is missing your C++ class name, the namespace is coming from somewhere else. Here's one of my Nan Init() functions. The line following the // Prepare constructor template qualifies the New argument with a class namespace.
void Metadata::Init(v8::Local<v8::Object> exports) {
Nan::HandleScope scope;
// Prepare constructor template
v8::Local<v8::FunctionTemplate> ctor = Nan::New<v8::FunctionTemplate>(Metadata::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(2);
ctor->SetClassName(Nan::New("Metadata").ToLocalChecked());
// Prototype
Nan::SetPrototypeMethod(ctor, "copy", Metadata::copy);
Nan::Set(exports, Nan::New("Metadata").ToLocalChecked(), ctor->GetFunction());
}
I haven't tried running/loading in an Electron environment, nor on a Mac, so I can only say this works fine on Linux. But because your error message refers to "FunctionTemplate3New" it's a guess.

crypto.createHmac is undefined after rollup

I'm trying to rollup my library's code into a dist folder.
Right now I have a problem with the built in crypto library.
terminal output:
$ yarn run build
...
lib/helpers/security.js
createHmac is not exported by node_modules/rollup-plugin-node-builtins/src/es6/empty.js
...
Rollup config
...
plugins: [
builtins(),
resolve(),
json(),
babel({
exclude: ['node_modules/**','**/*.json']
})
]
...
Source code
A snippet from my source code:
// lib/helpers/security.js
import * as crypto from 'crypto'
crypto.createHmac('sha256',nonce).update(text).digest('base64');
Result
From the rolled-up, bundled js output:
undefined('sha256', nonce).update(text).digest('base64');
Crypto.js source code
For reference the relevant export statement in node/crypto.js on github shows that createHmac is being exported.
node/crypto.js L147
Update 1 ( Solution? )
It seems that removing the import line from security.js resolves the issue. I understand that crypto is a built in node module.
I want to understand why I should not import in this case while examples in the documentation do import the module.
So this is the solution I came up with which works fine for me.
Install rollup-plugin-node-builtins in your project as a dev dependency. And import it in your rollup.config.js:
import builtins from 'rollup-plugin-node-builtins'
Set crypto to false when using builtins(). It defaults to the commonjs version from browserify. That's not I wanted or needed.
// set crypto: false when using builtins()
...
builtins({crypto: false}),
...
Make sure to add crypto to your external option:
// add `crypto` to the `external` option
// you probably already have
// one or more libs defined in there
let external = ['crypto']
Now I can use crypto in my library without the previous problems when using my built files.
import { createHmac } from "crypto";
The result is a module, 4KB in size, which depends on several external dependencies, without having them included in the built files.
For context: my source code is written in ES6 and I am building three versions of my module: cjs, umd and es.
I would avoid to babel server-side files, it can be done, but I prefer not doing it.
So you will probably not have the errors if you use require() instead of import (import is not built-in in Node.js v8):
var crypto = require("crypto");

R.js compilation of non-AMD modules

I have non-AMD backbone, non-AMD underscore and non-AMD jquery in my project. I also have a lot of third party libraries that are not AMD compatible.
What is the best way of having them compile alongside AMD modules using r.js? Should I start wrapping all of them into AMD modules?
I ran r.js on a module I had which was using non-AMD libraries and underscore and backbone, it generated an output but in the output wherever there is a require("backbone") call, it returns undefined which I'm suspecting is because backbone is not registered as an AMD module.
At the same time something very strange to me is that if I do not run r.js and just run the website regularly using require.js loading, the following lines returns correct values even though they are not AMD modules:
var _ = require("underscore")
var Backbone = require("backbone")
I have those paths configured as aliases in my require.config.
Why do you think, that backbone, underscore or jquery are not AMD compatible? They do! Just a bit not out of box. You just need to add a bit more configuration to your main.js. For example like this:
require.config({
paths : {
jquery : 'jquery-2.0.3',
backbone: 'backbone',
underscore: 'underscore'
},
shim : {
underscore: {exports: '_'},
backbone: {deps: ['underscore'], exports: 'Backbone'}
}
});
require(['jquery', 'backbone'], function($, Backbone) {
console.log('Type of $: ' + typeof $);
console.log('Type of Backbone: ' + typeof Backbone);
});
There aren't very much libraries, which are fully not AMD compatible (i. e. can't be used via RequireJs). Every library, which exposes itself to global scope via some property may be used via RequireJs.
But if you would like to use CommonJs modules (which are exposed via module.exports), then the way I see, you have 2 options:
Wrap your CommonJs modules with this.
Use this construction:
define(function (require) {
var $ = require('jquery');
})
Both options work nice with RequireJs optimizer, as I tested.
Still, I would prefer use shim option in your main.js file.

Resources