Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught TypeError: Class constructor LitElement cannot be invoked without 'new' #54

Closed
rjcorwin opened this issue May 11, 2018 · 60 comments
Assignees

Comments

@rjcorwin
Copy link

I'm trying out Lit Element in a vanilla Angular 6 project and running into Uncaught TypeError: Class constructor LitElement cannot be invoked without 'new' when trying out the hello world lit element example. This commit shows how I added webcomponentjs / litelement packages, allow custom schema in angular, declare the my-element LitElement example, and then use that element in the app. That commit was made right after running the ng new command.

screen shot 2018-05-11 at 3 33 16 pm

If you want to poke at it, run the following commands...

git clone https://github.com/rjsteinert/angular-with-lit-element.git
cd angular-with-list-element
npm install
npm start
@jsilvermist
Copy link

Is it being compiled to es5 without adding the custom-elements-es5-adapter.js file?

@rjcorwin
Copy link
Author

@jsilvermist Good idea! Unfortunately, after adding it the same error persists.

@TimvdLippe
Copy link
Contributor

@rjsteinert The imports you specified are not loaded at all. E.g. the webcomponents-loader as well as the adapter are never actually executed. You can see this by opening the website in Firefox, it will break.

Now, I tried to add the loader and adapter to index.html, but your node_modules/ are not in src/, so I was unable to load them via a script tag. I don't think the loader is compatible with ES modules. It has to be loaded via script tag.

@rjcorwin
Copy link
Author

@TimvdLippe I found a ticket relared to ES modules in the webcomponentjs issue queue webcomponents/webcomponentsjs#882

This not working in Firefox is definitely a concern and as you said related to the polyfills not loading. Does Chrome need the polyfills to make this work? I'm assuming not, and if that's the case then I wonder what is up with this error Class constructor LitElement cannot be invoked without 'new'.

@TimvdLippe
Copy link
Contributor

@rjsteinert Chrome does not need the polyfill, but does require the adapter to be loaded. When I ran your project, I did not see the adapter being loaded. Therefore it would break in Chrome, as Chrome requires the adapter to be loaded if you define your custom elements in ES5.

@hfjallemark
Copy link

I'm getting the same error with the custom-elements-es5-adapter script loaded. I am trying to get lit-element working with Elm:

screen shot 2018-05-17 at 07 09 07

@NicolasRannou
Copy link

Same behavior with create-react-app.

index.html:

<head>
  <script src="./webcomponents-bundle.js"></script>
</head>
...

App.js:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import {LitElement, html} from '@polymer/lit-element';

class MyElement extends LitElement {

  static get properties() { return { mood: String }}

  _render({mood}) {
    return html`<style> .mood { color: green; } </style>
      Web Components are <span class="mood">${mood}</span>!`;
  }

}

customElements.define('my-element', MyElement);

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <my-element/>
      </div>
    );
  }
}

export default App;

@moebiusmania
Copy link

same here,
building a pure vanilla/lit-element project, transpiled with Babel 6 (with preset env defaults) adding the custom-elements-es5-adapter before the polyfill results in:

Uncaught TypeError: Class constructor LitElement cannot be invoked without 'new'

it seems like the adapter is not... adapting.

I'm also using code-splitting via Webpack but trying to going back to single-bundle-file didn't changed the result.

any clue about this?
thanks

@sorvell sorvell assigned dfreedm and TimvdLippe and unassigned dfreedm Jun 8, 2018
@web-padawan
Copy link
Contributor

Related to Polymer/tools#398

@thosakwe
Copy link

From what I can tell, the issue is years-old in Babel, and is a bug preventing the usage of extended native classes without new. So not really sure if this is a Polymer problem, so much as Babel.

@dkundel
Copy link

dkundel commented Jun 12, 2018

Hey @rjsteinert,

do you need it to be downtranspiled to ES5? I changed my tsconfig.json to target ES2015 and then using the polyfill without the adapter works. You can see an example here: dkundel/vote-my-talk@8b7f29a

Cheeers,
Dominik

@jkga
Copy link

jkga commented Jun 12, 2018

I experienced the same error when transpiling using webpack and babel-preset-env.
And after a few hours of trying, using es2017 works for me.

npm install --save-dev babel-preset-es2017

then change the option in your webpack configuration to es2017

options: {
   presets: ['es2017']
}

or in .babelrc

{
  "presets": ["es2017"]
}

@web-padawan
Copy link
Contributor

Fixed with babel/babel#8501 and included in Babel 7 release, so the issue can be closed.
See https://github.com/web-padawan/polymer3-webpack-starter for proper config.

@rjcorwin
Copy link
Author

rjcorwin commented Sep 4, 2018

@dkundel Changing Agnular's tsconfig.json target property to es2015 did the trick for Chrome, however Firefox has a strange error white screen of death now. Perhaps the babel fix that @web-padawan mentioned will make it into an angular-cli release sometime soon and all our problems will be solved? I was trying this on a fresh angular-cli install/fresh project.

@ernsheong
Copy link
Contributor

What is the real resolution to this? So much confusion across the issues.

@thosakwe
Copy link

I’m assuming the new Babel update will fix this.

Waiting on support Babel 7 in Parcel, haha. Until then, I guess you could use Webpack?

@ernsheong
Copy link
Contributor

I am already on Webpack actually :/

@web-padawan
Copy link
Contributor

The 7.0.0 stable release of Babel works properly as I mentioned above. You can also find a config example here: https://github.com/web-padawan/lit-components

@ernsheong
Copy link
Contributor

Thanks @web-padawan, that was helpful. I wasn't willing to let go of "preset-env" just yet.

In summary, the issue is... ES6 classes must only be called with new on instantiation. Transpiling to ES5 will not solve this issue. So one must also include custom-elements-es5-adapter.js somewhere to resolve that.

A suggested strategy is to have separate babel builds:

  1. Targets modern browsers with ES6 class support (e.g. { targets: { chrome: 60 }})
  2. Targets IE11 with ES5 support + custom-elements-es5-adapter.js

Then in production server needs to figure out whether to serve 1 or 2, which is admittedly more complexity. (Or just tell your customers to download Chrome)

For now I'll go with 1 and configure 2 later.

@Westbrook
Copy link
Contributor

@ernsheong if you’re interested in a world that combines 1 and 2 while making sure that users on each side get the best code for them, you might be interested in something like https://philipwalton.com/articles/deploying-es2015-code-in-production-today/ It’s looking really good for the applications I’m working on, which use polymer build to output multiple builds, but the webpack approach in the blog post looks useful if you’re into it and should be portable in some way to Rollup, etc as needed, not that I know that from experience.

@ernsheong
Copy link
Contributor

@Westbrook thanks for sharing the article, definitely looks promising (and more doable)! I like this other article from the same author too: https://philipwalton.com/articles/loading-polyfills-only-when-needed/ (from which I got the idea of punishing older browsers rather than newer ones)

@tonai
Copy link

tonai commented Nov 16, 2018

Hi,
I'm trying to display LitElement components using storybook.

  • the project has been initialized using the pwa-starter-kit.
  • then I have installed @storybook/html (v4.0.7) and babel-loader (v8.0.4)
  • and I have created a simple story using the counter-element component that exists in the pwa-starter-kit:
import { storiesOf } from '@storybook/html';

import './counter-element';

storiesOf('CounterElement', module)
  .add('default', () => `<counter-element clicks="3" 1alue="1"></counter-element>`);

But then I got the error Class constructor LitElement cannot be invoked without 'new' when trying to display the component.
I have read the discussion above, but I don't know I still got that issue.
Does someone know what is missing ?
(I haven't load the polyfills since I'm testing on Chrome 69)

@moebiusmania
Copy link

moebiusmania commented Nov 16, 2018

@tonai I'm using LitElement & Storybook with @storybook/polymer and it's going fine, had some issue with LitElement and @storybook/html.

@tonai
Copy link

tonai commented Nov 16, 2018

@moebiusmania What version of @storybook/polymer do you use ?

I just switch my above story using @storybook/polymer (v4.0.7) and still have the same issue.

My storybook config file .storybook/config.js looks like this:

import { configure } from '@storybook/polymer';

const req = require.context('../src', true, /\.stories\.js$/);
function loadStories() {
  req.keys().forEach((filename) => req(filename))
}
configure(loadStories, module);

I also tried to initialize the storybook using the cli npx -p @storybook/cli sb init but still the same error...

@moebiusmania
Copy link

@tonai 4.0.2, you can check it out here https://github.com/bitrockteam/amber-components , hope it helps.

@jennasalau
Copy link

If you are seeing this error, you are likely in need of two important babel plugins. Additionally if you have ES6 code inside node_modules you MUST include them in your babel loader. LitElement library itself is ES6.

I was having this issue with Gatsby. Gatsby 2 by default includes code from all node_modules so all I had to do was

Install these modules and add this to my .babelrc, the order is important.

"plugins": [
	["@babel/plugin-proposal-class-properties", { "loose": true }],
	["@babel/plugin-transform-classes", {"loose": true}]
]

For Gatsby, I did this by following the instructions at https://www.gatsbyjs.org/docs/babel/#how-to-use-a-custom-babelrc-file

@ghost
Copy link

ghost commented Jul 31, 2019

To anyone else that ends up here, lit-element is distributed as es2015 so you must transpile it to es5 as part of your build process. If you're using Webpack add the following to your JavaScript rule:

{
  include: [
    // These packages are distributed as es2015 modules, therefore they need
    // to be transpiled to es5.
    /node_modules(?:\/|\\)lit-element|lit-html/
  ]
}

It solves the problem for me, but for some reason it prevents arrow functions from being transpiled. In other words, arrow syntax is not replaced neither in lit-element package nor in my app code.

Here's a snippet from package.json

    "@babel/core": "^7.4.3",
    "@babel/preset-env": "^7.4.3",
    "babel-loader": "^8.0.5",

@mihaisavezi
Copy link

If you are seeing this error, you are likely in need of two important babel plugins. Additionally if you have ES6 code inside node_modules you MUST include them in your babel loader. LitElement library itself is ES6.

I was having this issue with Gatsby. Gatsby 2 by default includes code from all node_modules so all I had to do was

Install these modules and add this to my .babelrc, the order is important.

"plugins": [
	["@babel/plugin-proposal-class-properties", { "loose": true }],
	["@babel/plugin-transform-classes", {"loose": true}]
]

For Gatsby, I did this by following the instructions at https://www.gatsbyjs.org/docs/babel/#how-to-use-a-custom-babelrc-file

THIS works, and the problem happens even on Chrome 75. So I don't see why this isn't included by default.

@justinfagnani
Copy link
Contributor

@mihaisavezi Included where by default?

@n-devr
Copy link

n-devr commented Oct 24, 2019

Has anyone solved this issue yet?

I have tried everything in this thread and I'm still seeing this error in Chrome if I transpile my LitElements down to ES5 even when the custom-elements-es5-adapter.js is loaded.

I tried @Manidos 's Webpack config:

{
  include: [
    // These packages are distributed as es2015 modules, therefore they need
    // to be transpiled to es5.
    /node_modules(?:\/|\\)lit-element|lit-html/
  ]
}

and the error goes away in Chrome. But upon further inspection I believe that's because the include statement means the only things that will be transpiled are lit-element and lit-html within node_modules. This means that none of the actual LitElement component definitions within my application are transpiled, thus they work just fine in Chrome.

If you rewrite the config to the following:
exclude: /node_modules\/(?!(lit-element|lit-html)\/).*/
it will exclude all node modules except lit-element and lit-html. In this case, the LitElement component definitions in the app are still transpiled, and the error persists.

I have tried including the es5-adapter in JavaScript as an import in my webpack entry file as well as in my HTML as a script tag but it doesn't seem like the adapter works at all. I know the adapter is being loaded because when I inspect the HTMLElement property of window I see that it has been modified:
image

@web-padawan do you think this is a Babel issue again?

I am using the following config:

"devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/preset-env": "^7.6.3",
    "babel-loader": "^8.0.6",
    "webpack": "^4.41.1",
    "webpack-cli": "^3.3.9"
  }

and my .babelrc is as follows:

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "corejs": 3,
                "debug": true
            }
        ]
    ]
}

Any guidance would be greatly appreciated. I have enjoyed my experience with LitElement so far and would really like to adopt it into some of my projects. I am currently just excluding the LitElements from my babel-loader in order to continue building, but I would love to put this issue to bed because at some point I will need to properly support IE11.

@web-padawan
Copy link
Contributor

@n-devr consider using webpack-babel-multi-target-plugin which outputs ES module bundle + ES5 "nomodule" bundle for legacy browsers. We are using it and it works nice.

@n-devr
Copy link

n-devr commented Oct 25, 2019

Thanks for your reply @web-padawan - I did see that solution referenced in other issues and even found the open-wc compatibility docs as well. The concept sounds great and I like the idea of reducing the bundle size for modern browsers, but with the useBuiltIns option of babel working for me I am not adding much weight to my bundle size by transpiling down to ES5 and I'd much prefer to keep my Webpack config on the simpler side. Is there no way to use the es5-adapter to accomplish this without having to produce multiple bundles?

I'm happy to create a new repo to isolate the problem and make a new issue for it if that would help. It might also save people some time to know that it's not a viable option.

@web-padawan
Copy link
Contributor

@n-devr you only need ES5 adapter if you transpile to ES5. Otherwise, you should not include it.

Also, you can set esmodules target for @babel/preset-env:
https://babeljs.io/docs/en/babel-preset-env#targetsesmodules

Regarding useBuiltIns, I haven't tried how it works with corejs 3.
But AFAIK it should not affect custom elements classes when they aren't transpiled.

@n-devr
Copy link

n-devr commented Oct 25, 2019

Thanks for your time and quick reply @web-padawan !

My goal is to have a single bundle transpiled to ES5 that I serve to all browsers. Sorry if the useBuiltIns piece confused the matter, I was trying to explain that I wouldn't see much benefit in serving separate modern and legacy bundles because the bundle sizes would be almost the same size. I believe I am bundling and transpiling everything correctly, and my LitElements are rendering just fine when I transpile them except when I try to view them in Chrome. I am including the es5-adapter in that case but I don't think it is working properly. Is that use case simply not supported by LitElement any more?

@sdykae
Copy link

sdykae commented Oct 30, 2019

@n-devr Sir Did you found any solution? with webpack targeting ie 11?

@n-devr
Copy link

n-devr commented Oct 30, 2019

@sdyalor my issue is not the IE11 support in and of itself - if you use the webpack and babel config I referenced above you should be able to generate a bundle that is transpiled down to ES5 and works in IE11. Unfortunately, that same bundle does not work in Chrome, and the custom-elements-es5-adapter.js script that is supposed to fix this no longer seems to be working. While I haven't found a solution as of yet, @web-padawan has offered a workaround that does work, but it requires you to generate two different bundles. You can combine a plugin like: webpack-babel-multi-target-plugin with this approach: Deploying ES2015+ Code in Production Today. While it does work, I don't think it should be absolutely necessary in order to adopt lit-elements and support IE.

@web-padawan I also want to reiterate my offer to create a public repo with a simple project to demonstrate the issue. It seems like there are a good number of people who are having this issue, and if you think it would help the team to debug and potentially solve the problem I'm happy to help.

@sdykae
Copy link

sdykae commented Oct 30, 2019

@n-devr So, excluding Internet Explorer and knowing that custom-elements-es5-adapter.js does not work when targeting babel to ie: 11

What the formula to cover wide range of browsers is?

When I target to esmodules: true, things works well but when this is done, Do I need to load webcomponents polyfill? <script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script> with corejs3

@web-padawan
Copy link
Contributor

@n-devr if you create an example repository, I could take a look.

However, please keep in mind the following problems:

  1. IE11 does not work well with web components because of ShadyDOM performance issues:
  1. Also, ShadyDOM breaks DevTools in IE11 (the issue is closed but not fixed):
  1. Finally, by transpiling to ES5 you also send more code to evergreen browsers.

As a result, developer experience with IE11 is horrible and the apps are too slow.
This BTW is a reason why Salesforce uses own polyfill for LWC.

@sslotsky
Copy link

sslotsky commented Mar 4, 2020

Sorry to add to a closed thread but what is the solution to this for TypeScript and Rollup? Most of what I see here is for babel and webpack. I've tried adding this to my tsconfig

    "target": "ES2015"

Rollup config looks like this

import typescript from '@rollup/plugin-typescript';
import resolve from 'rollup-plugin-node-resolve';

export default {
  input: 'src/client/main.ts',
  output: [
    {
      file: 'src/server/dist/bundle.js',
      format: 'iife',
      sourcemap: false,
    },
    {
      file: 'src/server/dist/bundle.esm.js',
      format: 'esm',
      sourcemap: false,
    },
  ],
  plugins: [
    resolve(),
    typescript({
      lib: ['es5', 'es6', 'dom'],
      target: 'es5',
    }),
  ],
};

What should I change?

@justinfagnani
Copy link
Contributor

@sslotsky do you need to support IE11? If not, change target: 'es5' in the Rollup config.

@huangjihua
Copy link

Encountered the same problem and not resolved

@ghost
Copy link

ghost commented May 16, 2021

I'm using typescript and currently compiling to es6 but I need to support IE11 so eventually must switch to compiling to es5. Is there a solution for this yet?

@justinfagnani
Copy link
Contributor

There has been a solution - compile your app to ES5 and either serve ES5 to IE11 and ES2017+ to Chrome, or serve ES5 to all browsers and include the custom-elements-es5-adapterjs to all ES5 to construct HTML elements: https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs#custom-elements-es5-adapterjs

@ghost
Copy link

ghost commented May 16, 2021

I've done that by importing the following files in my rollup.js input:

import '@webcomponents/webcomponentsjs/webcomponents-loader.js';
import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js';
import 'lit/polyfill-support.js';

However, the Class constructor LitElement cannot be invoked without 'new' error still occurs on both Firefox and Chrome.

@coolcorexix
Copy link

is there any update on this? I tried to inject a web component to Youtube but this error was thrown

image

@justinfagnani
Copy link
Contributor

@coolcorexix what kind of update are you looking for?

You either need to serve native classes to browsers (which you really should be doing - all browsers support classes now) or use the ES5 adapter: https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs#custom-elements-es5-adapterjs

@coolcorexix
Copy link

@coolcorexix what kind of update are you looking for?

You either need to serve native classes to browsers (which you really should be doing - all browsers support classes now) or use the ES5 adapter: https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs#custom-elements-es5-adapterjs

@justinfagnani I think I just did first option without knowing it

I have just solved the problem but I don't know if this can be simpified, the rough idea is like this:

  • I saved original CustomElements and HTMLElement in another var at start
  • I let the UI that requires es5 polyfill to run
  • I then swap the polyfilled vars with the original ones I have from step 1
  • Run my web-component logic
  • Restore polyfilled context for any further app logic

The app I am talking about here is Youtube and I am injecting some UI by using a chrome extension. The whole process is very hacky so I just don't know if there is any other ways.

@justinfagnani
Copy link
Contributor

The other way is to not compile away classes - use native classes.

@coolcorexix
Copy link

coolcorexix commented Aug 22, 2024

The other way is to not compile away classes - use native classes.

@justinfagnani I dont get what you mean, can you give me an example on how to do this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests