Encountering a console error in a TypeScript Express app when using MUI and Preact: "Unexpected prop `children` passed to `InnerThemeProvider`, was expecting a ReactNode."

I'm working on integrating MUI with a Preact app. In VSCode, everything seems to be set up correctly, but when I try to view it in the browser, nothing renders and I get this console error:

react-jsx-runtime.development.js:87 Warning: Failed prop type: Invalid prop `children` supplied to `InnerThemeProvider`, expected a ReactNode.
 at InnerThemeProvider (http://localhost:8080/main.js:54463:70)
 printWarning   @   react-jsx-runtime.development.js:87
 error  @   react-jsx-runtime.development.js:61
 checkPropTypes @   react-jsx-runtime.development.js:631
 validatePropTypes  @   react-jsx-runtime.development.js:1164
 jsxWithValidation  @   react-jsx-runtime.development.js:1284
 jsxWithValidationDynamic   @   react-jsx-runtime.development.js:1301
 ThemeProvider  @   ThemeProvider.js:34
 M  @   preact.js:1
 I  @   preact.js:1
 b  @   preact.js:1
 I  @   preact.js:1
 b  @   preact.js:1
 I  @   preact.js:1
 N  @   preact.js:1
 (anonymous)    @   main.tsx:24
 (anonymous)    @   main.tsx:24
 (anonymous)    @   main.tsx:24

I've tried adjusting settings in webpack and tsconfig, but without specific guidance, it feels like guesswork. It seems like no one else is encountering this exact issue. My intuition tells me it might be related to aliasing since it mentions react-related things.

The project structure looks like this:

.
├── index.ts
├── main.pug
├── main.tsx
├── package.json
├── tsconfig.json
└── webpack.config.js

There are only 6 key files of interest (I have simplified the list):

  1. index.ts: the server file
import express = require("express");
import { Server } from 'http';
import { Application, Request, Response } from "express";

const PORT = 8080;

const setupServer: () => Promise<void> = async () => {
    let app = express();
    const http = new Server(app);
    
    app.use(express.json());
    app.use(express.static(__dirname));

    // setting up pug template engine
    app.engine("pug", require("pug").__express);
    app.set("views",__dirname);

    app.get("*", async (req: Request, res: Response) => {
        res.render("./main.pug");
    });

    // confirming that the server is running
    http.listen(PORT, function() {
        console.log(`Listening on port ${PORT}`);
    });
};
setupServer();
  1. main.tsx: the behavior file referenced by the pug file
import { h, render } from "preact";
import { Button, createTheme, ThemeProvider } from '@mui/material';
import { red } from '@mui/material/colors';

const theme = createTheme({
    palette: {
      primary: {
        main: red[500],
      },
    },
});

function Main() {
    return (
        <ThemeProvider theme={theme}>
            <Button variant="contained">Hello World</Button>
        </ThemeProvider>
    );
};
render(<Main />, document.body);
  1. webpack.config.js
"use strict";
const { merge } = require('webpack-merge');
const nodeExternals = require('webpack-node-externals');

module.exports = env => {

    // shared configuration for all bundles
    const baseConfig = {
        mode: "development",
        devtool: "source-map",
        resolve: {
            extensions: [".js", ".json", ".ts", ".tsx"],
        },
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    use: 'ts-loader',
                    exclude: /node_modules/,
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: ["babel-loader"]
                },
                {
                    test: /\.css$/,
                    use: [ 'style-loader', 'css-loader' ]
                }
            ]
        }
    };

    // client config
    const clientMainBundleConfig = merge(baseConfig,{
        name: 'main',
        entry: { 'main': __dirname + "/main.tsx" },
        target: 'web',
        output: {
            path:  __dirname,
            filename: "[name].js"
        },
        resolve: {
            alias: { 
                "preact/hooks": require.resolve('preact/hooks'),
                "preact": require.resolve('preact')
            }
        }
    });

    // the config for the index file on server side
    const serverBundleConfig = merge(baseConfig,{
        target: 'node',
        name: 'index',
        externals: [nodeExternals()],
        entry: { 'index':  __dirname + "/index.ts" },
        output: {
            path:  __dirname,
            filename: "[name].js"
        },
    });

    return [serverBundleConfig,clientMainBundleConfig];
};
  1. tsconfig.json
{
  "compilerOptions": {
    "jsx": "react",                           
    "jsxFactory": "h",                        
    "jsxFragmentFactory": "Fragment",         
    "baseUrl": "./",                   
    "target": "es6",                               
    "module": "commonjs",                                                     
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,      
    "skipLibCheck": true,
    "sourceMap": true,
    "paths": {                              
      "react": ["./node_modules/preact/compat"],
      "react-dom": ["./node_modules/preact/compat"]
    },             
  },
  "exclude":[
    "./node_modules"
  ]
}
  1. package.json
{
  "name": "preact-mui",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --stats-error-details",
    "start": "node ./index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@emotion/core": "^11.0.0",
    "@emotion/react": "^11.10.5",
    "@emotion/styled": "^11.10.5",
    "@mui/material": "^5.11.0",
    "@types/express": "^4.17.15",
    "@types/express-session": "^1.17.5",
    "@types/node": "^18.11.15",
    "express": "^4.18.2",
    "http": "^0.0.1-security",
    "preact": "^10.11.3",
    "preact-cli": "^3.4.1",
    "preact-render-to-string": "^5.2.6",
    "preact-router": "^4.1.0",
    "pug": "^3.0.2",
    "ts-loader": "^9.4.2",
    "typescript": "^4.9.4",
    "webpack-cli": "^5.0.1",
    "webpack-merge": "^5.8.0",
    "webpack-node-externals": "^3.0.0"
  }
}
  1. main.pug (not particularly significant but included for completion)
<!DOCTYPE html>
html(lang="en")
  head
    meta(charset="utf-8")
    meta(http-equiv="X-UA-Compatible", content="IE=edge")
    meta(name="viewport", content="width=device-width, initial-scale=1")
  body.container-fluid
    div#mainDiv
    script(type='text/javascript', src="./main.js").

I attempted to alias react and react-dom to point to preact/compat, hoping that redirecting them back to preact would resolve the issue automatically. Unfortunately, that approach did not work. Next, I updated tsconfig.json based on MUI's guide, adding:

  "compilerOptions": {
    "lib": ["es6", "dom"],
    "noImplicitAny": true,
    "noImplicitThis": true,
    "strictNullChecks": true,
    ...

However, no changes were observed. As I can't find any relevant information online, I'm unsure of the next steps to take.

Answer №1

It seems like there may be some confusion about what aliasing entails.

Aliasing involves giving X instead of Y when Y is requested. In your current code, you are simply aliasing preact and preact/hooks to themselves, which has no effect.

In order to avoid errors when passing a React component to Preact (or vice versa), it is necessary to properly alias them. The use of preact/compat serves as a bridge to accomplish this.

To correctly configure your base settings, include the following:

resolve: {
    alias: { 
        "react": "preact/compat",
        "react-dom/test-utils": "preact/test-utils",
        "react-dom": "preact/compat",     // Make sure this is below test-utils
        "react/jsx-runtime": "preact/jsx-runtime"
    }
 }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it necessary to verify the apiKey or does the authentication of the user suffice for an HTTPS callable function?

I'm interested in creating a cloud function that can be executed from both the client and the backend. After exploring the documentation, I learned that an HTTPS callable function will automatically include user authentication data, accessible through ...

Modify the UI color of the progress bar when the <Input> component is in focus

I'm in the process of identifying the specific class that needs to be overridden in order to change the color of the bar for the component I'm working with. Below is the code snippet: <Input id="email" ...

Guide on building an npm package that seamlessly allows for installation both locally and globally (-g) using webpack and typescript

As I work on developing an npm package with options for both local and global (-g) installations, I find myself puzzled by the distinctions between the src and lib directories and the purpose of the bin directory. In my previous projects, I typically util ...

Modifying the hue of Material UI tab label

I attempted to modify the label color of a tab to black, but it seems to be stuck as white. Is this color hard-coded in material-ui? If not, how can I change it? Here's what I've tried: const customStyles = { tab: { padding: '2p ...

When adjusting the Material-UI theme Font Size, certain components may display an irregular layout

After customizing my Material-UI theme and setting the font size to 20, I noticed that the Speed Dial Component's icon appeared larger but was not centered within the button. It seems that adjusting the font size only affects the SVG icon size, while ...

Hover shows no response

I'm having trouble with my hover effect. I want an element to only be visible when hovered over, but it's not working as expected. I've considered replacing the i tag with an a, and have also tried using both display: none and display: bloc ...

Having trouble with the state in ReactJS Material UI?

I'm facing an issue where I want the state of my component to change when I click on a MenuItem. Here's how I'm trying to achieve it: export default class MenuAlumno extends React.Component { constructor() { super(); this.state = { ...

Trouble with Nested Routing in React Router Version 6: Route not Rendering

I'm facing issues nesting a path within another path in react-router-dom version 6. When I try to visit the nested argument's page (/blog/1), it shows up as a blank non-styled HTML page. However, when I add a child path to the root like /blog, it ...

What is the best method for translating object key names into clearer and easier to understand labels?

My backend server is sending back data in this format: { firstName: "Joe", lastName: "Smith", phoneNum: "212-222-2222" } I'm looking to display this information in the frontend (using Angular 2+) with *ngFor, but I want to customize the key ...

The Angular Material date picker unpredictably updates when a date is manually changed and the tab key is pressed

My component involves the use of the Angular material date picker. However, I have encountered a strange issue with it. When I select a date using the calendar control, everything works fine. But if I manually change the date and then press the tab button, ...

Having trouble understanding JSON data in React, unsure if I have made any conceptual mistakes

I'm currently utilizing the MaterialUITable to showcase tabular data, all within the confines of React as my primary framework. Fetching a JSON file from a parallel root directory is part of my workflow, with an aim to exhibit the information stored ...

Angular 9's Jasmine Mocking Provider Featuring Unique Methods and Properties

Currently, I am attempting to mimic the functionality of the angularx-social-login npm package. My goal is for the default test to be created and passed successfully. In my test specification, the following code is included: let component: Component; l ...

Is it possible to pass a Styled Components Theme as Props to a Material UI element?

After spending 9 hours scouring the internet for a solution, I am at my wit's end as nothing seems to work. Currently, I am developing a React component using TypeScript. The issue lies with a simple use of the Material UI Accordion: const Accordion ...

Ensuring a child element fills the height of its parent container in React Material-UI

Currently, I am in the process of constructing a React Dashboard using MUI. The layout consists of an AppBar, a drawer, and a content area contained within a box (Please correct me if this approach is incorrect)... https://i.stack.imgur.com/jeJBO.png Unf ...

Having trouble with the react-redux-starter-kit crashing when running npm run dev?

Exploring React/Redux with the help of the react-redux-starter-kit boilerplate, but encountered a new issue. Previously, npm run dev was functioning smoothly, but now it is crashing and showing this error message: [email protected] dev /Users/unoma ...

Utilize JavaScript destructuring to assign values to a fresh object

When working with JavaScript/Typescript code, what is a concise way to destructure an object and then assign selected properties to a new object? const data: MyData = { x: 1, y: 2, z: 3, p: 4, q: 5 } // Destructuring const { x, z, q } = data; // New O ...

Adding child arrays to a parent array in Angular 8 using push method

Upon filtering the data, the response obtained inside the findChildrens function is as follows: My expectation now is that if the object length of this.newRegion is greater than 1, then merge the children of the second object into the parent object's ...

How to toggle visibility of child elements in an HTML template using Angular 4+

I'm currently working on incorporating a basic "hover over a comment to display a reply button" feature in my angular application. Is it possible to create this effect using template reference variables exclusively? Something like this... <mat-l ...

Comparing TypeScript and C++ in terms of defining class reference member variables

class B; class A { A(B b_) : b{b_} {} B &b; }; In C++, it is possible to have a reference member variable like 'b' in class A. Can the same be achieved in TypeScript? Alternatively, is there a specific method to accomplish this in ...

The integration of Pure Bootstrap v4 with ReactJs is experiencing difficulties

I was eager to incorporate pure Bootstrap v4 into my React.js application. Initially, I set up my app using create-react-app and added Bootstrap assets to the index.html file in the public folder. Initially, everything worked fine. However, when I introdu ...