Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency Pre-Bundling does not bundle styles #7719

Open
7 tasks done
ascott18 opened this issue Apr 13, 2022 · 15 comments
Open
7 tasks done

Dependency Pre-Bundling does not bundle styles #7719

ascott18 opened this issue Apr 13, 2022 · 15 comments

Comments

@ascott18
Copy link

ascott18 commented Apr 13, 2022

Describe the bug

Dependency pre-bundling does not bundle CSS (or other css langs; in this case, SASS) imports within dependencies.

The result of this is that in serve mode when using component frameworks like Vuetify with per-component imports, each individual CSS file for each individual component is loaded with an independent HTTP request, even though all the scripts for these components are bundled into a single file.

This results in 100+ extra HTTP requests in serve mode.

Reproduction

https://github.com/ascott18/repro-vite-css-prebundling

System Info

System:
    OS: Windows 10 10.0.19044
    CPU: (16) x64 Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz   
    Memory: 12.01 GB / 31.94 GB
  Binaries:
    Node: 16.13.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.15.2 - C:\Program Files (x86)\Yarn\bin\yarn.CMD  
    npm: 8.1.3 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: 100.0.4896.75
    Edge: Spartan (44.19041.1266.0), Chromium (100.0.1185.36)
    Internet Explorer: 11.0.19041.1566
  npmPackages:
    vite: 2.9.3 => 2.9.3

Used Package Manager

npm

Logs

(including image because I can't capture Chrome network tools output in a reasonable text format)
image

Validations

@ascott18
Copy link
Author

ascott18 commented Apr 14, 2022

After some tinkering, I was able to achieve the desired outcome here using the following configuration. Took a while to figure out since extensions is undocumented. (Other experimental features are documented, like SSR - is this an oversight?):

    optimizeDeps: {
      extensions: [".scss", ".sass"],
      esbuildOptions: {
        plugins: [
          (await import("esbuild-sass-plugin")).sassPlugin({
            type: "style",
            // Setting `logger.warn` to no-op is a workaround for
            // https://github.com/sass/sass/issues/3065#issuecomment-868302160.
            // Since `optimizeDeps` is only processing third party dependencies and only during dev,
            // we don't care about *any* deprecation warnings. The `quietDeps` SASS option doesn't work.
            logger: { warn() {} },
          }),
        ],
      },
    },

Would there ever be consideration to making this functionality baseline? Since build mode supports popular CSS preprocessors, I think it would make sense to also support them here in serve. I realize that different "glue" would have to be built to plug them into esbuild rather than rollup (as to not add third-party dependencies like I did in my config here). Is this something that would be worth my while to start a PR for?

@bluwy
Copy link
Member

bluwy commented Apr 14, 2022

The extensions option is intentionally undocumented since it's not ready for public use, unlike SSR which is more on the stable side (though still experimental). I think prebundling styles is something worth exploring too, and it's great to see extensions covers this case too. I'm not sure there's any gotchas doing so at the moment, but if we can experiment this in userland as a Vite plugin to gather feedback, that would be helpful to justify bringing into core.

@stratdev3
Copy link

@ascott18 thanks for the workaround.

One more precision

vuetify 2 is limited to sass v1.32, see discussion vuetifyjs/vuetify#13694 (comment)

To satisfy this dependencie, need to have { "esbuild-sass-plugin": "^1.7.0" } in package.json

@ricardovanlaarhoven
Copy link

Is there any news on this?

@ascott18 When i add your code to my vite.config.ts i'm getting the following error:

X [ERROR] Top-level await is currently not supported with the "cjs" output format

    vite.config.ts:39:9:
      39 │         (await import("esbuild-sass-plugin")).sassPlugin({
         ╵          ~~~~~

What am i doing wrong?
i've installed the esbuild-sass-plugin package

@ghost
Copy link

ghost commented May 3, 2023

@ricardovanlaarhoven I assume an object is passed to your defineConfig instead of an async function.

export default defineConifg(async () => ({
// now you can do await import
}))

@ricardovanlaarhoven
Copy link

Thanks that helped (makes real sense. That i didn't think of that myself). Unfortunately it doesn't result in what i'd hoped for.
Every time a new view is opened. It's loading really slow and eventually it fails and when i reload it works immediately

image

@ghost
Copy link

ghost commented Jun 3, 2023

@ricardovanlaarhoven It's the same for me and on huge projects is very time consuming.

@stratdev3
Copy link

@ricardovanlaarhoven

X [ERROR] Top-level await is currently not supported with the "cjs" output format

    vite.config.ts:39:9:
      39 │         (await import("esbuild-sass-plugin")).sassPlugin({
         ╵          ~~~~~

What am i doing wrong? i've installed the esbuild-sass-plugin package

I've had the same issue.

It's nodes and you need to edit your package.json to set type

{
  "type": "module",
}

It fix all my problem and vite/vue(2.7)/vuetify(2) perform well and fast at each request even on cold start.

@ricardovanlaarhoven
Copy link

vite.config

// Plugins
import vue from "@vitejs/plugin-vue";
import vuetify, { transformAssetUrls } from "vite-plugin-vuetify";

// Utilities
import { defineConfig } from "vite";
import { fileURLToPath, URL } from "node:url";

// https://vitejs.dev/config/
export default defineConfig(async () => ({
  cacheDir: "/etc/cache/vite",
  plugins: [
    vue({
      template: { transformAssetUrls },
    }),
    // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin
    vuetify({
      autoImport: true,
      styles: {
        configFile: "src/styles/settings.scss",
      },
    }),
  ],
  define: {
    "process.env": {},
    __VUE_I18N_FULL_INSTALL__: true,
    __VUE_I18N_LEGACY_API__: false,
    __INTLIFY_PROD_DEVTOOLS__: false,
  },
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
    extensions: [".js", ".json", ".jsx", ".mjs", ".ts", ".tsx", ".vue"],
  },
  server: {
    host: true,
    port: 30002,
  },
  optimizeDeps: {
    extensions: [".scss", ".sass"],
    esbuildOptions: {
      plugins: [
        (await import("esbuild-sass-plugin")).sassPlugin({
          type: "style",
          // Setting `logger.warn` to no-op is a workaround for
          // https://github.com/sass/sass/issues/3065#issuecomment-868302160.
          // Since `optimizeDeps` is only processing third party dependencies and only during dev,
          // we don't care about *any* deprecation warnings. The `quietDeps` SASS option doesn't work.
          logger: { warn() {} },
        }),
      ],
    },
  },
}));

added to the package.json:

        "esbuild-sass-plugin": "^2.10.0",
        "esbuild": "^0.18.0"

and "type": "module",

result is still the same, with often a reload of the complete site.

image

@ghost
Copy link

ghost commented Aug 26, 2023

@ricardovanlaarhoven Now Vue VLS 1.8.8 reports incompatible type for esbuild-sass-plugin inside the vite.config.ts

Vue: Type

import("/path/to/project/node_modules/esbuild/lib/main").Plugin

is not assignable to type

import("/path/to/project/node_modules/vite/node_modules/esbuild/lib/main").Plugin

Types of property setup are incompatible.

optimizeDeps: {
    extensions: [".scss", ".sass"],
    esbuildOptions: {
      plugins: [
        sassPlugin({ // 
          type: "style",
          logger: { warn() {} },
        }),
      ],
    },
 }

The current workaround I found:

optimizeDeps: {
    extensions: [".scss", ".sass"],
    esbuildOptions: {
      plugins: [
        sassPlugin({ // 
          type: "style",
          logger: { warn() {} },
        }),
      ],
    } as DepOptimizationConfig['esbuildOptions']
 }

@sotirr
Copy link

sotirr commented Sep 21, 2023

@ascott18 It's work but it's breaks the next settings:

css: {
  preprocessorOptions: {
    sass: {
      additionalData: [
        '@import "./src/styles/variables.sass"',
        '',
      ].join('\n'),
    }
  }
},

@ricardovanlaarhoven
Copy link

ricardovanlaarhoven commented Jan 22, 2024

Vuetify does only seem to have this problem when you use the config file option in the vite config.

  styles: {
    configFile: 'src/styles/settings.scss',
  },
})

This option is needed when doing component specific sass variable overrides. (which i need..)

Also

import { defineConfig, DepOptimizationConfig } from "vite";
import Vue from "@vitejs/plugin-vue";
import vuetify, { transformAssetUrls } from "vite-plugin-vuetify";
import { fileURLToPath, URL } from "node:url";
import { sassPlugin } from "esbuild-sass-plugin";


if (process.env.NODE_ENV === "development") {
  const dotenv = await import("dotenv");
  dotenv.config({
    path: "./.env.development",
  });
}
const API_HOST_DEVELOPMENT = process.env.API_HOST_DEVELOPMENT;
const apiHost = API_HOST_DEVELOPMENT ? process.env.API_HOST_DEVELOPMENT.replace(/\/$/, "") : "";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    Vue({
      template: {
        transformAssetUrls,
      },
    }),
    // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme
    vuetify({
      styles: {
        configFile: "src/styles/settings.scss",
      },
    }),
  ],
  define: {
    "process.env": {},
  },
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
    extensions: [
      ".js",
      ".json",
      ".jsx",
      ".mjs",
      ".ts",
      ".tsx",
      ".vue",
    ],
  },
  server: {
    port: 4000,
    proxy: {
      "/api/": {
        target: apiHost,
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },



  optimizeDeps: {
    extensions: [".scss", ".sass"],
    esbuildOptions: {
      plugins: [
        sassPlugin({ //
          type: "style",
          logger: {
            warn () {},
          },
        }),
      ],
    } as DepOptimizationConfig["esbuildOptions"],
  },
});

The optimize deps doesn't seem to really speed thing up. It looks like its 7s where it was 10s pending, in a failry fresh project

@ricardovanlaarhoven
Copy link

With vuetify this specific time issue happens when you use vuetifys sass variables file AND use component specific sass variables.

So once you add this to the vite config:

export default defineConfig({
  plugins: [
    // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme
    vuetify({ styles: { configFile: "src/styles/settings.scss" } }),
  ],

and change
@use 'vuetify' with ( into @use 'vuetify/settings' with ( in your settings.scss

I guess because every sass file vuetify imports needs to be recompiled to add the settings.scss above it.

I've had contact with the founder from vuetify, but they don't know how to resolve it and if they are doing something the wrong way, they like to know it.

Hopefully anyone knows how to handle this, in any way.
Can i do something?
Does vuetify have to do something?
Does vite need to change anything?

@NotAsea
Copy link

NotAsea commented Jun 22, 2024

I remove the option

 styles: {
        configFile: "src/styles/settings.scss",
      },

and i observe the web load near instant, my guess is include this scss file make Vite have to run sass compile all the sass file of vuetify thus make loading feel like century, another reason to have a nonstyle component like PrimeVue so we can swap to use more performance css system like tailwindcss or unocss

@ricardovanlaarhoven
Copy link

ricardovanlaarhoven commented Jun 24, 2024

This option is necessary for component-specific SASS variable overrides. Webpack does not have this issue. I tried adding all components and SASS from Vuetify to the Vite server warmup configuration (https://vitejs.dev/config/server-options.html#server-warmup), but that doesn't seem to work either.

I'm wondering if this is a Vite issue or a Vuetify issue. I've spoken to @johnleider from Vuetify, and they are unsure what to do differently with the Vuetify loader. It would be great if someone from Vite could let us know if Vuetify needs to make any changes or if this is a Vite issue that we need to wait for a fix on.

And perhaps the label "has workaround" should be removed, or could anyone tell me what the workaround is, i've tried everything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants