Sunday, December 18, 2016

Upgrading Grails-2.2.1 to Grails-3: Static Assets take a BIG move . . .

I recently upgraded a Grails 2.2.1 web-app to Grails 3.2.1. It was a BIG move forward. Moving static assets (JavaScripts, CSS and Images) to their new assets directory, organizing & setting up directives/manifests in their new home directory, making all required changes to views & templates, testing all views for styles & images, and testing views with AJAX functionality involving JavaScripts... overall, it took a considerable amount my time during the whole upgrade efforts.

Following are some key points I have from my efforts:
  • Grails 3 doesn't come with Resources plugin and hence you will not have ResourceTagLib in your classpath. If you want, you can probably still use Resources plugin in Grails-3 app, but Asset-Pipeline plugin seems to be the viable option.
  • Static assets which can be handled by Asset-Pipeline plugin need a move from web-app directory to grails-app/assets directory, their new home. Files under web-app/css, web-app/js and web-app/images now go into grails-app/assets/stylesheetsgrails-app/assets/javascripts and grails-app/assets/images respectively.
  • Grails-3 comes with jquery-2.2.0.min.js and bootstrap.js(3.3.6). If your Grails 2.2.1 app was dependent on these, you probably had jquery-1.7.2.min.js and bootstrap.js(2.2.2). If so, you will be better off retaining older versions to start with the upgrade process to eliminate this new variance in upgrading-equation.
  • The recommended approach to upgrade Grails 2.x app to Grails 3.x is to first create a new Grails-3 application and start copying all artifacts from old to new locations. Grails-3 documentation's Upgrading section has very well documented details on old and new locations. With respect to static assets, when a new Grails-3 app is created, you will notice images, javascripts and stylesheets sub directories under grails-app/assets. Also, you will have a bunch of static assets already sitting in there. You may have to do some cleanup with these files.
  • Modularize your assets
    1. AppResources.groovy is Resources plugin’s way of modularizing JavaScripts and CSS files by grouping these static assets into modules. But Asset-Pipeline plugin minifies compresses all JavaScript & CSS files, also enables browser cache, and hence static assets are only served once for all pages. So, it may not be required to group/ modularize static assets. If truly needed, for every module (e.g. module1) in AppResources.groovy, an equivalent manifest/directive with module-name.js (e.g. modul1.js) file can be created listing all it’s dependencies.
    2. The directive files application.js and application.css are main manifest files for JavaScripts and CSS.
    3. If you have modularized static assets in Grails-2 app, your main static resource AppResources.groovy should be your reference for re-organizing your static assets in Grails-3 app to minimize changes in views and view templates.
    4. You can modularize your static assets in Grails-3 the same way as in Grails-2 app with no need for ApprRsources.groovy file but with equivalent module manifests/directives created.
    5. Create a one-to-one asset-pipeline directive/manifest file for each of your module defined in AppResources.groovy. For instance, if you have, let's say a common module defined listing all it's dependency resources (both JavaScripts and CSS files), create common.js and common.css asset-pipeline directives that list required JavaScript and CSS dependencies respectively in Grails-3 app.
    6. If you have many modules in your application, your grails-app/assets/javascripts and grails-app/assets/stylesheets will get cluttered and mixed with manifest files and actual assets. You will be better off keeping directives separate from actually assets by keeping actual javascript and css assets under grails-app/assets/javascripts/lib and grails-app/assets/stylesheets/shared sub-directories respectively so that asset-pipeline manifest files can be under main grails-app/assets/javascripts and grails-app/assets/stylesheets directories.
  • Modify views & view templates and change resources tags to equivalent asset-pipeline tags
    1. Replace all <r:script> </r:script> with <asset:script type=”text/javascript”> </asset:script>
    2. Replace <r:external file="/static/images/favicon.ico"/> with <asset:link rel='shortcut icon' href="favicon.ico" type="image/x-icon"/>
    3. Remove all <r:layoutResources/> in <head></head> and replace all <r:layoutResources/> at the very bottom of layout pages with <asset:deferredScripts/> (This is Asset-Pipeline plugin's equivalent of Resources plugin’s deferring scripts to the bottom of the page)
    4. If you have modularized assets in Grails 2.2.1 app, for example, for module 'module1'  replace all <r:require module=”module1”/> with <asset:stylesheet src=”module1”/> and <asset:javascript src=”module1”/> if module1 has both JavaScripts and CSSs in it.
  • If there are other static assets like pdf files that are referenced in views by grails resource tag or it's equivalent method call, it can safely be moved from Grails-2's web-app/pdf to Grails-3's grails-app/assets/pdf and be served by Assets-Pipeline plugin. These assets, like images, need no manifest/directive files and it simply works.

Summary

Grails moved away from Resources plugin in favor of Asset-Pipeline plugin starting from 2.4. Upgrading prior versions of Grails 2.4 apps to 3.x certainly requires considerable development and testing efforts with respect to static assets. So, just be prepared for this BIG move.

References

Resources Plugin Docs
Asset-Pipeline Plugin Docs
Asset-Pipeline Plugin - GitHub source code
Grails Team Blog Post on Migrate from Resources Plugin to Asset-Pipeline Plugin
Very nice Introduction to Asset Pipeline Plugin

My previous posts on Upgrading Grails application from 2.2.1 to 3.2.1

15 comments:

  1. So do we need to add dependency in grails project for asset pipeline..My build.gradle project has already runtime "org.grails.plugins:asset-pipeline" ..but when I try to run simple jquery code in my gsp page with code
    $( "#tags" ).autocomplete({
    source: availableTags
    });

    I get aucomplete function not found..So for some reason jquery is not loading properly ..Can you please help me with this problem

    ReplyDelete
  2. You don't need any other explicit dependency.
    Just make sure that you have a reference to the JQuery lib's js file (e.g. //= require lib/jquery-ui-1.8.21.min) in which that aucomplete function is defined in the assset-pipeline manifest file (application.js or whatever your project specific)

    ReplyDelete
  3. This is a topic that is near to my heart... Many thanks!
    Where are your contact details though?

    ReplyDelete
  4. I am glad you checked this post. I appreciate your comment. As you left this comment as Anonymous, I don't even have your contacts. I didn't put my email address anywhere on my blog, but I can be reached via email: gpottepalem@gmail.com

    ReplyDelete
  5. Hello Sir ,
    I have couple of questions

    1.My current project is in grails 2x.
    After all the changes you mentioned here ..it got me thinking as to WHY should we actually move to Grails3x ? Couls you please share your views how can my application performance be excelled by Grails 3x.

    2.We currently use Easygrid plugin for grids which is unavailable in 3x.
    What replacement for this ?

    ReplyDelete
  6. Hi Madhu,
    1. It's always good to catch up with later versions of Grails for several reasons like: to get benefited from what it offers better than t's own earlier versions, bug fixes, underlying newer versions of Spring, Hibernate and many other such etc. Otherwise, as time goes by upgrading efforts may end up completely rewriting certain parts of the app. Of course, as always there would be some performance benefits given in newer versions. This requires your own benchmark.

    2. Upgrading plugins is the very first step in the this process of upgrading Grails app from 2.x to 3.x as there are some ground breaking changes. I haven't experienced Easygrid, so I won't be able to comment on this. If this plugin is not migrated to 3.x, you are stuck. So, check with contributors of that plugin and see what the plans are. If nobody is maintaining that plugin anymore, some one has to take initiative to migrate it to 3.x. We migrated couple of plugins that we needed by ourselves during our migration. Another option is, see if you can ditch EasyGrid plugin and go with any similar plugin available for Grails 3.x. In any case you will have to evaluate all your options before starting this effort.

    Hope this helps in evaluating your options and making a decision.

    Best
    Giri

    ReplyDelete
    Replies
    1. Thank you for your insights Giridhar.

      Any article you posted on how to edit login page/functionality in grails3-spring-security ?

      Delete
    2. Madhu,
      Your question is not very clear to me. One of my posts covers securing Restful API app. There is also a post on LDAP security. Other than that, I did not post anything specifically covering security.

      Delete
  7. Hi Madhu its a good one.
    I have a query. Suppose if you have multiple modules in ApplicationResources.groovy
    Eg module1, module2, module3, module4, module5
    module 3 depends on module1,module2
    To migrate this to Assets. Do we need to create 5 files as suggested one for each module?
    And in corresponding module3.js how to specify the dependency of module1 and module2

    ReplyDelete
  8. Hi Giridhar,

    I am migrating grails application 2.5.6 to 3.2.3. i have restful api controller it is causing an migration errors. The classes used to create controller are not available in 3.2.3 version.
    We were using classes from import net.hedtech.restfulapi.config.* for V2.5.6
    Let me know if you have any suggestion. Its would be a great help..!!

    Thanks
    Khodal

    ReplyDelete
    Replies
    1. Hi Khodal,
      That seems like a Grails 2.x plugin. I guess you need Grails 3.x version of that plugin. I am not sure of anybody upgraded that to Grails 3.
      Thanks,
      Giri

      Delete
  9. Hi Giridhar,
    Thanks for this summary, I am in the process of upgrading a Grails 2 app to Grails 4, and I was for a while clueless on how to replace the asset modules in Grails 4, until now. Your article makes perfect sense and is a huge help!
    Cheers

    ReplyDelete
    Replies
    1. Hi Eshton,
      Thanks for taking a minute to post this comment. I am very happy to know that even after 3 years after my blog post, it's helpful. Grails rocks! I have been a huge fan of Grails and Groovy since Grails ver 0.6.
      Cheers,
      Giri

      Delete