nrwl / nx

Smart Monorepos · Fast CI
https://nx.dev
MIT License
23.68k stars 2.36k forks source link

Nx, React, Lit and Storybook: Class constructor `LitElement` cannot be invoked without `new` #9535

Closed sgammon closed 1 year ago

sgammon commented 2 years ago

Current Behavior

Hey there Nx devs. I'm new to Nx but loving it so far. When I try to use Lit with the React stack, however, I'm unclear about how to properly configure Nx/Babel/Webpack to work with Lit and Storybook.

This actually may be something simple in Babel or Webpack, based on some prior related issues, all of which point to es5 / other transpilation settings. However, being new to Nx, I'm unable to reconcile these hints with what I should do in .storybook to get things to interoperate correctly. Any help would be deeply appreciated as Nx looks awesome and we'd love to adopt.

Expected Behavior

Through the @lit-labs/react adapter, I should theoretically be able to define a Lit component, wrap it in a React component, and then display it in Storybook as a React component

Steps to Reproduce

Please find a Github repo here reproducing these steps

  1. Execute npx create-nx-workspace@latest --preset=react --packageManager=yarn
  2. Provide answers (in my case, I provided below values)
    • Workspace name: test
    • Application name: test
    • Default stylesheet format: styled-components
    • Use Nx Cloud? no
  3. Jump in and run a quick build
    • cd test && nx build
  4. Add Storybook (directions here)
    • yarn add --dev @nrwl/storybook
    • nx g @nrwl/react:storybook-configuration test, provide answers
    • Config cypress e2e... true
    • Automatically generate *.stories.ts... true
    • Automatically generate *.spec.ts... true
  5. Run Storybook to make sure it works with nx run test:storybook. All should be fine.
  6. Define a Lit component, like so:
    • yarn add lit
    • Add code below
import * as React from 'react';
import { LitElement, html, TemplateResult } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';
import {createComponent} from '@lit-labs/react';

@customElement("test-element")
export class TestElement extends LitElement {
    override render(): TemplateResult {
        return html`<b>hello lit</b>`;
    }
}

export const MyElementComponent = createComponent(
    React,
    'test-element',
    TestElement,
    {
        onactivate: 'activate',
        onchange: 'change',
    }
);
  1. Run the build and Storybook and all still works.
  2. Now, clone the sample story and tweak it to show the component:
import { Story, Meta } from '@storybook/react';
import { MyElementComponent } from './test';

export default {
  component: MyElementComponent,
  title: 'My Element',
} as Meta;

const Template: Story = (args) => <MyElementComponent {...args} />;

export const Primary = Template.bind({});
Primary.args = {};
  1. Run Storybook again. Observe in the console that it fails with:
test.ts:8 Uncaught TypeError: Class constructor LitElement cannot be invoked without 'new'
    at new TestElement (main.iframe.bundle.js:1120:24)
    (... full stacktrace provided below...)

Failure Logs

test.ts:8 Uncaught TypeError: Class constructor LitElement cannot be invoked without 'new'
    at new TestElement (main.iframe.bundle.js:1120:24)
    at createElement (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:69152:34)
    at createInstance (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:70349:20)
    at completeWork (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:79621:28)
    at completeUnitOfWork (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:82964:16)
    at performUnitOfWork (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:82939:5)
    at workLoopSync (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:82859:5)
    at renderRootSync (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:82822:7)
    at performSyncWorkOnRoot (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:82445:18)
    at scheduleUpdateOnFiber (vendors-node_modules_babel_runtime_helpers_inheritsLoose_js-node_modules_babel_runtime_helper-69b7d5.iframe.bundle.js:82033:7)

Environment

➜  test git:(main) ✗ nx report

 >  NX   Report complete - copy this into the issue template

   Node : 16.14.0
   OS   : darwin arm64
   yarn : 1.22.17

   nx : 13.9.4
   @nrwl/angular : undefined
   @nrwl/cypress : 13.9.4
   @nrwl/detox : undefined
   @nrwl/devkit : 13.9.4
   @nrwl/eslint-plugin-nx : 13.9.4
   @nrwl/express : undefined
   @nrwl/jest : 13.9.4
   @nrwl/js : 13.9.4
   @nrwl/linter : 13.9.4
   @nrwl/nest : undefined
   @nrwl/next : undefined
   @nrwl/node : undefined
   @nrwl/nx-cloud : undefined
   @nrwl/nx-plugin : undefined
   @nrwl/react : 13.9.4
   @nrwl/react-native : undefined
   @nrwl/schematics : undefined
   @nrwl/storybook : 13.9.4
   @nrwl/web : 13.9.4
   @nrwl/workspace : 13.9.4
   typescript : 4.5.5
   rxjs : 6.6.7
   ---------------------------------------
   Community plugins:
sgammon commented 2 years ago

cc / @justinfagnani who may be able to shed some light as well... this feels like a simple config issue, but being that the React adapter is in labs, maybe this is new?

justinfagnani commented 2 years ago
Uncaught TypeError: Class constructor LitElement cannot be invoked without 'new'

This usually means that a subclass of LitElement has been compiled to no longer be a real class (ie, compiled to an "ES5 class") and is invoking the LitElement constructor like LitElement.call(this). That doesn't work with real classes.

The solution is to either compile all of your libraries to ES5 (and use the custom elements es5 adapter), or none of them. Unless you're supporting IE11 there's really no reason to compile to ES5 anymore.

sgammon commented 2 years ago

@justinfagnani thank you for the quick reply! I owe you a beer or a coffee by now, you have helped me so many times! 😁

I understand that ES5 transpilation isn't needed anymore, but I guess in this case I'm unclear how to prevent it. Perhaps that points to this being a configuration issue, I'll try and pursue with Nx. If you happen to know what Babel or Webpack settings are needed to bump up to ES6+ or know where I might find those I'm happy to dig in and see if I can apply to my case.

sgammon commented 2 years ago

(For context, I've used the OpenWC method of integrating Lit with Storybook before, but I know that package takes a rather aggressive stance at packaging everything with ESM, and so ships its own pre-packaged Storybook. Now that I'm in React land, I'm unclear how to use Storybook easily with Lit)

GuskiS commented 2 years ago

I'm facing same problem, but it is not related with Lit - I'm trying to extends three.js classes. I can't seem to be able switch away from compilation to ES5. 🤷‍♂️ I tried changing TS target to anything else - no luck.

broken commented 2 years ago

I was facing the same problem, but with a simple web (js based) app. To fix, I used the "swc" compiler for building, and created a .swcrc file in my app (apps/my-app) directory. I then copied the default json (https://swc.rs/docs/configuration/swcrc) into this file and updated the target to es2017 (I also had to remove the comment).

herrKlein commented 2 years ago

We also have the exact same setup, we included some of our webcomponents in the preview.js. And get the same error: Class constructor LitElement cannot be invoked without 'new'

tamazlykar commented 2 years ago

I'm facing same problem, but it is not related with Lit. In my code I extend a class from a third party library and got an error as described in this topic. To fix this I provide a .babelrc file with a custom configuration in the package/.storybook folder and it fix an error. For my project I use next babel setup:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry",
        "corejs": "3"
      }
    ],
    "@babel/preset-typescript",
    "@babel/preset-react"
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "version": "legacy"
      }
    ]
  ]
}
mandarini commented 1 year ago

Hello all! Since there seem to be workarounds to this issue, I will be closing this issue! Also, don't forget to try out the latest version of Nx, maybe this is fixed natively.

Please feel free to ping me and I will reopen this issue, if you think it's still a problem!

github-actions[bot] commented 1 year ago

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.