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.
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
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
๐ 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
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
file and its dependencies and will trigger a full page reload if it finds anyconst 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
๐ 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):
If your project works with previous of Node or NPM open an issue to fix this section.