Reputation: 126
I'm using code-splitting techniques for a web app built with Vue 2 and Webpack 3. The JS chunks work well in an asynchronous manner, giving me a good score on the Lighthouse performance audits.
By opening the 'Coverage' tab on DevTools, however, I can see that about 99% of my CSS styles go unused on the first contentful paint (i.e the first page load). The reason for this is simple: my main.scss
file (as shown below) imports all the stylesheets for the project, creating a big chunk of render-blocking code. I've followed a general, popular design pattern for the Sass files but obviously it doesn't fit well in the Component-based pattern used by Vue.
I've tried to load the Component stylesheets from the '.vue' Single-File Components, but I get into another issue: because Webpack parses these files before the main App.vue
file where I import my main.scss
, all Sass variables used throughout the code go 'undeclared', thus throwing errors all over the place.
My main.scss
file looks a bit like this:
//base style
@import 'base/variables';
@import 'base/fonts';
@import 'base/tools';
@import 'base/typography';
@import 'base/general';
@import 'base/buttons';
@import 'base/elements';
// ...
//components style
@import 'components/topnav';
@import 'components/header';
@import 'components/sidemenu';
@import 'components/footer';
@import 'components/login';
// ...
//responsiveness
@import 'base/responsiveness';
// cross browser styles
@import 'base/cross-browser';
Is there a way to split this big file and load styles accordingly and asynchronously, only when they are needed, just like with the other JS chunks?
I don't believe there is some special Webpack loader/plugin that would do this for me, and I'm looking for a solution with the least amount of refactoring to be made. The whole ordeal is increasing my Time to Interactive metrics to about 6-7 seconds.
Upvotes: 3
Views: 1328
Reputation: 126
So: after some fail and error, and after finding this page on vue-loader's docs I think I found a plausible solution, broken down in the following:
sass-loader
and node-sass
installed {
loader: 'sass-loader',
options: {
data: `path/to/_variables.scss`,
includePaths:[__dirname, 'src']
}
}
main.scss
file: left only the imports of the base styles, such as the Sass variables, fonts, mixins, responsive styles, forms and such.main.scss
file in App.vue
, which automatically removed the huge 700 KB load in the app.js chunk.<style lang="scss" scoped>
@import 'path/to/main.scss'; // **IF YOU HAVE `vue-cli` VERSION > 3.X, THEN YOU DON'T HAVE TO IMPORT GENERAL STYLE SHEETS SUCH AS THIS**
@import 'path/to/component/component.scss';
...
</style>
The reason why importing the main stylesheet file isn't an issue, is because it's non-blocking code, keeping the execution thread going - differently from before when a huge style sheet blocked the thread and left the page blank for too long. Obviously, Vue's out-of-the-box support of code-splitting in its own .vue files, makes all of this "legit" and super-fast.
The initial page load was (amazingly) under 1.5 seconds (was 4.5-6), as the Lighthouse performance score hit a solid range of 95-97... on Development environment, where I haven't even enabled JS or text compression! Previously, the score was around 45-55. I'm looking forward to deploying this in the other environments to get some more stats, where more tuning is configured, but it does look a very promising solution.
Upvotes: 1