Trouble Transpiling startsWith() Using Babel and Rollup - javascript

I'm having unexpected trouble transpiling ES2015's startsWith using Rollup and Babel. I'm using babel-preset-env and have the following in my .babelrc:
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "not ie >= 10"]
},
"debug": true
}]
]
}
My rollup.config.js is set up to respect my .babelrc, and I'm seeing that it's correctly outputting in my debugging information that it's respecting my browser targets. Still, in my bundled JS, I'm seeing startsWith untouched, with no sight of a polyfill anywhere.
What might I be doing wrong?

Babel only transpiles syntax (like let/const, arrow functions, classes, etc.) and not API methods (like .startsWith() or .includes()).
For that, you'll need a polyfill, like babel-polyfill. However, if you only need the .startsWith function, a simpler polyfill will suffice. That, or you could simply make your own startsWith() function and use that.

Related

How can I use "exports" in package.json today for nested submodules and typescript

Latest Update (2022-06-06): TS 4.7 supports "exports"
tl;dr
// package.json
"type": "module"
// tsconfig.json
"module": "node12" // or "nodenext"
Update: TS 4.5 does not support "exports" (also see this issue):
... support for Node.js 12 has been deferred to a future release, and is now only available as an experimental flag in nightly releases. This was not an easy decision, but our team had a combination of concerns around ecosystem readiness and general guidance for how/when to use the feature.
[2022-04-01] The feature is still not available in TS 4.6.
Original question:
I am wanting to take advantage of the new-ish "exports" feature of NodeJS/package.json so that I can do the following:
"exports": {
".": "./dist/index.js",
"./foo": "./dist/path/to/foo.js"
}
And users can do the following:
import { foo } from 'my-package/foo';
Typescript 4.5 should support the "exports" field, yet it does not seem to work. I am building a simple package using TS 4.5.2, and I am consuming that package in a project using TS 4.5.2. I have looked at other SO questions and this github thread and this bug report but can't seem to find a consensus on the issue and whether it should work today.
Note 1: I am still able to import using the more verbose syntax:
import { foo } from 'my-package/dist/path/to/foo.js';
Note 2: I have also tried the object notation for exports, to no avail:
"exports": {
".": { "require": "./dist/index.js", "import": "./dist/index.js" },
"./foo": { "require": "./dist/path/to/foo.js", "import": "./dist/path/to/foo.js" }
}
Question(s):
Is this feature ready to be used with typescript projects today? If not, I just want to know.
If yes to #1, what am I missing? Specifics about tsconfig would be useful for both the source project and consuming project. The TS compiler complains about node12/nodenext being used for either the module or moduleResolution fields (I am definitely using TS 4.5.2).
I've been looking to use nested folders for a design system package we created at Pipefy, and after deep research, I found how to do it.
The package exports React components, and we use to import them like this import { Button } from '#mypackage/design-system;
Later on, we've added tokens to our design system library, like Colors, Spacing, and Fonts, but we don't want to import everything from the index, it isn't productive.
After some exhaustive research, I found how to export nested folders using TypeScript. My purpose is to use tokens like this import { Colors } from '#mypackage/design-system/tokens;
To use your TypeScript lib like this you should use the typesVersions inside the package.json file.
Here I use it like this
"typesVersions": {
"*": {
"index": [
"lib/components/index.d.ts"
],
"tokens": [
"lib/tokens/index.d.ts"
]
}
},
It worked like a charm for me, it would work for you too!
Without knowing what error you are getting, or in what other way TypeScript doesn't seem to be working for you (not sure why you would not want to share such crucial information), I can tell that your exports section appears to be missing types information. Typically, if your .d.ts files were located next to their respective .js files, your exports section would look like this:
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./foo": {
"types": "./dist/path/to/foo.d.ts",
"default": "./dist/path/to/foo.js"
}
}
I'm posting my own answer because there has been a lot of confusion around this topic.
NodeJS has supported exports since v12.7.0 (Jul. 2019)
When I asked this question (Dec. 2021), NodeJS had supported the exports field for nearly 2.5 years. It seemed reasonable to assume that Typescript supported it.
Typescript did not support the exports field when I asked this question.
When I asked this question (Dec. 2021), the exports field in package.json was not supported by the current version of Typescript at the time (v4.5). This was particularly confusing because the TS 4.5 beta announcement said that it would support the package.json exports.
Typescript 4.7 (Jun. 2022) finally supported package.json exports
After much testing and quite a bit of secrecy, typescript finally supported the exports field for package.json. Wine and whiskey were consumed with this announcement.
Using typesVersions in package.json is not the solution
Several people suggested using typesVersions - but thats a completely separate feature which is specific to typescript only (read more about it here). The exports field in package.json is supported by ANY npm package - typescript or not.
What you need in order for this to work
Your typescript project must be using TS v4.7 or later
Your tsconfig should be using moduleResolution: node, node16, or nodenext.
You don't have to set moduleResultion if you are using module with a value of CommonJS, ES2015, ES6, ES2020, or ESNEXT
TypeScript only respects export maps in package.json if you use "moduleResolution": "NodeNext"(or "Node16") instead of the widespread "moduleResolution": "Node". (I guess "moduleResolution" defaults to the same value as "module", but it's hard to find documentation of this?
See: https://www.typescriptlang.org/docs/handbook/esm-node.html
However a number of TS libraries out there (including many of Microsoft's own) have errors with "moduleResolution": "NodeNext" right now because of things like relative imports without explicit file extensions.

SCRIPT1003: Expected ':' on IE ~ Vue.js ~ MDBootstrap

I have a simple Vue.js application which works perfectly on other browsers than IE, which shows a blank page with an error SCRIPT1003: Expected ':'. I have added a vue.config.js file which looks like that:
module.exports = {
transpileDependencies: ["bootstrap-css-only", "mdbvue"]
};
My .babelrc file is a default one taken from the official project starting page, this is:
{
"presets": [
[
"env",
{
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}
],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}
In my main.js file I tried 2 approaches:
import "core-js/stable";
import "regenerator-runtime/runtime";
and
import "#babel/polyfill";
Both didn't change anything and the error and behaviour is the same. The only one thing which still comes to my mind to solve this problem is mentioned here, i.e. in export default I'm using the following syntax for component:
components: {
mdbContainer,
mdbRow,
mdbCol,
mdbCard,
mdbCardBody,
mdbInput,
mdbBtn,
mdbIcon,
mdbModalFooter,
mdbView
}
Edit2: But if I'll drop this lines then all my UI elements from MDBootstrap are gone. Is there any other way to use it? I wanted simply to use polyfills.
I tried to create babel.config.js file, but also didn't help. The logic in this file is like that:
module.exports = {
presets: [["#vue/app", { useBuiltIns: "entry" }]]
};
Is there anything I'm missing? What I understood the vue.config.js file doesn't has to be imported anywhere, because vue.config.js is an optional config file that will be automatically loaded by #vue/cli-service. Here are my questions:
Any ideas what can be wrong?
Shall I have babel.config.js and .babelrc or only one of these?
Is babel.config.js file automatically detected like vue.config.js?
[Edit] Maybe something in webpack configuration should be changed?
Vue CLI version:
$ vue --version
3.11.0
I had a similar issue. I recreated the project using vue-cli 4 and left all the defaults alone.I did not reference babel or core-js in my main.js. I looked at the console error in IE to see which library was causing the script error,( lets call it some-imported-lib ). Then I added that library in vue.config.js as follows
transpileDependencies:['some-imported-lib']
The problem is that IE11 doesn't support shorthand property notation, but you're using that in your components list. Your .babelrc isn't set to ensure that the resulting code can run on IE11.
You'll want to review the browserlist documentation to fine-tune your browsers setting, but for instance adding IE 11 to it will ensure that the transpiled code has all the transforms required to run on IE11.
Note that IE11 basically doesn't support anything in ES2015+. (It has const and a broken version of let, but that's basically it.) So doing this will effectively transpile all your code to ES5 levels. You may want to serve different bundles to IE and to other, more modern browsers.

Babel / Rollup errors transpiling and bundling ES2017

I'm getting an error transpiling ES2017 JavaScript (specifically async/await functions) into ES5 using Rollup and Babel:
Error transforming \src\index.js with 'babel' plugin: Options
{"modules":false} passed to
\node_modules\babel-preset-es2017\lib\index.js which does not accept
options.
My .babelrc file:
{
"presets": [
"es2017"
],
"plugins": [
"transform-runtime"
],
"comments": false
}
Naturally, the error goes away if I change the presets from es2017 to es2015 and comment out the async/await code.
Note that while the application uses ES2017 features (i.e. async/await), it is published as an NPM package (as an ES6 (ES2015) module) that is later transpiled to generic ES5 (ES2009).
How do I get past this error and get my ES2017 happily transpiling to ES5?
It seems that the actual configuration you provided is:
{
"presets": [
"es2017", {modules: false}
],
"plugins": [
"transform-runtime"
],
"comments": false
}
You should remove the {modules: false} option for babel-preset-es2017, which accepts none, as it applies to babel-preset-es2015.
Target es2015 in your .babelrc file:
"presets": [
"es2015"
],
and preprocess the es2017 features by first adding the Rollup Async functions plugin, which:
replaces async functions with generator functions that can run in
modern browsers or in most versions of node.js during bundling
Add to your project:
npm install --save-dev rollup-plugin-async
And then insert async preprocessing to your rollup.config.js plugins array, before babel():
import async from 'rollup-plugin-async';
...
plugins: [
async(),
babel(babelrc())
],
The key insight was found in this Rollup Github issues thread, wherein #Victorystick confirms that (as of Oct 10, 2016):
Rollup currently only targets ES6, although it'll likely get extended
to ES7 shortly. For now, if you use >ES6 features, they'll need to be
transpiled for Rollup to process them
As async/await are likely to be standardized in the next version of ECMAScript, ES2017 (aka ES8), you'll need an extra plugin to process them before Babel runs.
NOTE:
YMMV, but I later received AsyncHelper not found run time Errors using rollup-plugin-async on Windows 7, so my solution was to (npm uninstall --save-dev rollup-plugin-async and) rollback use of async/await in favor of ES6 Promises throughout my codebase.

Babel 6 react JSX transformer - disable strict

Issue
I'm using babel 6 for react JSX transforms. However I'm not using the react preset, I am ONLY using the 'transform-react-jsx' plugin (and trying strict-mode disable option), here is my .babelrc
{
"plugins": [
["transform-react-jsx"]
],
"sourceMaps": true,
"strictMode": false
}
However I have required a thirdparty javascript that uses 'with' (out of my control) which emits following error:
[SyntaxError: foo.js: 'with' in strict mode .. ]
So I need to disable strict mode, This is same problem as this issue however I am NOT using es6/es2015 stuff, only jsx transforms.
With babel 6 there is no blacklist and I've only specified ONE plugin, so I'm suspect there is no way to disable.
According to this line, the strictMode option is indeed parsed.
I don't understand the syntax you used for your .babelrc, though. Why an array?
Try this:
{
"plugins": [
["transform-react-jsx"]
],
"sourceMaps": true,
"strictMode": false
}
transform-strict-mode is used only to include the strict mode not to disable it. So setting it to false ["transform-strict-mode", {"strict": false}] will change nothing, in your case better remove this plug-in then including it.
But if somewhere else you are using a plugin or preset that includes the strict mode, try maybe to use es2015-loose :
install
npm install --save-dev babel-preset-es2015-loose babel-preset-es2015
config
{"presets": ["es2015-loose"]}

syntastic complaining about ES6 module syntax

I love syntastic for javascript but I am using the new ES6 module tranpiler and syntastic is not happy about these type of statements:
import Typeahead from './lib/components/ember-typeahead';
Is there anyway that I can keep syntastic quiet about this type of statement?
Syntastic will use JSHint to check JavaScript syntax if it's available (which I recommend over jslint).
JSHint supports es6 syntax with the esnext flag, which includes support for the export and import module syntax.
I suggest adding a .jshintrc file to your project to control JSHint's behavior (and thus Syntastic's) for your entire project:
{
"esnext": true
}
Note: be careful, since using the esnext flag will add support for all of es6's new language sytax that JSHint currently supports, not just the module syntax.
Note: esnext has now been deprecated in favour of the esversion syntax.
{
"esversion": 6
}
To work around this, I'd suggest the following steps as recommended here: Configure Vim for React:
Install eslint and babel-eslint:
npm install -g eslint babel-eslint
Create a local .eslintrc config in your project or a global ~/.eslintrc configuration:
{
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true
},
"settings": {
"ecmascript": 6
},
"rules": {
"strict": 0 // you can add more rules if you want
}
}
Finally, configure syntastic to use eslint:
let g:syntastic_javascript_checkers = ['eslint']

Categories