3
votes

I am using grails for almost a year. Since now when I wanna link a css or js file in a gsp. I did the following:

  1. I created a new file (eg the resources file) under web-app folder and I put there all my files of folders (eg when importing bootstrap I had a parent folder bootstrap under resources and under bootstrap there were css, img and js folders with their files).

  2. Then, to import a css file I did the following (here is documentation for this):

<link rel="stylesheet" href="${resource(dir: 'resources/bootstrap/css', file: 'bootstrap.min.css')}" type="text/css">

<script src="${resource(dir: 'resources/bootstrap/js', file: 'bootstrap.min.js')}"></script>

This worked great, but when I tried to create a new Project in grails 2.2.4 I had a Resource not found Error (404 to browser and the following to console).

ERROR resource.ResourceMeta  - Resource not found: /resources/bootstrap/css/bootstrap.min.css
ERROR resource.ResourceMeta  - Resource not found: /resources/bootstrap/js/bootstrap.min.js
ERROR resource.ResourceMeta  - Resource not found: /resources/bootstrap/css/bootstrap.min.css
ERROR resource.ResourceMeta  - Resource not found: /resources/bootstrap/js/bootstrap.min.js

As I realized these Errors in console were once from the resources function and once from the GET that client(browser) requested.

When looking at resources plugin I see that they suggest using the js and css folders. Is that meaningful to split a tool (eg twitter bootstrap) in these two directories?

5
So in general the question could be: is there a plain & simple way to put static folders inside webapp (eg twitter bootstrap, chosen js, jquery widget) keeping their directory structures AND avoiding splitting these resources into the three grails resource plugin directories (images, js, css)? Am I right? And If so, this approach worked well in pre 2.2.4 releases, but since 2.2.4 is no more working.tmanolatos
Yes, this is exactly my questionwannaKnowItAll
Have you tried using resource modules instead, with your setup?dmahapatro
if you mean the g:resource tag, I tried itwannaKnowItAll
I meant <r:require modules="...."/>. In line with what @codelark is referring to as BootstrapResources.groovy.dmahapatro

5 Answers

1
votes

ok I believe I have a (semi) working solution:

Suppose we need to include both Twitter Bootstrap 3 and TinyMce

Under webapp directory I create the following directories:

resources/bootstrap/
resources/bootstrap/css/
resources/bootstrap/css/bootstrap.min.css
resources/bootstrap/fonts/
resources/bootstrap/fonts/glyphicons-halflings-regular.eot
resources/bootstrap/fonts/glyphicons-halflings-regular.svg
resources/bootstrap/fonts/glyphicons-halflings-regular.ttf
resources/bootstrap/fonts/glyphicons-halflings-regular.woff
resources/bootstrap/js/
resources/bootstrap/js/bootstrap.min.js
resources/jquery/
resources/jquery/jquery-2.0.3.min.js
resources/tiny_mce/
resources/tiny_mce/langs/ /*many files here*/
resources/tiny_mce/plugins/ /*many files here*/
resources/tiny_mce/themes/ /*many files here*/
resources/tiny_mce/utils/ /*many files here*/
resources/tiny_mce/tiny_mce_popup.js
resources/tiny_mce/tiny_mce_src.js
resources/tiny_mce/tiny_mce.js

Then I declare my resources in ApplicationResources.groovy

modules = {
    application {
        resource url:'js/application.js'
    }

    jquery {
        resource url:'resources/jquery/jquery-2.0.3.min.js'
    }

    bootstrap {
       dependsOn 'jquery'
       resource url:'resources/bootstrap/css/bootstrap.min.css'
       resource url:'resources/bootstrap/js/bootstrap.min.js'
    }

    tinymce {
        resource url:'resources/tiny_mce/tiny_mce.js'
    }
}

And in Config.groovy

grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*']   /*no changes here*/
grails.resources.adhoc.excludes = ['/**/langs/**/*.*', '/**/themes/**/*.*']  /*to permit some Ajax calls from tiny_mce.js to relevant resources*/
grails.resources.debug=true 
/* 
this is why I call my solution SEMI working. 
If set grails.resources.debug to false, TinyMce is NOT working because the above excludes are not active, and I receive 404 errors
*/

Then, in main.gsp

<!DOCTYPE html>
    <head>
        <g:javascript library="application"/>
        <g:javascript library="bootstrap"/>
        <g:javascript library="tinymce"/>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title><g:layoutTitle default="Grails"/></title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon">
        <link rel="apple-touch-icon" href="${resource(dir: 'images', file: 'apple-touch-icon.png')}">
        <link rel="apple-touch-icon" sizes="114x114" href="${resource(dir: 'images', file: 'apple-touch-icon-retina.png')}">
        <link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}" type="text/css">
        <link rel="stylesheet" href="${resource(dir: 'css', file: 'mobile.css')}" type="text/css">

        <r:layoutResources />
        <g:layoutHead/>
    </head>
    <body>
        <div id="grailsLogo" role="banner"><a href="http://grails.org"><img src="${resource(dir: 'images', file: 'grails_logo.png')}" alt="Grails"/></a></div>
        <g:layoutBody/>
        <div class="footer" role="contentinfo"></div>
        <div id="spinner" class="spinner" style="display:none;"><g:message code="spinner.alt" default="Loading&hellip;"/></div>

        <r:layoutResources />
    </body>
</html>

And in index.gsp

<head>
...
<script type="text/javascript">
$(function() {
    tinymce.init({selector:'textarea'});
});   
</script>
</head>
<body>
...
<h1>Welcome to Grails</h1>
check bootstrap - start
    <span class="glyphicon glyphicon-search"></span>
    <button type="button" class="btn btn-default btn-lg">
     <span class="glyphicon glyphicon-star"></span> Star
    </button>
check bootstrap - stop

<textarea>Your content here.</textarea>
...
</body> 

Using the above, I have fully operational JQuery, Bootstrap3 and TinyMCE But if a I set in Config.groovy

grails.resources.debug=true 

I am receiving 404-errors related to the grails.resources.adhoc.excludes resources that TinyMce dynamically fetches after page load.

Any clues? I am really close to find the solution so I will glad to get your input This test project can be downloaded from here: https://docs.google.com/file/d/0B8epX7R4j7jeaVh5OTFiQlV4V0U/edit?usp=sharing

1
votes

Another answer to the question is the following:

  1. Clean your project
  2. Change 'BuildConfig.groovy' and use a newer version of resources plugin
  3. Do a refresh dependencies to your project

and everything is working great now

0
votes

I had the same issue, I don't know exactly what setup you have but I have this at the top of my mail.gsp-page:

<link rel="stylesheet" href="${resource(dir: 'css', file: 'bootstrap.css')}" type="text/css">

(Inside the -tag)

If you need to import .js-files this is what works for me:

<script src="${resource(dir: 'js', file: 'bootstrap.js')}"></script>

This is at the very bottom om the page inside the -tag.

I'm using Grails 2.1.1.

0
votes

The /css and /js directories are part of the default "adhoc resources" patterns that the resources plugin adds to Config.groovy. If you want a different structure for your static resources, you'll either have to create a resource definition file (eg. BootstrapResources.groovy) or add your directory structure to the adhoc patterns:

// What URL patterns should be processed by the resources plugin
grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*', '/resources/*']

This would make everything in the /web-app/resources an adhoc resource and subject to the resource plugin's processing.

0
votes

I am beginning to think that the most flexible way is to serve static content by using a proxy in front of Tomcat / Grails such as Nginx (for all the 'resources/*' URIs)and letting Grails to handle all the dynamic stuff (for the rest URIs).

After all it should be more efficient to use Nginx for serving static files than letting Tomcat / Grails do this.

But, as an afterthought, it should be pity for Resources Plugin to force you splitting the resources in three directories - and driving Grails cumbersome for simple scenarios like using Ext.js, WYSIWIG editors etc which have myriads of files to be included...