Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

local tomcat server with grunt watch auto-reload

The project

I have a maven based project which I need to deploy into a local tomcat server (for development).

Now, on the front-end, I want to have a grunt dev-build ( jslint, concat, karma, sass, etc).

What I need

  • A solution which is not tied to only one IDE ( and should also work in the command line )
  • I don't want to deploy a war file only a dist folder.
  • I don't want to recompile java each time I change a client-side resource: js,css,html,images etc.
  • grunt should watch the files and do pre processing / concatenation / lint / tests
  • after the watch grunt should deploy the files to a local tomcat and autoreload the page
  • It MUST be fast! and I mean less than a second.

I looked at some questions, but I cannot figure out how to make it all work

like image 252
Ilan Frumer Avatar asked Mar 03 '14 15:03

Ilan Frumer


2 Answers

This may or may not work for you as I'm not sure if you want everything to be entirely integrated.

This method will let you run your Tomcat server, allowing you to make front-end changes with automatic reloading (plus any additional tasks you may want to run) and no Java recompiling/reloading in Tomcat. I use it and for front-end development it's extremely fast.

Summarized idea:

  1. Run your Java application using any means (maven tomcat plugin, Eclipse Servers tab, etc). Run it on a standard port (e.g. 8080). I'll assume you know how to do this.

  2. Use grunt, grunt-contrib-watch, grunt-contrib-connect, grunt-contrib-proxy. Run grunt-contrib-connect on a different port than tomcat, e.g. 9000. Setup grunt-contrib-proxy to proxy requests from grunt-contrib-connect server to backend tomcat on different port, rewriting the URL if necessary.

To get you started, here is the relevant parts of the Gruntfile.js (modify to your app):

// Watches files for changes and runs tasks based on the changed files
watch: {
  js: {
    files: ['<%= my.app %>/scripts/**/*.js'],
    tasks: [],
    options: {
      livereload: '<%= connect.options.livereload %>'
    }
  },
  livereload: {
    options: {
      livereload: '<%= connect.options.livereload %>'
    },
    files: [
      '<%= my.app %>/**/*.html',
      '<%= my.app %>/.tmp/styles/**/*.css',
      '<%= my.app %>/images/**/*.{png,jpg,jpeg,gif,webp,svg}'
    ]
  }
},

// The actual grunt server settings
connect: {
  options: {
    port: 9000,
    // Change this to '0.0.0.0' to access the server from outside.
    hostname: 'localhost',
    livereload: 35729
  },
  proxies: [{
    context: '/rest',
    host: 'localhost',
    port: 8080,
    https: false,
    changeOrigin: true,
    rewrite: {
      '^/rest': '/myapp/rest'
    }
  }],
  livereload: {
    options: {
      open: true,
      middleware: function(connect) {
        return [
          require('grunt-connect-proxy/lib/utils').proxyRequest,
          connect.static('src/main/webapp/.tmp'),
          connect.static('src/main/webapp/'),
        ];
      }
    }
  },

To develop, you start your backend Tomcat app, then using a console, run: grunt serve. Make any front-end changes you want and they'll automatically be reloaded and any associated grunt tasks will run with every change. Your app will work as normal as all backend requests are proxied to Tomcat and frontend requests are handled with grunt-contrib-connect.

like image 74
dustin.schultz Avatar answered Sep 19 '22 16:09

dustin.schultz


Your layout is almost the same as that of many projects. It's common, dare I say typical, for Grunt to process client-side resources, and Maven to build the Java backend. As @wallace-sidhree says, Grunt also does most of the things you need out of the box.

I suggest you read up on Grunt first. The part of Grunt which threw me for a loop was it's odd configuration structure, so the configuration guide is a must-read. In short, you need to load the grunt-contrib-watch plugin, and that plugin expects a particular Javascript object for configuration in your initConfig.

A very simple example from the manual is

// Simple config to run jshint any time a file is added, changed or deleted
grunt.initConfig({
  watch: {
    files: ['**/*'],
    tasks: ['jshint'],
  },
});

Regarding Tomcat, putting the output of Grunt under Tomcat control, at least during development, is just going to cause headaches. For example, Tomcat will overwrite any client-side resources Grunt puts inside the exploded WAR whenever Tomcat explodes a changed backend WAR. And to avoid that you'd need to put client-side resources in a different WAR. But if you have to split them anyway, you're better off hosting the client-side resources with lighttpd or httpster, at least during development. That should help achieve your sub-second updates.

I'm not sure about IDE-independent auto-reloading of the page, I use JetBrains' Chrome extension for that; the other answers might cover it better.

like image 37
Emerson Farrugia Avatar answered Sep 19 '22 16:09

Emerson Farrugia