Parceljs 2 and transpiling a node module - babeljs

I am using Parcel version 2 to build my JavaScript app, and one of the modules in node_modules is CommonJS but uses "let" and "const" keywords, so I need to transpile it so it is compatible with IE 11, which we are still supporting for a few more months.
By default parceljs does not transpile code in node_modules, somehow expecting that package developers will know which browsers their users are targeting and provide ready-to-use code. I have read that parcel 2 is honors babel configuration files, and I have created one, but that alone does not tell it to transpile the code from node_modules. I do not need to transpile all the node_modules code, but apparently just the one module. Here is my .babelrc.json, which it seems to be looking at because I get some warnings about the use of parcel-env which I build:
{
"presets": [
["#babel/preset-env", {
"targets": "IE 11, last 2 versions"
}]
]
}
What other configuration am I missing to get to transpile either all of node_modules or a particular module?
Note: Other posts I have found around this topic were for version 1 of Parcel, and there were hints that there would be better options in version 2.

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.

Polymer build with custom babel plugins?

We'd like to be able to add custom functionality to polymer build and polymer serve by configuring custom babel plugins.
For example, since polymer-cli uses babel internally, we would add a babel.config.js file to our workspace/project-root, e.g.:
module.exports = function (api) {
api.cache(true);
const presets = [ ];
const plugins = [
"#babel/plugin-proposal-optional-chaining"
];
return {
presets,
plugins
};
}
...and then we could serve or build our project with support for optional-chaining, etc This would allow us to do all sorts of things by writing additional babel plugins to handle stuff like minification inside template HTML strings...
Unfortunately, this doesn't currently work. polymer-build seems to load the configuration (due to its use of babel/core?), but polymer-analyze doesn't. An error is generated in the build-optimization step performed by polymer-analyze as soon as it encounters optional-chaining syntax in our source:
error: Error: Unable to get document file:///.../somefile.js: This experimental syntax requires enabling the parser plugin:
'optionalChaining' (423:6)
at BuildAnalyzer.<anonymous> (/usr/local/share/.config/yarn/global/node_modules/polymer-build/lib/analyzer.js:342:23)
at Generator.next (<anonymous>)
at fulfilled (/usr/local/share/.config/yarn/global/node_modules/polymer-build/lib/analyzer.js:17:58)
at process._tickCallback (internal/process/next_tick.js:68:7)
polymer serve also generates an error:
Error { SyntaxError: This experimental syntax requires enabling the parser plugin: 'optionalChaining' (423:6)
at Parser.raise (/usr/local/share/.config/yarn/global/node_modules/babylon/lib/index.js:776:15)
at Parser.expectPlugin (/usr/local/share/.config/yarn/global/node_modules/babylon/lib/index.js:2084:18)
...
pos: 13056, loc: Position { line: 423, column: 6 },
missingPlugin: [ 'optionalChaining' ] }
In both cases, I've confirmed that the babel.config.js file is being loaded. But babel is included by several different packages used in polymer-cli, so my suspicion is that in some of them, babel is being used without (babel/core having loaded) configuration info.
Can anyone involved with the polymer project confirm whether I'm correct in identifying the main issue? I'm looking into the possibility of contributing a fix/enhancement if the scope isn't too large.
Thanks.
I think for this you need to write your own custom build. Polymer-cli will provide its tool also for this. Have a look at this example:
https://github.com/PolymerElements/generator-polymer-init-custom-build
For us, this issue was preventing us from using modern JS language features (like optional chaining and the nullish coalescing operator) which have wide support in modern browsers.
The only solution we could come up with was forking the Polymer tools monorepo and adding in support for the appropriate Babel plugins ourselves.
The file in question is /packages/build/src/js-transform.ts. Both serve and build use this file for Babel transforms. We switched to using Rollup for our build process, but we still needed a development server and couldn't get any others to work, so we forked the repo and built our own version of the standalone polyserve package. Would love to some day switch to Modern Web's #web/dev-server.

Babel: root programmatic options

I seem to absolutely not grasp where to put root programmatic options for the babel.
If I have a monorepo and need to tell the different sub packages that they shall look upwards for my babel.config.js then I should put rootMode: "upwards" into the .babelrc of the sub packages, correct? This does not work, because of the resulting error
Error: .rootMode is only allowed in root programmatic options
Somehow I simply can't find any example of where to put/use root programmatic options... Can anyone point me to the right direction?
If you are using Webpack, you need to put it there.
module: {
[..]
rules: [
// Transpile ES6 Javascript into ES5 with babel loader
{
test: /\.jsx?$/,
exclude: [/node_modules/, /json/],
loader: 'babel-loader',
options: {
rootMode: 'upward'
},
},
[..]
],
[..]
},
Otherwise I had the same issue than you, I can't put it in the package.json file using the key babel.
Any API-related options are called programmatic options. Take a look at my discussion with the primary maintainer of Babel: https://github.com/babel/babel/discussions/14405.
It's when you specify them directly to Babel (babel.transformSync(code, programmaticOptions) or to the Babel integration you are using (e.g. babel-loader, which can pass them to its internal babel.transform call). In other words, not in presets or config files. [...]
by #nicolo-ribaudo - Babel core team.
I got this error using my (probably non-standard) monorepo setup where I have top-level subdirectories for each of my packages. No top-level package. When I upgraded to Babel 7, my Jest tests were no longer transforming packages that were yarn linked into the package where I was running Jest.
I added a top-level babel.config.js as part of Babel's monorepo instructions. I had rootMode: "upwards" in these three places:
ui-package/webpack.config.js for transforming the app.
ui-package/babel-jest.js for the tests, where it appeared like:
module.exports = require("babel-jest").createTransformer({
rootMode: "upward",
})
and was referenced from jest.config.js in that same dir like:
transform: {
"^.+\\.jsx?$": "./babel-jest.js",
},
And in /babel.config.js, the newly added top-level babel conf file.
Removing it from the last one removed the error.

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.

React Serverside rendering Unexpected token, JSX and Babel

I'm having trouble finding the correct way to use babel to allow me to use jsx in serverside.
Node-jsx was deprecated for babel. It seems like babel-core/register is whats supposed to be used but I still get unexpected token issues.
I created a repo with the problem im having.
https://github.com/pk1m/Stackoverflow-helpme
When I run node app or npm run watch-js I keep getting unexpected token referring to the JSX code '<'.
How do I get babel to transpile JSX, or am I completely off, thanks.
You need to use babel-register (npm i babel-register --save). And run on your server:
require('babel-register')({
stage: 0
});
You can omit stage 0 if you aren't using experimental babel features. Also you might prefer to put those options in .babelrc instead.
Note that it will only work for files required AFTER calling that (so it would not have an effect on the file you include it in).
You could also have the presets and other options in a .babelrc file.
For babel 6x:
npm i babel-register babel-preset-es2015 babel-preset-react --save
require('babel-register')({
presets: ['es2015', 'react']
});
Note: there are also stage 0-2 presets.
For watching as you've written in your package.json you could try a CLI command like the one facebook are suggesting in the note here (or use webpack):
babel --presets react es2015 --watch app/ --out-dir build/