-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
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
Loading SCSS with the ?url
flag causes the import to fail
#2522
Comments
What do you expect to get by appending |
My expectation would be to point the the resulting CSS after compilation, so I can have a 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. |
Same 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. |
Any 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 |
I'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
Development ServerNumber 2 above, probably doesn't matter. the import behavior for JS is necessary for the intended behavior. I'm thinking if you import BuildBased 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 |
The same error happens when using |
The behavior of referencing CSS and SCSS in Vue files is also different。 when use CSS:=== App.vue ==
=== ./div1.css ===
=== ./style/div2.css ==
Compilation results:
The same code rename css to scss:Compilation results:
"background-image:url(../assets/logo.png); " is error in div2. |
It would be super useful if we could use something like:
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? |
I don't care if
however:
I think we should write it like:
|
My use case is when using CSS within a Web Component. So: import css from '../styles/webcomponent.css?url';
console.log(`Static import: ${css}`); // Static import: export default "/styles/webcomponent.css"
// vs
const css = new URL('../styles/webcomponent.css', import.meta.url).href;
console.log(`Import meta: ${css}`); // Import meta: http://localhost:3000/styles/webcomponent.css Import meta works fine, but I guess the stylesheet isn't processed? Correct me if I'm wrong. I'm not using some plugin yet (e.g.: autoprefixer), so I can't say for sure. |
Want to mention that the behavior for 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). |
Since the implementation details of CSS files differ between production and development, it seems like the file URL approach is too low-level. We need something that can allow us to manipulate where Vite applies styles during both production and development, like a config 😕 or lifestyle hooks 😱 |
Currently queries has these behaviors.
I think making it like below will have a consistency with the queries above.
Also these (it's a bit off-topic)
|
Same issue devs! Any updates on this? |
Same issue. My team needs to have fine control over the order/position at which css files are added to the DOM, hence we cannot rely on vite's built-in css import handler and must manually create The only work around we can think of is renaming the |
@patak-dev What if we could add or remove style roots through an API? The implementation details of the API would differ between production and development, and OFC without using the API things would behave as they do now. Something like the following might do the trick: // main.js (the entry file for index.html)
// typeof styleRootSet === Set<HTMLElement>
import { styleRootSet } from '@vite/client'
// runs before style tags are added to dom
export function setup() {
// setup details...
const shadowDOM = container.attachShadow?.({mode: 'closed'})
styleRootSet.delete(document.head) // CSS no longer goes here
styleRootSet.add(shadowDOM) // CSS now goes here
// finish setup...
}
// runs after style tags are loaded
export function mount() {
// mount your app, e.g.:
document.body.appendChild(container)
ReactDOM.render(<Content/>, root);
} The idea is that if an entry file exports two functions called I realize this might have performance implications for production and/or that something like this can be done other ways, but at least maybe we can get the conversation moving in a productive direction. |
It would be helpful to have a way to force style to load first before anything else. This would prevent the flash of unstyled elements on page reload during development mode. It will improve the development experience.
Using import styleUrl from './index.scss?url'
//...
const documentHtml = escapeInject`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="${logoUrl}" />
${dangerouslySkipEscape(`<link rel="stylesheet" href="${styleUrl}" />`)}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="${desc}" />
<title>${title}</title>
</head>
<body>
<div id="page-view">${dangerouslySkipEscape(pageHtml)}</div>
</body>
</html>` However it doesn't work in production since the URL becomes a base64 encoded data URI string :/. |
My use case: import contentCss from 'tinymce/skins/content/default/content.min.css?url'
import contentUiCss from 'tinymce/skins/ui/oxide/content.min.css?url' Expect <Editor
init={{
content_css: [contentCss, contentUiCss],
}}
/> But |
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. |
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)), []);
}; |
We'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. |
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> |
Describe the bug
Similar to #2455, when importing SCSS into a JS file, with the
?url
flag, the import will fail.A related, but apparently different bug, is that if
?url
is 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 sass
src/style.scss
App.vue
Error in console
System Info
vite
version: 2.1.0Logs (Optional if provided reproduction)
vite
orvite build
with the--debug
flag.The text was updated successfully, but these errors were encountered: