Visual Studio 2015 JSX/ES2015 syntax highlighting with babel - babeljs

What i am tring to do:
Based on this answer, i am seeing if i can swap out the react-tools transformer for the babel-core transformer with presets for react, es2015 and stage-1.
VS2015 community uses react tools on a node server to transpile the code on the fly, the nodeJs server.js file is located at:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\Web Tools\External\react-server
The following lines in the transformJsxFromPost function do the tranformation and return the elementMap to visual studio:
var transformed = reactTools.transformWithDetails(code, { elementMap: true });
result = { elementMappings: transformed.elementMappings };
When you start VS, this creates a temp folder in your local app data and starts a node server at the following location:
%localappdata%\Temp\{most-recent-generated-guid-folder}
Where i have got so far:
The visual studio External\react-tools\ folder has a node_modules folder, so i npm installed the following there:
npm install babel-core --save-dev
npm install babel-preset-es2015 --save-dev
npm install babel-preset-react --save-dev
npm install babel-preset-stage-1 --save-dev
Added the following to the top of the server.js file:
var babel = require('babel-core');
And replaced the lines in transformJsxFromPost mentioned above for the following lines:
var transformed = babel.transform(code, {sourceMaps: "inline"});
result = { elementMappings: transformed.map };
At this stage, restart visual studio and it works, i get a sourceMap returned (admittedly not in the same format as the react-tools elementMap yet).
Where i am stuck:
As soon as i try to get babel to use presets, i am getting errors. So when i change the first line to:
var transformed = babel.transform(code, {sourceMaps: "inline", presets: ['es2015', 'react', 'stage-1']});
I get the error:
JSX Parser: Couldn't find preset \"es2015\" relative to directory
\"C:\\Users\\
The presets are all dependencies in the package.json file in the react-server folder, and it's not having any issues with babel, so why is it looking in the temp directory for the plugin?

I had to pass the actual presets to the function in this case instead of importing them and passing their name by string like in webpack.
I added the following imports:
var es2015 = require('babel-preset-es2015');
var react = require('babel-preset-react');
var stage1 = require('babel-preset-stage-1');
and changed
presets: ['es2015', 'react', 'stage1']
to
presets: [es2015, react, stage1]
I have added an answer here to a similar question.

Related

Is there a way to set up Babel to continuously transpile and/or minify a src folder to a compiled folder?

Starting with an empty directory, is it possible to do that? Should I use stage-0 like it is on the Babel REPL?
I hope to transpile it just like how ReactJS does it. For some reason, I always got an error for just a file containing:
let obj = { a: 1 };
let newObj = {
...obj,
ha: 3
};
Other times, I can transpile a file, but if I transpile a folder, it'd say:
foo.js: Cannot read property 'contexts' of null
The commands I tried included:
npx babel src --out-dir compiled --presets=es2015,react,minify --watch
but the errors I mentioned above appeared. Also, when I do
npm install babel-minify
it reported
found 2489 vulnerabilities (849 low, 306 moderate, 1329 high, 5 critical)
There is also a notice
As of v7.0.0-beta.55, we've removed Babel's Stage presets.
Please consider reading our blog post on this decision at
https://babeljs.io/blog/2018/07/27/removing-babels-stage-presets
for more details. TL;DR is that it's more beneficial in the
long run to explicitly add which proposals to use.
and I wonder what should be done.
Is it possible to
just continuously minify a folder
transpile some ES6 or ES7, 8 syntax that are not yet commonly supported
transpile JSX as well
?
I have found some reliable ways to make it work, although I am not sure when I should use babel.config.json and when to use .babelrc.json or .babelrc. It seems I have to run babel as ./node_modules/.bin/babel and is it true if I don't npm install babel using the -g option.
Here is what works:
create a folder, such as TryBabel
cd TryBabel
Go to https://babeljs.io/setup.html and click "CLI"
You need a package.json, so use npm init and just press Enter a few times
It should lead you to install
a. npm install --save-dev #babel/core #babel/cli
b. now look at your package.json. Remove the script about test but use this: "build": "babel src -d lib"
Now npm run build or ./node_modules/.bin/babel src -d lib should work, but make sure you have some .js files in the src folder. The transpiled result will be in the lib folder.
Now to transpile things into "pre ES6", just follow the #babel/preset-env instructions:
a. npm install #babel/preset-env --save-dev
b. make your babel.config.json to contain { "presets": ["#babel/preset-env"] }
Now you can use npm run build to transpile once, or use ./node_modules/.bin/babel src -d lib --watch to keep on running it and "watch" the src folder and transpile files in it when the files change.
To do minification or make it work with JSX/React, see
https://babeljs.io/docs/en/babel-preset-minify
and
https://babeljs.io/docs/en/babel-preset-react
and make sure your babel.config.json file looks like:
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "entry"
}
],
["#babel/preset-react"],
["minify"]
]
}
and remove minify if you don't want the code to be minified.

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

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"
]

How to develop Babel 6 plugins

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.

How can I setup webpack to minify and combine scss and javascript like CodeKit?

I'm having trouble using webpack instead of Codekit v1.9.3. I started working to move from CodeKit to Grunt and Gulp, and then learned about webpack which sounds very cool. I just can't seem to get it working correctly.
"Like Codekit" means I can:
Write javascript with the coffeescript syntax
Have all script source files and libraries minified / uglified and combined into one file
Selectively include components of the bootstrap-sass (scss) framework as needed
Maintain a small file with bootstrap customizations via sass variables, like $brand-primary
Use webpack --watch to compile both scripts and styles automatically when they are changed
End up with one css file and one script file that can be included with a stylesheet and script tag.
Codekit Project Setup
Bower resources:
I'm currently storing these globally, outside of the project:
~/bower_components/twbs-bootstrap-sass/vendor/assets/stylesheets
Because CodeKit supports compass, I've got this in my config.rb file:
add_import_path "~/bower_components/twbs-bootstrap-sass/vendor/assets/stylesheets"
Project Structure
js/fancybox.js
js/main.js <-- currently the compiled js 'output' file
js/main.coffee
css/styles.css <-- currently the compiled css 'output' file
scss/styles.scss
scss/modules/_bootstrap-customizations.scss
scss/modules/_typography.scss
scss/partials/_header.scss
scss/partials/_footer.scss
Contents of styles.scss
#import "modules/bootstrap-customizations"; # local customizations
#import "bootstrap/variables";
#import "bootstrap/mixins";
... # load bootstrap files as required
#import "bootstrap/wells";
System Setup:
system: OS X 10.9
node - v0.10.32
npm - v2.1.7
zsh - zsh 5.0.7 (x86_64-apple-darwin13.4.0)
node was installed with homebrew's brew install node and seems to be working fine otherwise.
What I've Tried
I've read over these pages:
http://webpack.github.io/docs/configuration.html
https://github.com/petehunt/webpack-howto
http://webpack.github.io/docs/tutorials/getting-started/
https://www.npmjs.org/package/bootstrap-sass-webpack
I've attempted to create a webpack.config.js file several times, my latest attempt was several versions of this:
module.exports = {
entry: [
"./node_modules/bootstrap-sass-webpack!./bootstrap-sass.config.js",
"./js/main.coffee"
],
output: {
path: __dirname,
filename: "main.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
}
};
Webpack Error
When I run webpack I get this:
ERROR in ./~/bootstrap-sass-webpack/~/css-loader!/Users/cwd/~/sass-loader!./~/bootstrap-sass-webpack/bootstrap-sass-styles.loader.js!./bootstrap-sass.config.js
stdin:1: file to import not found or unreadable: "~bootstrap-sass/assets/stylesheets/bootstrap/variables
NPM Error
I get an error when attempting to npm install bootstrap-sass, and not had any luck when searching for a solution. I'm not even sure I need this module.
npm ERR! Darwin 13.4.0
npm ERR! argv "node" "/usr/local/bin/npm" "install" "bootstrap-sass"
npm ERR! node v0.10.32
npm ERR! npm v2.1.7
npm ERR! code EPEERINVALID
npm ERR! peerinvalid The package bootstrap-sass does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer bootstrap-sass-webpack#0.0.3 wants bootstrap-sass#~3.2.0
npm ERR! Please include the following file with any support request:
npm ERR! /Users/cwd/webpack-test/npm-debug.log
Sources of Confusion
The most confusing parts of webpack for me are:
Where should things like require("bootstrap-sass-webpack") be added - is it in the webpack.config.js file, or in the js/main.js file?
Should modules like this available to webpack as soon as they are installed with npm install ?
I thought that I should do npm install webpack -g so that webpack was installed globally, and use npm install without the -g for the other modules. However, I don't see any node_modules folder being created in my project. Shouldn't there be one?
How are the search paths determined / specified for things like require("bootstrap-sass-webpack") ?
What node modules should I install to be able to do this? And what should my webpack.config.js look like?
Introduction
Webpack is mainly a JavaScript-bundler. Its "native" language is JavaScript and every other source requires a loader which transforms it to JavaScript. If you require() an html-file for example...
var template = require("./some-template.html");
...you'll need the html-loader. It turns...
<div>
<img src="./assets/img.png">
</div>
...into...
module.exports = "<div>\n <img src=\"" + require("./assets/img.png") + "\">\n</div>";
If a loader doesn't return JavaScript, it needs to be "piped" to another loader.
How to load SASS-files
Configure loaders
In order to use SASS you'll need at least the sass-loader and the css-loader. The css-loader returns a JavaScript string. If you want to import the returned JavaScript string as StyleSheet, you'll also need the style-loader.
Run npm i sass-loader css-loader style-loader --save
Now you need to apply these loaders on all files that match /\.scss$/:
// webpack.config.js
...
module: {
loaders: [
// the loaders will be applied from right to left
{ test: /\.scss$/, loader: "style!css!sass" }
]
}
...
You can also pass options to node-sass as query parameters:
{
test: /\.scss$/, loader: "style!css!sass?includePaths[]=" +
path.resolve(__dirname, "./bower_components/bootstrap-sass/assets/stylesheets/"
}
Since bootstrap references icons via the url() statement, the css-loader will try to include these assets into the bundle and will throw an exception otherwise. That's why you'll also need the file-loader:
// webpack.config.js
...
module: {
loaders: [
{ test: /\.scss$/, loader: "style!css!sass" },
{ test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/, loader: "file" },
]
}
...
Configure entry
To include bootstrap into your bundle there are several ways. One is via the multi-entry option as you've already tried. I recommend to use a single entry where you require() your main sass-file:
// main.js
require("./main.scss");
Given that your includePaths are configured then you can do:
// main.scss
// Set the font path so that url() points to the actual file
$icon-font-path: "../../../fonts/bootstrap";
#import "bootstrap";
Please note that import statements inside scss-files are not touched by webpack because libsass has no api (yet) to provide custom resolvers.
To prevent code duplication it's also important to have a single main sass-file, because webpack compiles every sass-file individually.
With the coffee-loader installed via npm your final webpack.config.js should look like:
module.exports = {
entry: "./js/main.coffee",
output: {
path: __dirname,
filename: "main.js"
},
module: {
loaders: [
{ test: /\.scss$/, loader: "style!css!sass" },
{ test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/, loader: "file" },
{ test: /\.coffee$/, loader: "coffee" }
]
}
};
Webpack globally?
It's best not to install webpack globally, because it's a dependency of your project and thus should be controlled via npm. You can use the scripts-section of your package.json:
{
...
"scripts": {
"start": "webpack --config path/to/webpack.config.js & node server.js"
}
}
Then you just need to run npm start