I am a bit lost in the Babel options / config. I want to use recent js features and compile (with webpack) to browser code.
What is the difference between babel-polyfill and babel plugins with babel-preset-env?
Are they intended to work together?
Answer from this article:
The distinction between a babel transform plugin versus
babel-polyfill / babel-runtime is whether or not you can
reimplement the feature today, in ES5. For example, Array.from can
be rewritten in ES5 but there is nothing I can write in ES5 to add
arrow function syntax to JavaScript. Therefore, there is a transform
for arrow functions but none for Array.from. It will have to be
provided by a separate polyfill like babel-polyfill, or
babel-runtime.
As a side note, here is my current understanding of the babel eco-system.
Babel is a javascript compiler: it parses, transforms and outputs transformed code.
babel-core
This is the parse and output parts.
It does not do any transformation.
It can be used from the command line or from a bundler (webpack, rollup and co.)
babel-polyfill / babel-runtime
Acts on the transform part by prepending es5 javascript to your code to emulate es2015+ functions (like Object.assign).
Relies on Regenerator (to polyfill generators) and core-js (to polyfill all the rest).
Difference between babel-polyfill and babel-runtime: the former defines global methods (and pollutes the global scope) whereas the latter transforms your code to make the same functionnality available as explained in this answer.
babel plugins
Transform the code you wrote.
babel syntax / transform plugins: parse and transform es2015+ syntax (like arrow functions) to convert it to es5.
babel-plugins-stage-x (from stage-0 to stage-4): transform future javascript syntax which is not in the JS specs yet, starting at stage-0 (just an idea) down to stage-4 (will land in the babel-plugins soon).
babel-preset-env
babel-preset-env determines the Babel plugins and polyfills needed for a specific environment.
With no configuration, it will load all the plugins (including es2015, es2016 and es2017) required to transpile es2015+ to es5.
With a target option, it loads only the plugins required to run on a specific target.
With the builtIn option, it uses only the babel-polyfill which are not built-in the target.
Does not work with babel-transform-runtime yet (as of nov. 2017). (see this issue)
babel-preset-env is a Babel preset meant to automatically set up babel plugins and include the necessary babel polyfills based on a set of target environments checked against a feature compatibility table.
In order to make a fully working ES2015+ environment run on a non-ES2015+ client, simple code transpilation is sometimes not enough:
ES generators are enabled using regenerator library (provided by babel-polyfill)
Missing ES2015+ methods (like Promise, Map, Object.assign...) are polyfilled with core-js (provided by babel-polyfill, too)
Any other transpilable feature is generated by standard babel plugins, often used trough pre-configured babel-presets
So, back to your question, it's babel-preset-env that makes use of babel-polyfill and babel plugins.
Related
I'm using rollup with the Babel and CommonJS plugins, like this:
const inputOptions = {
input: "...",
plugins: [
resolve(),
babel({
exclude: "node_modules/**",
externalHelpers: true,
include: "**/components/**/*.js",
}),
commonjs(),
],
};
But what happens is that modules referenced from components don't seem to be recognized by the CommonJS plugin, they end up as plain require(...) statements in the output (just like the source input) where of course they cannot be resolved. Modules imported (also through require() statements) by modules outside the components directory get picked up properly and included in the bundle.
I have tried moving the babel plugin up (before the resolve plugin), but this had no effect. I also tried moving it down, but then Rollup chokes on the JSX in the components.
I also tried removing the include option, so that all files go through Babel and then the result is that no modules get picked up besides the entry point, so it really seems like the Babel and CommonJS plugins aren't playing along nicely, though I can hardly imagine I'm the only one with a setup like this. Am I missing something?
Update: One other thing that I notice is that the files for which the requires() aren't recognized, aren't properly exported either. Instead, for each component that fails, I see this in the output bundle:
module.exports = ComponentName;
var componentName = /*#__PURE__*/Object.freeze({
});
The module.exports line comes from the source, but that Object.freeze() statement is something rollup adds, maybe because it doesn't see any default export?
To add a bit of extra confusion: There's actually one component that gets transpiled by Babel and for which the module resolution works and the requires() get replaced like you'd expect, but all the components included from that component in turn have the defective behavior described above.
Update 2: I have been able to reproduce the problem in a minimal example as well, and it allowed me to pinpoint why things worked for the one component, but not by the components it includes in turn. Apparently, functional React components work properly, but class components trigger the issue. So now my hypothesis is that the Babel transform for ES6 classes somehow confuses the CommonJS plugin.
Update 3: As I believe this is a bug, I have also created issues with the relevant projects: https://github.com/rollup/rollup-plugin-babel/issues/297 and https://github.com/rollup/rollup-plugin-commonjs/issues/369
babel-preset-env allows to automatically determine the needed polyfills and transformation but how does it check at runtime if the target versions specified at compile time are really available.
Let say I target safari 10 using
"targets": {
"safari": 10
}
but the code is run on an older version of safari.
How does babel-preset-env recognize this or what are the typical ways to deal with this common problem?
babel-preset-env does not carry out any runtime checks. It enables only the transforms that are required for your specified environment. You're effectively setting your minimum supported environment, and opting out of any transforms that would be required to support lower versions.
For example, if all of the browser versions specified in my config supported ES2015 classes, Babel would not transform classes into an ES5-supported form, since it's not necessary to do so!
While using ReasonML and Bucklescript, is it possible to configure Bucklescript so it won't generate export statements? I'd prefer if the generated code could be used as is in a browser, that is, being ES5 (or ES6) compatible.
Edit: OK, while trying out the tool chain a bit more, I realize just turning off the export is not enough. See example below:
function foo(x, y) {
return x + y | 0;
}
var Test = /* module */[
/* foo */foo
];
exports.Test = Test;
This code will pollute global namespace if exports is removed, and is simply broken from an ES5 compatibility viewpoint.
Edit 2: Reading on Bucklescript's blog, this seems not possible:
one OCaml module compiled into one JavaScript module (AMDJS, CommonJS, or Google module) without name mangling.
Source.
BuckleScript can output modules in a number of different module formats, which can then be bundled up along with their dependencies using a bundler such as webpack or rollup. The output is not really intended to be used as a stand-alone unit, since you'd be rather limited in what you could do in any case, as the standard and runtime libraries are separate modules. And even something as trivial as multiplication will involve the runtime library.
You can configure BuckleScript to output es6 modules, which can be run directly in the browser as long as your browser supports it. But that would still require manually extracting the standard and runtime libraries from your bs-platform installation.
The module format is configured through the package-specs property in bsconfig.json:
{
...
"packages-specs": ["es6-global"] /* Or "es6" */
}
Having said all that, you actually can turn off exports by putting [###bs.config { no_export }] at the top of the file. But this is undocumented since it's of very limited use in practice, for the above mentioned reasons.
What is a babel preset and why do I need it?
There are several questions about specific babel presets but none explain the need for it (e.g. what's the difference between babel-preset-stage-0, babel-preset-stage-1 etc)
Also the babel docs do not explain the necessity: https://babeljs.io/docs/plugins/preset-latest/
Babel Presets:
Technically presets are collections of plugins (as Quentin says)
The usecase is the support of particular language features.
Read this excellent post: https://www.fullstackreact.com/articles/what-are-babel-plugins-and-presets
A preset is a set of plugins used to support particular language features.
The two presets Babel uses by default:
es2015: Adds support for ES2015 (or ES6) JavaScript
react: Adds support for JSX
... ES2015 is just another name used for ES6 ... [1]
Preset stages:
Stages represent the status of experimental features. Pre stage-3 should be used with caution.
... Beyond ES7, proposed JavaScript features can exist in various stages: [1]
stage-0 - Strawman: just an idea, possible Babel plugin.
stage-1 - Proposal: this is worth working on.
stage-2 - Draft: initial spec.
stage-3 - Candidate: complete spec and initial browser implementations.
stage-4 - Finished: will be added to the next yearly release. [2]
[1] https://www.fullstackreact.com/articles/what-are-babel-plugins-and-presets
[2] https://babeljs.io/docs/plugins/
From the docs:
Presets are sharable .babelrc configs or simply an array of babel plugins.
Babel is a tool for transforming JS.
A plugin a some code for performing a particular transformation.
You have to specify which plugins you want to use with a config.
A preset is just a prewritten config you can use to get common sets of transforms.
A fairly common method of configuration for Haskell applications is having the program as a library, with a main function provided with a bunch of optional parameters for configuration. Upon being run, the executable itself looks for a dotfile containing a main function using this default function, which it then compiles and run instead. This sort of configuration scheme allows the user to add arbitrarily complex functionality without recompiling the entire program. Examples of this are the Dyre library and the XMonad window manager. How can this be done in Scala cleanly? It appears that SBT does something similarly internally.
Using SBT externally would require having the sources of the whole program somewhere, and lacks the cleanliness of just having a single dotfile. Typesafe config, Configrity, Bee Config, and fig all seem to only be meant for normal string based configuration.
https://github.com/typesafehub/config is a great config library.
supports files in three formats: Java properties, JSON, and a human-friendly JSON superset