This boilerplate provides the a simple setup needed to create development and production environments to create Vue apps using tailwind and building them into production with Webpack. Everything is explained step by step so you can understand what is going on and use this as the base to start building your own apps. Every step of the setup is fully explained and documented.
- Vue + tailwind + webpack boilerplate
To get started simply install the project using npm install
and use the following commands:
npm run serve:dev
to serve the project locally using the development buildnpm run serve:prod
to serve the project locally using the production buildnpm run build:prod
to build the project in production mode, the output will be saved in ๐dist. Run this command before putting the application live.
.
โโโ ๐dist # Distribution folder, contains your latest build
โโโ ๐node_modules # Test files (alternatively `spec` or `tests`)
โโโ ๐public # Contains the index.html template
โโโ ๐src # Source code of the application
โ โโโ ๐assets # Any assets used by the application (images, fonts...)
โ โโโ ๐components # Folder with all the Vue components used by the application
โ โโโ ๐css # All stylesheets used by the Vue components
โ โโโ ๐App.vue # Top level vue component
โ โโโ ๐main.js # Our application entry point
โโโ โ๏ธpackage.json # Configuration file to manage the project dependencies, scripts, version...
โโโ โ๏ธpostcss.config.js # Configuration file to manage the postCSS configuration and plugins
โโโ ๐README.md # This :)
โโโ โ๏ธtailwind.congif.js # Configuration file to manage tailwind-specific options
โโโ โ๏ธwebpack.config.js # Main webpack's configuration file
The first thing is to install the vue library. to do so simply run the following command:
npm install vue
This will install the latest stable version of Vue (docs)
Next thing we will install webpack. From now on all dependencies are used only during development so they will all include the -D
flag.
npm install -D webpack webpack-cli
- webpack: This installs the webpack main functionalities
- webpack-cli: Since webpack version 4, the command line interface (CLI) got removed from the main package and added to its own repo and package. If you want to access the
webpack
command install this too. These two first dependencies make up for the most basic local webpack installation (docs)
๐ NOTE: The CLI is linked inside the
node_modules/.bin
folder. This means that you won't be able to usewebpack
normally through the console but your scripts insidepackage.json
will access it without issue.
๐ NOTE: You can still access the
webpack
command using thenpx
command shipped with Node 8.2/npm 5.2.0. You can try to runnpx webpack --version
to check if the command works and the installed dependencies versions.
Vue loader is a webpack loader that allows us to process Single-File Components (SFC). (docs)
npm install -D vue-loader vue-template-compiler style-loader
- vue-loader: This installs the main vue-loader functionalities
- vue-template-compiler: The vue-template-compiler has two primary functions: converting templates to render() functions and parsing single file componens.
- style-loader: Adds CSS to the DOM by injecting a <style> tag (docs)
๐ NOTE: On the docs it is mentioned to use the
vue-style-loader
but this loader is not well maintained. Instead we will use thestyle-loader
provided by webpack.
๐ NOTE: In the webpack configuration we will be using
css-loader
(docs) too although there is no need to import it on our project since it was importes as a dependency byvue-loader
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: [
'style-loader',
//other css loaders
]
},
//other rules
]
},
plugins: [
new VueLoaderPlugin(),
//other plugins
]
...
}
This plugin will create and dynamically inject the dependencies of our application into the main HTML file. (docs)
npm install --save-dev html-webpack-plugin
Since the HTML file created needs to have a <div id="app"> tag to load our Vue components in, we will be using a template located in public/index.html
.
const path = require('path')
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/index.html')
}),
//other plugins
],
}
Now we will install the tailwindCSS
library for our CSS styling on the page (docs)
npm install -D tailwindcss postcss-loader postcss
- tailwindcss: Installs the main tailwind functionalities
- postcss-loader: A webpack loader to process CSS with PostCSS (docs)
- postcss: A tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more (docs)
๐ NOTE: In the webpack configuration we will be using
css-loader
(docs) too although there is no need to import it on our project since it was importes as a dependency byvue-loader
Aside from the webpack.config.js
file, we will create the postcss configuration inside the postcss.config.js
file. The first thing is to call this loader from our webpack file:
webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [{
loader: 'css-loader',
options: {
// 0 => no loaders (default);
// 1 => postcss-loader;
// 2 => postcss-loader, sass-loader
importLoaders: 1
}
},
//other loaders
'postcss-loader'
]
},
//other rules
]
},
}
postcss.config.js
calling the needed plugins to process the tailwindCSS files and loading the tailwind configuration.
module.exports = {
plugins: [
require('tailwindcss')('./tailwind.config.js'),
require('autoprefixer'),
],
}
In order to integrate tailwind there are additional steps to take, first of all we will initialize its configuration file:
npx tailwind init
This will create the tailwind.config.js
file. Next we need to create a css file that includes all of the tailwind functionalities. This file is located under src/css/tailwind.css
and simply contains the following imports:
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
Finally this needs to be imported from our main.js
file, in this case using the line import './css/tailwind.css';
In order to configure purgeCSS, we will use the built in system tailwind comes with. To enable it we just need to modify the tailwind.config.js
file to add the purge
key. In there we will configure the files this module needs to look to purge the resulting css file (all the js, and html files):
module.exports = {
purge: {
enabled: true,
content: [
'./src/**/*.html',
'./src/**/*.vue',
'./src/*.js',
'./src/*.vue',
]
},
//other configuration
}
๐ NOTE: It seems that there is some kind of problem with the module environment variable where it is not being set correctly and this prevents purgeCSS from actually processing the files. To solve this we added
enabled : true
to force purgeCSS to go through regardless of the environment.
To test our builds we will set up a simple server used to test our project locally (docs)
npm install -D webpack-dev-server
In order to use the development server, we first need to configure a few fields:
- entry: This defines the entry point for our webpack process (docs)
- devtool: This option if and how source maps are generated (docs). They are useful for debugging once a bug is reproduced in a production environment, but will slow down build times.
- devServer: The devServer configuration
- watchContentBase: When enabled, it will look for changes on the
entry
file and its dependencies and will trigger a full page reload if it finds any - open: Tells dev-server to open the browser after server had been started.
- writeToDisk: Tells devServer to write generated assets to the disk.
- watchContentBase: When enabled, it will look for changes on the
const path = require('path')
module.exports = {
entry: path.join(__dirname, 'src/main.js'),
devServer: {
watchContentBase: true,
open: true,
writeToDisk: true,
},
}
This plugin extracts all our styles into separate .css
files, one for each .js
file in our application. In our case this will only generate a sinlge .css
file from our main.js
file (docs). To install we run:
npm install -D mini-css-extract-plugin
Once installed, we only need to configure it on our webpack.config.js
file:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
//other rules
{
test: /\.css$/,
use: [
// other loaders
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
]
},
]
},
plugins: [
// other plugins
new MiniCssExtractPlugin(),
],
// other config
}
Even though or styles files are not huge after using PurgeCSS, we can cut them in half what's left by just minifying their contents. To start first we need to install the dependency (docs):
npm install -D mini-css-extract-plugin
Following the docs above we only need to configure the CssMinimizerPlugin as an additional optimization step:
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
// other config
optimization: {
minimizer: [
// For webpack@5 you can use the `...` syntax to extend existing minimizers
'...',
new CssMinimizerPlugin(),
],
},
}
Since webpack version >4, the optimizations are set automatically for you, but they can be extended this way. Webpack includes webpack-terser-plugin
by default in order to minify the .js
files too. For this reason we want to make sure to uncomment the '...'
part so the rest of the optimization steps provided by webpack are left as is. The configuration above would be similar to the following (note that webpack takes more optimization steps in addition to minifying the .js
files):
// This serves just as an example, webpack provides more optimization steps when using '...'
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
// other config
optimization: {
minimizer: [
// For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
new TerserPlugin(),
new CssMinimizerPlugin(),
],
},
}
๐ NOTE: In the docs you can see the
minimize: true
option. This is also set depending on whether you are running in development or productio mode. In this project, the mode is defined through the--mode
flag on thepackage.json
commands and there is no need to include theminimize
option.
We will add a few icons to our interface too. To do so the choice is fontawesome
since it has a nice support for Tree Shaking (docs) as well as a package for vue specifically called vue-fontawesome
. To get started:
npm install -D @fortawesome/fontawesome-svg-core @fortawesome/vue-fontawesome@latest @fortawesome/free-solid-svg-icons @fortawesome/free-regular-svg-icons
- @fortawesome/fontawesome-svg-core: This contains the core javascript api (docs)
- @fortawesome/vue-fontawesome@latest: Has the component we will use on our Vue application to render the icons (docs)
- @fortawesome/free-solid-svg-icons: The package of solid icons of fontawesome
- @fortawesome/free-regular-svg-icons: The package of regular icons of fontawesome
๐ NOTE: In this case we will work with the free icons of font awesome, you can find how to import the solid, regular, brand or pro icons on the
"add more styles or pro icons"
section in the docs
We want to import the needed icons on each component instead of importing them all globally. To do so we will add the following lines on our main.js
file:
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { library } from '@fortawesome/fontawesome-svg-core'
Vue.component('font-awesome-icon', FontAwesomeIcon)
Vue.prototype.$library = library
First we import the dependencies needed to set up our vue component and our library. The component is created globally to make it accessible everywhere and the library will be made available creating a new instance property (docs).
Once both of these elements are set up, whenever we want to use an icon first we will import it to our component, then add them to the library and finally use them in our template, for example:
<script>
import { faAddressBook } from "@fortawesome/free-solid-svg-icons";
export default {
beforeCreate() {
this.$library.add(faAddressBook);
},
};
</script>
<template>
<font-awesome-icon :icon="['fas', 'address-book']" />
</template>
๐ NOTE: I recommend going through the docs if you've never used font awesome before and you can also search for icons here.
๐ NOTE: There are two things to look our for when using fontAwesome. The first thins is that, while the import name is in
camelCase
, the element itself will usekebab-case
. The second thing is that you need to make sure that you are using the right prefix (fas for solid, far for regular and fab for brands).