Advanced Integration Continued: Suggested CSS Setup
Now that you have your site compiling let's talk about how we might suggest setting up your CSS in this environment. Below we're going to show how to setup SASS but adapt to any precompiler.
Create a SASS folder in src
In src
create a sass
folder.
Create essentials.scss and global.scss
So, we're actually going to generate three css files. One is going to be loaded in the <head> of your HTML and the other two are going to be deferred and loaded at the bottom of the page. Why? Well, essentials is going to contain styles for everything (love this term 😑 ) "above the fold" while the meat of the CSS is going to be loaded at the bottom of the page to load everything up all snappy.
So, create src/sass/essentials.scss
and src/sass/global.scss
and maybe drop a test style into each.
Create styles folder and add two files inside it
Create a styles
folder inside the root of your CLI project (ex: project-name/project-app/styles
), add two javascript files and name them the same as your main SCSS files. In this example we're going to create essentials.js
and global.js
Place the following inside each of the files and change the contents appropriately.
import '../sass/essentials.scss';
At this point you should have a structure like so:
/project-name
....
/project-app
/src
/scss
/essentials
some-styles-we-want-in-the-head.scss
/globals
some-styles-we-are-ok-deferring.scss
essentials.scss
globals.scss
/styles
essentials.js
globals.js
buildpages.js (next step)
...
Create buildpages.js
To split out our styles we're going to need to do a little hacky bit here with Vue CLI. If anyone has any suggestions on a better way to do this we are all ears. In the root of the CLI project ( ex:project-name/project-app/)
create buildpages.js and add the following to it:
module.exports = {
app: {
// Styles coming from style tags in your components
// if you wish to do that
entry: 'src/main.js',
template: 'public/index.html',
filename: 'index.html',
title: 'App',
},
global: {
// Styles generated from globals.scss THROUGH globals.js
entry: 'src/styles/globals.js',
template: 'public/index.html',
filename: 'index.html',
title: 'App',
},
essentials: {
// Styles generated from essentials.scss THROUGH essentials.js
entry: 'src/styles/essentials.js',
template: 'public/index.html',
filename: 'index.html',
title: 'Essential',
},
};
Update your vue.config.js
Add the following into your vue.config.js
at the top
const PagesObject = require('./buildpages.js');
Then add this somewhere in the main module exports object:
module.exports = {
...
indexPath: undefined,
pages: PagesObject,
chainWebpack: (config) => {
config.plugins.delete('prefetch');
// TODO: Remove this workaround once https://github.com/vuejs/vue-cli/issues/2463 is fixed
// Remove preload plugins for multi-page build to prevent infinite recursion
Object.keys(PagesObject).forEach((page) => {
config.plugins.delete(`preload-${page}`);
config.plugins.delete(`prefetch-${page}`);
});
},
...
}
Finally, update your main layout
Add the following to the head
@if(App::environment() == 'production' || App::environment() == 'staging' )
<style><?php echo File::get( public_path( vuemix('/css/chunk-vendors.css', '/app') ) ) ?></style>
<style><?php echo File::get( public_path( vuemix('/css/essentials.css', '/app') ) ) ?></style>
@else
<link rel="stylesheet" href="{{vuemix('/css/chunk-vendors.css', '/app')}}">
<link rel="stylesheet" href="{{vuemix('/css/essentials.css', '/app')}}">
@endif
Add the following to just before </body>
<noscript id="deferred-styles">
<link rel="stylesheet" href="{{vuemix('/css/global.css', '/app')}}">
</noscript>
<script>
var loadDeferredStyles = function() {
var addStylesNode = document.getElementById("deferred-styles");
var replacement = document.createElement("div");
replacement.innerHTML = addStylesNode.textContent;
document.body.appendChild(replacement)
addStylesNode.parentElement.removeChild(addStylesNode);
};
var raf = requestAnimationFrame || mozRequestAnimationFrame ||
webkitRequestAnimationFrame || msRequestAnimationFrame;
if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
else window.addEventListener('load', loadDeferredStyles);
</script>
Congrats! You should be setup!
You should be setup and ready for destruction! Try building and see if the three files are created. If not do let us know in the issues and we can update this documentation.
Using Tailwind
Devise uses TailwindCSS under the hood for its own CSS. If you haven't used it before we couldn't recommend it enough. We have prefixed Devise styles with dvs
to prevent conflicts. Since no Devise styles are loaded unless you are logged in you shouldn't really rely on those. To get your own tailwind up and running add the following to your SCSS files listed above:
@tailwind preflight;
@tailwind components;
// Examples
@import "essentials/globals";
@import "essentials/navigation";
// End examples
@tailwind utilities;
Remove PostCSS config from package.json
If your package.json file includes the following be sure to remove it.
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
Create a postcss.config.js in your Vue CLI app
Add autoprefixer
to your dev dependencies and in your Vue CLI app add or edit postcss.config.js
to contain:
const tailwind = require('tailwindcss');
const autoprefixer = require('autoprefixer');
module.exports = {
plugins: [tailwind('./tailwind.js'), autoprefixer()],
};
Build and test
Try building your app from the Vue CLI UI. You should see your CSS in `` Now you an use Tailwind like so on your slices and components:
<div class="p-8 bg-pink font-bold font-sans text-xl">
Look! Extra large bolded sans font with padding and a pink background
</div>
Purging the fat
When using something like tailwind you may want to cut any styles that are not being used. Add @fullhuman/postcss-purgecss
, and glob-all
to your dev-dependencies and edit postcss.config.js
in the root of your Vue CLI project and add the following contents:
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable global-require */
const purgecss = require('@fullhuman/postcss-purgecss');
const glob = require('glob-all');
const path = require('path');
module.exports = {
plugins: [
require('tailwindcss')('./tailwind.js'),
require('autoprefixer')(),
process.env.NODE_ENV === 'production' ? purgecss({
content: [
'./src/**/*.vue',
'./../resources/**/*.blade.php',
],
extractors: [
{
extractor: class {
static extract(content) {
return content.match(/[a-zA-Z0-9-:_/]+/g) || [];
}
},
extensions: ['vue', 'html', 'php'],
},
],
// Example of when you have a package dependency that may have styles
// that you don't want to cut out. Purge will scan these files and prevent
// them from being purged.
paths: glob.sync([
path.join(__dirname, 'node_modules/tiny-slider/**/*.js'),
path.join(__dirname, 'node_modules/tiny-slider/**/*.css'),
]),
// Leave mobile, tablet, desktop, largeDesktop, and ultraWideDesktop as
// Those are Devise breakpoints. In this example "/tns-*/" is just an
// example for tinyslider and can be removed
whitelistPatterns: [
/mobile/,
/tablet/,
/desktop/,
/largeDesktop/,
/ultraWideDesktop/,
/tns-*/,
],
}) : '',
],
};
Last updated