2

When I try to access a scss file in all my Vue SFCs the styles are duplicated causing large css bundles and Dev Tools to crash when style debugging

I am using Webpack 4 and webpack-dev-server to build and run development services with hot reload. I did not create the project with Vue CLI.

I have quite a lot of SFCs (~50) and a sass file (index.scss) that contains global styles and variables. I need to be able to use the styles and variables in index.scss across my SFCs. My current approach is using the data option in my Webpack sass-loader.

module: {
    rules: [
        {
            test: /\.vue$/,
            loader: 'vue-loader',
        },
        {
            test: /\.js$/,
            loader: 'babel-loader',
        },
        {
            test: /\.scss$/,
            use: [
                isDev ? { loader: 'vue-style-loader', options: { sourceMap: hasSM }} : {loader: MiniCssExtractPlugin.loader },
                {   
                    loader: 'css-loader', 
                    options: {
                        sourceMap: hasSM 
                    }
                },
                { 
                    loader: 'sass-loader', 
                    options: { 
                        sourceMap: hasSM, 
                        data: `@import "@/styles/index.scss";`
                    }
                }
            ]
        }
    ]
}

This is successful, however I am noticing my index.scss styles included in every component. Local development with devserver is almost impossible because the duplication across 50 components is so vast and devtools can't cope. When I do a build to extract the css then I can see the duplication and the app.css file is huge. I can use a minifying process for deployments but this is not suitable at all for local development.

I have tried other approaches such as removing the data option from sass-loader using import ./styles/index.scss in my main.js file instead, however this fails to build because it can't find the variables I use in my SFCs.

Please see my code snippet for roughly how I have my loaders set up. I feel as if there is a better way to do this, whether it's using different loaders/plugins and I am open to using different approaches

FrazorLazer
  • 59
  • 1
  • 4

3 Answers3

2

I managed to solve. Essentially when every Vue component was being processed then the sass-loader was importing my global sass file that included Variables, Mixins and most importantly my Styles. The import statement in my main.js doesn't work because the Variables and Mixins are not available by the time the component is being processed.

So I only need to import Variables and Mixins in my components and the Styles can be external and included in my main.js. Since Variable and Mixins are just being included when required (with @include statements), then there is no duplication since it's getting compile to CSS.

So I split my Styles and Variables and Mixins into separate variables

Styles => styles.scss

Variable and Mixins => variableMixins.scss

then import ./styles/styles.scss in my main.js

and my webpack sass-loader would be like

            { 
                loader: 'sass-loader', 
                options: { 
                    sourceMap: hasSM, 
                    data: `@import "@/styles/variableMixins.scss";`
                }
            }
FrazorLazer
  • 59
  • 1
  • 4
2

Been trying to solve this for too long.

This solution works but isn't perfect for me because I want to keep variables and global styles for specific things together.

_typography.scss, for example should contain general styles and variables relating to global line-height and vertical rhythm.

Then more granularly, a component such as _H1.scss would contain it's own sandboxed styles.

I don't want those general styles duplicated for every component.

The value of using CSS is sharing styles and being able to adjust and rebrand in a project globally. Components do the opposite of this by sandboxing everything.

I think CSS is currently at odds with componentized development and perhaps the answer may be to create a new approach where we use 'component ecosystems' to create relationships between otherwise dumb nodes.

A bit like how we use revealing module patterns in JS.

2

We ended up splitting up css into separate files (one per component), imporing them all into index.scss and importing index in App.vue`

import '@/scss/index.scss'

This eliminated lots of bloat / duplication and significantly simplified workflow: using sourcemaps + workspaces we can now edit scss directly in devtools and it won't break layout or multiply <style> tags or do any other quakery described all over Webpack's and vue-cli's github issues.

Surprisingly, even code-splitting for css still works, and dynamically loaded modules have their separate css files.

If you need scoping (which you'd need), just use id="component-name" on main node and wrap your scss in

#component-name { 
...
}

It amazes me how unsupported modern css techniques by Devtools, Webpack etc. Every aspect is full of bugs and only simpliest scenarios sort of work out of the box (if work at all).

Benny K
  • 1,107
  • 12
  • 9