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

[FEATURE REQUEST] Support the CSS extraction from styles used in *.vue files #53

Closed else1fy closed 7 months ago

else1fy commented 7 months ago

Current behaviour

Build time is incredibly increased if there is an import of vue sfc components in the code, from 4 seconds to 80. If there is a link to the style file in this component, then the project is not built and crashes with an error.

Reproduction Example

I used vue-loader for processing sfc components, swc-loader for js/ts files and sass-loader for style files. And of course your plugin, if you remove it from the configuration and transfer only the ts file to webpack, everything works as expected

Environment

Additional context

After digging a little in the code, putting console.log wherever possible, I got to this place Collection->findDependenciesOfModule->walk, it looks like this function gets into some kind of infinite recursion, I may be wrong, but I hope it helps you somehow

webdiscus commented 7 months ago

Hello @else1fy,

thanks for the issue report. I don't use vue, can you please create a small repo with reproducible issue.

webdiscus commented 7 months ago

The html-bundler-webpack-plugin is designed as replacer of the html-webpack-plugin. As far as I know, Vue is mostly used with Vite.

else1fy commented 7 months ago

Hello @webdiscus,

I switched to webpack and your plugin because Vite does not give me the same flexibility in terms of the structure of files/folders in dist as webpack, it decides a lot for me, and I can't influence it, and this is very important in my work

I was not able to reproduce a serious increase in build time in a minimal configuration, I will try to understand what is the matter a little later. In the current repository, I reproduced an error with connecting a scss file inside the sfc component

https://github.com/else1fy/html-bundler

webdiscus commented 7 months ago

@else1fy thanks for the repo. I try to fix it.

As a workaround, you can define the SCSS file directly in HTML, not in *.vue file, because the plugin works with scripts (js, ts, mjs, etc.). But I'm trying to extend functionality for vue.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Home</title>
       <!-- define SCSS styles here and remove it from *.vue -->
        <link href="./MyButton.scss" rel="stylesheet" />
    </head>
    <body>
        <div id="app">
            <h1>{{ title }}</h1>
            <my-button></my-button>
        </div>
        <script src="./index.ts"></script>
    </body>
</html>
else1fy commented 7 months ago

@else1fy thanks for the repo. I try to fix it.

As a workaround, you can define the SCSS file directly in HTML, not in *.vue file, because the plugin works with scripts (js, ts, mjs, etc.). But I'm trying to extend functionality for vue.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Home</title>
       <!-- define SCSS styles here and remove it from *.vue -->
        <link href="./MyButton.scss" rel="stylesheet" />
    </head>
    <body>
        <div id="app">
            <h1>{{ title }}</h1>
            <my-button></my-button>
        </div>
        <script src="./index.ts"></script>
    </body>
</html>

Thanks for the suggestion, I thought about it, but the first thing that came to my mind was that importing dozens or even hundreds of component style files into an html file is too much.

But taking another look at your example, now I think it's possible to import all these files into one other style file, and plugging it into html could be the solution.

And yet, I would like to be able to keep the components completely isolated, so that by importing just one file, we would pull all its dependencies, including styles.

else1fy commented 7 months ago

I was able to reproduce the build time increase (~10 times), this happens when we import any style file directly into the ts file into which the sfc vue component is imported.

You can view all this in the same repository, in the "build time" branch.

webdiscus commented 7 months ago

importing dozens or even hundreds of component style files into an html file is too much.

Yes you are right.

import all these files into one other style file, and plugging it into html

This is the fastest way, the plugin does not have to recursively find a parent module.

I would like to be able to keep the components completely isolated, so that by importing just one file, we would pull all its dependencies, including styles

Yes, that makes sense. I'll try to add support for Vue, but it is not easy. The current version can extract imported styles from JS/TS files.

webdiscus commented 7 months ago

@else1fy can you please test the beta version 3.1.0-beta.0

This is only beta version to test. The build time of the example "Hello World" is tooo long, ~ 1 sec, because the Webpack generate tooo much needles dependency modules for each Vue runtime component :-/

webdiscus commented 7 months ago

@else1fy

I have tested the v3.1.0-beta.0 with both branches the main and build-time. The build time is the same: ~ 1-1.3 sec.

if I open the compiled html in a browser, I see empty page.

The generated html contains div with tags:

      <div id="app">
            <h1>{{ title }}</h1>
            <my-button></my-button>
        </div>

In the browser inspector is:

<div id="app" data-v-app=""><!----></div>

So the Vue app replaces the div#app with empty string. What's wrong? Why can't I see "Hello World?"

else1fy commented 7 months ago

There are a couple of points

  1. For some reason, when I install the beta version and try to build it, it gives an error. But it disappears if you delete the node_modules folder and the package-lock.json file, and re-run npm i image_2023-11-20_15-12-34
  2. If you specify the language of the style file in vue sfc using the lang="scss" attribute, it also gives an error image_2023-11-20_15-22-18
else1fy commented 7 months ago

@else1fy

I have tested the v3.1.0-beta.0 with both branches the main and build-time. The build time is the same: ~ 1-1.3 sec.

if I open the compiled html in a browser, I see empty page.

The generated html contains div with tags:

      <div id="app">
            <h1>{{ title }}</h1>
            <my-button></my-button>
        </div>

In the browser inspector is:

<div id="app" data-v-app=""><!----></div>

So the Vue app replaces the div#app with empty string. What's wrong? Why can't I see "Hello World?"

This is because I did not specify a special alias for vue, I fixed it in the main branch, I also added the lang="scss" attribute there, which causes an error during the build. If you remove it and build it, then index.html in dist should display the content as expected

webdiscus commented 7 months ago

delete the node_modules folder and the package-lock.json file, and re-run npm i

I can't reproduce it. By me local works w/o error.

If you specify the language of the style file using the lang="scss" attribute, it also gives an error

yes, I can reproduce it. W/o the lang attribute works fine, but with the attribute it gives an error. Just added an attribute total breaks the workflow of inner processes in Webpack :-/ I try to fix it.

webdiscus commented 7 months ago

If you specify the language of the style file using the lang="scss" attribute, it also gives an error

ah, I have read the vue docu.

If you add the lang attribute, then will be applied the sass loader to the resource. The lang attribute should be added only when no html bundler plugin used, because the bundler plugin self resolve the source SCSS file and apply own style loader.

Also, it makes no sense to use lang="scss" attribute in vue, just remove it, the plugin does it for you.

P.S. I try to catch this double use case (via vue and plugin loader) and fix it.

The Vue loader do much non-standard things in Webpack that break default process pipeline. All such "special cases" I must catch&fix manually.

webdiscus commented 7 months ago

@else1fy

in the v3.1.0-beta.1 is fixed issue when using the lang="scss" attribute. So, using the html bundler plugin, the lang="scss" attribute is not needed, it takes no effect. For the compatibility with existing components, which already have the lang attribute , this attribute will be in the plugin ignored.

else1fy commented 7 months ago

@webdiscus Yes, it works, thanks a lot!

Now I don’t have the opportunity to test this assembly on a full-fledged project, but it will be tomorrow. At first glance there shouldn't be any problems)

You've made an amazing plugin, keep it up!

webdiscus commented 7 months ago

@else1fy thank you for the very interesting use case :-)

else1fy commented 7 months ago

@webdiscus There is one more point: styles written directly in the