babel - es2015 and es2017 preset not working together - javascript

I have two js files : play.js and myStore.js.
I want to import code from myStore.js into play.js and use it there. I'm using es2015 plugin for the import, But it makes my es2017 friendly code fail, even though I have es2017 setup.
play.js:
import G from '../functions/myStore.js'; // import needs es2015
// this works with es2017, but not when es2015 is also included
for(k in [1,2,3]) console.log(k)
myStore.js
var G = {}
export default G
Output: If I did not import anything, and just used the es2017 preset, this would run fine, but using es2015 along with es2017 makes this fail as below:
for (k in [1, 2, 3]) {
^
ReferenceError: k is not defined
I'm executing this from terminal via npm start . Here's my package.json:
{
"name": "functions",
"version": "1.0.0",
"description": "",
"main": "play.js",
"scripts": {
"start": "babel-node play.js"
},
"author": "Somjit",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.24.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-es2015-node5": "^1.2.0",
"babel-preset-es2017": "^6.22.0"
}
}
and my babel.rc:
{ "presets": ["es2015", "es2017"] }

Ok. My short answer would be...
1) Babel reads your code and if it sees some new js feature it translate it to regular js by using presets. For example, if it sees let a = 1 Babel uses preset-es2015 (that knows what let is) and translate this line into var a = 1 so your browser could understand this line.
2) If you look to the docs of babel-preset-es2017 you'll see that it supports only two features. You have not this features in your code. So babel don't use this preset while reading code that you've provided. So es2017 don't matter in your problem.
3) If you run your code without es2015 it allows you to declare variables without var (because you can do this in js without strict mode). But when you use this preset Babel reads your code and trows an Error because according to new js standarts you need to declare variables with var, let or const and can't just write a = 1;

when I started with babel even small stuff where taking too much time to understand.
then I found this tutorial which helped me a lot.

In Your case, absolutely your problem is not babel-preset-es2017. you must install babel-plugin-transform-runtime and put it in your .babelrc file as plugin.
installing:
npm install --save-dev babel-plugin-transform-runtime
setting .babelrc file:
{
"presets": [
"es2015",
"es2017"
],
"plugins": [
"transform-runtime"
]
}

Related

how can I use top level "await" in typescript next.js

When I use "await" on top-level like this:
const LuckyDrawInstance=await new web3.eth.Contract(abi)
I got a warning on the terminal: "set experiments.topLevelAwait true". When I tried to add this to "tsconfig.json", it still does not work. it says "experiments" property does not exist.
I could wrap it inside an async function but I want to set it without a wrapped function.
It is nothing to do with the tsconfig.json. You have to set it inside next.config.js. New version of next.js uses webpack5 and webpack5 supports top level await.
module.exports = {
webpack: (config) => {
// this will override the experiments
config.experiments = { ...config.experiments, topLevelAwait: true };
// this will just update topLevelAwait property of config.experiments
// config.experiments.topLevelAwait = true
return config;
},
};
NOTE
You have to use it outside the functional component:
export default function Navbar() {
// this will throw error
// Syntax error: Unexpected reserved word 'await'.
const provider=await customFunction()
return (
<section>
</section>
);
}
Warning
Since it is experimental, it might be broken in some versions
The latest solution as of writing this post that worked for me is using Babel instead of SWC since Next.js does not allow custom SWC configuration, therefore, you cannot allow topLevelAwait through .swcrc file.
Add Babel plugin called #babel/plugin-syntax-top-level-await into your package.json.
eg.
{
"devDependencies": {
"#babel/plugin-syntax-top-level-await": "^7.14.5"
}
}
Create .babelrc file in the root directory of your project where package.json lives.
Inside .babelrc make sure to include next/babel preset and the topLevelAwait plugin.
eg.
{
"presets": ["next/babel"],
"plugins": [
"#babel/plugin-syntax-top-level-await"
]
}
This is the easiest solution until Next.js team allows us to include SWC configuration. Note that by doing this you will not have SWC performance benefit since it will be disabled in favor of Babel.
I have been struggling with this for 2-3 days. Here is a solution that works. Please follow the following steps.
1. Copy paste the following in your package.json
{
"name": "projectname",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha",
"dev": "next dev"
},
"author": "",
"license": "ISC",
"dependencies": {
"#truffle/hdwallet-provider": "^2.0.1",
"fs-extra": "^10.0.0",
"ganache-cli": "^6.12.2",
"mocha": "^9.1.4",
"next": "^12.0.8",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"solc": "^0.8.9",
"web3": "^1.7.0",
"#babel/plugin-syntax-top-level-await": "^7.14.5"
},
"devDependencies": {
"#babel/plugin-syntax-top-level-await": "^7.14.5"
}
}
2. Delete your node_modules folder
3. Goto your project's root directory and reinstall all the packages using npm install command
4. Create a new file in your project's root directory and call it "next.config.js"
5. Copy paste following code in next.config.js file and save.
module.exports = {
// target: 'experimental-serverless-trace',
webpack: (config) => {
config.experiments = config.experiments || {};
config.experiments.topLevelAwait = true;
return config;
},
};

Jest testing with ES6 Modules (without babel) [duplicate]

Is it possible to test ES6 Modules with Jest without esm or babel? Since node v13 supports es6 natively have tried:
//package.json
{
…
"type": "module"
…
}
//__tests__/a.js
import Foo from '../src/Foo.js';
$ npx jest
Jest encountered an unexpected token
…
Details:
/home/node/xxx/__tests__/a.js:1
import Foo from '../src/Foo.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
When babel is added a transpiler, it works, but can es6 modules be used natively as well?
Yes, it is possible from jest#25.4.0. From this version, there is a native support of esm, so you will not have to transpile your code with babel anymore.
It is not documented yet, but according to this issue you have to do 3 easy steps to achieve that (At the time of writing this answer):
Make sure you don't transform away import statements by setting transform: {} in your jest config file
Run node#^12.16.0 || >=13.2.0 with --experimental-vm-modules flag
Run your test with jest-environment-node or jest-environment-jsdom-sixteen.
So your jest config file should contain at least this:
export default {
testEnvironment: 'jest-environment-node',
transform: {}
...
};
And to set --experimental-vm-modules flag, you will have to run Jest from package.json as follows (I hope this will change in the future):
"scripts": {
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
}
I hope, this answer was helpful to you.
Note that this is is still experimental, but we have documented how to test this, so there's hopefully less confusion.
https://jestjs.io/docs/en/ecmascript-modules
The steps in https://stackoverflow.com/a/61653104/1850276 are correct
I followed the tips provided in the accepted answer, but I added the property "type": "module" in my package.json in order to jest works properly. This is what I done:
In package.json:
"devDependencies": {
"jest": "^26.1.0",
"jest-environment-jsdom-sixteen": "^1.0.3",
"jest-environment-node": "^26.1.0"
},
"scripts": {
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
},
"type": "module",
"jest": {
"transform": {},
"testEnvironment": "jest-environment-jsdom-sixteen"
}
To run jest from "jest" extension in VSCode with "--experimental-vm-modules" flags, put this config in your global or workspaces settings.json:
"jest.nodeEnv": {
"NODE_OPTIONS": "--experimental-vm-modules"
}
In addition to #Radovan Kuka's answer, here's how to run Jest with ES modules, using npx:
"test:monitoring": "npx --node-arg=--experimental-vm-modules jest -f monitoring.test.js --detectOpenHandles",
The benefit is that one doesn't need to provide the absolute node_modules path.
Without Babel, here's a complete, minimal example that works on recent Jest versions. Run with npm test.
$ tree -I node_modules
.
├── package.json
├── src
│   └── foo.js
└── __tests__
└── foo.spec.js
package.json:
{
"type": "module",
"scripts": {
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
},
"devDependencies": {
"jest": "^29.3.1"
}
}
src/foo.js:
export const bar = () => 42;
__tests__/foo.spec.js:
import {bar} from "../src/foo";
describe("foo.bar()", () => {
it("should return 42", () => {
expect(bar()).toBe(42);
});
});
The secret sauce is in the package.json: "type": "module" and NODE_OPTIONS=--experimental-vm-modules jest.
If you want to add a mock, it's a bit complicated. See this answer.

VS Code: debugging of javascript. Different behaviour between Node.js versions

I try to learn how to use the debugger in VS Code for my Node.js application. I've found quite a few posts here and there about this, but I can't manage to have things work smoothly.
The end goal is to have a Typescript project with Babel 7 handling the compilation. And I want it to run on the latest version of Node.js (11.0.0).
I had average results so far, but I found a very good article on Medium which presents exactly what I want to do, except that it doesn't have typescript and it runs on Babel 6. But I figure that it is a great starting point to learn, so I try to reproduce it ... and I find that it doesn't behave the same way depending on the version of Node.js that I am running.
Here is what I do...
Running Node.js 8.12.0 and VS Code 1.28, I create a new project folder and I run the commands npm init -y and npm install --save-dev babel-cli babel-preset-es2015.
I update my package.json as follows:
// package.json
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1"
},
"babel": {
"presets": [
"es2015"
]
}
I then create 2 javascript files containing my code:
// src/app.js
import {add, multiply} from './math';
const num1 = 5, num2 = 10; // breakpoint on this line
console.log('Add: ', add(num1, num2));
console.log('Multiply: ', multiply(num1, num2));
// src/math.js
export function add(num1, num2) {
return num1 + num2; // breakpoint on this line
}
export function multiply(num1, num2) {
return num1 * num2; // breakpoint on this line
}
I update the package.json file with the following script
// package.json
"scripts": {
"compile": "babel src --out-dir .compiled --source-maps --watch"
},
When I run npm run compile, 4 files are created in the ./.compile/ folder, 2 of which are .map files.
Until now, everything goes fine. I then proceed with configuring the debugger in VS Code.
I create a .vscode/launch.json file and I edit it as follows:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch App.js",
"program": "${workspaceRoot}/src/app.js",
"outFiles": [
"${workspaceRoot}/.compiled/**/*.js"
]
}
]
}
After placing 3 breakpoints (see my comments in the code above) in my code, I run the debugger which stops on all 3 breakpoints.
Happy with my results, I update Node.js to v9.11.2. I run the debugger again, and it performs the same. Good.
Then, I update Node.js v10.13.0. Without modifying anything in VS Code or in my code, I run the debugger again. This time, only the breakpoint in src/app.js is considered. The 2 breakpoints in src/math.js are ignored. Why?
When updating Node.js to v11.0.0, I make the same observation.
I figure that something has changed in the way Node.js performs the debugging when they updated from v9.x.x to v10.x.x, but I can't find what.
I believe that I just need to configure launch.json a bit differently, and I have tried many things without success. My current launch.json is the following:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch App.js",
"program": "${workspaceFolder}/src/app.js",
"outFiles": [
"${workspaceFolder}/.compiled/**/*.js"
],
"sourceMaps": true,
"protocol": "inspector"
}
]
}
Any idea why it doesn't work with Node v10.x and above, and how I can fix this?
Many thanks!

How do you use Istanbul Code Coverage with transpiled Typescript?

I've been reading articles on this all morning trying to get my environment setup correctly. But for some reason I'm not getting it. My setup-
/app
... source (mixed js and ts)
/scripts
... copied source (js)
typescripts.js // transpiled typescript with inline mapping
Tests run fine, and with the mapping debugging in the chrome debugger is mapped correctly. But Istanbul sees the typescripts.js file as one file instead of the concatenation of dozens of other files.
To generate the typescript source I'm using gulp-typescript. The source (excluding tests) are transpiled to the aforementioned typescripts.js, and the tests are transpiled individually and copied to /scripts.
var ts = require('gulp-typescript');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
module.exports = function (gulp, config) {
'use strict';
// Runs dot ts files found in `www` through the typescript compiler and copies them as js
// files to the scripts directory
gulp.task('typescript', ['typescript:tests'], function () {
return gulp.src(config.paths.typescript) // [ './www/app/**/*.ts', '!./www/app/**/*.test.ts', '!./www/app/**/*.mock.ts' ]
.pipe(sourcemaps.init())
.pipe(ts(ts.createProject(config.paths.tsConfig))) // './tsconfig.json'
.js
.pipe(concat(config.sourcemaps.dest)) // typescripts.js
.pipe(sourcemaps.write(config.sourcemaps)) // { includeContent: false, sourceRoot: '/app' } - i've also tried absolute local path
.pipe(gulp.dest(config.paths.tmpScripts)); // ./www/scripts
});
gulp.task('typescript:tests', [], function() {
return gulp.src(config.paths.typescriptTests) // [ './www/app/**/*.test.ts', './www/app/**/*.mock.ts' ]
.pipe(ts(ts.createProject(config.paths.tsConfig))) // './tsconfig.json'
.pipe(gulp.dest(config.paths.tmpScripts)); // ./www/scripts
});
};
The resulting typescripts.js has the inline sourcemap. With the sourcemap, the dozen or so ts files results in 106kb.
So from here tests and debugging works fine.
Now in an attempt to get Istanbul code coverage working properly i've installed karma-sourcemap-loader and added it to the preprocessors.
preprocessors: {
'www/scripts/typescripts.js': ['sourcemap'],
'www/scripts/**/*.js': ['coverage']
},
I'd think this is what I'd need to do. But it does not show code coverage on the source files. I tried the absolute path from C:/ but that didn't work either. I also tried the different options in gulp-sourcemaps like adding source (which pushed the file to 160kb) but no like either.
Has anyone gotten this to work? Any ideas what I could be doing wrong?
TL;DR: There is a tool: https://github.com/SitePen/remap-istanbul described as A tool for remapping Istanbul coverage via Source Maps
The article on Sitepan describes it in more detail:
Intern as well as other JavaScript testing frameworks utilise Istanbul
for their code coverage analysis. As we started to adopt more and more
TypeScript for our own projects, we continued to struggle with getting
a clear picture of our code coverage as all the reports only included
the coverage of our emitted code. We had to try to use the compilers
in our minds to try to figure out where we were missing test coverage.
We also like to set metrics around our coverage to let us track if we
are headed the right direction.
A couple of us started exploring how we might be able to accomplish
mapping the coverage report back to its origins and after a bit of
work, we created remap-istanbul, a package that allows Istanbul
coverage information to be mapped back to its source when there are
Source Maps available. While we have been focused on TypeScript, it
can be used wherever the coverage is being produced on emitted code,
including the tools mentioned above!
How to use the tool with gulp: https://github.com/SitePen/remap-istanbul#gulp-plugin
If you want source map support with Istanbul, you can use the 1.0 alpha release as the current release does not support source maps. I have it set up using ts-node in http://github.com/typings/typings (see https://github.com/typings/typings/blob/bff1abad91dabec1cd8a744e0dd3f54b613830b5/package.json#L19) and source code is being mapped. It looks great and is nice to have my tests and code coverage all running in-process with zero transpilation. Of course, you can use Istanbul 1.0 with the transpiled JavaScript.
For the browser implementation you're using, I'd have to see more of code of what you're doing to see this'll just work for you, but try the 1.0.0-alpha.2 and see what happens.
As blakeembrey mentioned. Istanbul 1.x handles it well.
Below an example of pure npm script that does it with Jasmine.
See https://github.com/Izhaki/Typescript-Jasmine-Istanbul-Boilerplate.
package.json (the relevant stuff)
{
"scripts": {
"postinstall": "typings install dt~jasmine --save --global",
"test": "ts-node node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json",
"test:coverage": "ts-node node_modules/istanbul/lib/cli.js cover -e .ts -x \"*.d.ts\" -x \"*.spec.ts\" node_modules/jasmine/bin/jasmine.js -- JASMINE_CONFIG_PATH=jasmine.json"
},
"devDependencies": {
"istanbul": "^1.1.0-alpha.1",
"jasmine": "^2.4.1",
"ts-node": "^0.9.3",
"typescript": "^1.8.10",
"typings": "^1.3.1"
},
}
Output
This is repo works. I ran the repo and can see the tests running. Html view is also generated.
https://github.com/Izhaki/Typescript-Jasmine-Istanbul-Boilerplate
None of the examples provided worked for my Node.JS project (written in TypeScript). I wanted to run unit tests in Jasmine, and covered by Istanbul.
I ended up getting it working with the following.
package.json:
{
"scripts": {
"lint": "tslint 'src/**/*.ts'",
"remap": "./node_modules/.bin/remap-istanbul -i ./coverage/coverage-final.json -t html -o ./coverage && rimraf ./coverage/dist",
"test": "npm run lint && rimraf dist coverage && tsc --project tsconfig-test.json && ./node_modules/.bin/istanbul cover ./node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json && npm run remap"
},
"devDependencies": {
"#types/jasmine": "2.8.6",
"#types/node": "9.6.6",
"istanbul": "0.4.5",
"jasmine": "3.1.0",
"remap-istanbul": "0.11.1",
"rimraf": "2.6.2",
"tslint": "5.9.1",
"typescript": "2.8.1"
}
}
jasmine.json
{
"spec_dir": "dist",
"spec_files": [
"**/*.spec.js"
],
"stopSpecOnExpectationFailure": false,
"random": false
}
.istanbul.yml
instrumentation:
root: ./dist
excludes: ['**/*.spec.js', '**/fixtures/*.js']
include-all-sources: true
reporting:
reports:
- html
- json
- text-summary
dir: ./coverage
tsconfig-test.json
{
"compilerOptions": {
"declaration": true,
"lib": [
"dom",
"es6"
],
"module": "commonjs",
"noImplicitAny": true,
"outDir": "dist",
"sourceMap": true,
"target": "es5"
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}

How to remove global "use strict" added by babel

I'm using function form of "use strict" and don't want global form which Babel adds after transpilation. The problem is I'm using some libraries that aren't using "use strict" mode and it might throw error after scripts are concatenated
As it has already been mentioned for Babel 6, it's the transform-es2015-modules-commonjs preset which adds strict mode.
In case you want to use the whole es2015 preset without module transformations, put this in your .babelrc file:
{
"presets": [
["es2015", { "modules": false }]
]
}
This will disable modules and strict mode, while keeping all other es2015 transformations enabled.
Babel 5
You'd blacklist "useStrict". For instance here's an example in a Gruntfile:
babel: {
options: {
blacklist: ["useStrict"],
// ...
},
// ...
}
Babel 6
Since Babel 6 is fully opt-in for plugins now, instead of blacklisting useStrict, you just don't include the strict-mode plugin. If you're using a preset that includes it, I think you'll have to create your own that includes all the others, but not that one.
There's now a babel plugin that you can add to your config that will remove strict mode: babel-plugin-transform-remove-strict-mode. It's a little ugly in that the "use strict" gets added and then removed, but it makes the config much nicer.
Docs are in the GitHub repo:
https://github.com/genify/babel-plugin-transform-remove-strict-mode
Your .babelrc ends up looking like this:
{
"presets": ["env"],
"plugins": ["transform-remove-strict-mode"]
}
I also came accross this rather ridiculous limitation that you cannot disable or overwrite settings from an existing preset, and have resorted to using this preset instead: https://www.npmjs.com/package/babel-preset-es2015-without-strict
plugins: [
[
require("#babel/plugin-transform-modules-commonjs"),
{
strictMode: false
}
],
]
You can tell babel that your code is a script with:
sourceType: "script"
in your babel config file. This will not add use strict. See sourceType option docs
Source: https://github.com/babel/babel/issues/7910#issuecomment-388517631
Babel 6 + es2015
We can disabled babel-plugin-transform-es2015-modules-commonjs to require babel-plugin-transform-strict-mode.
So comment the following code in node_modules/babel-plugin-transform-es2015-modules-commonjs/lib/index.js at 151 line
//inherits: require("babel-plugin-transform-strict-mode"),
just change .babelrc solution
if you don't want to change any npm modules, you can use .babelrc ignore like this
{
"presets": ["es2015"],
"ignore": [
"./src/js/directive/datePicker.js"
]
}
ignore that file, it works for me!
the ignored file that can't use 'use strict' is old code, and do not need to use babel to transform it!
Personally, I use the gulp-iife plugin and I wrap IIFEs around all my files. I noticed that the babel plugin (using preset es2015) adds a global "use strict" as well. I run my post babel code through the iife stream plugin again so it nullifies what babel did.
gulp.task("build-js-source-dev", function () {
return gulp.src(jsSourceGlob)
.pipe(iife())
.pipe(plumber())
.pipe(babel({ presets: ["es2015"] }))// compile ES6 to ES5
.pipe(plumber.stop())
.pipe(iife()) // because babel preset "es2015" adds a global "use strict"; which we dont want
.pipe(concat(jsDistFile)) // concat to single file
.pipe(gulp.dest("public_dist"))
});
This is not grammatically correct, but will basically work for both Babel 5 and 6 without having to install a module that removes another module.
code.replace(/^"use strict";$/, '')
Since babel 6 you can install firstly babel-cli (if you want to use Babel from the CLI ) or babel-core (to use the Node API). This package does not include modules.
npm install --global babel-cli
# or
npm install --save-dev babel-core
Then install modules that you need. So do not install module for 'strict mode' in your case.
npm install --save-dev babel-plugin-transform-es2015-arrow-functions
And add installed modules in .babelrc file like this:
{
"plugins": ["transform-es2015-arrow-functions"]
}
See details here: https://babeljs.io/blog/2015/10/31/setting-up-babel-6
For babel 6 instead of monkey patching the preset and/or forking it and publishing it, you can also just wrap the original plugin and set the strict option to false.
Something along those lines should do the trick:
const es2015preset = require('babel-preset-es2015');
const commonjsPlugin = require('babel-plugin-transform-es2015-modules-commonjs');
es2015preset.plugins.forEach(function(plugin) {
if (plugin.length && plugin[0] === commonjsPlugin) {
plugin[1].strict = false;
}
});
module.exports = es2015preset;
Please use "es2015-without-strict" instead of "es2015". Don't forget you need to have package "babel-preset-es2015-without-strict" installed. I know it's not expected default behavior of Babel, please take into account the project is not mature yet.
I just made a script that runs in the Node and removes "use strict"; in the selected file.
file: script.js:
let fs = require('fs');
let file = 'custom/path/index.js';
let data = fs.readFileSync(file, 'utf8');
let regex = new RegExp('"use\\s+strict";');
if (data.match(regex)){
let data2 = data.replace(regex, '');
fs.writeFileSync(file, data2);
console.log('use strict mode removed ...');
}
else {
console.log('use strict mode is missing .');
}
node ./script.js
if you are using https://babeljs.io/repl (v7.8.6 as of this writing), you can remove "use strict"; by selecting Source Type -> Module.
Using plugins or disabling modules and strict mode as suggested in the #rcode's answer didn't work for me.
But, changing the target from es2015|es6 to es5 in tsconfig.json file as suggested by #andrefarzart in this GitHub answer fixed the issue.
// tsconfig.json file
{
// ...
"compilerOptions": {
// ...
"target": "es5", // instead of "es2015"
}

Categories