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-distThe 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.csssrc.cssForPrint in order and put the concatenated file in ./src/main/webapp/assets/dist/css/javatmp-plugins-print-all.min.cssjavatmp.min.js in ./web/assets/src/js-src/javatmp.js to ./src/main/webapp/assets/dist/js/javatmp.min.jssrc.js in order and put the concatenated file ./src/main/webapp/assets/dist/js/javatmp-plugins-all.min.jssrc.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.csssrc.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.jsSo, 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