Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The portlet specification includes a mechanism for producing an ID that's unique to a portlet instance.  This ID is not predictable and may not be consistent over time, but it is guaranteed not to conflict with any other IDs.  Jasig portlet typically use this string to produce a unique ID for a top-level wrapper element for each portlet.  As an example, the top-level element for the news portlet might become <div id="<portlet:namespace/>-news-container">.  This ID is now guaranteed to be unique and can be used for targeting via JS.

Of course, an unpredictable, a dynamic ID is difficult to use from static JS documents.  Jasig script libraries typically accept a wrapper div ID as a parameter, use that as the main scoping container, and select sub-elements by CSS classname.

JavaScript Scoping

Routing

any routing has to be specific to a DOM container rather than the whole page

 

RESTful Services

 

...

Library Imports

Each portlet is managed and maintained as a completely separate project, not connected to a particular version of uPortal (or even to uPortal itself), or connected to any other portlet projects.  A given Jasig portlet might be deployed in multiple major versions of uPortal, as well as in Liferay.  This project structure allows a modular deployment approach in which the portal and each portlet may be upgraded in isolation, providing adopters with greater flexibility.

To better support this approach, each Jasig portlet may use a different version of JS libraries than the portal itself.  All libraries imported by the portal are added to a "up" namespace, then removed from the shared namespace by using jQuery.noConflict(true) or its equivalent.  Each portlet follows a similar approach, importing all the resources it requires, then clearing the public namespace to leave a clean slate for the next portlet.  To prevent the browser from actually downloading several copies of each shared library (such as jQuery, etc.), the portal and all portlets download these shared resources from a common location.  Since the URL for the library is identical for each import, the browser only downloads one copy.  This shared location is provided by the Resource Server, a special webapp automatically deployed in Tomcat alongside uPortal.  

Even though the browser only downloads one copy, it does have to evaluate the library multiple times, which leads to noticeable slowdowns in mobile environments.  Some portlets allow the deployer to indicate whether the portlet can use uPortal's copy of shared libraries such as jQuery.  While this option should be disabled by default, if a deployer knows that the version of all libraries included by uPortal will work with the portlet, this is a nice option for improving browser-side performance.  In this case, the portlet needs to be careful about the manner in which it imports any additional scripts.  For example, jQuery is no longer visible in the global namespace, so any custom portlet javascript code would need to know to initialize against the up.jQuery variable (and this behavior would need to be configurable to continue to support portlet-only javascript versions).  The portlet would also need to ensure that additional resources wouldn't be imported twice if the portlet was added to a page multiple times.

Jasig has found that some libraries and plugins do not support a no-conflict style of initialization or aren't sufficiently tested under such settings.  Any libraries or plugins used in uPortal or portlets should be tested thoroughly for compatibility.  Plugins without adequate support can sometimes be patched (and patches may be submitted back to the project).  Any custom portlet code also needs to be tested to make sure it doesn't leave variables in the shared namespace and that it functions if imported into the page more than once.

URLs

As mentioned above, portlets cannot manually construct portal URLs.  A JSP page may construct URLs using the portlet tag library, then inject these dynamically-generated URLs into JS code and configuration.  As a result, any static JS code must allow parameterization with valid dynamic URLs.  Some modern javascript frameworks make assumptions about the structure of URLs, expecting predictable RESTful formats.  While we love REST URLs, they are not valid in portal environments and uPortal requires frameworks and libraries that allow dynamic URL format configuration.

Portal URL generation strategies also complicate the routing strategies used by many modern JS frameworks.  Such frameworks often tie content to the hashtag portion of a URL, allowing back-button navigation and bookmarking.  While these are excellent features we'd like to make use of, we have multiple portlets on page and only one hash tag.  If we allow a single portlet to overtake the hashtag, it will overwrite information being used by other portlets.  uPortal is left with a choice between disabling routing functionality, using it without hashtags, and implementing a custom routing implementation that divides a hashtag between multiple portlets.

HTTP Request Count

Since the portal includes multiple portlets on any given page, HTTP request behavior should be carefully examined.  For example, if a single-page app includes a couple templates via script imports, this might not result in a noticeable slowdown in page initialization.  If five portlets on a page each request two scripts, however, 10 script imports are much more likely to be noticed.  uPortal generally aggregates all custom JS resources for a single portlet together to reduce latency.  In best practice, any portlet-specific script imports should allow aggregation, or script templates should be included inline in the page.

Needs and Requirements

Templating and Event Handling

...