How to develop Babel 6 plugins - babeljs

What process do you use to develop Babel 6 plugins?
Here's what I came up with to develop a plugin (babel-plugin-test):
1) In an empty folder run:
npm install babel-cli babel-preset-es2015
2) Create the file src/test.js (to test the plugin) with just:
class Person {
}
3) Create the folder node_modules/babel-plugin-test with the following contents
node_modules/babel-plugin-test/package.json
{
"name": "babel-plugin-test",
"version": "0.1.0",
"main": "lib/index.js",
"dependencies": {
"babel-runtime": "^5.0.0"
},
"devDependencies": {
"babel-helper-plugin-test-runner": "^6.3.13"
}
}
node_modules/babel-plugin-test/src/index.js
export default function ({types: t }) {
return {
visitor: {
ClassDeclaration: function (node, parent) {
console.log("XXX");
}
}
};
}
4) Create a script that runs:
node_modules/babel-plugin-test/babel --presets es2015 --out-dir lib src
babel --plugins babel-plugin-test --presets es2015 --out-dir out src
So it compiles the plugin and then compiles test.js using the plugin and I see the console log and the output file (in this example I'm not changing anything).
There has to be a better way to do this. Maybe some way to use WebStorm or another Node debugger to put a breakpoint and play around (at least be able to inspect variables).

The way to go is to run babel in code so you can get the transpiled code and compare against what you expect.
First transpile your plugin as you did, then in the test folder
var transformFileSync = require('babel-core').transformFileSync
var path = require('path')
var fs = require('fs')
var plugin = require('../lib/index').default
describe('My test', function (){
it ('Transform', function(){
var transformed = transformFileSync(path.join(__dirname, 'testFilePath'), {
plugins: [[plugin]]
}).code
var expectedCode = fs.readFileSync(..)
assert.equal(transformed, expected)
})
})
You can find an example here. It is also possible to write the tests in ES6 importing modules, for that you need to provide mocha with a compiler, see here for an example.

For basic testing I use the wonderful astexplorer. Just set the parser to babylon 6 and turn on transform and set it to babelv6. Then you can put your code in one pane, see the AST results in another, put your babel plugin in a third pane and see the plugin result in the fourth.
For a more complicated test I create two projects, one for the plugin and another one i want to test the plugin on. I npm link the two and configure the test project to use my plugin in babelrc. Then, whenever my plugin changes i just run babel on my file/project and see the results.
Im not sure if this is the best way but it works for me.

Related

Vscode intellisense AMD requirejs durandal

i am running an app in aspnetcore which uses plain js files for the view part,
in this case is a legacy app using :
jquery
Requirejs with AMD modules
Durandal (now aurelia) which enforces the use of those modules
Knockoutjs (mvvm lib)
here an example of durandal/amd module code (if anyone has seen it already)
define(['durandal/app',
'plugins/dialog',
'global',
'knockout',
'services/datacontext',
'services/appsecurity'],
function (app, dialog, global, ko, datacontext, appsecurity) {
/// ... function body using modules but no intellisense...
}
this is the structure of my app
--src
----aspnectoreapp
-------wwwroot
---------App (contains app code using durandall structure)
-----------Config.js (requirejs config file)
-----------Main.js (entry point)
---------Scripts (contains js libs like all the aboves)
how can i make this to work with vscode intellisense?
i tried adding packages with npm init, and npm install -D
adding both packages and types..
i also tried adding this in my wwwroot/jsconfig.json
{
"compilerOptions": {
"module": "amd",
"target": "es6"
}
}
but got no luck.
I also tried installing the requirejs vscode extension specifying a settings.json workspace solution file (at top level), with this values
{
"requireModuleSupport.modulePath": "./src/aspnectoreapp/Scripts",
"requireModuleSupport.configFile": "./src/aspnectoreapp/App/Config.js"
}
but got no luck .
Anyone which tried any of those settings or knows a way this could work?

What babel or other settings do I need to run Mocha Test Explorer on a vue-cli-3 project?

I've created a vue3 cli project with Mocha testing:
vue create vue_proj_with_mocha_testing
(accept defaults)
cd vue_proj_with_mocha_testing
vue add unit-mocha
Then in Visual Code I install the Mocha Test Explorer extension, restart, add the folder to the workspace, click the folder, ctrl-shift-p and Mocha Test Explorer : "Enable for a workspace folder". Out of the box Mocha Test Explorer doesn't seem to like vuecli's example.spec.js test:
import { expect } from 'chai'
import { shallowMount } from '#vue/test-utils'
import HelloWorld from '#/components/HelloWorld.vue'
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message'
const wrapper = shallowMount(HelloWorld, {
propsData: { msg }
})
expect(wrapper.text()).to.include(msg)
})
})
I add this entry to settings.json so that Test Explorer finds the vue "tests" folder, which is different from the default of "test".
"mochaExplorer.files": ["tests/**/*.spec.js"],
And then receive this error in Test Explorer:
import { expect } from 'chai';
^^^^^^
SyntaxError: Cannot use import statement outside a module
This indicates I have some transpiling work to do, and Mocha Test Explorer indicates the way to do that is the "mochaTestExplorer" fields in settings.json, but I'm not sure what combination of babel packages would be required. What should be done to run this out-of-the-box vue-cli-3 test in Mocha Test Explorer in Visual Studio Code? Here is my current guess:
"mochaExplorer.require": [
"#babel/preset-env",
"#babel/register",
"#babel/polyfill",
"#babel/plugin-transform-runtime"
],
First, add #babel/register in yours devDependencies.
After, add in your Visual Studio Code settings.json:
"mochaExplorer.files": "tests/**/*.spec.js",
"mochaExplorer.env": {
"NODE_ENV": "test"
},
"mochaExplorer.require": [
"#babel/register"
]
Finally, changes your babel.config.js to like this:
const presets = [];
if (process.env.NODE_ENV === 'test') presets.push('#babel/preset-env');
else presets.push('#vue/cli-plugin-babel/preset');
module.exports = {
presets,
};
I'm afraid what you want is not possible - problem is it is not enough to setup Babel correctly. Vue single file components (.vue) need to be processed by Vue Loader which is Webpack loader plugin.
And there is no easy way how to setup Mocha Test Explorer to use webpack as indicated by the author himself in this thread - Support for vue cli projects
So I decided to split my tests into two groups, tests/ui (tests using Vue components) and tests/unit (non-ui tests) and use setup described by Fernando with these modifications:
Configure Mocha Test Explorer to only search for non-ui tests:
"mochaExplorer.files": "tests/unit/**/*.spec.js",
package.json:
"test:unit": "vue-cli-service test:unit tests/unit/**/*.spec.js tests/ui/**/*.spec.js",
...to include both folders when running tests from command-line
Note: Last step - modifying babel.config.js - is not needed, everything works fine without it....
On a slightly different config, i worked for me: in .vscode/settings.json
{
"mochaExplorer.require": "esm"
}
esm should also be in your dev dependencies

Using other NPM packages in own cordova plugin

I created an own cordova plugin for use in an Ionic 3 project.
The js-module requires other npm/node packages (in my case for XML processing).
e.g.
var builder = require('xmlbuilder');
I read X articles about hooks and other crazy stuff, but nothing really helpful.
Is there no easy way to add such a trivial thing to the build-chain just by some simple configuration of the dependencies?
Edit:
Let´s take that simple plugin as example: https://github.com/don/cordova-plugin-hello
The great function in https://github.com/don/cordova-plugin-hello/blob/master/www/hello.js should be able to use the xmlbuilder.
So I changed the file to:
/*global cordova, module*/
var builder = require('xmlbuilder');
module.exports = {
greet: function (name, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "Hello", "greet", [name]);
}
};
I added the module via npm install to the ionic project, but that doesn´t help. How can I make the modules somehow available for the plugins?

import with jest error: Unexpected token import

I've seen similar questions but still can't find a viable solution.
I'm trying to integrate Jest into a working project, which uses import/export default in hundreds of places. The following test does work for Jest using require:
const bar = require('../../flows/foo');
test('adds 1 + 2 to equal 3', () => {
expect(bar.foobar(1, 2)).toBe(3);
});
when export is:
module.exports = {
foobar: foobar,
fizz: fizz
}
The functions I'll want to be testing however are exported using:
export default {
foobar: foobar,
fizz: fizz
};
So when I try to update my test to import:
import foobar from '../../flows/foo';
With export:
export default {foobar: foobar};
I get the error
SyntaxError: Unexpected token import
All it takes:
// run this command (or npm equivalent)
yarn add #babel/core #babel/preset-env
// add babel.config.js
module.exports = {
presets: [
[
'#babel/preset-env',
{
targets: {
node: 'current'
}
}
]
]
};
Jest automatically picks it up, no other configuration required.
You have not set up a .babelrc file in your project, so transpiling is not happening. You need to transpile the ES6+ syntax (import, export, etc) into browser readable ES5.
I ran into this and solved it this way thanks to this GitHub issue post:
If you're using babel to transpile your code then remember to use the transform-es2015-modules-commonjs plugin.
To use it, you'll need to:
Install the plugin for BabelJS by entering this command in the CLI:
npm install --save-dev babel-plugin-transform-es2015-modules-commonjs
Add the plugin to your list of plugins in your babel config
plugins: [
"transform-es2015-modules-commonjs"
]

babel-jest doesn't handle ES6 within modules

I am trying to set up Jest on a React based project which uses ES6 modules. However I seem to be having issues with ES6 modules, I am using babel-jest and believe I have this set up properly (Jest detects it automatically).
Jest doesn't seem to have a problem using ES6 imports however as soon as it hits on an import statement within one of the imported modules it chokes. It's as if it is only transpiling the initial test script and not any of the imported modules. I have tried various configurations and tried searching Google with no luck. Running tests without any imports works fine.
Here is the error:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import Predications from './predications';
^^^^^^
SyntaxError: Unexpected token import
Here are the relevant bits of config:
jest.conf.json
{
"testRegex": "\/test\/spec\/.*\\.js$",
}
.babelrc
{
"presets": ["es2015", "stage-0", "react"]
}
Test script
import React from 'react';
import { mount, shallow } from 'enzyme';
import Slider from 'react-slick';
import Carousel from '../../client/components/carousel/carousel.js'; // test chokes on when I include this module
describe('carousel component', () => {
it('is a test test case', () => {
expect(1 + 2).toEqual(3);
});
});
Update:
As suggested, I have tried running the test without jest.conf.js, however the testRegex is needed in order for Jest to find my tests, I tried moving tests to the default test directory and they still fail.
I would like to clarify that tests themselves are running fine, the issue seems to be where one of my imported modules uses ES6, in my example above, if I don't import my carousel component the test runs fine, as soon as I import that the test chokes on the import statement within that file. It seems as though the imported modules are not getting transpiled.
Update #2
After some investigation it appears the issue is that babel is not transpiling ES6 within node_modules. I have created an example repo to demonstrate this here: https://github.com/jamiedust/babel-jest-example
I understand that third party modules should be handling their own transpiling, however we have a number of modules which are hosted on our own npm registry and are re-used between projects, in these cases Webpack handles transpiling, for the Jest tests we need these node_modules to be transpiled by Babel, or a way of leveraging our webpack set up to do this for us.
Solution
Add the following config in package.json (or Jest config file).
"jest": {
"transformIgnorePatterns": [
"/node_modules/(?!test-component).+\\.js$"
]
}
By default any code in node_modules is ignored by babel-jest, see the Jest config option transformIgnorePatterns. I've also created a PR on your example repo, so you can see it working.
While this works, I've found it to be extremely slow in real applications that have a lot of dependencies containing ES modules. The Jest codebase has a slightly different approach to this as you can find in babel-jest transforming dependencies. This can also take much longer on Windows, see Taking 10 seconds on an empty repo.
If doing "unit" testing, mocking is probably the better way to go.
You could try adding the transform-es2015-modules-commonjs plugin to your babel config file for testing only. Here is an example config file which tells babel to transpile modules only when in a testing environment. You can put it underneath your presets:
{
"presets": [
"react",
["es2015", {"modules": false, "loose": true}]
],
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}
You can read about the plugin here:
https://www.npmjs.com/package/babel-plugin-transform-es2015-modules-commonjs
Then, when running your Jest tests on the command line specify NODE_ENV=test (you may need to add the --no-cache flag to the command the first time after making the change to the babel config because Jest caches babel output, but after that you can leave it off:
NODE_ENV=test jest --no-cache
I learned about this issue in a React seminar by Brian Holt at Frontend Masters. https://frontendmasters.com/courses/
faced the same issue, followed the steps to resolve,
install babel-jest
in jest config add this configuration
transform: {
'^.+\\.js?$': require.resolve('babel-jest')
}
make sure you have babel.config.js present (your config might be different than provided below)
module.exports = {
"env": {
"test": {
presets: [
[
'#babel/preset-env',
{
targets: {
node: 'current',
},
},
],
]
}
}
};
I faced the same problem (node_module not transpiled by babel-jest), without being able to solve it.
Instead, I finally succeed by mocking the node_module, like described here https://facebook.github.io/jest/docs/manual-mocks.html
NB: setting mocks in __mocks__ subfolders did not work for me. So I passed the mock as the second parameter of the jest.mock() function. Something like :
jest.mock('your_node_module', () => {})
Another possible cause. Babel now ignores your .babelrc inside node_modules and uses the one provided by the dependency. If you have control of the dependency you would have to add a .babelrc to it and babel would use those settings for it.
this can cause problems though if your dependency and your project use different babel versions or modules.