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

@HotkeysTarget TypeError: class constructors must be invoked with |new| #3604

Closed
nagylzs opened this issue Jun 16, 2019 · 34 comments · Fixed by #4532
Closed

@HotkeysTarget TypeError: class constructors must be invoked with |new| #3604

nagylzs opened this issue Jun 16, 2019 · 34 comments · Fixed by #4532

Comments

@nagylzs
Copy link

nagylzs commented Jun 16, 2019

Environment

  • Package version(s): "@blueprintjs/core": "^3.15.1", "typescript": "3.5.1"
  • Browser and OS versions: Ubuntu 18.04, FireFox 67.0.2

Steps to reproduce

import { Hotkey, Hotkeys, HotkeysTarget } from "@blueprintjs/core";
@HotkeysTarget
export class MyComponent extends React.PureComponent<{}> {
     public render () { return <div>Hello there</div> };
     public renderHotkeys() {
        return <Hotkeys>
            <Hotkey
                combo="up"
                label="Up"
                onKeyDown={() => { alert('Need to go up'); } }
            />
        </Hotkeys>;
    }    
}

Actual behavior

The component cannot be rendered. I get an error that starts with this:


TypeError: class constructors must be invoked with |new|
HotkeysTargetClass
node_modules/@blueprintjs/core/lib/esm/components/hotkeys/hotkeysTarget.js:32

  29 | tslib_1.__extends(HotkeysTargetClass, _super);
  30 | 
  31 | function HotkeysTargetClass() {
> 32 |   return _super !== null && _super.apply(this, arguments) || this;
     | ^  33 | }
  34 | 
  35 | HotkeysTargetClass.prototype.componentWillMount = function () {

Full traceback available, but probably not needed.

Expected behavior

The component should be rendered and the hotkey should be working.

@adidahiya
Copy link
Contributor

Can you reproduce this in a code sandbox?

@nagylzs
Copy link
Author

nagylzs commented Jun 19, 2019

I have created an exampe project:

https://github.com/nagylzs/bug3604

You can recreate the problem by:

[email protected]:nagylzs/bug3604.git
cd bug3604
yarn install
yarn run start

@nagylzs
Copy link
Author

nagylzs commented Jun 19, 2019

Also tried to create a code sandbox example. It does not throw an error!

https://codesandbox.io/s/blueprint-sandbox-tkrkk

But the bug3604 project is really buggy. I'm not sure what is the difference between them. It might be an incompatibility between a create-react-app dependency and blueprintjs? But I doubt it.

@nagylzs
Copy link
Author

nagylzs commented Jun 19, 2019

I have tried the same example project on a different computer. I got a sightly different error message:

Uncaught TypeError: Class constructor App cannot be invoked without 'new'
    at new HotkeysTargetClass (hotkeysTarget.js:32)
    at constructClassInstance (react-dom.development.js:11786)
    at updateClassComponent (react-dom.development.js:15264)
    at beginWork (react-dom.development.js:16262)
    at performUnitOfWork (react-dom.development.js:20279)
    at workLoop (react-dom.development.js:20320)
    at HTMLUnknownElement.callCallback (react-dom.development.js:147)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
    at invokeGuardedCallback (react-dom.development.js:250)
    at replayUnitOfWork (react-dom.development.js:19503)
    at renderRoot (react-dom.development.js:20433)
    at performWorkOnRoot (react-dom.development.js:21357)
    at performWork (react-dom.development.js:21267)
    at performSyncWork (react-dom.development.js:21241)
    at requestWork (react-dom.development.js:21096)
    at scheduleWork (react-dom.development.js:20909)
    at scheduleRootUpdate (react-dom.development.js:21604)
    at updateContainerAtExpirationTime (react-dom.development.js:21630)
    at updateContainer (react-dom.development.js:21698)
    at ReactRoot.push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.development.js:22011)
    at react-dom.development.js:22163
    at unbatchedUpdates (react-dom.development.js:21486)
    at legacyRenderSubtreeIntoContainer (react-dom.development.js:22159)
    at Object.render (react-dom.development.js:22234)
    at Module../src/index.tsx (index.tsx:7)
    at __webpack_require__ (bootstrap:781)
    at fn (bootstrap:149)
    at Object.0 (serviceWorker.ts:143)
    at __webpack_require__ (bootstrap:781)
    at checkDeferredModules (bootstrap:45)
    at Array.webpackJsonpCallback [as push] (bootstrap:32)
    at main.chunk.js:1

index.js:1375 The above error occurred in the <HotkeysTarget(App)> component:
    in HotkeysTarget(App) (at src/index.tsx:7)

This is the transpiled line that is causing an error:

    function HotkeysTargetClass() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

It seems that _super is a class, and it cannot be "applied" without the new keyword.

I have no idea why this problem is not coming out on code sandbox, but it surely does not work with a default "create-react-app --typescript" project.

@wph95
Copy link

wph95 commented Jul 10, 2019

@nagylzs I think I have a problem like you
when I changed tsconfig.json compilerOptions.target to es5 the problem is solved

@sgaloux
Copy link

sgaloux commented Jul 14, 2019

I have the same issue, even if set compilerOptions.target to es5 :

hotkeysTarget.js:32 Uncaught TypeError: Class constructor HotKeyRoot cannot be invoked without 'new'
at new HotkeysTargetClass (hotkeysTarget.js:32)
at constructClassInstance (react-dom.development.js:11786)
at updateClassComponent (react-dom.development.js:15264)
at beginWork (react-dom.development.js:16262)
at performUnitOfWork (react-dom.development.js:20279)
at workLoop (react-dom.development.js:20320)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
...

I also use create-react-app --typescript for this project.

@jtheisen
Copy link

@sgaloux I second you.

Used create-react-app --typescript in my project, I checked I have the same blueprint and react versions as the codesandbox thing, yet I get the error in my project.

Also having es5 as target.

@kresli
Copy link

kresli commented Sep 23, 2019

experiencing same issue with cra 3 and typescript changing target to es5 doesn't help.

Here is the repo with failing decorator https://github.com/kresli/cra3-bp3-decorator-error

@alxmiron
Copy link
Contributor

I met the same error (but I dont use TS, just ES6 + webpack + babel).

HotkeysTargetClass() { 
    return _super !== null && _super.apply(this, arguments) || this; 
}

This is a tanspiled to ES5 HotkeysTargetClass class constuctor. The problem is that it expects _super (which is WrappedComponent actually) to be a function (ES5-style class). If in your code WrappedComponent is a ES6 class, it throws an error.

I solved it by using packages/core/lib/esnext/components/hotkeys/hotkeysTarget.js instead of packages/core/lib/esm/components/hotkeys/hotkeysTarget.js, because HotkeysTargetClass is declared in modern way there:

return _a = class HotkeysTargetClass extends WrappedComponent {
   ...
}

@tuxflo
Copy link

tuxflo commented Nov 7, 2019

Thanks @alxmiron it took my a while to find your workaround (which is working so far)
But now my question is: how to do this properly?
Is there a way to "tell" blueprintjs to use the esnext modules?
Usually I don't want to manually modify stuff in the node_modules folder

@alxmiron
Copy link
Contributor

alxmiron commented Nov 7, 2019

Thanks @alxmiron it took my a while to find your workaround (which is working so far)
But now my question is: how to do this properly?
Is there a way to "tell" blueprintjs to use the esnext modules?
Usually I don't want to manually modify stuff in the node_modules folder

Easy. Change default resolve.mainVields webpack config value

const webpackConfig = {
  resolve {
    mainFields: ['esnext', 'browser', 'module', 'main']
  }
}

But be careful, it will look for esnext target in other modules too, not only blueprintjs. This is recommended if you support only evergreen browsers

@maclockard
Copy link
Contributor

This was fixed by #3230.

Also @alxmiron it can be safe to add esnext to resolve.mainFields even if you support older browsers as long as you are using babel-loader and you are babeling your dependencies. Check out this blog post from the babel folks on their thoughts towards babeling deps.

@maclockard
Copy link
Contributor

An alternative solution to #3230 would be to create something like a hook or a higher order component that gives you the same functionality as @HotkeysTarget without using the class decorator. This would avoid the need to edit your webpack config's resolve.mainFields since it would avoid the need for blueprint to instantiate your class component.

pmclachlan pushed a commit to pmclachlan/blink-mind that referenced this issue Jan 16, 2020
@pcdv
Copy link

pcdv commented Mar 6, 2020

I started suddenly to have the same problem. The strange thing is that I cannot reproduce it when I build the application (CRA + typescript) myself, but the CI build has the issue. I tried several versions of typescript / blueprint / react (I first thought that bumping to the latest version caused the problem but it didn't).

Maybe this has to do with node version. I'm using 13.7.0 locally (no issue) but CI uses older versions (one env uses 8.x, the other I'm not sure).

Edit: I applied the same workaround as in commit just above and it did the trick 👍

@CodeMaven
Copy link

I'm having exactly this problem as well. I'm not really a JS developer, I'm a Java developer who is muddling my way though some react code and I don't really understand how any of this stuff works. I am just using plain JS (no typescript) and the app was originally created with create-react-app so there is a package.json file but no webpack config.
I don't know how to apply any of the above work-arounds, can anyone help? Is there something I can do in my package.json file?

@maclockard
Copy link
Contributor

create-react-app does use a webpack config, its just not editable unless you "eject". Would recommend trying this workaround right now if you don't feel comfortable diving into js build tooling right now: pmclachlan/blink-mind@79511a5

@CodeMaven
Copy link

Thankyou @maclockard - that worked for me.

@Kupstas
Copy link

Kupstas commented Aug 28, 2020

I have same error using Babel + Webpack without ts. Is there any ways to fix it?

@maclockard
Copy link
Contributor

@Kupstas This is a solution: #3604 (comment)

if you are unable to do that, then this could also work: pmclachlan/blink-mind@79511a5

@tnrich
Copy link
Contributor

tnrich commented Aug 28, 2020

@adidahiya is there an official fix coming for this? Both of the two solutions mentioned above are really workarounds not true fixes. Also I've tried both and neither is working for me unfortunately :(

Does anyone know what caused this issue to start showing up? What changed exactly, the blueprintjs code or babel or webpack?

Thanks!

@maclockard
Copy link
Contributor

@tnrich if you are curious, the reason why this started happening is that more people starting using es6, which has native classes. The underlying issue is that typescript's shim for classes when targeting es5 are not fully compatible with es6 classes (specifically instantiating es6 classes from an es5 shim class).

Also, if neither solution above didn't work for you, it wouldn't surprise me if you are running into a different issue preventing HotkeysTarget form working than the es5/es6 incompatibility. mind posting some error information?

@Kupstas
Copy link

Kupstas commented Aug 31, 2020

@maclockard none of these 2 solutions work for me =(

@Kupstas
Copy link

Kupstas commented Aug 31, 2020

Actually I see a very strange error log

Uncaught exception TypeError: Class constructor Filter cannot be invoked without 'new'
    at new HotkeysTarget(Filter) (/Users/nikolaykupstas/Projects/bus-kit/frontend/node_modules/@blueprintjs/core/src/components/hotkeys/hotkeysTarget.tsx:41:12)

@maclockard
Copy link
Contributor

maclockard commented Aug 31, 2020

@Kupstas could you include a code snippet showing how you are importing and using HotkeysTarget using the second solution?

@tnrich
Copy link
Contributor

tnrich commented Aug 31, 2020

@maclockard here's what I see when I tried:

import {HotkeysTarget} from '@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysTarget.js';
 ERROR  in ./node_modules/@blueprintjs/core/lib/esnext/components/button/buttons.js 29:38
Module parse failed: Unexpected token (29:38)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|             : (ref) => {
|                 this.buttonRef = ref;
>                 this.props.elementRef?.(ref);
|             };
|     }
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/toast/toast.js 24:0-57 48:36-42 72:39-51
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/index.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysDialog.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysEvents.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysTarget.js
 @ ./src/withEditorInteractions/createSequenceInputPopup.js
 @ ./src/withEditorInteractions/index.js
 @ ./src/index.js
 @ ./demo/src/index.js
 @ multi ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ReactRefreshEntry.js (webpack)-dev-server/client?http://localhost:3344/ ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ErrorOverlayEntry.js (webpack)/hot/only-dev-server.js ./demo/src/index.js

 ERROR  in ./node_modules/@blueprintjs/core/lib/esnext/components/forms/asyncControllableInput.js 45:42
Module parse failed: Unexpected token (45:42)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|                 localValue: this.state.externalValue,
|             });
>             this.props.onCompositionStart?.(e);
|         };
|         this.handleCompositionEnd = (e) => {
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/forms/inputGroup.js 24:0-66 50:32-54
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/index.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysDialog.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysEvents.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysTarget.js
 @ ./src/withEditorInteractions/createSequenceInputPopup.js
 @ ./src/withEditorInteractions/index.js
 @ ./src/index.js
 @ ./demo/src/index.js
 @ multi ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ReactRefreshEntry.js (webpack)-dev-server/client?http://localhost:3344/ ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ErrorOverlayEntry.js (webpack)/hot/only-dev-server.js ./demo/src/index.js

 ERROR  in ./node_modules/@blueprintjs/core/lib/esnext/components/forms/numericInput.js 54:58
Module parse failed: Unexpected token (54:58)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|             shouldSelectAfterUpdate: false,
|             stepMaxPrecision: NumericInput_1.getStepMaxPrecision(this.props),
>             value: getValueOrEmptyValue(this.props.value ?? this.props.defaultValue),
|         };
|         // updating these flags need not trigger re-renders, so don't include them in this.state.
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/index.js 38:0-37 38:0-37
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysDialog.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysEvents.js
 @ ./node_modules/@blueprintjs/core/lib/esnext/components/hotkeys/hotkeysTarget.js
 @ ./src/withEditorInteractions/createSequenceInputPopup.js
 @ ./src/withEditorInteractions/index.js
 @ ./src/index.js
 @ ./demo/src/index.js
 @ multi ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ReactRefreshEntry.js (webpack)-dev-server/client?http://localhost:3344/ ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ErrorOverlayEntry.js (webpack)/hot/only-dev-server.js ./demo/src/index.js

I got similar looking webpack errors when trying the "mainFields" solution.

@Kupstas
Copy link

Kupstas commented Aug 31, 2020

I added like in example. But I have got an error. Something like Cannot use import statement outside a module. Because I needed a fast solution, I removed HotkeysTarget and used another library

Also I had the same errors like @tnrich by using first solution

tnrich added a commit to TeselaGen/openVectorEditor that referenced this issue Aug 31, 2020
@maclockard
Copy link
Contributor

@tnrich the issue you are seeing there is due to the fact something in you loader chain can't handle the optional chain operator being used by blueprint when targeting esnext. As per this comment, #3604 (comment) you need to both be using babel-loader and be babeling blueprint (or all upstream dependencies). If you are currently doing this and still seeing that error, make sure that the versions of babel you are resolving is at least 7.8.0. This is the version that babel-parser added support for optional chaining. (Make sure that its all the babel deps since they share a version number!).

There's a chance that create react app by default is babeling upstream deps already for you, if that's the case then all you need to do is fix what version of babel is being resolved.

For webpack, to babel dependencies/blueprint just change the include/exclude option of the relevant rule config for the babel loader.

@Kupstas you could try using require instead of import, since it sounds like you don't have es modules or typescript setup.

Also, a third possible solution here instead of using the esnext target version of blueprint is to make it so that your build targets es5 or change your browserlist such that it makes babel polyfill classes instead of using native classes.

In my personal opinion, I think that an ideal fix would be HOC versions of HotkeysTarget and ContextMenuTarget, and to possibly deprecate the existing decorator versions. This would remove any need to change configs to use them and would be more 'reactish'. Using class decorators across a module boundary gets really messy if one side is polyfilling classes. Hooks may also be a good fit here, but I think blueprint supports react 15, so that would be a no go.

@maclockard
Copy link
Contributor

Also, I might be wrong about babel being the thing that's failing to parse the optional chain operator, its just usually been the culprit in the past. If its still giving that error after making sure that blueprint is being babel and making sure that babel is at least 7.8.0, the parse error could be a different loader in your loader chain. In that case, try bumping the versions of these loaders and/or of webpack to see if later versions support optional chaining.

@tnrich
Copy link
Contributor

tnrich commented Aug 31, 2020

In my personal opinion, I think that an ideal fix would be HOC versions of HotkeysTarget and ContextMenuTarget, and to possibly deprecate the existing decorator versions. This would remove any need to change configs to use them and would be more 'reactish'. Using class decorators across a module boundary gets really messy if one side is polyfilling classes. Hooks may also be a good fit here, but I think blueprint supports react 15, so that would be a no go.

This seems like the best solution to me as well. I use nwb on top of webpack and don't feel like digging into the babel stuff right now so just downgraded nwb to a previous version where everything was working. This is fine for the time being but it would be great to have a simple HOC solution.

@Kupstas
Copy link

Kupstas commented Sep 1, 2020

Why we cannot just render HotKey inside of view?

@tnrich
Copy link
Contributor

tnrich commented Oct 8, 2020

Any movement on this one @adidahiya @maclockard ? Thanks!

@alexkreidler
Copy link

Some thoughts on this: Create React App does not support decorators by default, see here.

I propose just moving away from decorators for now, as many libraries (e.g. MobX) have done, or at least adding another option for users to declare HotKeys, maybe a React hook.

@tnrich
Copy link
Contributor

tnrich commented Feb 1, 2021

This issue has been plaguing me for quite a while now. I fully support what @alexkreidler suggests which is to provide another option for this functionality that doesn't require decorators support which can be quite finicky to get tooling to support. In my case it works when using blueprint as a regular requirement but not when I try to link blueprint locally as a webpack alias (helpful for local development https://medium.com/@tnrich_29519/a-better-alternative-to-npm-yarn-link-for-the-front-end-667f03d497a6).

@adidahiya
Copy link
Contributor

I'm working on this as part of Blueprint v4.0 changes, it's the next thing on my list, should be able to prototype something later this week.

@adidahiya adidahiya self-assigned this Feb 1, 2021
@adidahiya adidahiya mentioned this issue Feb 18, 2021
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.