This boilerplate provides the a simple setup needed to create development and production environments for Vue 3 apps using Tailwind and FontAwesome, building them afterwards into production with Webpack. Everything is explained step by step, to better understand what is going on, so it is easy to 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
- Quickstart
- Folder structure
- Installing vue
- Installing webpack
- Installing Vue-loader
- Installing html-webpack-plugin
- Installing tailwind
- Setting up a webpack dev server
- Setting up MiniCssExtractPlugin
- Setting up CssMinimizerPlugin
- Setting up FontAwesome for our icons
- Setting up dark mode with Tailwind.css
- Troubleshooting
- Other
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:dev
to build the project in development mode, the output will be saved in πdist. Good to test the development build files generated or to work using an extension like live servernpm 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 # Node dependencies
βββ π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 Vue 3 running the following command:
npm install vue
π NOTE: If Vue 3 is not yet the main release use the command
npm install vue@latest
Next thing is to 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
commands 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 see 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 css-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)
- css-loader: Gives you more control over importing .css files. (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: We need to import
css-loader
since it is not a dependency ofvue-loader
anymore.
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 autoprefixer postcss-import postcss-loader
- tailwindcss: Installs the main tailwind functionalities
- 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)
- postcss-loader: A webpack loader to process CSS with PostCSS (docs)
- autoprefixer: Parses CSS files adding vendor prefixes to CSS rules so you can forget and write normal CSS (docs)
- postcss-import: Offers the ability to organize your CSS into multiple files and combine them at build time by processing @import statements in advance (docs)
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("postcss-import"),
require("tailwindcss"),
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';
π NOTE: PurgeCSS is not needed with Tailwind 3 since it uses a new engine that generates only the styles you need. (docs)
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
- open: Tells dev-server to open the browser after server had been started.
- devMiddleware: Provide options to webpack-dev-middleware which handles webpack assets.
- writeToDisk: Tells devServer to write generated assets to the disk.
- static: This option allows configuring options for serving static files from the directory
- watch: 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
- watch: When enabled, it will look for changes on the
const path = require('path')
module.exports = {
entry: path.join(__dirname, 'src/main.js'),
devServer: {
open: true,
devMiddleware: {
writeToDisk: true,
},
static: {
watch: 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, we can cut them in half of 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
π NOTE: If the default fontawesome import is still for versions 2.x of vue, use
npm i -D @fortawesome/vue-fontawesome@prerelease
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 to import the dependency and register the component:
...
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
...
const app = createApp(App)
.component("font-awesome-icon", FontAwesomeIcon)
.mount("#app");
Once the library is imported and the component registered, whenever we want to use an icon first we will import the icon, the library and then add the icon to the library and finally use them in our template, for example:
<script>
import { faAddressBook } from "@fortawesome/free-solid-svg-icons";
import { library } from "@fortawesome/fontawesome-svg-core";
export default {
beforeCreate() {
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).
Dark mode support comes built-in with Tailwind.css
making things much easier to set up (docs). This mode is disabled by default in order to keep the size at a minimum and needs to be enabled on the tailwind.config.js
file by setting the darkMode
option:
tailwind.config.js
module.exports = {
content: [
'./src/**/*.html',
'./src/**/*.vue',
'./src/*.js',
'./src/*.vue',
],
darkMode: 'class', // or 'media' or false
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
Since we want to toggle the dark mode manually through the use of a class we will set the darkMode
option to class
. Then on our root element we will set that class dynamically when the user clicks on the moon icon at the bottom-left corner:
src/App.vue
<template>
<div :class="{ dark: isDarkModeActive }">
<div class="flex flex-row h-screen antialiased text-gray-800">
<Sidebar @toggle-dark-mode="isDarkModeActive = !isDarkModeActive" />
<Chat />
</div>
</div>
</template>
Using this approach, we will receive an event from the Sidebar.vue
component (where the moon button is) that will toggle the isDarkModeActive
variable to activate the dark
class conditionally, applying the styles on all the page accordingly.
If you are finding any trouble with this project, you can try one of the following methods to try and solve any issues you may be facing:
Having older versions of NPM and node may throw errors. This project has been tested with the following minimum verions (ref):
- Node: 15.6.0
- NPM: 7.4.0
If your project works with previous of Node or NPM open an issue to fix this section.