NPM module Browser-Sync in Java / Web projects
Browser-Sync is a handy Node.js based NPM module which can be used for a faster web development. Browser-Sync synchronizes file changes and interactions across many devices. The most important feature is the live reloading. We can use the Browser-Sync in Java / Web projects too. Cagatay Civici created a great
video tutorial how to use this module with the PrimeFaces showcase. The PrimeFaces showcase has a built-in Jetty server which looks to the source folder src/main/webapp as the web context root. After the Browser-Sync installation via the Node.js package manager NPM
npm install -g browser-sync
we have to start the Jetty server for the PrimeFaces showcase at http://localhost:8080/showcase. Afther that we can use this URL as proxy for a built-in server included in the Browser-Sync. The Browser-Sync should listen to changes under src/main/webapp
browser-sync start --proxy "http://localhost:8080/showcase" --files "src/main/webapp/**/*"
As result, a default browser will be started at http://localhost:3000/showcase with the PrimeFaces showcase. The port 3000 is the default port for the Browser-Sync.
This approach works well until you have made changes in Java files. Java files are not web resources under src/main/webapp. In Maven projects they located under src/main/java. That means, changes in Java files will not be recognized. The solution is exploded WAR. An exploded WAR is a directory where the web application gets deployed from. Every application server can deploy an exploded WAR. For Maven projects, this directory is normally target/webapp. The Maven WAR plugin has the goal war:exploded too. If you have an IDE, you can configure your web application as an exploded WAR. I have blogged about Hot Deployment with IntelliJ IDEA a couple of years ago. In IntelliJ, you can automatically copy changed files (CSS, JS, HTML resources and compiled Java files) to the directory for the exploded WAR.
Now, if you refresh the browser manually, you will see the changes in Java classes too. But we want to do this better. We want to use the highly praised live reloading! To achieve this goal, set files to be watched as follows
browser-sync start --proxy "http://localhost:8080/showcase" --files "target/classes/**/*.class, target/webapp/**/*"
The output looks like
[BS] Proxying: http://localhost:8080 [BS] Access URLs: --------------------------------------------------------------------- Local: http://localhost:3000/showcase External: http://192.168.178.27:3000/showcase --------------------------------------------------------------------- UI: http://localhost:3001 UI External: http://192.168.178.27:3001 ---------------------------------------------------------------------
Now, I can do any changes in all important files and see something like in the console
[BS] Watching files... [BS] File changed: target\webapp\META-INF\MANIFEST.MF [BS] File changed: target\webapp\WEB-INF\classes\some\showcase\bean\SomeBean.class [BS] File changed: target\webapp\views\someView.xhtml [BS] File changed: target\webapp\META-INF\MANIFEST.MF
The browser page gets updated by the Browser-Sync automatically (which uses WebSockets by the way). If you have trouble with your IDE, you can use Gulp to rescue! Here my idea for a gulpfile.js (Gulp 4).
var browsersync = require('browser-sync').create(); // init Browser-Sync gulp.task('browser-sync', function() { browsersync.init({ proxy: "http://localhost:8080/my-showcase" }); }); // compile changed Java files by Maven "mvn compile" // compiled classes will be transfered to target/classes automatically gulp.task('java', function () { // use 'spawn' to execute command using Node.js var spawn = require('child_process').spawn; // set the working directory to project root where gulpfile.js exists process.chdir(__dirname); // run "mvn compile" var child = spawn('mvn', ['compile']); // print output child.stdout.on('data', function(data) { if (data) { console.log(data.toString()); } }); }); // copy changes from src/main/webapp to target/webapp gulp.task('webapp', function () { return gulp.src('src/main/webapp/**/*', since: {gulp.lastRun('webapp')}) .pipe(gulp.dest('target/webapp')); }); // watch files for changes gulp.task('watch', function () { gulp.watch('src/main/java/**/*.java', ['java']); gulp.watch('src/main/webapp/**/*', ['webapp']); gulp.watch(['target/classes/**/*.class', 'target/webapp/**/*'], browsersync.reload); }); // default task gulp.task('default', gulp.series('browser-sync', 'watch'));
This file should be placed in the project root folder. Now, you are able to execute the command (Gulp should be installed of course)
gulp
and enjoy the live reloading! Please consider, the Gulp java task. Maven only compiles changed files. It works very fast! Without changes there are nothing to be compiled – the output of the mvn compile looks like:
[INFO] Nothing to compile - all classes are up to date
If we make a change in one Java file, the output looks like:
[INFO] Compiling 1 source file to <path>\showcase\target\classes
I can also imagine some complex Gulp tasks, such as compiling Java classes in dependent JAR files, build JARs and copy them to the WEB-INF/lib folder of the exploded WAR.
Reference: | NPM module Browser-Sync in Java / Web projects from our JCG partner Oleg Varaksin at the Thoughts on software development blog. |