(Quick Reference)

6.2.5 静态资源 - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: null

6.2.5 静态资源

Grails 2.0 integrates with the Resources plugin to provide sophisticated static resource management. This plugin is installed by default in new Grails applications.

The basic way to include a link to a static resource in your application is to use the resource tag. This simple approach creates a URI pointing to the file.

However modern applications with dependencies on multiple JavaScript and CSS libraries and frameworks (as well as dependencies on multiple Grails plugins) require something more powerful.

The issues that the Resources framework tackles are:

  • Web application performance tuning is difficult
  • Correct ordering of resources, and deferred inclusion of JavaScript
  • Resources that depend on others that must be loaded first
  • The need for a standard way to expose static resources in plugins and applications
  • The need for an extensible processing chain to optimize resources
  • Preventing multiple inclusion of the same resource

The plugin achieves this by introducing new artefacts and processing the resources using the server's local file system.

It adds artefacts for declaring resources, for declaring "mappers" that can process resources, and a servlet filter to serve processed resources.

What you get is an incredibly advanced resource system that enables you to easily create highly optimized web applications that run the same in development and in production.

The Resources plugin documentation provides a more detailed overview of the concepts which will be beneficial when reading the following guide.

Grails 2.0集成了资源插件以提供更复杂的静态资源管理。此插件在新建Grails应用中是缺省安装的。

在你的应用中要引用一个静态资源链接的基本方法,就是使用resource标签。此种方式会创建一个指向文件的URI。

但是,现在的应用往往会依赖于多个JavaScript、CSS库和框架(即依赖于多个Grails插件),这就要求一些更强大的功能来支撑。

本资源(Resources)框架要解决的主要问题如下:

  • Web应用的性能调优是非常困难的
  • 正确地对资源排序,推迟引用JavaScript
  • 依赖于其他的资源必须要优先加载
  • 在插件和应用中需要采用一种标准的方式来暴露静态资源
  • 需要扩展性更好的处理链来优化资源
  • 阻止同样的资源被多次引用

本插件通过引入新的工件(artefacts)和服务器端的本地文件系统来达到上述目标。

新增的工件用以声明资源,这些声明式的“映射(mappers)”可以对资源进行处理,一个servlet过滤器使用那些被处理过的资源。

通过此高级的资源系统,你能得到的不可思议结果是,在同样的开发和生产环境中,你能够轻松地创建高优化的web应用。

资源插件的官方文档提供了更详细的概念概述,对于阅读后续的内容,颇有裨益。

6.2.5.1 通过资源标签引用资源

Pulling in resources with r:require

To use resources, your GSP page must indicate which resource modules it requires. For example with the jQuery plugin, which exposes a "jquery" resource module, to use jQuery in any page on your site you simply add:

<html>
   <head>
      <r:require module="jquery"/>
      <r:layoutResources/>
   </head>
   <body><r:layoutResources/>
   </body>
</html>

This will automatically include all resources needed for jQuery, including them at the correct locations in the page. By default the plugin sets the disposition to be "head", so they load early in the page.

You can call r:require multiple times in a GSP page, and you use the "modules" attribute to provide a list of modules:

<html>
   <head>
      <r:require modules="jquery, main, blueprint, charting"/>
      <r:layoutResources/>
   </head>
   <body><r:layoutResources/>
   </body>
</html>

The above may result in many JavaScript and CSS files being included, in the correct order, with some JavaScript files loading at the end of the body to improve the apparent page load time.

However you cannot use r:require in isolation - as per the examples you must have the <r:layoutResources/> tag to actually perform the render.

使用r:require获取资源

要使用资源,你的GSP页面必须要知道那些资源模块是所需要的。以jQuery插件为例,其导出了一个"jquery"的资源模块,要在你站点的任何页面使用jQuery,你需要简单地增加如下代码:

<html>
   <head>
      <r:require module="jquery"/>
      <r:layoutResources/>
   </head>
   <body><r:layoutResources/>
   </body>
</html>

这将自动地包含所有需要jQuery的资源,并且要在页面的正确位置引用它们。缺省情况下,插件将其放置到"head",以便在页面中尽早加载。

你可以在GSP页面中多次调用r:require,也可以使用"modules"属性提供一个模块列表:

<html>
   <head>
      <r:require modules="jquery, main, blueprint, charting"/>
      <r:layoutResources/>
   </head>
   <body><r:layoutResources/>
   </body>
</html>

在上例的结果中,很多的JavaScript和CSS文件以正确的顺序被包含进来,而另外一些JavaScript文件则在body的末尾被加载,以提高页面的加载时间。

不过,你还是不能单独使用r:require的-正如示例所示,你必须使用<r:layoutResources/>标签来执行实际的渲染。

Rendering the links to resources with r:layoutResources

When you have declared the resource modules that your GSP page requires, the framework needs to render the links to those resources at the correct time.

To achieve this correctly, you must include the r:layoutResources tag twice in your page, or more commonly, in your GSP layout:

<html>
   <head>
      <g:layoutTitle/>
      <r:layoutResources/>
   </head>
   <body>
      <g:layoutBody/>
      <r:layoutResources/>
   </body>
</html>

This represents the simplest Sitemesh layout you can have that supports Resources.

The Resources framework has the concept of a "disposition" for every resource. This is an indication of where in the page the resource should be included.

The default disposition applied depends on the type of resource. All CSS must be rendered in <head> in HTML, so "head" is the default for all CSS, and will be rendered by the first r:layoutResources. Page load times are improved when JavaScript is loaded after the page content, so the default for JavaScript files is "defer", which means it is rendered when the second r:layoutResources is invoked.

Note that both your GSP page and your Sitemesh layout (as well as any GSP template fragments) can call r:require to depend on resources. The only limitation is that you must call r:require before the r:layoutResources that should render it.

使用r:layoutResources渲染资源链接

当在你的GSP页面中声明所需要的资源模块时,插件框架需要在正确的时间渲染那些资源的链接。

要正确地处理,你必须在你的页面中引用两次r:layoutResources标签,或者更通用的方式是在你的GSP布局中处理:

<html>
   <head>
      <g:layoutTitle/>
      <r:layoutResources/>
   </head>
   <body>
      <g:layoutBody/>
      <r:layoutResources/>
   </body>
</html>

上例描绘了一个最简单的支撑资源的Sitemesh布局。

资源框架的每一个资源都有“安排(disposition)”的概念。这意味着在页面合适位置,资源将被包含进来。

缺省的安排依赖于资源的类型。所有的CSS必须在HTML的<head>中渲染,因此对所有的CSS来说,"head"是其缺省值,并且将被第一个r:layoutResources所渲染。当页面内容被加载完后,再加载JavaScript,那么页面的加载时间将得到很好的提高,因此对于JavaScript文件来说,其缺省值是"defer",这意味着它们将在第二个r:layoutResources被调用的时候被渲染。

注意!不管你是GSP页面还是Sitemesh布局(即任何GSP模板片段)都可以根据资源来调用r:require。此处唯一的限制就是你必须在r:layoutResources渲染之前调用r:require。

Adding page-specific JavaScript code with r:script

Grails has the javascript tag which is adapted to defer to Resources plugin if installed, but it is recommended that you call r:script directly when you need to include fragments of JavaScript code.

This lets you write some "inline" JavaScript which is actually not rendered inline, but either in the <head> or at the end of the body, based on the disposition.

Given a Sitemesh layout like this:

<html>
   <head>
      <g:layoutTitle/>
      <r:layoutResources/>
   </head>
   <body>
      <g:layoutBody/>
      <r:layoutResources/>
   </body>
</html>

...in your GSP you can inject some JavaScript code into the head or deferred regions of the page like this:

<html>
   <head>
      <title>Testing r:script magic!</title>
   </head>
   <body>
      <r:script disposition="head">
         window.alert('This is at the end of <head>');
      </r:script>
      <r:script disposition="defer">
         window.alert('This is at the end of the body, and the page has loaded.');
      </r:script>
   </body>
</html>

The default disposition is "defer", so the disposition in the latter r:script is purely included for demonstration.

Note that such r:script code fragments always load after any modules that you have used, to ensure that any required libraries have loaded.

使用r:script增加特定页面的JavaScript代码

在资源插件安装以后,Grails的javascript标签将被适配到优先使用资源插件,即便如此,如果你需要直接使用JavaScript代码片段,还是推荐你直接调用r:script

这可以让你写一些“内联(inline)”的JavaScript,但实际 不在 内联时渲染,而是根据其安排,决定是在<head>或者body的结尾。

假设一个Sitemesh布局如下所示:

<html>
   <head>
      <g:layoutTitle/>
      <r:layoutResources/>
   </head>
   <body>
      <g:layoutBody/>
      <r:layoutResources/>
   </body>
</html>

...在你的GSP中,你可以插入一些JavaScript代码到head或者如下面所示的页面推迟区域:

<html>
   <head>
      <title>Testing r:script magic!</title>
   </head>
   <body>
      <r:script disposition="head">
         window.alert('This is at the end of <head>');
      </r:script>
      <r:script disposition="defer">
         window.alert('This is at the end of the body, and the page has loaded.');
      </r:script>
   </body>
</html>

在本演示中,其缺省的安排是"defer",所以在后面的安排中,r:script只是单纯地被包含进来。

注意!r:script的代码片段 总是 在你要使用的模块之后加载,因此要保证任何所依赖的都以及加载就绪。

Linking to images with r:img

This tag is used to render <img> markup, using the Resources framework to process the resource on the fly (if configured to do so - e.g. make it eternally cacheable).

This includes any extra attributes on the <img> tag if the resource has been previously declared in a module.

With this mechanism you can specify the width, height and any other attributes in the resource declaration in the module, and they will be pulled in as necessary.

Example:

<html>
   <head>
      <title>Testing r:img</title>
   </head>
   <body>
      <r:img uri="/images/logo.png"/>
   </body>
</html>

Note that Grails has a built-in g:img tag as a shortcut for rendering <img> tags that refer to a static resource. The Grails img tag is Resources-aware and will delegate to r:img if found. However it is recommended that you use r:img directly if using the Resources plugin.

Alongside the regular Grails resource tag attributes, this also supports the "uri" attribute for increased brevity.

See r:resource documentation for full details.

使用r:img链接图片

此标签被用以渲染HTML的<img>标签,并且通过资源框架来处理那些频繁访问的资源(如果配置了的话,比如使其永久的缓存)。

如果资源在以前已经被声明为一个模块的话,那么r:img会包含<img>标签的任何额外属性。

基于此机制,你可以在声明资源模块的时候,来指定width、height以及其他任何属性,然后在需要的时候获取一下即可。

比如:

<html>
   <head>
      <title>Testing r:img</title>
   </head>
   <body>
      <r:img uri="/images/logo.png"/>
   </body>
</html>

注意!Grails内置的g:img标签只是渲染静态资源<img>的一个快捷方式而已。Grails的img的标签如果感知到资源插件,那么将会将其代理给r:img。即便如此,如果使用了资源插件的话,还是推荐直接你使用r:img

跟常规的Grails的resource标签属性一样,为了增加简洁性,r:img也支撑"uri"属性。

更多完整的详细信息请参考r:resource文档

6.2.5.2 其他资源标签

r:resource

This is equivalent to the Grails resource tag, returning a link to the processed static resource. Grails' own g:resource tag delegates to this implementation if found, but if your code requires the Resources plugin, you should use r:resource directly.

Alongside the regular Grails resource tag attributes, this also supports the "uri" attribute for increased brevity.

See r:resource documentation for full details.

r:resource

这跟Grails的resource标签相当,都是返回一个处理过的静态资源链接。如果发现资源插件已经安装,Grails自带的g:resource标签将代理给r:resource,但是如果你的代码依赖资源插件,最好还是直接使用r:resource的好。

跟常规的Grails的resource标签属性一样,为了增加简洁性,r:resource也支撑"uri"属性。

更多完整的详细信息请参考r:resource文档

r:external

This is a resource-aware version of Grails external tag which renders the HTML markup necessary to include an external file resource such as CSS, JS or a favicon.

See r:resource documentation for full details.

r:external

这是一个资源感知(resource-aware)版本的Grails的external标签,用以渲染那些必要的HTML标签所需要的外部资源文件,比如CSS、JS或者favicon。

更多完整的详细信息请参考r:resource文档

6.2.5.3 声明资源

A DSL is provided for declaring resources and modules. This can go either in your Config.groovy in the case of application-specific resources, or more commonly in a resources artefact in grails-app/conf.

Note that you do not need to declare all your static resources, especially images. However you must to establish dependencies or other resources-specific attributes. Any resource that is not declared is called "ad-hoc" and will still be processed using defaults for that resource type.

Consider this example resource configuration file, grails-app/conf/MyAppResources.groovy:

modules = {
    core {
        dependsOn 'jquery, utils'

resource url: '/js/core.js', disposition: 'head' resource url: '/js/ui.js' resource url: '/css/main.css', resource url: '/css/branding.css' resource url: '/css/print.css', attrs: [media: 'print'] }

utils { dependsOn 'jquery'

resource url: '/js/utils.js' }

forms { dependsOn 'core,utils'

resource url: '/css/forms.css' resource url: '/js/forms.js' } }

This defines three resource modules; 'core', 'utils' and 'forms'. The resources in these modules will be automatically bundled out of the box according to the module name, resulting in fewer files. You can override this with bundle:'someOtherName' on each resource, or call defaultBundle on the module (see resources plugin documentation).

It declares dependencies between them using dependsOn, which controls the load order of the resources.

When you include an <r:require module="forms"/> in your GSP, it will pull in all the resources from 'core' and 'utils' as well as 'jquery', all in the correct order.

You'll also notice the disposition:'head' on the core.js file. This tells Resources that while it can defer all the other JS files to the end of the body, this one must go into the <head>.

The CSS file for print styling adds custom attributes using the attrs map option, and these are passed through to the r:external tag when the engine renders the link to the resource, so you can customize the HTML attributes of the generated link.

There is no limit to the number of modules or xxxResources.groovy artefacts you can provide, and plugins can supply them to expose modules to applications, which is exactly how the jQuery plugin works.

To define modules like this in your application's Config.groovy, you simply assign the DSL closure to the grails.resources.modules Config variable.

For full details of the resource DSL please see the resources plugin documentation.

系统提供了一个DSL专门用于声明资源和模块。其可以位于Config.groovy中特定应用的资源容器,或者更常用的是grails-app/conf下的一个资源工件中。

注意!你并不需要声明所有的静态资源,尤其是图片。但是你必须要建立所需依赖或者其他资源相关的属性。没有被声明的资源称之为"ad-hoc",并且根据其资源类型被缺省处理。

假设如下所示的grails-app/conf/MyAppResources.groovy资源配置文件:

modules = {
    core {
        dependsOn 'jquery, utils'

resource url: '/js/core.js', disposition: 'head' resource url: '/js/ui.js' resource url: '/css/main.css', resource url: '/css/branding.css' resource url: '/css/print.css', attrs: [media: 'print'] }

utils { dependsOn 'jquery'

resource url: '/js/utils.js' }

forms { dependsOn 'core,utils'

resource url: '/css/forms.css' resource url: '/js/forms.js' } }

示例定义了三个资源模块:'core'、'utils'和'forms'。这些模块中的资源将根据模块的名称自动地打包到更少的文件中。对于每个资源,你可以使用bundle:'someOtherName' 来覆盖之,或者调用模块的defaultBundle(更多请参考资源插件文档)。

通过dependsOn来声明的依赖关系,可以控制资源的加载顺序。

当你在的GSP中引用<r:require module="forms"/>的时候,它将从'core'和'utils'还有'jquery'中获取所有的资源,并以正确的顺序加载。

你将会注意到core.js文件中的disposition:'head' 。它将告诉资源插件当所有的其他JS文件推迟到body末尾加载的时候,此文件(core.js)必须要在<head>加载。

用于打印风格的CSS文件通过attrs映射选项来添加自定义属性,并且在渲染到资源链接的时候,它们将被传递给r:external标签,因此你可以自定义HTML的属性来生成链接。

模块或者你定义的xxxResources.groovy工件的数量是没有限制的,插件也可以将资源模块暴露给应用,正如jQuery插件所做的那样。

要在你应用中的Config.groovy定义模块,你可以简单地将DSL闭包赋给grails.resources.modules配置变量。

完整的资源DSL信息请参考资源插件文档

6.2.5.4 覆盖插件资源

Because a resource module can define the bundle groupings and other attributes of resources, you may find that the settings provided are not correct for your application.

For example, you may wish to bundle jQuery and some other libraries all together in one file. There is a load-time and caching trade-off here, but often it is the case that you'd like to override some of these settings.

To do this, the DSL supports an "overrides" clause, within which you can change the defaultBundle setting for a module, or attributes of individual resources that have been declared with a unique id:

modules = {
    core {
        dependsOn 'jquery, utils'
        defaultBundle 'monolith'

resource url: '/js/core.js', disposition: 'head' resource url: '/js/ui.js' resource url: '/css/main.css', resource url: '/css/branding.css' resource url: '/css/print.css', attrs: [media: 'print'] }

utils { dependsOn 'jquery' defaultBundle 'monolith'

resource url: '/js/utils.js' }

forms { dependsOn 'core,utils' defaultBundle 'monolith'

resource url: '/css/forms.css' resource url: '/js/forms.js' }

overrides { jquery { defaultBundle 'monolith' } } }

This will put all code into a single bundle named 'monolith'. Note that this can still result in multiple files, as separate bundles are required for head and defer dispositions, and JavaScript and CSS files are bundled separately.

Note that overriding individual resources requires the original declaration to have included a unique id for the resource.

For full details of the resource DSL please see the resources plugin documentation.

因为一个资源模块定义了捆绑(bundle)组和资源的其他属性,因此你可能会发现设置所提供的并不适合你的应用。

比如,你可能希望将jQuery和其他的库捆绑到一个文件中。此处就要根据加载时间和缓存做一个权衡,但是在此种情况下,你经常会想重载这些配置的一部分。

这时候,DSL提供了"overrides"子句来完成此功能,子句内你可以修改一个模块的defaultBundle,或者每个单独资源的属性,不过每个资源必须要声明一个唯一的id:

modules = {
    core {
        dependsOn 'jquery, utils'
        defaultBundle 'monolith'

resource url: '/js/core.js', disposition: 'head' resource url: '/js/ui.js' resource url: '/css/main.css', resource url: '/css/branding.css' resource url: '/css/print.css', attrs: [media: 'print'] }

utils { dependsOn 'jquery' defaultBundle 'monolith'

resource url: '/js/utils.js' }

forms { dependsOn 'core,utils' defaultBundle 'monolith'

resource url: '/css/forms.css' resource url: '/js/forms.js' }

overrides { jquery { defaultBundle 'monolith' } } }

上述示例会将所有的代码放到一个单独的'monolith'捆绑束中。注意,结果依然可能分散在多个文件中,因为安排head和defer所需的捆绑束是不同的,JavaScript和CSS文件被分开捆绑的。

注意重载单独的资源,需要原来的资源声明一个唯一的id。

更多详细完整的资源DSL信息请参考资源插件文档

6.2.5.5 优化资源

The Resources framework uses "mappers" to mutate the resources into the final format served to the user.

The resource mappers are applied to each static resource once, in a specific order. You can create your own resource mappers, and several plugins provide some already for zipping, caching and minifying.

Out of the box, the Resources plugin provides bundling of resources into fewer files, which is achieved with a few mappers that also perform CSS re-writing to handle when your CSS files are moved into a bundle.

资源框架使用"映射器(mappers)"来将资源转变为最终用户所需的格式。

资源映射器以一个特定的顺序将每一个静态资源处理一次。你可以创建你自己的资源映射器,有一些插件已经提供了比如压缩(zipping)、缓存(caching)和缩少(minifying)等映射。

除此之外,资源插件还提供了捆绑多个资源到较少的文件功能,在将你的CSS文件移动到一个捆绑束的时候,其使用一些映射器执行重写CSS处理。

Bundling multiple resources into fewer files

The 'bundle' mapper operates by default on any resource with a "bundle" defined - or inherited from a defaultBundle clause on the module. Modules have an implicit default bundle name the same as the name of the module.

Files of the same kind will be aggregated into this bundle file. Bundles operate across module boundaries:

modules = {
    core {
        dependsOn 'jquery, utils'
        defaultBundle 'common'

resource url: '/js/core.js', disposition: 'head' resource url: '/js/ui.js', bundle: 'ui' resource url: '/css/main.css', bundle: 'theme' resource url: '/css/branding.css' resource url: '/css/print.css', attrs: [media: 'print'] }

utils { dependsOn 'jquery'

resource url: '/js/utils.js', bundle: 'common' }

forms { dependsOn 'core,utils'

resource url: '/css/forms.css', bundle: 'ui' resource url: '/js/forms.js', bundle: 'ui' } }

Here you see that resources are grouped into bundles; 'common', 'ui' and 'theme' - across module boundaries.

Note that auto-bundling by module does not occur if there is only one resource in the module.

捆绑多个资源到较少的文件

缺省情况下,'bundle'映射器会操作使用"bundle"定义的任何资源-或者继承自模块的defaultBundle子句。模块有一个隐含的跟模块名称相同的缺省捆绑束名。

同样类型的文件将会被汇集到当前的捆绑束文件中。捆绑束是通过模块的边界来操作的:

modules = {
    core {
        dependsOn 'jquery, utils'
        defaultBundle 'common'

resource url: '/js/core.js', disposition: 'head' resource url: '/js/ui.js', bundle: 'ui' resource url: '/css/main.css', bundle: 'theme' resource url: '/css/branding.css' resource url: '/css/print.css', attrs: [media: 'print'] }

utils { dependsOn 'jquery'

resource url: '/js/utils.js', bundle: 'common' }

forms { dependsOn 'core,utils'

resource url: '/css/forms.css', bundle: 'ui' resource url: '/js/forms.js', bundle: 'ui' } }

此处你可以看到资源被分组到捆绑束:'common'、'ui'和'theme' - 通过模块边界。

注意!如果模块中只有一个资源,那么根据模块自动捆绑将 不会 发生。

Making resources cache "eternally" in the client browser

Caching resources "eternally" in the client is only viable if the resource has a unique name that changes whenever the contents change, and requires caching headers to be set on the response.

The cached-resources plugin provides a mapper that achieves this by hashing your files and renaming them based on this hash. It also sets the caching headers on every response for those resources. To use, simply install the cached-resources plugin.

Note that the caching headers can only be set if your resources are being served by your application. If you have another server serving the static content from your app (e.g. Apache HTTPD), configure it to send caching headers. Alternatively you can configure it to request and proxy the resources from your container.

让资源“永久”地缓存在客户浏览器

在客户端“永久”地缓存资源只有在资源有一个唯一的名字的情况下,才切实可行,并且当资源的内容变化时,其名字也要做相应的变化,还要求在响应中设置缓存标头(caching headers)。

cached-resources插件提供了一个映射器来完成此功能,它是通过对你的文件做哈稀校验并根据校验值来重命名来实现的。此插件也会在每一次的响应中根据这些资源的情况来设置缓存标头。要使用它,只需要简单的安装cached-resources插件即可。

注意!只有在你的应用管辖范围内的资源,才会有可能设置缓存标头.如果你有另外一个服务器专门管理你应用的静态资源(比如Apache的HTTPD),那么需要配置此服务器来发送缓存标头。或者你也可以配置它来请求和代理你容器内的资源。

Zipping resources

Returning gzipped resources is another way to reduce page load times and reduce bandwidth.

The zipped-resources plugin provides a mapper that automatically compresses your content, excluding by default already compressed formats such as gif, jpeg and png.

Simply install the zipped-resources plugin and it works.

压缩资源

返回用gzip压缩过的资源是另外减少页面加载时间和带宽的方法。

zipped-resources插件提供了一个映射器来自动地压缩你的资源内容。当然那些已经压缩过地除外,比如gif、jpeg和png。

简单地安装zipped-resources插件后,即可工作。

Minifying

There are a number of CSS and JavaScript minifiers available to obfuscate and reduce the size of your code. At the time of writing none are publicly released but releases are imminent.

缩少资源

已经有很多的CSS和JavaScript缩少器可以用来混淆和减少你代码的大小。这可以解决发布迫在眉睫,而现在编码时没有什么可公开发布的情况。

6.2.5.6 调试

When your resources are being moved around, renamed and otherwise mutated, it can be hard to debug client-side issues. Modern browsers, especially Safari, Chrome and Firefox have excellent tools that let you view all the resources requested by a page, including the headers and other information about them.

There are several debugging features built in to the Resources framework.

当你的资源正在移动、重命名以及其他变动的时候,要调试客户端的问题是非常困难的。现代的浏览器,尤其是Safari、Chrome和Firefox,都有非常优秀的工具来查看一个请求页面的所有资源,包括其请求头和其他的信息。

除此之外,Resources框架还提供了几个内置的调试特性。

X-Grails-Resources-Original-Src Header

Every resource served in development mode will have the X-Grails-Resources-Original-Src: header added, indicating the original source file(s) that make up the response.

X-Grails-Resources-Original-Src信息头

在开发模式下,每一个用到的资源都会添加X-Grails-Resources-Original-Src的头信息,用以表示此响应对应的原始代码文件。

Adding the debug flag

If you add a query parameter _debugResources=y to your URL and request the page, Resources will bypass any processing so that you can see your original source files.

This also adds a unique timestamp to all your resource URLs, to defeat any caching that browsers may use. This means that you should always see your very latest code when you reload the page.

添加调试标记

如果在你的URL和请求页面的参数中增加 _debugResources=y 的话,Resources将会不管任何处理,而直接显示和使用原始的代码文件。

此外,你资源的URLs还会添加一个唯一的时间戳,用以处理浏览器导致的缓存问题。这意味着在你重现加载页面的时候,你总是得到最新的代码。

Turning on debug all the time

You can turn on the aforementioned debug mechanism without requiring a query parameter, but turning it on in Config.groovy:

grails.resources.debug = true

You can of course set this per-environment.

打开调试

你可以在不需要额外请求参数的情况下打开如上所述的调试机制,要如此,只要在Config.groovy中配置一下即可:

grails.resources.debug = true

当然,你也可以在每个单独的环境设置。

6.2.5.7 阻止资源处理

Sometimes you do not want a resource to be processed in a particular way, or even at all. Occasionally you may also want to disable all resource mapping.

有时候,你并不想以一种特别的方式处理资源,甚至根本就不想。偶尔,你还想禁止所有的资源映射。

Preventing the application of a specific mapper to an individual resource

All resource declarations support a convention of noXXXX:true where XXXX is a mapper name.

So for example to prevent the "hashandcache" mapper from being applied to a resource (which renames and moves it, potentially breaking relative links written in JavaScript code), you would do this:

modules = {
    forms {
        resource url: '/css/forms.css', nohashandcache: true
        resource url: '/js/forms.js', nohashandcache: true
    }
}

阻止到一个单独资源的特定映射

所有的资源声明都支持noXXXX:true的用法,此处的XXXX是一个映射器的名称。

因此在下例中,要阻止"hashandcache"映射器应用到一个资源(重命名,移动甚至断开JavaScript代码中的相关链接)你可以这样做:

modules = {
    forms {
        resource url: '/css/forms.css', nohashandcache: true
        resource url: '/js/forms.js', nohashandcache: true
    }
}

Excluding/including paths and file types from specific mappers

Mappers have includes/excludes Ant patterns to control whether they apply to a given resource. Mappers set sensible defaults for these based on their activity, for example the zipped-resources plugin's "zip" mapper is set to exclude images by default.

You can configure this in your Config.groovy using the mapper name e.g:

// We wouldn't link to .exe files using Resources but for the sake of example:
grails.resources.zip.excludes = ['**/*.zip', '**/*.exe']

// Perhaps for some reason we want to prevent bundling on "less" CSS files: grails.resources.bundle.excludes = ['**/*.less']

There is also an "includes" inverse. Note that settings these replaces the default includes/excludes for that mapper - it is not additive.

从特定映射器中 排除/包含 路径和文件类型

映射器的排除/包含使用Ant语法来控制是否要应用到给定的资源上。映射器会根据其活动情况来设置缺省的感知类型,以资源压缩(zipped-resources)插件为例,其"zip"映射器会缺省地排除那些镜像文件。

你可以通过你的Config.groovy文件地映射器名称来配置相关信息,比如:

// We wouldn't link to .exe files using Resources but for the sake of example:
grails.resources.zip.excludes = ['**/*.zip', '**/*.exe']

// Perhaps for some reason we want to prevent bundling on "less" CSS files: grails.resources.bundle.excludes = ['**/*.less']

反之,你也可以使用"includes"。要注意的是,上述操作将替换映射器缺省的includes/excludes设置-而不是追加。

Controlling what is treated as an "ad-hoc" (legacy) resource

Ad-hoc resources are those undeclared, but linked to directly in your application without using the Grails or Resources linking tags (resource, img or external).

These may occur with some legacy plugins or code with hardcoded paths in.

There is a Config.groovy setting grails.resources.adhoc.patterns which defines a list of Servlet API compliant filter URI mappings, which the Resources filter will use to detect such "ad-hoc resource" requests.

By default this is set to:

grails.resources.adhoc.patterns = ['images/*', '*.js', '*.css']

控制"ad-hoc"(遗留)资源

Ad-hoc资源是那些未声明的,并且 使用Grails或者Resources的链接标签(resource, img or external),而是在你的应用中直接链接的资源。

这可能会在那些遗留插件或者硬编码路径的时候会碰到。

Config.groovy中的 grails.resources.adhoc.patterns 配置就是用来定义一系列Servlet API兼容的URI映射的过滤器,其资源过滤器通常用来检测那些"ad-hoc resource"请求。

其缺省值如下:

grails.resources.adhoc.patterns = ['images/*', '*.js', '*.css']

6.2.5.8 其他资源感知的插件

At the time of writing, the following plugins include support for the Resources framework:

截至到书写为止,资源框架已经被下列插件所支撑: