Maybe you can start by extracting it to a separate file.
<template></template>
<style src="pathToCssFile"></style>
<script></script>
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
I could have sworn that I saw someplace, either a plugin for Mix, or maybe webpack, that would allow you to extract single page vue component styles to their own stylesheet during compilation.
Am I trippin? Or is this a thing and I just can't find the docs for it?
Thanks.
Maybe you can start by extracting it to a separate file.
<template></template>
<style src="pathToCssFile"></style>
<script></script>
what do you mean extract to their own stylesheet? do you mean scoped?
<template>
<div>
//html code
</div>
</template>
<script>
//js code
</script>
<style scoped>
//css code
</style>
Perhaps I wasn't being clear.
I have an existing application that I downloaded, within it there are a ton of components that have style tags like so:
<style scoped lang="scss">
.dashboard {
.img-wrapper {
@apply w-full;
@apply flex;
@apply justify-center;
@apply items-center;
@apply mb-4;
}
h1 {
@apply text-center;
@apply text-gray-900;
@apply font-semibold;
@apply text-2xl;
@apply mt-2;
@apply mb-4;
}
.button-wrapper {
@apply flex;
@apply justify-center;
@apply my-2;
a {
@apply text-white;
@apply font-bold;
@apply py-1;
@apply px-4;
@apply rounded-full;
@apply mx-1;
}
}
}
</style>
I seem to recall there was a Mix or Webpack plugin that will extract those style chunks from each component into it's own css file.
Was I imaging this?
I can't find any documentation so perhaps I was.
@vkronlein googled and found this post link
Thanks man.
I think I did come across that answer ... but since it was 5 years old I disregarded it.
I'm using Webpack 5 with Mix 6, so I wonder if this works still.
The Vue Loader docs don't have anything listed for Webpack 5.
Thanks though, I'll keep looking into it.
Maybe the Webpack 5 docs will have something now that I know what to look for.
If I understand correctly, you want something like this?
<style scoped lang="scss">
@import "style.scss";
</style>
Nope.
I want to extract the styles from the components completely and have them stored in a stylesheet.
No styles in SFC for me. ;)
So you want to import each scoped styles in each components without having style tags? Or do you want a tool that will take all scoped scss styles in each components and build a single file with class prefixes? Not entirely sure I understand your needs.
2nd.
See the link that @maverickchan posted
Ok! Good luck then (can't really help you unfortunately)! I personally don't think it is possible to do what you ask because if the scoped style is not in a Vue file, I don't think vue-loader will be able to interpret it properly. I might be wrong though, so keep us posted! I'd be interested in your findings 🙂
This has nothing to do with scoped styles. Adding the scoped attribute to the style tag in a component just keeps your styles from leaking outside of the component, it has nothing at all to do with whether the vue-loader can interpret it. Vue-loader reads anything inside a style tag, scoped or not.
The Webpack ExtractTextPlugin will extract any text within a given tag and save it to whatever you file to specify, I'm just not up to date now on which version of Webpack is supported at this point.
But I will update you when I find out.
This is the answer of Thorsten Lünborg (from Vue's core team) to a similar question:
Plainly spoken, that’s not possible. No .vue files, no scoped styles, as they don’t / can’t run through vue-loader.
You could use css modules, but that would require rewriting a lot of template code.
Which makes sense, because it assigns a unique property (data-v-xxxxxxx) to each element having a class contained within the scoped styling. Without that parsing, this property won't be added, which means no scoped style (except if you prefix classes and modify the template's code).
But if I understand correctly, you want to keep these style tags in your actual code, and you want them get moved to an external CSS file when Vue files get compiled (via the extract plugin)? If that's the case. it seemed possible with the newer mini-css-extract-plugin when running Webpack 4 with a minor issue related to scope styles (see this issue).
I also dug deeper and found that they implemented Webpack 5 compatibility since v0.11.0 (and they kept improving it: the latest Webpack 5 related tag is v1.3.7). The doc is misleading though by saying the plugin requires Webpack 4 to work. They should probably write Webpack 4+.
Awesome ... thanks @piljac1
i am sorry could not help more , good luck pal.
No worries mate ... thanks so much for trying to help out, much appreciated!
https://laravel-mix.com/docs/6.0/examples#extract-vue-single-file-component-css-to-its-own-file
mix.js('src/app.js', 'js')
.vue({ extractStyles: 'css/vue-styles.css' });
If you are using Vue 2 don't forget to tell mix about that:
mix.js('src/app.js', 'js')
.vue({
version: 2,
extractStyles: 'css/vue-styles.css'
});
Note: assuming Mix version 6 is being used.
Good catch! It seems like it's what he's looking for!
Thanks @piljac1 =)
@vkronlein if you are still using Mix 5 I found the docs for it too:
https://laravel-mix.com/docs/5.0/options#laravel-mix-options
But from memory I think you can't use a custom css output file name.
I knew I saw it somewhere ... that it was built into Mix.
Using Mix 6 with Webpack 5.
Now I can run this once to create the stylesheet and then go through and delete these style tags.
Will it know to save as SCSS since they have lang="scss" attributes on the tags?
I guess we'll see ;)
You only need to compile the project once and never update it?
I only need to compile it once the get all the styles from the components into a single stylesheet.
I will manage them from there, building that new sheet into the style bundle, and removing the style tags from the components.
Feel me?
But will you need to update the Vue files in question? Because I'm pretty sure it won't work on the next compilation if you do that. Because randomly generated unique IDs are assigned to scoped classes when compiling. That means that if you don't have the scoped style section in your Vue file anymore, the compiler won't set unique IDs as HTML tag properties.
Random ids are added if @vkronlein used the scoped attribute (which I recommend)
if you use only:
<style lang="scss">
/* ... */
</style>
Random ids are not added.
So if you choose to not scope your styles be sure to choose distinct class names to avoid conflicts between components (which is what scoped styles tries to prevent).
I would take @piljac1 advice and keep the styles into their components. But I can see where you are heading and depending on the size/complexity of your project it can be manageable from there.
Ok let me explain better:
This is the starting component:
<template>
<div>
<p class="dashboard-p">
I am a <span class="green">Vue</span> component.
</p>
</div>
</template>
<script>
export default {
name: 'dashboard',
...
}
</script>
<style lang="scss" scoped>
.dashboard {
@apply text-gray-900;
.green {
@apply text-green-600;
}
}
</style>
When compiled this will create a uuid hashed scope component.
After extraction I will have (hopefully) a _dashboard.scss file for this component like so:
.dashboard {
@apply text-gray-900;
.green {
@apply text-green-600;
}
}
Then I will edit the component, removing the style tag:
<template>
<div>
<p class="dashboard-p">
I am a <span class="green">Vue</span> component.
</p>
</div>
</template>
<script>
export default {
name: 'dashboard',
...
}
</script>
When compiled this will NOT created a uuid hashed scope component since there's no css to scope to.
Then I can import all the component scss files into my app.scss file and compile them as normal.
I hope this makes it more clear.
Style in SFC is an anti-pattern to me.
Especially when using Tailwind ... I'm hoping that after getting all this style tag pollution out of these components I can go back and apply the classes directly on the html as Tailwind was designed for.
But I'm assuming that some of these are doing some sort of card type structures that need to be used over and over.
We'll see.
I got it first time.
As it seems you don't conflicting class names you can remove the scoped attribute, to avoid manually removing the hashes on your first generated css file from style extraction.
What I was referring to is this scenario:
<template>
<div class="green">
I am a green!
</div>
</template>
<style lang="scss">
.green {
@apply text-green-600;
}
</style>
<template>
<div class="green">
I am also green! But lighter!
</div>
</template>
<style lang="scss">
.green {
@apply text-green-100; /* different shade of green */
}
</style>
Now when extracting you are going to get this CSS:
.green {
color: #000055;
}
.green {
color: #0000FF;
}
note: sample color values
And as those classes share the same name, and same selector specificity, the latter will override the former.
Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
So be sure to either have different class names, or to lightly scope every component with a root class-name, for example:
<template>
<div class="foo">
<div class="green">
I am green!
</div>
</div>
</template>
<style lang="scss">
.foo {
.green {
@apply text-green-600;
}
}
</style>
<template>
<div class="bar">
<div class="green">
I am also green! But lighter!
</div>
</div>
</template>
<style lang="scss">
.bar {
.green {
@apply text-green-100;
}
}
</style>
So you get an output without class names conflicts:
.foo .green {
color: #000055;
}
.bar .green {
color: #0000FF;
}
As I said before, scoped styles and component hashes are for this reason.
If your concern is to avoid having Vue generating the hashes in runtime to increase performance, don't worry, those hashes are calculated at compilation time, not at runtime (when using Vue Single File Components).
Otherwise CSS extraction would not work at all as the hashes would never match.
@rodrigo.pedra The existing application that he downloaded is using scoped styles (see the 4th reply, including the original question) 🙂
Saw your last response after sending mine.
If you are using tailwind, why you have those style tags anyway?
Isn't easier to just replace the classes generated in the <style> tags by tailwind built-in utility classes?
I remember Adam Whatan talking about being reluctant on adding @\apply , but ended up adding it fearing people would be reluctant from the mindset shift needed to embrace utility classes.
@piljac1 I see that, but as the workflow he is describing is:
<style> tagsRemoving the scoped attribute by careful search and replace, seems easier than the second step by a lot.
At least in my opinion.
@rodrigo.pedra There's probably a good reason why they used scoped style, so I'm guessing that looking for style collision would be a pain. I think that converting custom scoped classes to their applied utility classes would be the way to go. It would probably take longer, but the behavior would be as expected. But that's assuming all classes only use @apply directives and no custom CSS.
An other way to go could be explicitly defining data-v-xxxxxxx properties related to each components. But that could be painful to do, and not really clean in my opinion.
In the end, I don't think there's an easy solution.
Either you:
@apply directive classesdata-v-xxxxxxx identifiers on HTML tagsThis is more of an experiment really ... this application has quite a few features I need for what I want to build, and is an actual package that you install in Laravel. But it runs as a Vue app.
I've extracted the package to become the actual app itself moving all the package classes up to their corresponding place in the main App structure.
I may not even choose to use this at all if I can't strip away all the pieces I don't want ... but the first step is extracting out all this sass and determining what's actually needed for pre-build structures and what can be implemented in the component as a utility class.
So for the moment ... it's just for fun and learning, but hopefully it'll turn out that it works for what I want to build.
So it turns out that
vue({
version: 2,
extractStyles: true
})
does nothing.
Nothing extracted anywhere I could find.
Weird.
.vue({
version: 2,
extractStyles: 'css/vue-styles.css'
})
Does indeed extract the css to the correct file, writing proper css for each sass file, so that's less than desirable.
But it also maps each selector to a component like so:
.header-left-logo .header-left-logo-text[data-v-5d142428] {
@apply text-2xl;
letter-spacing: 1px;
color: var(--header-text-color);
}
So as it turns out, it'll be easier to just manually extract the scss into a file and delete the style tags.
Pity, I was hoping to avoid this.
Anyway, that's how it works.
Please or to participate in this conversation.