Repository navigation
Loading SCSS with the ?url flag causes the import to fail #2522
Description
Activity
What do you expect to get by appending
?urlto an SCSS file? Multiple CSS files are going to be concatenated into one file during build so it's not a 1 to 1 mapping like static assets.Reacted by Jack AsherMy expectation would be to point the the resulting CSS after compilation, so I can have a
linktag that I inject at runtime reference it, so in development it would be/src/style.scss(which the vite dev server compiles on request) and in production it would bedist/assets/style.b4186631.cssor whatever is output.If I understand, the problem of what to do is that the styles are concatenated, scoped to the JS, but I'm trying to reference a style directly, so it may be part of one or more bundles that's associated with various scripts, not a single CSS bundle for that SCSS entrypiont.
The usecase I'm trying to solve is scoping my CSS inside of a shadow DOM element. Another domain is including a script from my site to get a component. I want to omit adding the CSS until I manually add it to the shadow node.
Reacted by tarnishablec, BARNZ, Nate Moore, xiaoming, Tim van Herwijnen, eristhea, Enteleform, Bogac Guven, Thor-Björn Andersson, Pavlos Touboulidis and 6 moreSame problem for me basically. We want to load different SCSS files for different pages and use React Helmet for that and would like to point to the URL of the file dynamically instead of having Vite appending the style automatically to the page.
Reacted by EviSONG and Tim van HerwijnenAny progress yet? I am facing a similar scenario when dealing with shadowdom, need to get scss compilation result and inject a preload link into head
Reacted by EviSONG, Jack Asher, Tim van Herwijnen and TAI've started some hacking on it #4604 for a few hours, but the build tools are bringing my poor machine to its knees. (It's pretty old and lightweight.) Sorry for dropping my brain dump here.
Here's what I've learned so far. It looks like most of the relevant (development) changes will be made in
packages/vite/src/node/plugins/css.ts- Using fd0a0d9 as an example, getting
?urlto return. (I have a hacky solution with detecting the?url, I didn't look too hard for the correct way to get that.); avoids the compile error. - When directly accessing a css preprocessed file, vite behaves differently when a JS/TS/etc file imports it.
- If a js file imports
/src/style.scss, the dev server returns JS that appends the compiled CSS to the document - If no js file imports
/src/style.scss, the dev server returns the raw source code (not compiled) - The css source file needs to be resaved for the dev server to update the result (it's cached across restarts)
vite builddoesn't produce an output for/src/style.scsseven if it's imported with or without?urlvite buildadds stylesheet links to the built HTML with the compiled css.
Development Server
Number 2 above, probably doesn't matter. the import behavior for JS is necessary for the intended behavior. I'm thinking if you import
/src/style.scssit should returnexport default "/src/style.scss?compiled", then a new?compiledquery would return the results of compiling the source file.Build
Based on behavior, I'm guessing there is some sort of registration when a CSS import is encountered in a script file. With my dumb patch, a
/src/style.scss?urldoesn't include the compiled contents of/src/style.scssin an output css file (as it shouldn't). I'm hoping it wouldn't be too difficult to register a new css file (the manifest already returns an array of css files per JavaScript file) and output the css linked similarly as a normal CSS file and inline the URL in. I haven't looked at the build portion too much.- Using fd0a0d9 as an example, getting
The same error happens when using
rawfor scss files (import text from './src/style.scss?raw')Reacted by tarnishablec, Alex Zheng, Francois Valdy, Emanuel Pilz and Matheus SanchesThe behavior of referencing CSS and SCSS in Vue files is also different。
when use CSS:
=== App.vue ==
<template> <div class="div1">div1</div> <div class="div2">div2</div> </template> <style lang="scss" scoped> @import "./div1.css"; @import "./style/div2.css"; </style>=== ./div1.css ===
.div1{ background-image: url(./assets/logo.png); width: 80px; height:80px; }=== ./style/div2.css ==
.div2{ background-image: url("../assets/logo.png"); width: 80px; height:80px; }Compilation results:
.div1[data-v-243a7a0a]{ background-image:url(./logo.03d6d6da.png); width:80px; height:80px } .div2[data-v-243a7a0a]{ background-image:url(./logo.03d6d6da.png); width:80px; height:80px }The same code rename css to scss:
Compilation results:
.div1[data-v-12b736e0]{ background-image:url(./logo.03d6d6da.png); width:80px; height:80px } .div2[data-v-12b736e0]{ background-image:url(../assets/logo.png); width:80px; height:80px }"background-image:url(../assets/logo.png); " is error in div2.
It would be super useful if we could use something like:
import conditionalStylesUrl from 'conditionalStyles.scss?url'Ideally this would allow retrieving of a path to the resulting compiled css file which could then be dynamically inserted as a stylesheet conditionally based on some application logic. I'd love to know if there is already a way to do this?
Reacted by Tim van Herwijnen, Thor-Björn Andersson, TA, Kieran Pilkington, Arvin Sevilla and sabercoyI don't care if
scssfile has its compiled css's url, but I thinkcssfile should get its url.import cssUrl from 'someCssFile.css?url': syntax like this should be supported. We need a way to let vite help us organize our files but we use those files in our way, like add link element after component A mounted and remove that link after A is destroyed.however:
import compiledCssUrl from 'someScssFile.scss?url': this has different meaningsI think we should write it like:
import scssUrl from 'someScssFile.scss?url' import compiledCssUrl from 'someScssFile.scss?url?scss'Reacted by Jonathan Duck, Tim van Herwijnen, Enteleform, Thor-Björn Andersson, TA and Arvin SevillaWant to mention that the behavior for
import styles from './styles.css?url'is inconsistent between production and development.During production, it returns a Data URL, while in development it returns the path to the file. That seems okay-ish, but neither reference the concatenated output CSS file (which doesn't exist in development).
6 remaining items
My use case:
tinymceeditor requires css url to be present, I don't need postprocessing and other stuffs, just want toimport contentCss from 'tinymce/skins/content/default/content.min.css?url' import contentUiCss from 'tinymce/skins/ui/oxide/content.min.css?url'
Expect
contentCssandcontentUiCssto be the url of these files after build, I could use them:<Editor init={{ content_css: [contentCss, contentUiCss], }} />
But
vitecannot handle this situation.small world, @sep2, that is exactly what blocked my team too. We have to put tinymce skin css files into the public folder with a manual copying step during in build. If you adopt the same workaround, make sure you add a version prefix/suffix somewhere in the public file path for immutable caching, or your user might get stuck with that version forever.
Reacted by FelixWhat do you expect to get by appending
?urlto an SCSS file? Multiple CSS files are going to be concatenated into one file during build so it's not a 1 to 1 mapping like static assets.It does map 1 to 1 in the manifest file like static assets, or at least appears to do so:
"resources/css/app.css": { "file": "assets/app-99133e62.css", "src": "resources/css/app.css", "isEntry": true }, "resources/scss/themes/light.scss": { "file": "assets/light-987e26d3.css", "src": "resources/scss/themes/light.scss", "isEntry": true }, "resources/scss/themes/dark.scss": { "file": "assets/dark-618dbc8a.css", "src": "resources/scss/themes/dark.css" }
Note that I do specify the these files as input in the vite.config.
Looking at the manifest is mildly infuriating since we can clearly see that the scss is being compiled, but we are not able to use it dynamically because we need the url of the generated css. There has to be a way to return the url, right?
We have the same problem coming from CRA. Our use case is to import dynamic theme scss from a third party package based on a user setting. The css files are too big and too many to preload all of them, so we want to load them on demand. In CRA we imported the scss as url and appended it to the html head. Now in Vite that seems impossible as ?url doesn't transform the sass css in build/preview mode.
I hope this will be fixed by e.g. ?inline&url, but for now I want to share our workaround. We ended up using dynamic import(), like import('@/stylesheets/themes/theme.light.scss'). This automatically bundles the sass as a separate css file in the assets folder and automatically links it in the html head on demand. The problem with this approach though is that the css files are appended but never removed. So here comes the "hacky" part: after import you need to toggle the dynamically linked css by using the media attribute. In dev mode this needs to be done on the appended <style ...> tag, and in production mode on the <link ...> tag. Downside of this approach is that all imported theme css files are attached to the DOM forever, but I think browsers are smart enough to allocate resources accordingly.
Our stripped-down react code is as follows:
// Globally configured themes const themes = { 'light': { id: 'light', import: () => import('@/stylesheets/themes/theme.light.scss'), }, 'dark': { id: 'dark', import: () => import('@/stylesheets/themes/theme.dark.scss'), }, }; // Theme DOM updater. If undefined, it will unmount all themes const applyTheme = (themeId) => { // Dev mode uses <style> and production mode uses <link> const oldStyles = document.querySelectorAll( `style[data-vite-dev-id*="/theme."], link[href*="/theme."]` ); oldStyles.forEach((oldStyle) => oldStyle.setAttribute('media', 'disabled')); if (themeId) { const newStyle = document.querySelector( `style[data-vite-dev-id*="/theme.${themeId}"], link[href*="/theme.${themeId}"]` ); newStyle?.removeAttribute('media'); } }; // Component to automatically mount and apply current theme const ThemeManager = ({ themeId }) => { const theme = themes[themeId]; // Get theme config with its import method const themeIdRef = useRef(); // Dynamically import its css file and update the DOM useEffect(() => { themeIdRef.current = theme.id; theme.import().then(() => applyTheme(themeIdRef.current)); }, [theme]); // On unmount disable all theme css useEffect(() => () => applyTheme((themeIdRef.current = undefined)), []); };
Reacted by Tim van HerwijnenWe're having the same issue. We need to pass a URL to a CSS overrides file to a 3rd party library, which loads it internally. We used ?url which seemed to work fine on development, but once deployed, it returns a URL to the original SCSS file, which the browser won't accept. We need it to process the SCSS and return the URL of the resulting parsed file, but this doesn't currently seem possible with Vite.
- addedp3-significantHigh priority enhancement (priority)High priority enhancement (priority)
on Oct 30, 2023 For nuxt 3, I wanted something like:
<script setup> // alternative: // const styleHref = new URL("~/assets/styles/app.scss", import.meta.url).href import styleHref from "~/assets/styles/app.scss?url" useHead({ link: [{ href: styleHref, rel: "stylesheet" }] }) </script>
However, since "?url" doesn't seem to work for scss how I wanted it to (compile scss -> css, then output the path as string), this is my workaround:
<script setup> import lAppStyle from "~/assets/styles/app.scss?inline" useHead({ style: [lAppStyle] }) </script>
- locked and limited conversation to collaborators
on Jan 27, 2024
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsHas plan
Describe the bug
Similar to #2455, when importing SCSS into a JS file, with the
?urlflag, the import will fail.A related, but apparently different bug, is that if
?urlis used with a CSS file, it evaluates to a string likeexport default "/src/style.css". This may deserve a separate issue.Reproduction
This can be reproduced with:
yarn create @vitejs/app --template vue vite-sample; cdyarn add sasssrc/style.scssApp.vueError in console
System Info
viteversion: 2.1.0Logs (Optional if provided reproduction)
viteorvite buildwith the--debugflag.