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

Angular Elements: `document-register-element` breaking change #24390

Open
stevermeister opened this issue Jun 9, 2018 · 40 comments

Comments

@stevermeister
Copy link
Contributor

commented Jun 9, 2018

I'm submitting a...


[x ] Bug report  

Current behavior

Angular Elements

This package has breaking change -
https://github.com/angular/angular/blob/master/packages/elements/schematics/ng-add/index.ts#L34

After it's automatically updated to 1.9.0. It gives an error in browser:

Error: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

Environment


Angular version: 6.0.3


Browser:
- [x ] Chrome (desktop) version 67

@JenPeleva

This comment has been minimized.

Copy link

commented Jun 9, 2018

This might help: stackblitz/core#475
Or setting the 'target' in your tsconfig.json to es2015

@stevermeister

This comment has been minimized.

Copy link
Contributor Author

commented Jun 10, 2018

@JenPeleva thank you for the hint!
But I still think that current functionality should be hotfix in core
that's why I created this hotfix pull-request - #24391

@WebReflection

This comment has been minimized.

Copy link

commented Jun 11, 2018

alternatively, this is what landed in Babel 7:
https://github.com/WebReflection/babel-plugin-transform-builtin-classes

@KHappe

This comment has been minimized.

Copy link

commented Jun 11, 2018

So what is the fix or work around for this issue?

@WebReflection

This comment has been minimized.

Copy link

commented Jun 11, 2018

@KHappe you need to transpile code properly, in a way that doesn't break native classes extends.

@KHappe

This comment has been minimized.

Copy link

commented Jun 11, 2018

@WebReflection I'm just using the default setting generated by @angular/cli. Do I need to change tsconfig.json? What change do I need to make to have it transpile code correctly?

We go to production in 2 weeks with using angular elements and need to get this resolved ASAP.

@ngbot ngbot bot added this to the needsTriage milestone Jun 11, 2018

@WebReflection

This comment has been minimized.

Copy link

commented Jun 12, 2018

@KHappe if this project uses TypeScript I've no idea how to solve it, so the most pragmatic solution for the time being is pinning the DRE version to 1.8.1 which is the most updated version of the library before introducing changes that would break latest Chrome if the code is badly transpiled.

That being said, I suggest this project to find a solution to properly transpile classes, filing bugs at TypeScript if necessary, saying that this fails:

class AFailure extends HTMLElement {}
customElements.define('a-failure', AFailure);
const fail = new AFailure;

as this link easily demonstrates (try that transpiled code in Chrome or Safari and see same failure)

The alternative is to not change classes in TypeScript but I don't know what are your target browsers.

@WebReflection

This comment has been minimized.

Copy link

commented Jun 12, 2018

More on this topic, since it's a well known TypeScript issue since about ever:
microsoft/TypeScript#15397

there are some possible solutions in here too:
microsoft/TypeScript#12949

wickeym added a commit to wickeyware/wickeyappstore that referenced this issue Jun 12, 2018

CHANGES VERSION 2.12.5
FIX: [WASjs] Fix error on Chrome 67 - [Angular issue
24390](angular/angular#24390).

davinkevin added a commit to davinkevin/angular42 that referenced this issue Jun 12, 2018

@njl07

This comment has been minimized.

Copy link

commented Jun 12, 2018

Same problem for me and downgrade document-register-element to v1.8.1 solved it

@KHappe

This comment has been minimized.

Copy link

commented Jun 13, 2018

V1.8.1 worked for me too. Thanks for finding that!!!

@tndk1995

This comment has been minimized.

Copy link

commented Jun 15, 2018

thanks @njl07 It worked for me too! Thanks :D

@njl07

This comment has been minimized.

Copy link

commented Jun 15, 2018

You can try my library to load custom elements if you want https://github.com/hapinessjs/ng-elements-loader

@PeterKassenaar

This comment has been minimized.

Copy link

commented Jun 20, 2018

Pinning DRE to 1.8.1 does not work for me, not even with a blank new CLI project out of the box.

No element can be registered, I always get the error "Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function."

So Angular Elements is basically unusable at this point?

@WebReflection

This comment has been minimized.

Copy link

commented Jun 20, 2018

I'd like to underline this is not directly an issue of DRE. DRE was using a feature detection on Chrome that was failing, because Chrome supports native classes, native Custom Elements V0, and native Custom Elements V1, including builtins extend.

As soon as Chrome fixes that funny feature detection failure on checking the is attribute, the DRE, based on feature detections, at any version, will stop patching Chrome, and this is expected, but also, correct, from a polyfill perspective.

What you need to do is to switch to Babel 7 or transpile at least your output before TypeScript, through Babel 6, and this plugin: https://github.com/WebReflection/babel-plugin-transform-builtin-classes (which is the one basically merged into Babel 7).

@WebReflection

This comment has been minimized.

Copy link

commented Jun 20, 2018

Alternatively, you need to target es2015 instead of es5, so that classes are left untouched the support is 88.31%, and you'll live happily ever after with classes from that time on.

@WebReflection

This comment has been minimized.

Copy link

commented Jun 20, 2018

another alternative is to force patch customElements no matter what:
https://github.com/WebReflection/document-register-element#avoiding-ce-built-in

const installCE = require('document-register-element/pony');

// by default, the second argument is 'auto'
// but it could be also 'force'
// which ignores feature detection and force
// the polyfill version of CustomElements
installCE(global, 'force');

please note I am using the /pony fill, not the polyfill.

@PeterKassenaar

This comment has been minimized.

Copy link

commented Jun 20, 2018

@WebReflection Thanks for the clarification - but I tried to set the options in my main tsconfig.json to "es2015" and still no go. Weird.

I think I understand what is going wrong and why, but I can't get my (basic) Angular project to compile correctly. It's using TS 2.7.2 by default.

@WebReflection

This comment has been minimized.

Copy link

commented Jun 20, 2018

@PeterKassenaar then try:

import {dre} from 'document-register-element/pony';
dre(window, 'force');

if that works, it is not a long term solution, but at least it should enable this project.

@jessndaa

This comment has been minimized.

Copy link

commented Jun 20, 2018

Hi, I have solved this issue by changing the "target":"es5" in the tsconfig.json to "target":"es2015"
these is my tsconfig.json file

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es2015",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}```
@WebReflection

This comment has been minimized.

Copy link

commented Jun 21, 2018

@jessndaa that would be my best suggestion and your best bet for the present, and the future

@PeterKassenaar

This comment has been minimized.

Copy link

commented Jun 21, 2018

@jessndaa @WebReflection I updated the tsconfig.json to 'es2015' and somehow it did not work in the project when compiling and building the project. However, when I copied over the /src folder (and package.json) to a brand new project, it did work.

So I don't have a clue for the Why and How, but I'm happy for now.

Thanks again for your help and time.

@renebizelli

This comment has been minimized.

Copy link

commented Aug 9, 2018

V1.8.1 worked for me too. Tks!!!!

@haydenbr

This comment has been minimized.

Copy link

commented Sep 4, 2018

@jessndaa's solve worked for me. On angular 6.1.6, that's the only change I had to make and it worked fine.

@njl07

This comment has been minimized.

Copy link

commented Nov 9, 2018

If your application is built in es5 you can just add a new polyfills @webcomponents/webcomponentsjs/custom-elements-es5-adapter and all will work without problem.

document-register-element is only required if the browser doesn't support HTMLElement and can be in latest version now with the previous polyfill

@WebReflection

This comment has been minimized.

Copy link

commented Nov 9, 2018

document-register-element is only required if the browser doesn't support HTMLElement and can be in latest version now with the previous polyfill

No. document-register-element is the most deployed polyfill for Custom Elements out there, and it doesn't require any particular adapter, it works already with Babel 7 out of the box.

@WebReflection

This comment has been minimized.

Copy link

commented Nov 9, 2018

P.S. since people still write in here, feel free to read how to migrate to V1, requiring zero polyfills if not, eventually, the one for built-in elements.
https://github.com/WebReflection/document-register-element#important-how-to-migrate-to-native-v1

@njl07

This comment has been minimized.

Copy link

commented Nov 9, 2018

It’s the best poly fill for sure but you don’t need it if your browser already support all features.
You speak about babel7 but all projects are not in this version and maybe can’t migrate to it so have the polyfill I mentioned will fix the problem

@WebReflection

This comment has been minimized.

Copy link

commented Nov 9, 2018

there is a fix for babel 6 too, it's the same fix that eventually landed in babel 7
https://github.com/WebReflection/babel-plugin-transform-builtin-classes#readme

you don’t need it if your browser already support all features.

neither you need anything else ... if the browser natively supports customElements it's granted to support also native classes so that no poly is needed.

Again, this is explained in the link posted in
#24390 (comment)

@njl07

This comment has been minimized.

Copy link

commented Nov 9, 2018

there is a fix for babel 6 too, it's the same fix that eventually landed in babel 7

I'm sorry but I don't use Babel and only ts-loader so I've the problem and must have a polyfill.

neither you need anything else ... if the browser natively supports customElements it's granted to support also native classes so that no poly is needed.

It's not true because my browser is the latest version of Chrome and I've the problem when I build with webpack and it's not the problem of document-register-element which is not include but of the es5 compilation that needs custom-elements-es5-adapter to use @angular/elements implementation

@njl07

This comment has been minimized.

Copy link

commented Nov 9, 2018

@WebReflection I've just trying your solution babel-plugin-transform-builtin-classes and it doesn't work for me.

webpack.config.js

var path = require('path');

module.exports = {
    entry: { main: './main.ts' },
    resolve: { extensions: [ '.ts', '.js' ] },
    target: 'web',
    // this makes sure we include node_modules and other 3rd party libraries
    externals: [ /(node_modules)/ ],
    output: {
        path: path.join(__dirname),
        filename: '[name].js'
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [ 'babel-preset-env' ]
                        }
                    },
                    {
                        loader: 'ts-loader'
                    }
                ]
            }
        ]
    },
    stats: {
        warnings: false
    }
};

.babelrc

{
  "plugins": [
    "babel-plugin-transform-es2015-classes",
    ["babel-plugin-transform-builtin-classes", {
      "globals": ["Array", "Error", "HTMLElement"]
    }]
  ]
}

package.json

{
"devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-plugin-transform-builtin-classes": "^0.6.1",
    "babel-plugin-transform-es2015-classes": "^6.24.1",
    "babel-preset-env": "^1.7.0",
    "ts-loader": "^5.3.0",
    "webpack": "^4.23.1",
    "webpack-cli": "^3.1.2"
  }
}
@njl07

This comment has been minimized.

Copy link

commented Nov 9, 2018

@WebReflection I've just trying with Babel7 it doesn't work anymore.

webpack.config.js

var path = require('path');

module.exports = {
    entry: { main: './main.ts' },
    resolve: { extensions: [ '.ts', '.js' ] },
    target: 'web',
    // this makes sure we include node_modules and other 3rd party libraries
    externals: [ /(node_modules)/ ],
    output: {
        path: path.join(__dirname),
        filename: '[name].js'
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: [
                    {
                        loader: 'ts-loader'
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env']
                        }
                    }
                ]
            }
        ]
    },
    stats: {
        warnings: false
    }
};

package.json

{
"devDependencies": {
    "@babel/core": "^7.1.5",
    "@babel/preset-env": "^7.1.5",
    "babel-loader": "^8.0.4",
    "ts-loader": "^5.3.0",
    "webpack": "^4.23.1",
    "webpack-cli": "^3.1.2"
  }
}
@njl07

This comment has been minimized.

Copy link

commented Nov 9, 2018

So I think the problem isn't with document-register-element but with @angular/elements itself because first one isn't include in my file and I'm just calling angular feature.

When I'm including @webcomponents/webcomponentsjs/custom-elements-es5-adapter without document-register-element all works fine else I've this error:

TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

If @robwormald can check it'll be cool, thanks to him

@njl07

This comment has been minimized.

Copy link

commented Nov 9, 2018

If I'm in an Angular application and I'm setting target: es2015 in my tsconfig.json file all works fine without any polyfills.

When I'm using @angular/elements outside Angular and built with webpack and ts-loader, I must have @webcomponents/webcomponentsjs/custom-elements-es5-adapterpolyfill.

It'll be cool if we can have the webpack configuration used in Angular-CLI to work properly with @angular/elements outside Angular

@WebReflection

This comment has been minimized.

Copy link

commented Nov 9, 2018

the es5 compilation

I think you should never do that ... you should serve es5 only to legacy browsers, not all of them.

Also, about using typescript, if you transpile to ES5 classes are plain broken when it comes to builtin extends.

This is a long standing bug that won't get fixed. Watch out your tools.

@ChrisTheButcher

This comment has been minimized.

Copy link

commented Dec 13, 2018

Fix for ES5 as a target:

Add this to your polyfills.ts on the bottom of your file

/***************************************************************************************************
 * APPLICATION IMPORTS
 */
import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js'; 

make sure to have the module installed with npm install @webcomponents/webcomponentsjs --save-dev

@renevall

This comment has been minimized.

Copy link

commented Apr 19, 2019

@ChrisTheButcher Fix does not work for me sadly, just the changing target.

@blackat

This comment has been minimized.

Copy link

commented Apr 23, 2019

Solution that worked for me, thanks to @robwormald

Add this to your index.html VanillaJS page where you use the generated tag:
https://unpkg.com/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js

@CSchulz

This comment has been minimized.

Copy link

commented May 2, 2019

it seems using the custom-elements-es5-adapter.js makes the document-register-element script obsolete.

I am not familiar with both libraries, what are the main differences?

@ChristianUlbrich

This comment has been minimized.

Copy link

commented May 2, 2019

@CSchulz No it does not. custom-elements-es5-adapter.js simply allows transpiled ES5 code to utilize the native CustomElement API that for some unknown reason demands ES2015+ class syntax, whereas the document-register-element is polyfilling the CustomElement API.

tl;dr; You need document-register-element for legacy browsers not supporting it, i.e. IE11, Firefox 3, ... and custom-elements-es5-adapter.js for the ones supporting it, if you are using (transpiled) ES5 code, which you likely do.

@EugenMayer

This comment has been minimized.

Copy link

commented May 25, 2019

I am not entirely sure i contribute this way, but maybe this helps. Ran into the same issue, having target type es2015 and using 1.13.1 of DSR and was running into the mentioned issue.

It turned out i was not loading scripts.js which was added by DSL with ng add and i was not aware of. adding this fixed the issue right away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.