We manage all front-end plugins and framework dependencies like jQuery, Bootstrap using Node NPM and gulp tools.
npm is the package manager for the Node JavaScript platform. It puts modules in place so that node can find them,
and manages dependency conflicts intelligently. It is extremely configurable to support a wide variety of use cases.
Most commonly, it is used to publish, discover, install, and develop node programs and
Gulp
is a toolkit for automating painful or time-consuming tasks in your development workflow. We use gulp to automate
our building process like generating JS/CSS.
We add the dependencies using two methods:
We could add jQuery as npm dependency by invoking:
`npm install --save jquery`
Or by updating the package.json file and add the following entry to dependencies key:
`"jquery": "^3.2.1"`
And Then, invoking the following command:
`npm install`
NPM loads jquery into your local node_modules folder, and stores relevant metadata to package.json. We Repeated this for all of the dependencies that are available on NPM and we ended up with something like:
...
"dependencies": {
"bootstrap": "^4.3.1",
"jquery": "^3.3.1",
"popper.js": "^1.14.3",
...
},
...
There were mainly Three issues raised using above method:
For those issues we used a npm’s package called napa
which is a helper for installing repositories without a package.json with npm
napa NPM’s package link and napa npm’s github.com repository
We installed napa package using command:
npm install napa --save-dev
This command will install napa package and update main ./package.json file by adding an entry for napa package in devDependencies key:
...
"devDependencies": {
...
"napa": "^3.0.0",
...
},
...
We configured napa package by updating our package.json file like:
{
...
"napa": {
"blockui": "git+https://github.com/malsup/blockui.git",
"scrollup": "git+https://github.com/markgoodyear/scrollup.git",
...
}
}
napa
run when we invoke npm install
,npm update
, and npm run napa
commands:
{
...
"scripts": {
"install": "napa",
"update": "napa",
"napa": "napa"
},
...
}
napa-config
configuration options entry, mainly to disable repositories caching:
{
...
"napa-config": {
"cache": false,
"log-level": "debug"
},
...
}
Now, whenever we invoke npm install
command, all our front-end dependencies will be downloaded and installed
in local ./node_modules
folder by node.js
and napa
tools.
The following is our complete package.json file updated with all dependencies, devDependencies, and napa entries:
{
"name": "JavaTMP",
"version": "0.0.4",
"private": true,
"description": "JavaTMP Bootstrap Admin And Dashboard Template",
"keywords": [
"jquery",
"bootstrap",
"admin",
"template",
"dashboard"
],
"author": "javatmp",
"licenses": "JavaTMP License",
"contributors": [],
"dependencies": {
...
},
"devDependencies": {
...
},
"scripts": {
"install": "napa",
"update": "napa",
"napa": "napa"
},
"napa-config": {
"cache": true,
"log-level": "debug"
},
"napa": {
...
}
}
We can now reference the dependencies straight from ./node_modules
folder.
but our node_modules folder is outside context root folder ./web
and normally it is not a good idea to make
node_modules folder inside your context root folder, indeed not all files and directories are needed in node_modules folder.
The following is a high level web folder structures of our template web application:
web (Web Application Context Root Folder)
|---index.jsp (Main HTML Page references Front-end Libraries from components folder)
+---assets (Specific Template JS,CSS,fonts, and images folders and files)
+---components (Temporary destination for our Front-end resources Folders)
\---pages (HTML Pages reference Front-end Libraries from assets folder)
So we need a simple process that chooses and moves required and needed plugins and frameworks from ./node_modules
to ./web/components
folders and processes them if they need any minification or cleaning before move them.
We used Gulp to automate our building process. So, we created a simple gulp task that implements our requirements above by first
creating an object that hold need libraries. kindly go to gulpfile.js
file for more information.
the following object hold our required libraries:
var config = {
"sourceNodeLib": "./node_modules",
"destComponentsLib": "./web/components",
"destDist": "./src/main/webapp/assets/dist",
"plugins": {
"jquery": [
{"from": "${sourceNodeLib}/jquery/dist/jquery.min.js", "to": "${destComponentsLib}/jquery/dist"}
],
"popper.js": [
{"from": "${sourceNodeLib}/popper.js/dist/umd/popper.min.js", "to": "${destComponentsLib}/popper.js/dist/umd"}
],
"bootstrap": [
{"from": "${sourceNodeLib}/bootstrap/dist/css/bootstrap.min.css", "to": "${destComponentsLib}/bootstrap/dist/css"},
{"from": "${sourceNodeLib}/bootstrap/dist/js/bootstrap.min.js", "to": "${destComponentsLib}/bootstrap/dist/js"}
],
...
}
};
Actually it is not a standard nor optimal, but give us need functionality and flexibility to select only wanted file
and decide what we could do with them before moving or merging them . Kindly refer to gulp’s task called copy-components
that use the above configuration to copy folders and files and processes them from ./node_modules
to ./web/components
as defined in the above config object:
...
gulp.task('copy-components', ["delete-components"], function () {
// copy all above resources and process them from ./node_modules to ./web/components
});
We used gulp-if
plugins to check if the resource need any preprocessing. So if it is a Javascript file we apply gulp-uglify
plugin
on the resource and if it is CSS file we apply gulp-clean-css
plugin on the resource before move them.
We can simply add another gulp’s task called generate-dist
that will compile all SASS themes files and moved all resources
to ./src/main/webapp/assets/dist
folder.
generate-dist
The gulp’s task generate-dist
depends on task copy-components
described in details above.
The gulp’s task generate-dist
also depends on src
object that define needed resources and plugins to be combined together,
kindly refer to src
object in gulpfile.js for more information about it.
The Gulp’s task generate-dist
task makes the following things:
./web/assets/src/sass/themes/javatmp-*.scss
and generate base template CSS file and move them to ./src/main/webapp/assets/dist/css
foldersrc.css
in order and put the concatenated file in ./src/main/webapp/assets/dist/css/javatmp-plugins-all.min.css
src.cssForPrint
in order and put the concatenated file in ./src/main/webapp/assets/dist/css/javatmp-plugins-print-all.min.css
javatmp.min.js
in ./web/assets/src/js-src/javatmp.js
to ./src/main/webapp/assets/dist/js/javatmp.min.js
src.js
in order and put the concatenated file ./src/main/webapp/assets/dist/js/javatmp-plugins-all.min.js
src.fontFamilyFiles
and put the css file in ./src/main/webapp/assets/dist/css
, in above case ./src/main/webapp/assets/dist/css/font-family-en.min.css
src.img
files needed by plugins to ./src/main/webapp/assets/dist/img
foldersrc.fonts
to ./src/main/webapp/assets/dist/fonts folder
./web/components
folder as all front-end resources became combined and concatenated in TWO BIG LARGE MAIN files javatmp-plugins-all.min.css
and javatmp-plugins-all.min.js
So, The main output of generate-dist
task is folder ./src/main/webapp/assets/dist
which contains the following:
./src/main/webapp/assets/dist
+---css
+---font-family-en.min.css
+---javatmp-plugins-all.min.css
+---javatmp-plugins-print-all.min.css
+---javatmp-*.min.css (For each SASS theme files like javatmp-default.min.css)
+---javatmp-*-rtl.min.css (For each SASS theme files like javatmp-default-rtl.min.css)
+---fonts
+---context-menu-icons.eot
+---fa-brands-400.eot
+---open-sans-v15-latin-300.eot
+---slick.eot
+---summernote.eot
+---...
+---img
+---ajax-loader.gif
+---mCSB_buttons.png
+---js
+---javatmp-plugins-all-locale-*.min.js (For each Locale key defines `src.localeJS` object like `src.localeJS.en`)
+---javatmp-plugins-all.min.js
+---javatmp.min.js