preact icon indicating copy to clipboard operation
preact copied to clipboard

Uncaught TypeError: Cannot read properties of undefined (reading '__H')

Open nmocruz opened this issue 1 year ago • 15 comments

Got a problem when bundling preact with typescript

main.bundle.js:1 Uncaught TypeError: Cannot read properties of undefined (reading '__H') at main.bundle.js:1:12917 at main.bundle.js:1:12990 at ne (main.bundle.js:1:13138) at main.bundle.js:1:14979 at main.bundle.js:1:15040 at main.bundle.js:1:15062

I just added preact/hook import on a file. I have already tried to see if I was calling render more times, or id webpack is duplicating the module, but look,

I saw already some issues like this, all closed without a big explanation why it started to work.

nmocruz avatar Aug 08 '22 16:08 nmocruz

I mean, we will need a bit more of a reproduction 😅 generally these issues are caused by duplicate copies of Preact

JoviDeCroock avatar Aug 08 '22 17:08 JoviDeCroock

I gonna try to reproduce this, unfortunately my setup has webpack 5 and node 18, I gonna try to re-recreate a demo with same webpack+typescript configuration and uploaded it

nmocruz avatar Aug 08 '22 17:08 nmocruz

I made some modifications on a base typescript project and I end up reproducing the issue

I have node 18, windows 11, and using powershell

the code with the issue is on here

nmocruz avatar Aug 08 '22 19:08 nmocruz

The link is to your profile, looks like this is a preact-cli issue though so I will move it there, best to include some reproduction steps though

JoviDeCroock avatar Aug 08 '22 19:08 JoviDeCroock

I updated the link, sorry about missing the right repo, I was sure that I was in the right place. I used the cli, but I am using webpack 5

nmocruz avatar Aug 08 '22 19:08 nmocruz

Is it a Preact-CLI issue? You have various Webpack dependencies and a webpack.config.js sitting there.

It's unclear whether you're using Webpack directly or using Preact-CLI.

rschristian avatar Aug 08 '22 19:08 rschristian

I dont thing is Preact-CLI, I am using

npx webpack serve

Some transferred this, by I thing this is preact, maybe caused by something new that webpack 5 is doing, not sure

nmocruz avatar Aug 08 '22 19:08 nmocruz

Heh, sorry hence the ask for reproduction steps 😅 I saw preact-cli in the package json and that worked fine for me

JoviDeCroock avatar Aug 08 '22 19:08 JoviDeCroock

@JoviDeCroock Should I transfer this back?

@nmocruz It'd really help in that case to cut down your app to the minimal reproduction. It doesn't make much sense to have preact-cli installed (and scripts using Preact-CLI) when you're not actually using it.

rschristian avatar Aug 08 '22 19:08 rschristian

@rschristian I used the cli just to generate a demo, and then I adjusted the demo to use webpack 5, ts-loader and instead to be near my other project. My other project is using dotnet core, maybe hard to setup and run, but I was able to reproduce it like this

nmocruz avatar Aug 08 '22 19:08 nmocruz

That's totally fine, but you can probably imagine how maintainers might get confused? You say you use npx webpack serve, and yet your scripts don't show that at all:

"scripts": {
    "build": "preact build",
    "serve": "SET NODE_OPTIONS=--openssl-legacy-provider sirv build --cors --single",
    "dev": "preact watch",
    "lint": "eslint src",
    "test": "jest"
  },

The ReadMe in your project says npm run build is how to generate a build: https://github.com/nmocruz/preactjsdemo#cli-commands

It'd help us track down your problem if you removed these things and provided clear instructions alongside a minimal reproduction.

rschristian avatar Aug 08 '22 20:08 rschristian

yes, as I said I used the cli to build a quick/repo demo to show you the issue. I could remove all cli references on the original code generated by the cli or maybe have started one from scratch. but I fully understand the readme and the scripts should have that removed to not mislead you. I have going to updated the demo, so no one else gets confused. ps, done

nmocruz avatar Aug 08 '22 20:08 nmocruz

it seems like the problem is webpack or loaders on version 5, I downgraded the webpack toolset to use webpack 4 instead of 5 and it started to work

nmocruz avatar Aug 09 '22 14:08 nmocruz

I haven't looked too deep into your setup, however I have played with mine a bit which is also webpack 5 an example can be found here the bigger differences I saw were babel-loader, something might be related to those tsconfig paths and maybe webpack 5 needs an alias for Preact itself due to it being eager on duplicating stuff 😅

Might have some time to look into your specific one over the weekend

JoviDeCroock avatar Aug 09 '22 16:08 JoviDeCroock

ok, I didn't try babel-loader, only ts-loader. I'm not 100% sure if I tried esbuild-loader, but I have an idea that was my first attempt, and then I switched to ts-loader. But it can be also so problems on my tsconfig that is not clear that it will break the hooks import

nmocruz avatar Aug 09 '22 17:08 nmocruz

Screenshot 2022-08-11 at 09 11 53

Just opened your application and everything works fine, all I had to do was add mode: 'development' to your webpack config (which it was warning you about) and the UI renders fine

JoviDeCroock avatar Aug 11 '22 07:08 JoviDeCroock

that is strange, smells like it's an environment thing (node related with mode:development, because I also tried). do you tested with node 18 or 16? windows or linux? I saw on the past issue just because people used old powershell to run nodejs tools.

nmocruz avatar Aug 14 '22 10:08 nmocruz

Node 16 and 18, macOS

JoviDeCroock avatar Aug 14 '22 10:08 JoviDeCroock

Wondering if this can be webpack missing module types, like mjs with es6, or others? I am trying to bundle something to run SSR on a JavaScript engine under/bound to Dotnet core framework, not nodejs. Is a V8 engine so I think maybe the webpack is picking wrong module when mixing server rendering, preact and hooks with different module types

nmocruz avatar Aug 29 '22 19:08 nmocruz

still without any solution, I tried many modules types a few bundles it seems like the problem when render to string the currentComponent is null, not sure if I'm using this library right or not.

image

nmocruz avatar Sep 10 '22 10:09 nmocruz

The main reason currentComponent is null is when you have multiple versions of preact in your bundle. Hooks by design have to rely on a shared singleton. The preact/hooks import, loads preact and if that version is different from the Preact version you're using to render your application you'll get this exact error.

Like @JoviDeCroock, I cannot reproduce the error on my end. Just had to add mode: "development" to the webpack config to make the webpack error go away. Basically followed the instructions of the error message.

marvinhagemeister avatar Sep 10 '22 12:09 marvinhagemeister

It seems like my issue now can have same error but is a bit diferent

import { render } from 'preact-render-to-string';
import { createApp } from './pages/app';
render(createApp(url, data), {}, {})

and app

export function createApp (initialUrl: string, initialData: any){

    const [route, setRoute] = useState(initialUrl);
   
    function OnRouteChanged(event: any){
        setRoute(event.src)
    }

    useEffect(() => {
        window.addEventListener('navidate', OnRouteChanged);
        return () => window.removeEventListener('navigate', OnRouteChanged);
    }, []);
    
    const { Component } = getRoute(route)

    return <div>
        <Component />
    </div>
}

it seems like createApp is not a component but just a function that returns one, and hooks is not seeing that function as a component.

It more like a lack of knowledge and confusion on what that error was really telling us.

nmocruz avatar Sep 10 '22 12:09 nmocruz

@nmocruz that is because you're not calling it like a component. Hooks are only allowed to be used inside components.

- function createApp(url: string, data: any) {
+ function App({ url, data }) {
    const [route, setRoute] = useState(url);
    // ...
}

- render(createApp(url, data), {}, {})
+ render(<App url={url} data={data} />)

Or if you're nodejs pipeline isn't set up for JSX, you could call the JSX factory function manually:

import { createElement } from "preact";

render(createElement(App, { url, data }))

The reason for this, is that the JSX-transform (or manually calling the JSX factory) is what ultimately turns a plain function into a component.

marvinhagemeister avatar Sep 10 '22 14:09 marvinhagemeister

It works now, was just my lack of knowledge about using hooks on functions, or the difference between a function a component. I just recommend putting maybe that info handier, because I was spending time trying stuff around the bundling.

nmocruz avatar Sep 11 '22 08:09 nmocruz