webdiscus / html-bundler-webpack-plugin

Renders Eta, EJS, Handlebars, Nunjucks, Pug, Twig templates "out of the box". Uses HTML template as entry point. Resolves source files of scripts, styles, images in HTML. Supports for Vue.
ISC License
119 stars 12 forks source link

Strange Interaction Between This Plugin and MUI #59

Closed DylanVause closed 6 months ago

DylanVause commented 6 months ago

Current behaviour

When I import any component from @mui, the build process appears to freeze. There is no output (to console or files), and when I waited quite some time for the build to progress it did not.

For example, this will build fine (takes ~3500 ms):

import { createRoot } from 'react-dom/client';
import './index.css';

const root = createRoot(document.getElementById('app')!);

root.render(
<div>
    <p>Hello!</p>
    <p>How are you?</p>
</div>
);

But this appears to freeze the plugin:

import { createRoot } from 'react-dom/client';
import './index.css';
import Stack from '@mui/material/Stack';

const root = createRoot(document.getElementById('app')!);

root.render(
<Stack>
    <p>Hello!</p>
    <p>How are you?</p>
</Stack>
);

Expected behaviour

My expectation is a successful build similar to the result when not using MUI (as described above).

Reproduction Example

I have a mini reproduction example here: https://github.com/DylanVause/mui-webpack-bug

Environment

Additional context

My Webpack config is in the reproduction repository, but I will include it here as well for convenience:

const path = require('path');
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');

module.exports = [
    {
        name: 'client',
        mode: 'development',
        output: {
            path: path.resolve(__dirname, 'client-dist'),
            clean: true
        },
        resolve: {
            alias: {
                client: path.resolve(__dirname, 'client')
            },
            extensions: ['.js', '.ts']
        },
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    include: path.resolve(__dirname, 'client'),
                    exclude: /node_modules/,
                    use: [
                        {
                            loader: 'ts-loader',
                            options: {
                                transpileOnly: true,
                            },
                        },
                    ],
                },
                {
                    test: /\.css$/,
                    use: 'css-loader',
                    include: path.resolve(__dirname, 'client'),
                    exclude: /node_modules/,
                },
                {
                    test: /\.(ico|png|jp?g|svg)/,
                    type: 'asset/resource',
                    include: path.resolve(__dirname, 'client'),
                    exclude: /node_modules/,
                    generator: {
                        filename: 'img/[name].[hash:8][ext]'
                    }
                }
            ],
        },
        plugins: [
            new HtmlBundlerPlugin({
                entry: 'client/',
                js: {
                    filename: 'js/[name].[contenthash:8].js'
                },
                css: {
                    filename: 'css/[name].[contenthash:8].css'
                },
            })
        ],
        optimization: {
            usedExports: true,
        }
    },
];

By the way I absolutely love this plugin and apologize in advance if this 'bug' is just a result of me not knowing what I am doing.

webdiscus commented 6 months ago

Hello @DylanVause,

thanks for the issue report and the repo. I will research this use case.

webdiscus commented 6 months ago

Hi @DylanVause

I can reproduce the issue and I will try to fix it.

Temporary Workaroud

Instead of importing the style file in .tsx file, define the style directly in html:

<!DOCTYPE html>
<html>
  <head>
    <title>Test</title>
   <!-- define your styles here -->
    <link href="./style.css" rel="stylesheet" />
  </head>
  <body>
    <h1>Hello World!</h1>
    <div id="app"></div>
    <script src="index.tsx"></script>
  </body>
</html>

Remove the imported style from tsx file:

import { createRoot } from 'react-dom/client';
import Stack from '@mui/material/Stack';
//import './index.css'; // <= remove from js/tsx file

const root = createRoot(document.getElementById('app')!);

root.render(
  <Stack>
    <p>Hello!</p>
    <p>How are you?</p>
  </Stack>
);

P.S. this is realy a hard bug and will be fixed

DylanVause commented 6 months ago

@webdiscus Thank you for the workaround. I explored the bug some more today and learned that commenting out either import '@mui/material/Stack'; OR commenting out import './index.css'; allows for a successful build. It is only when they are BOTH included that the build fails.

I have modified my example to better illustrate this point:

import '@mui/material/Stack';  // <= disable this line or
import './index.css';          // <= disable this line to build successfully
// ^^^ If both these lines are enabled it will fail to build, regardless of the content of index.css

import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('app')!);

root.render(
<div>
    <p>Hello!</p>
    <p>How are you?</p>
</div>
);
webdiscus commented 6 months ago
import '@mui/material/Stack';  // <= disable this line or
import './index.css';          // <= disable this line to build successfully

yes, that's exactly what I noticed: only works with MUI or CSS.

Thank you!

webdiscus commented 6 months ago

@DylanVause

I found the problem. Webpack create many circular dependencies for MUI modules, so walking through circular dependencies occurs an infinite loop. I wrote a new algorithm to find all CSS files imported in JS, that avoids circular dependencies. By me local your example already works. I must yet optimise the algorithm. Also, I'm in process...

webdiscus commented 6 months ago

@DylanVause sorry for delay...

The issue is fixed in the version 3.4.4. Can you please check it?

DylanVause commented 6 months ago

Thank you! I can confirm this fix works for me as well.