How to use stage 3 syntax in svelte/sapper? - babeljs

I want to use class property and private fields in my sapper project. Apparently they have to be preprocessed by babel right now.
I tried to add the corresponding babel plugins to rollup.config.js, only to realize a few things.
the babel rollup plugin is only used in legacy mode.
the server part doesn't use babel at all.
I tried to add the babel rollup plugin to the end of server plugins like this,
babel({
extensions: ['.js', '.mjs', '.html', '.svelte'],
runtimeHelpers: true,
exclude: ['node_modules/#babel/**'],
plugins: [
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-private-methods',
],
}),
But it doesn't seem to take effect at all.
I also added it to the client plugins (before the legacy entry), but it complained about I needed to add #babel/plugin-syntax-dynamic-import, so looks like babel has to recognize the whole syntax in order to preprocess, and I don't really want to compile dynamic import for modern browsers.
How do I enable the use of esnext syntax in sapper?

You would need to preprocess the contents of <script>, using the preprocess option in rollup-plugin-svelte:
plugins: [
svelte({
// ...
preprocess: {
script: ({ content }) => {
return transformWithBabel(content);
}
},
// ...
})
]
In an ideal world we'd have a ready-made preprocessor plugin for doing this; as it is, the transformWithBabel function is left as an exercise to the reader for now. Essentially it would involve import * as babel from '#babel/core' and using the Babel API directly, which I guarantee will be lots of fun.
Note that #babel/plugin-syntax-dynamic-import doesn't compile dynamic import, it only allows Babel to parse it. Without it, Babel can't generate a valid AST from the code inside <script>.

Related

Specifying window (global) variable type hinting in VSCode from external JS file without typescript

This may be a silly question but I really don't know where to look.
I'm creating a browser testing environment for a pretty large-scale API written in typescript. This API uses esbuild to build the typescript files into a /dist/ folder with a single index.js entry-point and its appropriate d.ts file.
I've created a /tests/ folder to hold some browser files that includes an index.html file with Mocha and Chai imported. It also imports /dist/index.js which is set globally to a window.myAPI variable.
In /tests/index.html:
import * as myAPI from "./dist/index.js"
Alongside index.html in the tests folder, there are separate JS files included for different tests that run things on window.myAPI... to do assertion tests.
search.test.js
book.test.js
navigate.test.js
I then run a server to host at the root. These separate tests are then imported from /tests/index.html. The separate tests look like this inside:
const { chai, mocha } = window;
const { assert } = chai;
describe("Search", function() {
describe("Setup", function() {
it("Setting URL should work", function() {
const call = myAPI.someCall()
assert.ok(call);
});
});
});
mocha.run();
Everything works, but I have no code hinting for myAPI. I'd like to be able to see what functions are available when I type myAPI, and what parameters they take, and what they should return - along with all my comments on each function.
In typescript you can do things like ambient declarations, but I don't want to make my tests typescript because then I add an unnecessary build step to the tests. But it would be as easy as:
/// <reference path = "/dist/index.d.ts" />
How can I tell VSCode that window.myAPI is an import of /dist/index.js and should import the types as well so I can see them ?
I'm open to different solutions to this, but I feel like this should be pretty simple. I don't know if ESLint is capable of doing something like this, but I tagged it because I feel it's relevant.
Thanks!

How do react-css-modules (babel) and css-loader (webpack) work together?

When using webpack and babel together, one needs to configure both in order to use React CSS Modules. For example:
webpack.config.js will need a rule like this:
{
// Translates CSS into CommonJS modules
loader: 'css-loader',
options: {
modules: {
mode: "local",
localIdentName: CSS_CLASS_NAME_PATTERN,
},
sourceMap: true
}
babel.config.js will need a plugin like this:
[
'react-css-modules',
{
generateScopedName: CSS_CLASS_NAME_PATTERN,
filetypes: {
'.scss': {
syntax: 'postcss-scss',
plugins: ['postcss-nested']
}
},
}
]
Why the need to configure CSS Modules in two places? How the two work together? I.e. what happens in what order?
They don't. css-loader does its own thing: class name transformation in CSS, and replacement of CSS imports in JS code by mappings between original and generated names.
babel-plugin-react-css-modules works independently, and it replaces styleName attributes of react components by className with correct generated names. To do so it calculates class name mappings independently from css-loader, that's why it needs separate configuration matching that of css-loader, and that's why after a few years being abandoned by its creators it has compatibility issues with latest css-loader (css-loader changed internal class name generation logic).
Shameless self-promo: I maintain an up-to-date fork of babel-plugin-react-css-modules which solves compatibility issues with latest css-loader versions.

(How) can I use System.import in babel along with require.js?

I'm playing a little bit with the new ES6 functionalities and Babel. I'm successfully using the modules export/import functionalities by means of require.js (transpiling into AMD), but the experimental module loader doesn't want to work. Here is my code and configurations:
extract of front-app/tst.js
import {tstimp as functocall} from "front-app/tstimp.js";
...
/**
* LOADING MODULES DYNAMICALLY
*/
System.import('front-app/tst_dyn_mod')
.then(some_module => {
console('using the module!');
some_module.sayHello();
})
.catch(error => {
console.log('error!');
console.log(error);
});
My .babelrc looks like this:
{
"presets": ["es2015", "react"],
"plugins": ["transform-es2015-modules-amd"]
}
and the scripts I import are these ones, in that order:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="node_modules/babel-polyfill/dist/polyfill.min.js"></script>
<script data-main="front-app/tst" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.8/require.min.js"></script>
<script src="node_modules/es6-module-loader/dist/es6-module-loader.js"></script>
</head>
<body></body>
</html>
Unfortunately what I get is the following error by using firefox:
error! tst.js:695:9
Error: a is undefined
Error loading http://localhost/es6r1/front-app/tst_dyn_mod
what's that a? Am I missing something? Keep in mind my code is transpiled into AMD, but System is supposed to stay there in the transpiled code (and it IS there). The polyfill should do the dirty job, right?
I successfully get the thing working on Babel 6 with a slighlty different config (babel-node cli & thus commonjs) thanks to this plugin: https://www.npmjs.com/package/babel-plugin-system-import (npm install babel-plugin-system-import-transformer). Here's a excerpt of my .babelrc:
…
"plugins": [
"system-import-transformer",
{
"modules": "common"
}
]
…
Setting amd instead of common like indicated in the documentation should do the trick for you.
Only limitation of this tiny plugin, you should get a plain string module name like System.import("plainString") and not a computed one (nor string concatenation with +, nor new ES6 template literal and neither variable name). It seemds linked to that line of code.
I will try to PR a fix on that limitation if I can.
Just an update on this, https://github.com/thgreasi/babel-plugin-system-import-transformer has support for non string parameters. Just make sure not to use the updated alias package.

Babel plugins run order

TL;DR: Is there a way how to specify the order in which the Babel plugins are supposed to be run? How does Babel determine this order? Is there any spec how this works apart from diving into Babel sources?
I'm developing my own Babel plugin. I noticed, that when I run it, my plugin is run before other es2015 plugins. For example having code such as:
const a = () => 1
and visitor such as:
visitor: {
ArrowFunctionExpression(path) {
console.log('ArrowFunction')
},
FunctionExpression(path) {
console.log('Function')
},
}
my plugin observes ArrowFunction (and not Function). I played with the order in which the plugins are listed in Babel configuration, but that didn't change anything:
plugins: ['path_to_myplugin', 'transform-es2015-arrow-functions'],
plugins: ['transform-es2015-arrow-functions', 'path_to_myplugin'],
OTOH, this looks like the order DOES somehow matter:
https://phabricator.babeljs.io/T6719
---- EDIT ----
I found out that if I write my visitor as follows:
ArrowFunctionExpression: {
enter(path) {
console.log('ArrowFunction')
}
},
FunctionExpression: {
exit(path) {
console.log('Function')
}
},
both functions are called. So it looks like the order of execution is: myplugin_enter -> other_plugin -> myplugin_exit. In other words, myplugin seems to be before other_plugin in some internal pipeline. The main question however stays the same - the order of plugins in the pipeline should be determined & configurable somehow.
The order of plugins is based on the order of things in your .babelrc with plugins running before presets, and each group running later plugins/presets before earlier ones.
The key thing though is that the ordering is per AST Node. Each plugin does not do a full traversal, Babel does a single traversal running all plugins in parallel, with each node processed one at a time running each handler for each plugin.
Basically, what #loganfsmyth wrote is correct; there is (probably) no more magic in plugin ordering itself.
As for the my problem specifically, my confusion was caused by how arrow function transformation works. Even if the babel-plugin-transform-es2015-arrow-functions plugin mangles the code sooner than my plugin, it does not remove the original arrow-function ast node from the ast, so even the later plugin sees it.
Learning: when dealing with Babel, don't underestimate the amount of debug print statements needed to understand what's happening.

Is there any way to pass multiple browser via protractor cli

Just wanted to know is it possible to specify cli args to protractor like
--multiCapabilities.0.browserName chrome --multiCapabilities.1.browserName firefox
so that it overrides the multiCapabilities defined in protractor conf file.
A concrete example of Isaac Lyman's first suggestion:
CLI:
protractor ... --params.browsers="chrome,firefox"
conf.js:
var capabilities = {
chrome: {
browserName: 'chrome'
},
firefox: {
browserName: 'firefox'
}
};
...
getMultiCapabilities: function() {
var browsers = this.params.browsers.split(',');
// Using lodash to select the keys in `capabilities` corresponding
// to the browsers param.
return _( capabilities )
.pick(browsers)
.values()
.value();
},
There are a couple of things you could try.
How can I use command line arguments in Angularjs Protractor? explains how to pass in a "params" variable, which if you were totally pro you could reference later in the config file, with the multiCapabilities section (maybe use a helper function or an if statement so you don't have to pass in a complex object from the command line). Not easy to do, but possible.
https://sourcegraph.com/github.com/teerapap/grunt-protractor-runner (see the Options section) is a utility that lets you pass in these things from the command line without any trouble. It's open-source and seems like it would be easy to mod if it doesn't quite meet your needs.
The easiest option, assuming you just need a couple of different options, would just be to use two different config files, "protractor.chrome.conf.js" and "protractor.firefox.conf.js" and run whichever one you need at the moment.
This is a reasonable request. I've created a PR for this here: https://github.com/angular/protractor/pull/1770. For now, you can patch this PR to your local protractor to use this feature.