Extending MediaSource with Babel -- how to properly call super()? - javascript

I'd like to extend MediaSource. I'm using Babel.
class BradMediaSource extends MediaSource {
constructor() {
super();
}
}
const source = new BradMediaSource();
In Chrome directly, this works fine. In a transpiled build done with Babel, I get the following error:
Uncaught TypeError: Failed to construct 'MediaSource': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
This seems similar to this GitHub issue: https://github.com/babel/babel/issues/1966 I have also tried the following package, but it doesn't seem to apply to my specific situation... makes no difference: https://www.npmjs.com/package/babel-plugin-transform-custom-element-classes
My .babelrc:
{ "presets": [ "es2015" ] }
Is there a way around this problem?

Generally extending builtin types does not work with compiled classes from Babel, so you'd need to configure Babel to not process classes, and limit your application to only browsers that support classes.
Assuming your target browsers all support ES6 class syntax, the easiest approach would be to use babel-preset-env configured for those target environments.
You can also try to use transform-builtin-extend in your Babel config for MediaSource, though that does tend to vary with exactly which things can be extended.

Related

Enable destructuring objects rest properties with Babel?

I noticed that Babel wasn't transforming this:
function({ param, ...rest }) {}
This syntax is already supported in the latest popular browsers. However, according to Mozilla (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), it's not supported in browsers as new as Edge 79 (released this year).
I tried manually enabling some Babel plugins, but it didn't work:
#babel/plugin-transform-destructuring
#babel/plugin-proposal-object-rest-spread
#babel/plugin-syntax-object-rest-spread
#babel/plugin-transform-parameters
Is it possible to transform this syntax with Babel? I need to do testing in older browsers, but I'm getting SyntaxError: invalid property id because of this.
Sometimes babel needs to combine more than one plugins to transform something. In this case I think you would need to combine at least 2 plugins:
#babel/plugin-transform-destructuring
#babel/plugin-transform-parameters
npx babel /path/to/yourFile plugins=#babel/plugin-transform-destructuring,#babel/plugin-transform-parameters
To make life easier, I would suggest to use preset-env instead which supports official ES changes (since it includes all official plugins for you):
npx babel /path/to/yourFile presets=#babel/preset-env

What "plugins" property in .eslintrc does?

module.exports = {
root: true,
parser: '#typescript-eslint/parser',
plugins: ['#typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:#typescript-eslint/recommended',
],
};
Whenever I add or remove this line: plugins: ['#typescript-eslint']
eslint seems to behave the same. What exactly plugins property does and when using it is required?
This question is pretty straight forward if you think about what a plugin is.
The docs don't really do a good job of just out-right saying what an ESLint plugin is, though if you read through the docs (https://eslint.org/docs/user-guide/configuring), then it's pretty trivial to figure out:
ESLint supports the use of third-party plugins
When using rules, environments or configs defined by plugins. Before using the plugin, you have to install it using npm.
So a plugin is a 3rd party module that can define rules, environments, or configs.
So to answer your question:
What exactly plugins property does [sic]
the plugins property tells ESLint what plugins you want to use
and when using it is required? [sic]
when you use something from a plugin, you must first tell ESLint about it with the plugins property.
Plugins seem to work anyway when this field is omitted
If you use the extends option with the syntax plugin:<plugin>/<config>, then ESLint will load a specific file from the plugin ahead of time.
Why? Because this allows a plugin to provide a config and reduce the amount of config you need. A plugin's config can provide the plugins option for you, meaning you don't need to do it yourself.
I was also curious about what is parser and plugin
From documentation
"For example, once this parser successfully produces an AST for the TypeScript source code, it might well contain some information which simply does not exist in a standard JavaScript context, such as the data for a TypeScript-specific construct, like an interface.
The core rules built into ESLint, such as indent have no knowledge of such constructs, so it is impossible to expect them to work out of the box with them.
Instead, you also need to make use of one more plugins which will add or extend rules with TypeScript-specific features."
This helped me to understand it better.

SAFARI : Unexpected token '='. Expected an opening '(' before a method's parameter list

Got this code, that works perfectly in all browsers but not in Safari (Version 11.1.2).
class Account {
accountFields = ['field1', 'field2', 'field3']
}
Getting the following error in Safari debugger:
Unexpected token '='. Expected an opening '(' before a method's
parameter list
So I tried to add () everywhere, around the array, before, after, etc. Nothing works.
You're using a relatively new feature known as public field declarations. It's currently supported by most modern browsers. However, the only Safari versions that support this feature are v14.1 (released April 26th, 2021) and higher. If you need to support older versions of Safari / a wider variety of older browsers you'll need to follow one of the suggestions below.
Instead of using public field declarations, you can use a constructor() method to define the properties for your class instances. Using a constructor does have good browser compatibility (for IE support you can use a constructor function):
class Account {
constructor() {
this.accountFields = ['field1', 'field2', 'field3'];
}
}
As pointed out in the comments by #Baz, you can also use Babel as an alternative solution. Using babel means that you won't have to change your code, which can make things easier on you if you're using public field declarations a lot throughout your project. Babel will transpile/compile your modern JS code into older (ES5 and below) JS code which can be understood by many browsers. You can use this babel plugin like so.
First, install the babel plugin:
npm install --save-dev #babel/plugin-proposal-class-properties
Then add the plugin to your configuration file:
{
"plugins": ["#babel/plugin-proposal-class-properties"]
}
For other installation options (babel CLI, etc), see the usage section of the plugin's docs.
I got a similar issue, in my case it was working with Safari on my Mac, but not on my iPad.
I was using deno and esbuild to build my bundle, I just changed added the --target=safari11 option to esbuild command.
I changed something like this
deno bundle entry.js | esbuild --minify > bundle.js
to this
deno bundle entry.js | esbuild --minify --target=safari11 > bundle.js

Class constructor PolymerElement cannot be invoked without 'new'

Yesterday my app worked perfectly however when I now do polymer serve -o it opens the app and prints this error in the console.
Class constructor PolymerElement cannot be invoked without 'new'
Clear the Cached files and images from your browser cache.
If you loaded custom-elements-es5-adapter.js, remove it.
Then use $ polymer serve --compile never.
According to this post, this issue is cause because $ polymer serve compiles your code to es5 automatically. The --compile never flag stops $ polymer serve from doing this.
I had a similar Error the other day after moving my Polymer App to v.2.
This helped me:
To work around this, load custom-elements-es5-adapter.js before
declaring new Custom Elements.
Since most projects need to
support a wide range of browsers that don't necessary support ES6, it
may make sense to compile your project to ES5. However, ES5-style
custom element classes will not work with native Custom Elements
because ES5-style classes cannot properly extend ES6 classes, like
HTMLElement.
I build my Polymer App as es5-bundled, and serve it to Android App using WebView.
This problem often appears.
In your polymer.json, add custom-elements-es5-adapter to the excludes array to stop it from being compiled to ES5.
"builds": [
{
"bundle": {
"stripComments": true,
"inlineCss": true,
"sourcemaps": false,
"excludes": [
"bower_components/webcomponentsjs/webcomponents-loader.js",
"bower_components/webcomponentsjs/custom-elements-es5-adapter.js"
]
},
"js": {
"compile": true,
"minify": true
},
"css": {
"minify": true
},
"html": {
"minify": true
},
"addServiceWorker": false
The problem occurs because Custom Elements v1 requires your code to use ES6 syntax. So make sure you don't transpile to anything lower, like ES5.
For anyone running into this using the Parcel bundler like me; by default it compiles your code to ES5 or something, even if you're using Typescript and you've set the tsconfig target to ES6.
The solution is to tell Parcel what browsers you're targeting, so that it knows it doesn't have to transpile to ES5. One way to do it is to add a "browserlist" field in package.json.
I found out about this through this video. For more info I suggest you go watch that.

How can i get Object.assign() to work in the browser when using 6to5?

I'm using the 6to5 transpiler. When I try to use Object.assign() in my code, I get the following error: Uncaught TypeError: Object.assign is not a function. How can I enable this functionality?
In the latest release, where 6to5 has been renamed to Babel, you no longer need to do this. You can either configure it to use a polyfill or load the runtime. This is how I have set it up in gulp:
browserify({debug : true})
.transform(
// We want to convert JSX to normal javascript
babelify.configure({
// load the runtime to be able to use Object.assign
optional: ["runtime"]
})
);
You configuration should be pretty similar, no matter what tool you use. Using the package standalone would look like this:
require("babel").transform("code", { optional: ["runtime"] });
You can look at the documentation for runtime. Remember to update to the latest version of babel, though! It updates very frequently.
You have to include the browser-polyfill.js file:
Available from the browser-polyfill.js file within the 6to5 directory of an npm release. This needs to be included before all your compiled 6to5 code. You can either prepend it to your compiled code or include it in a <script> before it.
NOTE: Do not require this via browserify etc, use 6to5/polyfill.
http://6to5.org/docs/usage/polyfill/

Categories

Resources