History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: UP-2505
Type: New Feature New Feature
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Nicholas Blair
Reporter: Eric Dalquist
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
uPortal

Aggregate CSS & JS used by skin/theme

Created: 13/Oct/09 09:01 AM   Updated: 04/Dec/09 10:29 AM
Component/s: User Interface
Affects Version/s: None
Fix Version/s: 3.2.0-RC1

Original Estimate: Unknown Remaining Estimate: Unknown Time Spent: Unknown

Sub-Tasks  All   Open   
 Sub-Task Progress: 

 Description  « Hide
For a skin all CSS and JS for that skin should be listed in an XML file. The file needs two sections, one for CSS and one for JS. The CSS entries need a conditional attribute to allow for IE conditional CSS includes.

When building uportal-war this XML file should be read by a maven plugin (probably an extension of the yui compressor plugin). The CSS and JS must, as much as possible, be aggregated into a single file respectively, maintaining ordering as specified in the XML file. The aggregate files must be compressed and the resulting file name must include a hash of the file (MD5 or similar). Additionally the plugin must write out an XML file in the same format as the original but list the aggregated and compressed files instead.

In 'developer' mode the theme XSL will add the CSS and JS files listed in the original XML file into the portal's <head> exactly in the order specified in the XML file.

In 'production' mode the theme XSL will add the CSS and JS files listed in the generated XML file into the portal's <head> exactly in the order specified in the XML file.

 All   Comments   Work Log   Change History      Sort Order:
Nicholas Blair [13/Oct/09 08:58 PM]
Basic example:

<skin>
<javascript>path/to/javascript1.js</javascript>
<css>path/to/stylesheet.css</css>
</skin>

This skin has 1 javascript file and 1 stylesheet. Note that the paths do not start with "/" characters; this denotes these files are relative to the web context (e.g. /uPortal/path/to/javascript.js).


Nicholas Blair [13/Oct/09 09:00 PM]
Conditional example:

<skin>
<css>path/to/stylesheet.css</css>
<css conditional="if IE gt 6>path/to/ie6-hack.css</css>
</skin>

0 javascript files, 2 stylesheets. The 2nd stylesheet is included in an Internet Explorer conditional comment.


Nicholas Blair [13/Oct/09 09:03 PM]
portal.properties should contain the property for configuring "developer" or "production" modes described above.

Eric Dalquist [13/Oct/09 09:26 PM]
skin.xml file that would live in the skin directory:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
  <!-- base Fluid Skinning System -->
  <css>../common/css/fluid/fluid.reset.css</css>
  <css>../common/css/fluid/fluid.layout.css</css>
  <css>../common/css/fluid/fluid.text.css</css>
  
  <!-- For printing of portal pages. Common to all skins using the universality theme -->
  <css>../common/css/print.css</css>
  
  <!-- For layout of portal pages (in tandem with FSS fluid.layout.css). Common to all skins using the universality theme. -->
  <css>../common/css/layout.css</css>
  
  <!-- Support for legacy uPortal css classes. -->
  <css>uportal3_legacy.css</css>
  
  <!-- Default jqueryui css -->
  <css>/ResourceServingWebapp/rs/jqueryui/1.6rc6/theme/smoothness/ui.all.css</css>
  
  <!-- uPortal jqueryui override css -->
  <css>jquery.css</css>
  
  <!-- Visual style for the portal. Built and formatted as a Fluid Skinning System theme. -->
  <css>fluid.theme.uportal3.css</css>
  
  <!-- Visual style for portlet content. An extension of the uportal3 skin. -->
  <css>uportal3_portlet.css</css>
  <css>jsr168_portlet_spec.css</css>
  
  <!-- Overrides specific to IE6. -->
  <css conditional="if IE 6">uportal3_ie6override.css</css>
  
  <js>../common/javascript/uportal/ajax-preferences-jquery.js</js>
  <js>../common/javascript/uportal/up-channel-browser.js</js>
  <js>../common/javascript/uportal/up-group-browser.js</js>
  <js>../common/javascript/uportal/flyout-nav.js</js>
</resources>

Directory structure for the corresponding skin and shared files:

uportal-war/src/main/webapp/media/skins/universality
|-- common
|   |-- css
|   |   |-- fluid
|   |   |   |-- fluid.layout.css
|   |   |   |-- fluid.reset.css
|   |   |   `-- fluid.text.css
|   |   |-- layout.css
|   |   `-- print.css
|   `-- javascript
|       `-- uportal
|           |-- ajax-preferences-jquery.js
|           |-- flyout-nav.js
|           |-- up-channel-browser.js
|           `-- up-group-browser.js
|-- skinList.xml
|-- universality_full.gif
|-- universality_icon.gif
`-- uportal3
    |-- fluid.theme.uportal3.css
    |-- jquery.css
    |-- jsr168_portlet_spec.css
    |-- skin.xml
    |-- uportal3_ie6override.css
    |-- uportal3_legacy.css
    `-- uportal3_portlet.css

After running through the plugin the following skin.aggr.xml would exist:

<?xml version="1.0" encoding="UTF-8"?>
<resources>
  <!--
    | AGGREGATE OF:
    |  ../common/css/fluid/fluid.reset.css
    |  ../common/css/fluid/fluid.layout.css
    |  ../common/css/fluid/fluid.text.css
    +-->
  <css>../common/css/fluid/uportal3_aggr1_MD5GOESHERE.css</css>
  
  <!--
    | AGGREGATE OF:
    |  ../common/css/print.css
    |  ../common/css/layout.css
    +-->
  <css>../common/css/uportal3_aggr2_MD5GOESHERE.css</css>
  
  <!--
    | AGGREGATE OF:
    |  uportal3_legacy.css
    +-->
  <css>uportal3_aggr3_MD5GOESHERE.css</css>
  
  <!--
    | AGGREGATION BREAK:
    |  external resource, causes break in aggregation to maintain ordering
    +-->
  <css>/ResourceServingWebapp/rs/jqueryui/1.6rc6/theme/smoothness/ui.all.css</css>
  
  <!--
    | AGGREGATE OF:
    |  jquery.css
    |  fluid.theme.uportal3.css
    |  uportal3_portlet.css
    |  jsr168_portlet_spec.css
    +-->
  <css>../common/css/uportal3_aggr4_MD5GOESHERE.css</css>
  
  <!--
    | AGGREGATE OF: (break in aggregation due to change in conditional from previous <css> element)
    |  uportal3_ie6override.css
    +-->
  <css conditional="if IE 6">uportal3_aggr5_MD5GOESHERE.css</css>
  
  <!--
    | AGGREGATE OF:
    |  ../common/javascript/uportal/ajax-preferences-jquery.js
    |  ../common/javascript/uportal/up-channel-browser.js
    |  ../common/javascript/uportal/up-group-browser.js
    |  ../common/javascript/uportal/flyout-nav.js
    +-->
  <js>../common/javascript/uportal/uportal3_aggr1_MD5GOESHERE.js</js>
</resources>

Eric Dalquist [13/Oct/09 09:40 PM]
Another note, the above example uses the following format for the aggregate file name: skin_aggrN_MD5.type

Where skin is the name of the skin the resource definition XML file is for, aggrN is an incrementing value to make tracking aggregate order easier, MD5 is the MD5 hash of the file's contents and type is the file type css or js.


Eric Dalquist [13/Oct/09 09:41 PM]
Another idea for the developer/prod toggle would be to use a JVM property instead of an entry in portal.properties. That would let the setting be toggled without redeploying uPortal.

Nicholas Blair [25/Oct/09 04:05 PM]
Committed initial implementation on trunk of sandbox/maven-uportal-plugin project, includes:
  • XSD for XML representation of skin configuration
  • JAXB annotated classes for marshalling/unmarshalling skin configuration to/from Java data model
  • IResourcesAggregator interface and implementation; automatically aggregates Css and Js objects that are "aggregatable" (same parent path, conditional, and media values), optionally compressing using YUI compressor.
  • tests cases on sample skins

Outstanding work yet:

  • Resolve some problems using the JavaScriptCompressor in YUI Compressor package; I think it's very strict out of the box and fails to compress javascript if there are minor problems in the source
  • Test cases for the Mojo, incorporate with uportal3 build, verify works with universality skin
  • Integrate aggregated output with XSL transformation so the aggregated versions of the files are included in the head (toggled via runtime with System property)

Nicholas Blair [06/Nov/09 05:56 PM]
maven-uportal-plugin currently depends on YUI Compressor version 2.3.6 (the only version available via maven), however that version is broken.
There is a new release of YUI Compressor available - 2.4.2 - we will need to install this jar in the 3rd party repository.

Mojo has been tested successfully as part of the uPortal build.

Committed a copy of the resources/js/css object model in uPortal/trunk, along with a Xalan extension implementation that can convert the resources into the appropriate script and link HTML tags.

Outstanding work:

  • The requirements for this task locate the resources skin.xml file along with the css and javascript files, under uPortal/uportal-war/src/main/webapp/media. This location is not on the classpath, which will make it difficult to locate. Will need to come up with a way to either locate the skin.xml file on the classpath, or be able to resolve it's location from the theme xsl (which is on the classpath).
  • Update the StaticRenderingPipeline to set the configured Resources as a transformer parameter (which will result in the Xalan extension mentioned above rendering the script/link tags in the head)

Almost done!


Nicholas Blair [12/Nov/09 10:01 PM]
Resolution of skin.xml and the css/js it refers to is now complete.

I have an update to the StaticRenderingPipeline and universality's page.xsl that does in fact accomplish the goals of this task (it works!), however I have to hold off on checking it in until we:

1. resolve the YUI Compressor issue mentioned in the prior comment
2. release a version of the maven-uportal-plugin - I have an update to uportal-war/pom.xml that depends on that plugin, which isn't available via maven (I have it installed in my local repository)

Checking these last 2 modifications in before resolving the above would temporarily break trunk.


Nicholas Blair [19/Nov/09 09:47 PM]
YUICompressor issues resolved (required exclusion of Mozilla Rhino, as author includes own modified version of Rhino in yui compressor distribution).

uPortal trunk now has working implementation, depends on release 1.0.0-M2 of maven-uportal-plugin to aggregate during uportal-war build.