I have a bit perplexing case about default exports currently.
node --version -> v16.1.0, rollup -> 2.50.4, via #open-wc/building-rollup ^1.10.0 and update separately.
In bn.js there seem to be UMD export as far I understand as
if (typeof module === 'object') {
module.exports = BN;
} else {
exports.BN = BN;
}
BN.BN = BN;
BN.wordSize = 26;
then it is imported in other file BigNumber.ts as
import _BN from "bn.js";
import BN = _BN.BN;
However, in my build I receiver error
[!] Error: 'default' is not exported by node_modules\bn.js\lib\bn.js, imported by node_modules#ethersproject\bignumber\lib.esm\bignumber.js
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
node_modules#ethersproject\bignumber\lib.esm\bignumber.js (11:7)
9: import _BN from "bn.js";
10: var BN = _BN.BN;
11: import { hexlify, isBytes, isHexString } from "#ethersproject/bytes";
^
12: import { Logger } from "#ethersproject/logger";
13: import { version } from "./_version";
Error: 'default' is not exported by node_modules\bn.js\lib\bn.js, imported by node_modules#ethersproject\bignumber\lib.esm\bignumber.js
All right! I read from https://nodejs.org/api/esm.html and https://github.com/evanw/esbuild/issues/532 and https://github.com/rollup/rollup/issues/3514#issuecomment-640020081 (+ https://github.com/webpack/webpack/issues/11014#issuecomment-641550630 and https://sokra.github.io/interop-test/#rollup), for a good measure for lengthy, discussion about the issue (and other less authoritative places) and then I think I could perhaps just patch manually bn.js and its package.json in node_modules.
So off I go, copy-paste bn.js to bn.esm.js and alter its export to
export default { BN }
and add
"module": "lib/bn.esm.js"
And indeed, it succeeds! Now there is however other includes with a similar issue.
This is puzzling, since in rollups.config.js I have
plugins: [
resolve({ browser: true, preferBuiltins: true }),
commonjs()
]
which I thought does something similar already. Am I mistaken? Could something like tsconfig.json settings interfere with the process? If it matters, the project/configuration that produces this is at https://github.com/veikkoeeva/erc1155sample/blob/main/web/rollup.config.js#L25.
Related
I came across an issue and found out its because Babel does not polyfill .at as default
According to spec , Array.prototype.at is merely stage 4, and I already set browserslist to > 0.2%, which includes Chrome 86(not supported .at yet)
Why on the earth Babel doest not polyfill .at ?
Babel Playground
Hey guys I believe I've fond the reason;
TLDR, the CRA is setting the wrong core-js version config for babel
I'm using create-react-app to build my web app, where I fond polyfill not work properly after installing core-js and import in entry file, according to officail doc;
And the key reason is in babel-preset-react-app, the babel config which CRA pre-configured and not easily modifiyed by users, have set 3 for cors-js version;
code is here
Whereas, the Babel doc has strongly recommanded to use minor verision , Or :
It is recommended to specify the minor version otherwise "3" will be interpreted as "3.0" which may not include polyfills for the latest features.
And in conculsion, no matter what version of corejs we installed, it always use polyfill rule with 3.0 version , which would make mistake for some feature polyfills, like Array.prototype.at ;
And there is some method to resolve this problem
if u are using pure CRA, u have to do this to import all core-js into your bundle result;
import R from "core-js/stable";
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
// eslint-disable-next-line no-unused-expressions
R;
if u work with anything like react-app-rewired or craco, u can achieve this by a more elegant way by correcting the babel-preset-react-app code in your node_modules:
//resolve-core-js.js
const path = require("path");
const fs = require("fs");
const setBabelPresetConfig = (version = "3.24") => {
console.info(
`[cra-core-js-resolve] try set core-js to ${version} in babel-preset-react-app`
);
try {
const babelRuntimeEntry = require.resolve("babel-preset-react-app");
const babelPresetCreateAppCreate = path.resolve(
babelRuntimeEntry,
"../create.js"
);
const content = fs.readFileSync(babelPresetCreateAppCreate, {
encoding: "utf-8",
});
const template = "corejs: 3,";
if (!content.includes(template)) {
console.info("[cra-core-js-resolve] template not fond, do nothing");
return;
}
const replacedContent = content.replace(
"corejs: 3,",
`corejs: ${version},`
);
fs.writeFileSync(babelPresetCreateAppCreate, replacedContent);
if (require.cache["babel-preset-react-app"]) {
delete require.cache["babel-preset-react-app"];
}
console.info(`[cra-core-js-resolve] set core-js to ${version} .done`);
} catch (e) {
if (e.code === "MODULE_NOT_FOUND") {
console.info(
"[cra-core-js-resolve] babel-preset-react-app not fond, do nothing"
);
return;
}
console.error(
"[cra-core-js-resolve] error happened when set babel-preset-react-app "
);
console.error(e);
}
};
module.exports = setBabelPresetConfig;
//craco.config.js
const resolveCoreJs = require('/path/to/resolve-core-js.js')
resolveCoreJs()
module.exports={
//...
}
I'm trying to set up an angular project to work with jest. So far it works with the following config
// jest.config.js
module.exports = {
// other stuff
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/setup-jest.ts"],
globalSetup: "jest-preset-angular/global-setup",
globals: {
"ts-jest": {
tsconfig: "<rootDir>/tsconfig.spec.json",
stringifyContentPathRegex: "\\.html$",
useESM: true,
},
},
};
And the following in my setup-jest.ts
import 'jest-preset-angular/setup-jest';
import './jest-global-mocks';
Problem is that as soon as I introduce any code that brings in an ES module, it blows up (even though I've tried following the ESM support page on the jest-preset-angular docs). So far, I've just dealt with this by finding alternative packages. But when I try to turn on --coverage, I get this.
import { __decorate } from "tslib";
^^^^^^
SyntaxError: Cannot use import statement outside a module
1 | import { TestBed } from '#angular/core/testing';
> 2 | import { AppModule } from './app.module';
| ^
3 | import { APP_BASE_HREF } from '#angular/common';
4 |
5 | describe('The app module', () => {
I've tried dissecting jest-preset-angular and extracting the settings that seem like they should apply to projects using ES6, which has led me to making these changes:
// jest.config.js
module.exports = {
// other stuff
setupFilesAfterEnv: ["<rootDir>/setup-jest.ts"],
transformIgnorePatterns: ["/node_modules/(?!tslib)"],
transform: {
"^.+\\.(ts|html|svg)$": "jest-preset-angular",
},
extensionsToTreatAsEsm: [".ts"],
globals: {
"ts-jest": {
tsconfig: "<rootDir>/tsconfig.spec.json",
stringifyContentPathRegex: "\\.html$",
useESM: true,
},
},
};
And now its failing on the core angular mjs files
/Users/benwainwright1/repos/ng-budget/node_modules/#testing-library/angular/fesm2020/testing-library-angular.mjs:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as i0 from '#angular/core';
^^^^^^
SyntaxError: Cannot use import statement outside a module
This is even more confusing for me because as far as I can see
the transform key doesn't specify .mjs, so .mjs files should be left alone
I'm using node v16 and jest v28, which should automatically treat .mjs files as modules
I'm using Node v17.4 and want to consume the webcrypto API. Based on this example I'm trying to import subtle into my project but TypeScript comes up with the error
Property 'subtle' does not exist on type 'typeof webcrypto'.
The only thing the namespace webcrypto offers is this.
import crypto from 'crypto';
const { subtle } = crypto.webcrypto; // subtle doesn't exist
How do I get access to subtle ?
As you noted, #types/node includes only a stub for the webcrypto interface. One workaround is to extend the crypto module declaration to declare webcrypto.subtle as SubtleCrypto from the DOM type definitions:
// src/types/index.d.ts
declare module "crypto" {
namespace webcrypto {
const subtle: SubtleCrypto;
}
}
This allows writing a module like:
// src/digest.ts:
import * as crypto from "crypto";
// subtle has type SubtleCrypto, from the DOM type definitions
const { subtle } = crypto.webcrypto;
// Generate a cryptographic digest of the given message
export async function digest(message?: string, algorithm = "SHA-512") {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hash = await subtle.digest(algorithm, data);
return hash;
}
To use SubtleCrypto, the project must enable the DOM type definitions by adding dom to the lib array in tsconfig.json. For example, with the following packages installed:
$ npm install -D typescript#4.6 #types/node#17 #tsconfig/node17
and a tsconfig.json containing:
{
"extends": "#tsconfig/node17/tsconfig.json",
"compilerOptions": {
"lib": ["dom"],
"outDir": "dist",
"typeRoots": ["./node_modules/#types", "./src/types"]
},
"include": ["src/**/*"],
"exclude": ["dist", "node_modules"]
}
you can write an entrypoint that calls digest and prints the result:
// src/index.ts
import { digest } from "./digest";
const message = "Hello, World!";
(async () => {
const digestBuffer = await digest(message);
console.log(Buffer.from(new Uint8Array(digestBuffer)).toString("hex"));
})();
This builds and runs, like:
$ npx tsc && node dist/index.js
374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6cc69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387
How can i use pm2 in combination with a package based on ES Module (type:"module")
I looked into similar Questions without any useful help (some say it does not work on windows, but i am using linux)
I always receive the error:
Error [ERR_REQUIRE_ESM]: require() of ES Module /opt/app/server/lib/src/index.js not supported.
0|any| Instead change the require of index.js in null to a dynamic import() which is available in all CommonJS modules.
My ecosystem.config.js looks like:
const os = require('os');
module.exports = {
apps: [{
port : 3000,
name : "any",
script : "lib/src/index.js",
watch : true,
instances : os.cpus().length,
exec_mode : 'fork',
env: {
NODE_ENV: "production",
}
}]
}
index.js is a ES module using "import" syntax. How can i tell pm2 that is should use this way of importing
To achieve this you can create an intermediary CommonJS module which loads your application from ESModule. It's possible with import function available in commonJs modules.
This is how might this look:
ecosystem.config.js
lib/src/index.cjs CommonJS entry point (for PM2).
lib/src/index.js ESModule entry point (for ESM-compatible tools).
lib/src/app.js Application code.
ecosystem.config.js:
const os = require('os');
module.exports = {
apps: [{
port : 3000,
name : "any",
script : "lib/src/index.cjs", // 👈 CommonJS
watch : true,
instances : os.cpus().length,
exec_mode : 'fork',
env: {
NODE_ENV: "production",
}
}]
}
lib/src/index.js:
import {app} from './app.js'
app()
lib/src/index.cjs:
import('./app.js') // 👈 There is import function available in CommonJS
.then(({app}) => {
app()
})
lib/src/app.js:
import {hello} from './greet.js'
export function app() {
console.log(hello('World'))
}
lib/src/greet.js:
export function hello(name) {
return `Hello, ${name}!`
}
renaming ecosystem.config.js to ecosystem.config.cjs worked for me
I'm developing an Electron application in TypeScript, and I've run into a frustrating issue.
I'm attempting to run a module from a renderer process with the following code:
import { remote } from 'electron'
const myModule = remote.require('./my-module')
The only way I can use remote.require with my module, is by adding module.exports = myModule to the my-module.ts file.
// my-module.ts
export class myModule { ... }
module.exports = myModule
After adding the module.exports = myModule line, it causes errors where ever I import myModule with a standard TypeScript import.
For example
// main.ts
import { myModule } from './my-module'
// Error here
To fix this error, I can simply replace the import statement with
const myModule = require('./my-module')
But when I replace the import statement to the one above, my TypeScript does not recognise myModule and all it's members. The intelisense shows nothing for myModule and TypeScript throws a bunch of errors even though the program runs just fine.
Some things to note:
The contents of my tsconfig.json are:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"alwaysStrict": true,
},
"exclude": [
"node_modules"
]
}
In the compiled JavaScript code, it results in something like the following when used with a TypeScript import statement:
var my_module_1 = require("./my-module");
my_module_1.myModule.foo('bar');
Which gives me an error of TypeError: Cannot read property 'sayHi' of undefined.
The JavaScript should look like this instead for it to work:
var my_module_1 = require("./my-module");
my_module_1.foo('bar');
How can I use remote.require() with TypeScript?
When you implement your code in ESM and import it in commonjs (that's what remote.require() does), you will get the module namespace object:
// myModule.ts
export function foo() { ... }
// and to access the default export:
export default const boo = 'boo'
// consumer.js
const myModule = require('./myModule')
myModule = { foo() { ... }, default: 'boo' }
Therefore, your to use your myModule class, you need to do this:
const myModule = remote.require('./myModule')
const obj = new myModule.myModule()
const boo = myModule.default
UPDATE: remote.require() is a dynamic call, so TypeScript can't detect the type of the myModule and set it to any.
You can do the following to get the type back:
import * as MyModule from './myModule'
const myModule: typeof MyModule = remote.require('./myModule')