Babel 6 with just JSX transform and no other transforms - javascript

I want to use babel-plugin-transform-jsx, but no other transforms on some JSX files with some Javascript currently considered at stage 3 i.e. candidates.
Transpilation fails with a Syntax Error if those JSX files contain:
rest spread operators {...x, ...y}
async generators async function * () {}
The objective is to improve debug-ability of code in a modern browser, since the Babel transpilation of async generators in particular seems to break the dev tools for Chrome, Firefox i.e. breakpoints stop working, references to this fail, debugger calls are skipped, and numerous other observed problems.
There seems to be no alternative to using Babel to generate JSX in the above form — which works fine; an ideal solution would be to just have Babel ignore the async generators and rest-spread operators (and any other code it'd otherwise throw a syntax error on).
EDIT
Using the plugin suggested by Victor appears to be the correct solution but running babel-plugin-syntax-async-generators on this:
class SearchCriteria {
async * results (authManager) { }
}
Causes the error:
Unexpected token, expected "(" (2:10)
1 | class SearchCriteria {
> 2 | *async results(authManager) {
| ^
Reproducible here, when you add the syntax-async-generators plugin.

Babel has transform plugins and syntax plugins. Transform plugins apply transformations to your code. Syntax plugins allow Babel to parse specific types of JavaScript syntax, not transform it. Transform plugins will enable the corresponding syntax plugin so you don't have to specify both.
So in your case what you need is babel-plugin-transform-jsx transform plugin and two syntax plugins: babel-plugin-syntax-async-generators, babel-plugin-syntax-object-rest-spread.
The corresponding .babelrc will be:
{
plugins: ["babel-plugin-transform-jsx", "babel-plugin-syntax-async-generators", "babel-plugin-syntax-object-rest-spread"]
}
Minimal package.json:
{
"name": "babel-jsx",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "babel index.js"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-plugin-syntax-async-generators": "^6.13.0",
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
"babel-plugin-transform-jsx": "^2.0.0",
"react": "^16.4.1"
}
}
And if you have JavaScript code like this in index.js:
import React from 'react'
const MyComp = <div>Hello</div>;
async function* myfunc() {
const array = [1, 2, 3];
console.log(...array);
}
And run commands:
yarn
yarn build
Then the output will be:
$ babel index.js
import React from 'react';
const MyComp = {
elementName: 'div',
attributes: {},
children: ['Hello']
};
async function* myfunc() {
const array = [1, 2, 3];
console.log(...array);
}

Related

How do I correctly configure mocha tests with ts_transformer_keys?

I can't seem to set the custom transformer for ts-transform-keys with my mocha tests.
I’m using mocha 6.1.4
ts-node 8.3.0 https://www.npmjs.com/package/ts-node
ts-trasnformer-keys 0.3.5 https://github.com/kimamula/ts-transformer-keys
ttypescript 1.5.7 https://github.com/cevek/ttypescript
The ts-node documentation says that you cannot set a custom transformer on the CLI, only programatically. So I'm trying to use ttypescript to get around that restriction.
I've tried the following...
Note: test.ts contains the following
import { keys } from 'ts-transformer-keys';
describe("xyz"), () => {
it("123", (done) => {
keys<CustomInterface>();
});
});
Attempt 1) - Set the ts-node with an environment variable
TS_NODE_COMPILER="ttypescript" mocha test/test.ts --require ts-node/register
Then I have the following in test/tsconfig.json
{
"compilerOptions": {
"plugins": [
{ "transform": "ts-transformer-keys/transformer" }
]
}
}
This results in Uncaught TypeError: ts_transformer_keys_1.keys is not a function which indicates that the custom transformer wasn't used at compile time.
Attempt 2) Following the typescript API example from ts-transformer-keys
I added a mocha.opts file with the following
--file test/transformer-config.js
and a transformer-config.js file with the following
const ts = require('typescript');
const keysTransformer = require('ts-transformer-keys/transformer').default;
const program = ts.createProgram(['test/test.ts'], {
strict: true,
noEmitOnError: true,
target: ts.ScriptTarget.ES5
});
const transformers = {
before: [keysTransformer(program)],
after: []
};
const { emitSkipped, diagnostics } = program.emit(undefined, undefined, undefined, false, transformers);
if (emitSkipped) {
throw new Error(diagnostics.map(diagnostic => diagnostic.messageText).join('\n'));
}
Then I invoke it like this mocha test/test.ts --require ts-node/register
This results in the following error
/Users/jjohnson/Documents/OCS/hmp/git/hmp-server/server/test/ttypescript-register.js:17
throw new Error(diagnostics.map(diagnostic => diagnostic.messageText).join('\n'));
^
Error: [object Object]
[object Object]
[object Object]
at Object.<anonymous> (/Users/jjohnson/Documents/OCS/hmp/git/hmp-server/server/test/ttypescript-register.js:17:9)
at Module._compile (internal/modules/cjs/loader.js:777:30)
...
It feels like in Attempt 1 it wasn't ever calling the code that sets the custom transformer in tsconfig.json or if it was getting called the code was failing silently.
It feels like in Attempt 2 I'm creating a new instance of the typescript program and then that fails for some reason. And even if it succeeded I'm not sure that this is the right way to go about configuring things since the ts.createProgram wants a list of RootNames for the files it will transpile.
Maybe my entire approach is wrong.
All I really want is a way that in my mocha tests I can verify that the expected result type is what the method returned. And I'd like to be able to do this w/out touching too much of the source code.
you should be able to define your required module (see below) and run ts-node programmatically. In this way, you can safely use any customer transformer.
// tsnode.js
const transformer = require('ts-transformer-keys/transformer').default;
require("ts-node").register({
transformers: program => ({
before: [
transformer(program)
]
})
});
then you can run mocha with require
mocha --require './tsnode.js' --watch-extensions ts,tsx "test/**/*.{ts,tsx}
You can tell ts-node which compiler to use in tsconfig.json. This is covered in the ts-node docs. If your using transformers presumably your also using ttypescript compiler. You just need to add this:
"ts-node": {
"compiler": "ttypescript"
}

"TypeError not a constructor" when upgrading project from Babel v5 to v6+

I've been bashing my head against this brick wall for a day now so it's time to turn to SO for help I think! I'm trying to update a project off babel v5, I'm starting off with this in package.json:
"devDependencies": {
"babel": "^5.8.21",
"test": "mocha --require babel/register",
I've tried to upgrade to babel both v6 and v7 with no success either time. In both cases I end up with TypeError: _application.ApplicationClient is not a constructor when I attempt to run tests that worked fine with v5:
import { ApplicationClient } from '../src/wiotp/sdk/application';
...
let client = new ApplicationClient();
Using v6 as an example, I end up with the following in package.json:
"devDependencies": {
"babel-cli": "^6.0.0",
"babel-core": "^6.0.0",
"babel-preset-env": "^1.7.0",
"mocha": "6.1.4",
"test": "mocha --require babel-core/register --timeout 5000",
and created a .babelrc file (none existed previously):
{
"presets": ["env"]
}
I've read a dozen or more articles trying to understand what is going on here, I've done and undone numerous suggested "fixes" based on Google searches for similar problems, but I'm starting from zero and finding it incredibly hard to get simple plain-English explanation of what the actual problem is for a start, and how babel is supposed to be configured here to resolve it. I'm guessing something that happened by default in v5 needs to be configured somehow in .babelrc now, but /shrugs/ no idea where to go from here now.
babel5 to babel6 branch compare
babel5 to babel7 branch compare
Any pointers for someone struggling to wrap his head around babel, let alone the differences between v5, 6, & 7?
Edit:
src/wiotp/sdk/application/index.js has this:
import { default as ApplicationClient } from './ApplicationClient';
export default {
ApplicationClient
}
Where src/wiotp/sdk/application/ApplicationClient.js has a single class exported (I'm just trying to create an instance of that class in the test code):
export default class ApplicationClient extends BaseClient {
constructor(config) {
src/wiotp/sdk/application/index.js has this:
import { default as ApplicationClient } from './ApplicationClient';
export default {
ApplicationClient
}
This is horrible, and causing your problem. That module does default-export an object literal, instead of just using named exports. It might be a bug and they meant to write either
import { default as ApplicationClient } from './ApplicationClient';
export { ApplicationClient }
or
export { default as ApplicationClient } from './ApplicationClient';
It would recommend to report an issue and provide a patch.
If this is not considered a bug but was done on purpose, you will need to change your code to
import application from '../src/wiotp/sdk/application';
…
let client = new application.ApplicationClient();
// ^^^^^^^^^^^^
or just import it directly from the original module:
import ApplicationClient from '../src/wiotp/sdk/application/ApplicationClient.js';
// ^^^^^^^^^^^^^^^^^^^^^
…
let client = new ApplicationClient();

Babel can't parse "for each...in" statement

I'm attempting to transpile Salesforce Commerce Cloud's .ds files to JavaScript so we can apply standard testing tools (Jest, Mocha, etc.). The SFCC docs indicate that .ds files are "Rhino JavaScript", with a non-standard extension for Flow-like type checking.
So far, stripping out the type annotations has been simple, using the transform-flow-strip-types plugin. But SFCC supports a deprecated "for each...in" statement from JavaScript 1.6 that Babel is choking on.
All code below is available on github.
Here's my source src/index.ds file:
function dump(a: Array) {
for each (var x in a) {
console.log(x);
}
}
module.exports = dump;
And my gulfile.js:
const gulp = require('gulp');
const babel = require('gulp-babel');
gulp.task('test', function () {
gulp.src('src/**/*.ds')
.pipe(babel())
.pipe(gulp.dest('dst'));
});
And this is my package.json:
{
"name": "dspoc",
"version": "1.0.0",
"description": "poc",
"main": "index.ds",
"author": "cjr",
"license": "ISC",
"devDependencies": {
"babel": "^6.23.0",
"babel-core": "^6.26.3",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"gulp": "^3.9.1",
"gulp-babel": "^7.0.1"
},
"babel": {
"plugins": [
"transform-flow-strip-types"
]
}
}
When I run gulp test, I get this:
%> gulp test
[11:23:06] Using gulpfile ~/dev/dspoc/gulpfile.js
[11:23:06] Starting 'test'...
[11:23:06] Finished 'test' after 9.15 ms
events.js:163
throw er; // Unhandled 'error' event
^
SyntaxError: /Users/craser/dev/dspoc/src/index.ds: Unexpected token, expected ( (2:5)
1 | function dump(a: Array) {
> 2 | for each (var x in a) {
| ^
3 | console.log(x);
4 | }
5 | }
at Parser.pp$5.raise (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:4454:13)
at Parser.pp.unexpected (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:1761:8)
at Parser.pp.expect (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:1749:33)
at Parser.pp$1.parseForStatement (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:2008:8)
at Parser.pp$1.parseStatement (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:1836:19)
at Parser.parseStatement (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:5910:22)
at Parser.pp$1.parseBlockBody (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:2268:21)
at Parser.pp$1.parseBlock (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:2247:8)
at Parser.pp$3.parseFunctionBody (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:4235:22)
at Parser.parseFunctionBody (/Users/craser/dev/dspoc/node_modules/babylon/lib/index.js:5897:20)
I've spent quite a bit of time digging for a plugin that will let Babel transpile this to something like the for...of statement, but I can't seem to find anything.
I'm now at the precipice of digging into the for-of transform was built and creating something similar to transform for each...in, but I really don't want to have to put that work in if I can avoid it.
I feel like I'm missing something obvious here. Anyone know how this can be done?
for each...in was never an official part of the spec and didn't exist by the time Babel came around, so it is not supported by Babel. I'm afraid you've have to update all usage of that syntax before Babel will be able to process it.

Conditional import of peerDependency in es6

I am working on a JavaScript i18n library which localize dates (among other types and objects).
It is currently relying on moment.js, which is defined as a peerDependency (localization is one of the features but not the only one, it might not be used)
// package.json
{
"name": "my-i18n-library",
// ...
"scripts": {
// ...
"clean": "rimraf build",
"build": "babel src -d build",
"prepare": "npm run clean && npm run build"
},
"peerDependency": {
"moment": "~2.20.1",
"date-fns": "~1.29.0"
},
// ...
}
// .babelrc
{
"presets": ["env", "stage-1", "react"]
}
Basically something like (a bit more error-proof but I simplified the logic) :
import Moment from 'moment.js'
import 'moment/min/locales'
class Localizer {
localizeDate(value, locale, displayFormat = "L", parseFormat = "LTS") {
return Moment(date, parseFormat, locale).format(displayFormat);
}
}
Problem is, if moment.js is a nice work, it is like a backpack of stones, you would not bring it on a 50 miles trail, especially if you only need to localize one date in a whole application. Bandwidth-wise, it's not worth it IMO (actually in a lot of people opinions as well).
So I am considering switching to lighter libraries such as date-fns, but I figured out an option I think is even better :
what if we could let the other choose which library suits him the most?
I was thinking to define different implementations of library-related localizers, and conditionally import them depending of which peerDependency is installed :
// /Date/DateFnsLocalizer.js
import { parse } from 'date-fns/parse'
import { format } from 'date-fns/format'
class DateFnsLocalizer {
localizeDate(value, locale, displayFormat = "L") {
return format(parse(date), displayFormat, { locale })
}
}
Is that even possible in JavaScript ?
// /Localizer.js
if (isModuleDefined('moment.js')) {
import BaseLocalizer from './Date/MomentLocalizer'
} else if (isModuleDefined('date-fns')) {
import BaseLocalizer './Date/DateFnsLocalizer'
} else if (isModuleDefined('some-other-lib')) {
import BaseLocalizer './Date/SomeOtherLibLocalizer'
} else {
throw new Error('No date library defined! Please install at least one of ["moment.js", "date-fns", "some-other-lib"]')
}
export default class Localizer extends BaseLocalizer
I think "import" statements have to be made as first statements in the file. Maybe using require instead... (as suggested in ES6: Conditional & Dynamic Import Statements) ? And is it possible to test a module existence without importing it (basically how to code that isModuleDefined() method?)
I have seen those ones as well :
ES6 variable import name in node.js?
How can I conditionally import an ES6 module?
But as we are currently using babel to transpile this library, if this architecture is possible, could it cause compilation troubles in other building tools such as webpack, gulp, grunt etc.?

BabelJS class ordering when using inheritance [duplicate]

This question already has an answer here:
Bundling ES6 classes with Webpack. Is there a way to hoist extended classes?
(1 answer)
Closed 5 years ago.
I am trying to find a way to make babel load files in a particular order so that superclasses are loaded before childclasses.
An example given the following files:
src/fruit.js:
export class Fruit{
constructor(color){
this._color = color;
}
}
src/apple.js:
export class Apple extends Fruit{
constructor(){
super("green");
}
}
src/xecute.js:
var theApple = new Apple();
package.json
{
"name": "fruit",
"version": "1.0.0",
"description": "Fruit JS",
"scripts": {
"build": "babel src -o out/fruit-bundle.js"
},
"author": "Toby Nilsen",
"license": "MIT",
"devDependencies": {
"babel-cli": "^6.22.2",
"babel-preset-es2015": "^6.5.0"
}
}
.babelrc:
{
"presets": ["es2015"]
}
When I compile my files the following command
npm run build
And run my out/fruit-bundle.js with:
node out\fruit-bundle.js
I get the follwing error:
TypeError: Super expression must either be null or a function, not undefined
This is because babel parses apple.js before fruit.js. I can work around the problem by renaming my files to 0_fruit.js and 1_apple.js, but I would like to know if there is any way for babel to resolve the dependencies and order the output so that superclasses are loaded first?
Babel is just a transpiler. It just transpiles the syntax, but it does not do bundling for you. You'll need a bundler to resolve dependencies in the correct order. Consider checking out Rollup or Webpack. Going with Rollup, the simplest way to do this without the caching and other build optimizations is either to:
Run Rollup to bundle everything to one file then run Babel on Rollup's output.
Run Babel on all files, then use Rollup to bundle them all.
Also, so that the bundler knows the right order, import Fruit from Apple.
import Fruit from 'fruit';
export class Apple extends Fruit{
constructor(){
super("green");
}
}

Categories

Resources