Open ascott18 opened 2 years ago
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?
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.
@ascott18 thanks for the workaround.
One more precision
vuetify 2 is limited to sass v1.32, see discussion https://github.com/vuetifyjs/vuetify/issues/13694#issuecomment-852957010
To satisfy this dependencie, need to have { "esbuild-sass-plugin": "^1.7.0" }
in package.json
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
@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 }))
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
@ricardovanlaarhoven It's the same for me and on huge projects is very time consuming.
@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.
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.
@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']
}
@ascott18 It's work but it's breaks the next settings:
css: {
preprocessorOptions: {
sass: {
additionalData: [
'@import "./src/styles/variables.sass"',
'',
].join('\n'),
}
}
},
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
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?
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
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.
OP's reproduction is quite old (vite 2.9 and vuetify 2.4.8), so it would be great if someone can prepare a reproduction based on latest version of dependencies.
That would help us verifying whether optimizeDeps.extensions
based workaround is currently working on latest Vite.
Also orthogonal to this pre-bundling issue (which is about reducing the number of css requests from browser), there is an effort to improve sass processing in general by using latest feature of sass (and sass-embedded) package. It's not merged yet but hopefully this will be available soon (see performance comparison in the PR https://github.com/vitejs/vite/pull/17728#issuecomment-2247572134).
Hello @hi-ogawa, I forked the repro here and tried to upgrade it without changing it too much.
From what I see we still have a request per sass
file, but it is limited to the vuetify components used:
For the example I only used a few components from vuetify, but on a real project it can quickly go up
I've created a new vuetify project, added some sass variables and this is the result:
https://github.com/ricardovanlaarhoven/vuetify-vite-sass-speed-issues
run pnpm install
run pnpm dev
go to localhost:300
go to the network tab and see a lot of pending sass/scss requests
Once done, click on the Go to test link
And once again see a lot of pending requests
When you repeat this, the speed is excelent
When you cut the server, and rerun pnpm dev, the speed is slow again for the first time.
Keep in mind that this is a really really small project, just the starter of vuetify with 3 simple components on the test page. My pc the loading time is about 4s here. On my real project, it's about 20s and after every new page with 1 simple new component again. This test project only has 1 page.
You could add some more pages and components to see the difference in speed. For exmaple adding VDataTable adds makes it go up to 11 seconds
Thanks for providing a reproduction. I had a look and it appears that there are a few intertwined issues, so try to comment on them separately.
First of all, pre-bundling scss/sass files using esbuild-sass-plugin
should technically work at least for simple cases. I made a small example here https://github.com/hi-ogawa/reproductions/tree/main/vite-sass-pre-bundling and required configuration looks like this (which were briefly mentioned in https://github.com/vitejs/vite/issues/7719#issuecomment-1694483567)
import { defineConfig } from 'vite'
import { sassPlugin } from "esbuild-sass-plugin";
export default defineConfig({
optimizeDeps: {
extensions: [".scss", ".sass"],
esbuildOptions: {
plugins: [
sassPlugin({
// default `type: "css"` doesn't work since it emits separate css files
// and removes css import from js files.
// https://esbuild.github.io/content-types/#css-from-js
// https://github.com/glromeo/esbuild-sass-plugin#type-style
type: "style",
}),
]
}
}
})
The reason why this approach is not working specifically for vuetify is that because it relies on vite plugin to rewrite original .css
import into .sass
virtual module https://github.com/vuetifyjs/vuetify-loader/blob/e1587d8d6b9da45d159ec5eee39cfa901bc61aca/packages/vite-plugin/src/stylesPlugin.ts#L54-L58. This mechanism is probably difficult to apply to pre-bundling which is based on esbuild.
2nd issue is that current Vite's default sass setup is not best for speed performance. As I mentioned in https://github.com/vitejs/vite/issues/7719#issuecomment-2255383411, it's planned to integrate improved sass compilation API inside Vite. Before this feature is available, there are already two ways you might be able to improve performance by using css.preprocessorMaxWorkers
https://vitejs.dev/config/shared-options.html#css-preprocessormaxworkers or sass-embedded
package via alias (cf. https://github.com/vitejs/vite/issues/6734#issuecomment-1492975259). This is the result when I tested https://github.com/ricardovanlaarhoven/vuetify-vite-sass-speed-issues on my machine:
3rd issue is that you are likely experiencing frequent full-reload on navigation due to deps optimization triggered when discovering new dependencies in new pages. This is a different issue on its own and it happens when Vite's default heuristics is not able to discover dependencies used in user source code. For example, you can find a similar issue and potential solutions discussed on https://github.com/nuxt/nuxt/issues/26783 (I also remember other Vite frameworks like Sveltekit, Remix etc... experienced a similar issue).
I tried optimizeDeps.exclude: ["vuetify"]
in https://github.com/ricardovanlaarhoven/vuetify-vite-sass-speed-issues and indeed it looks like it can prevent spontaneous full-reload when navigating from /
to /test
(even though this will prevent pre-bundling and increase the number of js requests).
From what I can see, this issue having "has workaround" status seems right. I think it's still possible to improve vuetify (+ custom sass configFile) experience by figuring out 2nd and 3rd issues.
Thnx @hi-ogawa For taking so much time to investigate this with me. Perhaps @KaelWD from vuetify can read along with us.
I've tested it in my real-life project. I'm on a table page with already a lot of vuetify components, and going to a form page, it takes 48 seconds to load. When adding the following
optimizeDeps: { exclude: ["vuetify"] },
css: { preprocessorMaxWorkers: true },
it takes 9 seconds
When doing pnpm i -D sass@npm:sass-embedded@1.77.5
Mind that i have to change the version since vuetifyhas some deprecations (https://sass-lang.com/d/mixed-dec)
it takes 9 seconds
But i do still use the optimizeDeps and preprocessorMaxWorkers. And perhaps i'm not doing enough?
I'm grateful for the impressive time-cut.
a few points/questions:
adding the optimizeDeps has one downside, the first time you open the app, it goed to a white screen after loading. Then i can refresh the browser page and sometimes it's immidiatly there, sometimes i have to refresh one last time.
Figuring this out requires more domain knowledge of framework/library side and app specifics. I'm not familiar with Vue in general, so probably it's better to seek a help elsewhere.
did i do anything wrong with the sass embed workaround?
When using sass-embedded
override, having preprocessorMaxWorkers: true
might have a negative effect. Can you try removing it? (cf. https://github.com/hi-ogawa/test-vite-sass/issues/1#issuecomment-2249076746)
When to excpect the improbed sass api? vite 5.4? or 6 or?
Hopefully the improvement will be available in v5.4. One PR is merged https://github.com/vitejs/vite/pull/17728 and next one https://github.com/vitejs/vite/pull/17754 is also hopefully merged for 5.4.
When using sass-embedded override, having preprocessorMaxWorkers: true might have a negative effect. Can you try removing it? (cf. https://github.com/hi-ogawa/test-vite-sass/issues/1#issuecomment-2249076746)
Tried it a couple of times, results in about 12 seconds.
Which is also a huge time decrease. But less then the preprocessorMaxWorkers: true option.
@ricardovanlaarhoven can you update your repro to use latest vite 5.4.0-beta.0 and switch sass api to modern? I guess there is some sass cache, starting dev server and navigating takes only 3/4 seconds first time, next dev server restarts is faster:
define: { 'process.env': {} },
optimizeDeps: { exclude: ["vuetify"] },
css: {
preprocessorOptions: {
sass: {
api: 'modern'
},
},
preprocessorMaxWorkers: true
},
EDIT: removing preprocessorMaxWorkers
is even faster (restarting dev server with root page takes 2/3 seconds, once loaded, navigating to test page is almost instant)
In my real life project, going to a second page just like my comment before https://github.com/vitejs/vite/issues/7719#issuecomment-2257880959
perhaps it has something to do with caching building up??
The start of the project itself seems better to, i just didnt measure it before and don't mind the startup being a bit slow, thats just once or twice a day.
I'm curious if this PR addresses your the issues mentioned here: https://github.com/vitejs/vite/pull/14467 I filed it over a year ago and there are some conflicts that need to be resolved, but I'm happy to revive it if it seems like other people would benefit. I wasn't very successful in getting any of the project owners to respond on the PR though and eventually just gave up on it. The PR I believe only handles .css files directly and not sass, but it could presumably be extended if needed.
I'm no vite expert, but i think when css/sass/scss is getting pre compiled and not optimized on the fly. I would benefit from it.
What i saw is that on starting the dev server, there are a lot of css files loaded, and then when they are completed, the next batch of css files is loaded. And when i click on a link with new css files, those are loaded at that point.
And those loads are showing in my cli's log as optimize deps as i remember correctly.
for me it helped by raising this issue on vite's discord. Perhaps that could also help for your PR. There is a channel for contributing.
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
Used Package Manager
npm
Logs
(including image because I can't capture Chrome network tools output in a reasonable text format)
Validations