To make an app elegant and pleasing to the eye we usually need a lot of javascript and css code. The times of templates cluttered with script and style tags, however, are long gone. Check out how to manage static resources with gulp.
What we are going to build
Our goal is to set up a Spring Boot application with a polished homepage. To keep everything organized and imposing we will use:
- Material Design Bootstrap 4 – a free, good looking and responsive Material Design UI kit for Bootstrap 4,
- jtwig – a template engine to keep our presentation logic isolated,
- Gulp – a toolkit for automating time-consuming tasks, such as concatenation of external javascript files and stylesheets,
- npm – a package manager for javascript libraries.
Requirements
- We are working on a fresh Spring Boot project with the Web package dependency. You can read about setting up this project in How to create a new Spring Boot Project.
- I assume that you use a git tool to track the features – if not, see the Keep your code safe through repositories post first.
- You will also need to have
npm
installed locally, remember that theNode.js
has to be installed. Check out the post about managing project dependencies with npm if your project lacks a javascript package manager.
Install the theme
Create a new branch
We want to keep features in our project separated and merge them to the develop
branch only when they are completely finished. Create a new branch in your repository:
1 |
$ git checkout -b feature/static_resources |
Download the theme
You can install any theme of your choice. Bear in mind that the easiest to work with will be based on Bootstrap. In this example I will install Material Design for Bootstrap:
1 2 |
$ cd src/main/resources/static/ $ npm install --save-dev mdbootstrap |
If the node_modules
directory is already ignored by git
, the status should be displayed like this:
1 2 3 4 5 |
$ git status Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: package.json |
In the package.json
file you can see the dev dependency for the newly installed theme:
1 2 3 4 5 6 7 |
/*static/package.json*/ … "devDependencies": { … "mdbootstrap": "^4.5.5" } … |
There is still some work to be done in order to handle our new assets properly. Let’s see how we can use gulp to build our resources.
Implement gulp
Install the tool and its libraries
We want all external assets to be concatenated into a file – vendor.css
for css styles and vendor.js
for javascript libraries. We will use already minified versions of the downloaded modules, but you can easily add gulp-minify to the tasks if you want to attach the extended versions.
We will install gulp
globally, just for the benefit of its accessibility, and locally, for this project. From many plugins available for the asset management, we are going to install gulp-concat
:
1 2 3 |
$ sudo npm install gulp -g $ npm install --save-dev gulp $ npm install --save-dev gulp-concat |
Check your package.json
file:
1 2 3 4 5 6 7 8 |
/*static/package.json*/ … "devDependencies": { "gulp": "^3.9.1", "gulp-concat": "^2.6.1", … } … |
We have now installed everything that we will need to complete our objective.
Make installed gulp modules available within gulpfile.js
We will build css, javascript and font resources from the installed material theme. Remember, that, for a Spring Boot project, you need to be in the static resources location:
1 2 |
$ pwd /home/little_pinecone/projects/spring_boot/awesome-project/src/main/resources/static |
Here you can create a gulpfile.js file for storing all commands responsible for managing assets with gulp – you can specify what tasks should be performed to organize the resources you just downloaded into your project.
For our example, we will create three tasks: css
, js
and font
, to run during the build process:
1 2 3 |
$ gulp css $ gulp js $ gulp font |
and have all assets neatly arranged.
We will start our gulpfile.js
with code responsible for making downloaded gulp module and its plugins accessible. We can achieve this in two ways:
- Assign each required module to a variable:
123//static/gulpfile.jsvar gulp = require('gulp');var concat = require('gulp-concat');
Every added gulp plugin will be accessible in the file by the variable’s name, e.g.concat
. - On the other hand, to get rid of many
require
declarations at the top of the file, we can use a gulp-load-plugins plugin to make every gulp module listed inpackage.json
available forgulpfile.js
. Add this plugin to your project:
1$ npm install --save-dev gulp-load-plugins
Put this code on the beginning of yourgulpfile.js
:
123//static/gulpfile.jsvar gulp = require('gulp');var $ = require('gulp-load-plugins')();
Every added gulp plugin will be accessible in the file by plugins.name() e.g.plugins.concat()
. No need of requiring every one of them separately.
For this post I will stick to the first option, with every required module listed on the top of the gulpfile.js . |
Create gulp tasks for handling asset building
Gulp
processes a task according to the following sequence:
- Stream listed source files with
gulp.src
. - Transform the content of these files – every function modifying the files is called with
.pipe
. - Save the changed code to a destination directory with
gulp.dest
.
We can proceed with our first task – gulp css
. We want it to concatenate all css files of the downloaded theme into one file – vendor.css
and save it in the public/css
folder. Copy this code to your gulpfile:
1 2 3 4 5 6 7 8 9 10 11 |
//static/gulpfile.js … gulp.task('css', function () { return gulp.src([ 'node_modules/mdbootstrap/css/bootstrap.min.css', 'node_modules/mdbootstrap/css/mdb.min.css', 'node_modules/mdbootstrap/css/style.min.css', ]) .pipe(concat('vendor.css')) .pipe(gulp.dest('public/css/')); }); |
To concatenate javascript files, add:
1 2 3 4 5 6 7 8 9 10 11 12 |
//static/gulpfile.js … gulp.task('js', function(){ return gulp.src([ 'node_modules/mdbootstrap/js/popper.min.js', 'node_modules/mdbootstrap/js/jquery-3.3.1.min.js', 'node_modules/mdbootstrap/js/bootstrap.min.js', 'node_modules/mdbootstrap/js/mdb.min.js', ]) .pipe(concat('vendor.js')) .pipe(gulp.dest('public/js')) }); |
Make sure, that in your gulpfile.js you specified exactly those versions of modules that you have just downloaded, e.g the MDBoostrap version that I used utilizes jquery-3.3.1, but this may be changed in the future so don’t copy and paste carelessly. |
The theme we used also requires access to the Roboto font, therefore add the following to gulpfile.js
:
1 2 3 4 5 6 7 8 |
//static/gulpfile.js … gulp.task('font', function() { return gulp.src([ 'node_modules/mdbootstrap/font/roboto/*' ]) .pipe(gulp.dest('public/font/roboto/')); }); |
You can call all three commands now, just note the working directory from which you do it:
1 2 3 4 5 6 7 8 9 10 11 12 |
little_pinecone:~/projects/spring_boot/awesome-project/src/main/resources/static$ gulp css [16:16:40] Using gulpfile ~/projects/spring_boot/awesome-project/src/main/resources/static/gulpfile.js [16:16:40] Starting 'css'... [16:16:40] Finished 'css' after 40 ms little_pinecone:~/projects/spring_boot/awesome-project/src/main/resources/static$ gulp js [16:16:43] Using gulpfile ~/projects/spring_boot/awesome-project/src/main/resources/static/gulpfile.js [16:16:43] Starting 'js'... [16:16:43] Finished 'js' after 39 ms little_pinecone:~/projects/spring_boot/awesome-project/src/main/resources/static$ gulp font [16:16:48] Using gulpfile ~/projects/spring_boot/awesome-project/src/main/resources/static/gulpfile.js [16:16:48] Starting 'font'... [16:16:48] Finished 'font' after 26 ms |
Check the commands’ results in the public/
folder – there should be three new directories with assets: css/
, js/
, font/roboto/
.
To keep our repository clean and robust, update the .gitignore file by adding the files that are going to be created during the building process:
1 2 3 4 5 |
### .gitignore ### … src/main/resources/static/public/css/* src/main/resources/static/public/js/* src/main/resources/static/public/font/* |
The git status should display:
1 2 3 4 5 6 7 |
$ git status Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: package.json modified: .gitignore new file: src/main/resources/static/gulpfile.js |
Take care of the view layer
If you already have a template engine in your project, do not forget to declare the vendor.css
and vendor.js
files in a base view. If you still haven’t chosen a template engine, I recommend you the jtwig template engine in a Spring Boot application post.
The assets will be accessible across the whole app if you add them in a template that is common for all views – we are taking advantage of inheritance in jtwig. The base template can look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!--templates/layout/base.twig--> <!DOCTYPE html> <html class="full-height"> <head> <meta charset="utf-8"/> <title>Page Title</title> <link rel="stylesheet" type="text/css" href="public/css/vendor.css"/> </head> <body> {% block content %} {% endblock content %} <script src="public/js/vendor.js"></script> {% block javascript %} {% endblock javascript %} </body> </html> |
Verify that the installed assets work
Now you can rebuild your project and check the outcome in a browser. Make sure you created a controller that fetches a view with:
1 2 |
<!--templates/landing_page.twig--> {% extends 'layout/base.twig' %} |
To be sure that everything works smoothly, refresh your application page. You should notice that your page is now using the installed theme. If you haven’t created any controller or view yet, don’t worry, and, again, check out the jtwig template engine in a Spring Boot application post to see how quickly set up a landing page to test your view layer.
After completing this chunk of work, it’s time to commit our progress:
1 |
$ git commit -m "Theme downloaded. Gulp tasks implemented." |
Merge this feature branch to develop
After you have successfully applied a new theme, built the assets with Gulp and created a testing view, feel free to merge this branch with develop:
1 2 3 |
$ git checkout develop $ git merge feature/static_resources $ git push develop |
Troubleshooting
- Older versions of Material Design for Bootstrap needed Apache Commons to work properly. In case of problems try adding the folloiwng to the
pom.xml
file:
1 2 3 4 5 |
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.6</version> </dependency> |
- Make sure that in
gulpfile.js
you declared exactly the same module versions as those actually downloaded into the node_modules directory.
Photo by Matheus Bertelli on StockSnap
Please update the above…
Got the below exception:
org.jtwig.parser.ParseException: Invalid template format