how do I use babel 6 (es7) plugins like the (es6) polyfill? - node.js

Problem
I have a reasonable amount of experience using Babel in my projects, but I've come across a situation which I am not sure about:
I have an es5 project, which has a dependency of an es7 node module (a deployment tool).
I want the es5 project to use the es7 module without "polluting" the es5 project with Babel infrastructure.
If my deployment tool module only used es6, I could include the es6 polyfill.
But as there is not es7 polyfill it looks like i should be using [plugins] (https://www.npmjs.com/package/babel-plugin-array-includes).
EDIT #1: As an analogy: If I was using coffeescript, I'd just transpile and save the output in my-coffee-module/dist/index.min.js. How could I do the same with Babel?
I'd perfer to not use the CLI, or another tool (like rollupjs - which is good, but it seems unnecessary).
Previous work
When I put a .babelrc in my module (or use the require hook):
require("babel-core").transform("code", {
presets: ['babel-preset-es2015'],
plugins: ["array-includes"]
});
and then use it from my es5 project I get:
ReferenceError: Unknown plugin "babel-array-includes" specified in "base" at 0
If I use the API (via gulp-babel) I get:
TypeError: undefined is not a function
at exports.default (/Users/me/deploy-tool/node_modules/babel-plugin-array-includes/lib/index.js:11:10)
which is a complaint about Plugin being undefined in the plugin :
/*
... babel-plugin-array-includes/lib/index.js: lines 11-13
*/
return new Plugin("array-includes", {
metadata: {
group: "builtin-post"
},
Any advice or opinion would be appreciated, thanks
EDIT #2: Partial solution: It seems it is not possible without using the Babel CLI at this time, which I will do with npm build scripts.
I'll leave this question open, pending my github issue.

Related

Node.js --experimental-vm-modules command line option vs "type": "module" in package.json

I'm currently rewriting a NodeJS project from a messy combination of CommonJS and Babel-transpiled ES Modules to be completely ES Module based.
In the process, I've become a bit confused by how Node handles these things. I've tried to read up on it, but I seem to be missing one final piece in my understanding.
I was assuming I would no longer need to use Babel to transpile the ES Modules. This seems to be correct. However, when I run my (Jest) tests, I still need to use the --experimental-vm-modules Node flag to make everything work.
My question is: what does that flag do? Reading the documentation, this seems to enable ES Modules, but didn't I already enable ES Modules by specifying "type": "module" in the package.json file?
Relevant links:
https://nodejs.org/api/esm.html#enabling
https://nodejs.org/api/cli.html#--experimental-vm-modules
https://jestjs.io/docs/ecmascript-modules
Specifying type: "module" in package.json just telling library authors your source code is based on ESM.
For jest, you need to use experimental-vm-modules because the node api jest uses to enable ESM support is still not stable as of node 18.x
https://jestjs.io/docs/ecmascript-modules

Using babel with preset-env on a small node project, unable to convert import/export statements to commonjs

I'm trying to set up a node project so I can use the common import/export syntax, and for compatibility, use babeljs to convert the import and export statements to requires.
When I try transpiling using babel though, I'm not seeing any changes and I don't know why.
Here's my babel.config.js
// babel.config.js
module.exports = {
// I thought this was what I would need to add for making the changes, based on the docs
plugins: ["#babel/plugin-transform-modules-commonjs"],
// env takes care of the majority of changes I might need to convert code to make
// easy to run on a wider range of machines
presets: [
[
"#babel/preset-env",
{
targets: {
// target an older version where I know there is no ESM support
node: "10"
}
}
]
],
// this was in the docs too - I'm not sure if I need it TBH
sourceType: "module"
}
I have a bunch of code using import/export, and async/await in a directory, that I wanted to transpile and put into another directory, lib.
Here's the command I am using:
npx babel src --out-dir lib
My package.json file online too, and there's nothing too esoteric there. I've tried to follow the documentation faithfully.
I would expect to see changes in the code to replace the import/export calls with requires in the lib, but no joy.
What am I doing wrong here? I worked on a related project 6-7 months ago, where I am using babel like this and it does make the changes for me.
You can see the branch with the problem code on github, with the package.json, and here's the source code for other project mentioned where it is working.
Please be gentle, fellow SO commenters - I'm trying my best, I really am.
It looks like you're using "babel-cli": "^6.26.0" instead of "#babel/cli": "^7.11.6" that should fix it.

How does mocha / babel transpile my test code on the fly?

My question is not about why something is not working, but rather why it is. Yes.
I have a small nodeJS command line tool, which contains features that nodeJS does not yet support out of the box, most notably:
import statements
String.includes().
Thus for delivery(build) I transpile+bundle my source code (using parcel, just like webpack).
As a positive wonder, all (but one) of my mocha tests run directly against my classes, not the bundle. Still, they work! Including many import statements. And including an 'ES6 self-test':
it( 'String - include', () => {
var s = 'Southern Bananas'
assert( s.includes( 'anana' ) )
assert( !s.includes( 'kiwi' ) )
} )
Thus:
I have String.include in my test code, not just in the source under test. And there is no place where I transpile or bundle my test codeā€¦ Thus apologies for my dumb question:
Why is this working? Is there a secret just-in-time compilation somewhere? (and if yes, could I use that for a debug flavour of my deliverable code-under-test as well?)
my mocha.opts are rather simple:
--require #babel/register
--require ./test/once.js (nothing special here, either)
--reporter list
--recursive
my .babelrc has this:
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"Electron": "3.0",
"Node": "8.0"
}
}
]
],
"plugins": [
"#babel/plugin-transform-runtime"
],
"retainLines": true,
"comments": false,
"sourceMaps": true
}
#babel/plugin-transform-runtime is apparently not to blame praise, as it explicitly states
NOTE: Instance methods such as "foobar".includes("foo")
will not work since that would require modification of
existing built-ins (you can use #babel/polyfill for that).
Is #babel/polyfill contained in the minimalistik-modern afaik #babel/preset-env? What else an I doing right :+)? Is there a way to use this live compilation for my (debug) build as well?
Long story short
String.prototype.includes is supported by Node.js since v6.5. #babel/register is causing your code to be compiled on the fly, that's why your import statements work. I doubt you need the #babel/plugin-transform-runtime plugin, unless I'm missing something that you're trying to achieve.
What can cause this confusion?
I think there are two root causes to this (totally understandable) mystery:
The Babel authors have made it really easy to use the tool; and sometimes it is hard to know how/when it is being invoked (especially when paired with another tool like Mocha).
What is/isn't supported natively by Node.js (in terms of ES2015, ES2016, etc.) has traditionally been hard to keep up with.
So, on to the two mysteries.
Why does String.prototype.includes work?
This one has the easier explanation. String.prototype.includes has been supported natively since as early as Node.js v6.5 (as you can see, a vast majority of ES2015 support has been supported since that version).
So, while you're correct that you don't have #babel/polyfill configured (as far as I can tell) and that you would need it in an environment that doesn't support String.prototype.includes, your environment already supports it!
From a Node.js v8.x REPL:
> 'ES2015'.includes('2015')
true
Why does your import statement work?
As you've stated, Node.js v8.x does not natively support ECMAScript Modules. However, there are some good write ups about how it has been enabled as an experimental feature starting in Node.js v9.x.
So, you get the following with native Node.js v8.x (via REPL):
> import path from 'path';
import path from 'path';
^^^^^^
SyntaxError: Unexpected token import
The reason your imports are working is because your code is being compiled by Babel using the #babel/preset-env preset. Furthermore, that compilation is being triggered by your --require #babel/register Mocha option.
#babel/register works by "bind[ing] itself to node's require and automatically compile files on the fly".
Here is a basic example of #babel/register in action:
From the command line:
$ node main.js
You will see this, because there is no syntax error!
main.js
require('#babel/register');
// This next file is compiled on the fly
require('./file1.js');
file1.js
import path from 'path';
console.log('You will see this, because there is no syntax error!');
The good thing is, this is how Mocha recommends you integrate Babel in their documentation. The --require option basically does what the above example does: require('#babel/register'); is called before Mocha uses require to import all of your test files.
Hope this helps! Again, this is a totally understandable mystery in the modern age of rapidly-evolving JavaScript.

ts-node programmatic usage with require('ts-node/register')

ts-node suggests to use require('ts-node/register'). And this can be seen in angular2-webpack-starter Protractor configuration.
What is require('ts-node/register') supposed to do? Does it patch require to transpile TS files, so a part of Node.js application could be written in TypeScript?
It does what you think it does. require('ts-node/register') is actually the same as:
require('./').register({
lazy: true
})
See examples here: https://github.com/TypeStrong/ts-node/tree/master/register
The .register function registers the Typescript compiler for files with .ts and .tsx extension for compilation on the fly.

How to get support of generators in typescript without setting target to ES6?

Got a situation here.
I use nodejs with --harmony flag to get support of generators.
Next i'm trying to switch my project to TypeScript and get a problem: in "target":"ES6" mode it transpiles import commands as is (instead of require).
And node with --harmony flag doesn't support that:
import * as fs from 'fs';
^^^^^^
SyntaxError: Unexpected reserved word
Transpiling option "module":"commonjs isn't allowed with "target":"ES6".
Have anyone solved this problem without using any external require/import utilities?
These settings have worked for me:
tsconfig.json
{
"compilerOptions": {
"target":"ES6",
"moduleResolution": "classic",
}
}
ES6 support for generators
No import stuff transpiling due to
"moduleResolution": "classic"
And so the problem's gone!
As you can see in the TypeScript roadmap (Version 1.7) one of the current issues is "Support --module with --target es6".
I'm afraid your are going to need a temporal solution until TypeScript 1.7 is released. Maybe Polyfill for the ES6 Module Loader or SystemJS?
Another way to get all i want is a build stack:
Transpile TS to ES6
Transpile es6-js to es5-js with Babel

Resources