uPortal Javascript Framework Requirements

Portlet-Specific Concerns

Before discussing requirements, it may be useful to summarize some of the concerns that may be unique to a portal environment.  In many current web applications, a JS framework has the opportunity to control the whole page, often resulting in a app-as-single-HTML-page development strategy.  In a portal environment, each portlet is responsible for only a small subsection of the page, and doesn't know what content might be rendered alongside it.  As a result, the portlet cannot assume control of the entire page, or even the entire URL.  

To support multiple independent pieces of content, the portal controls the URL such that parameters for each portlet may be encoded in a single URL.  This means that all URLs must be generated through calls to a backend API, and portlets cannot make assumptions about the format or content of the URL string itself.

Element IDs and Wrappers

An individual portlet controls only part of a page, and one portlet may even be installed twice on a page.  For example, a user might add a base RSS reader portlet twice to the same page, configuring one instance to display a feed from the New York Times, while another displays a feed from the user's university.  If a portlet were to include a static element ID (for example <div id="news-container">), this ID could appear more than one time on a single page, breaking WC3 validation.  Worse, JS attempting to use this ID as a handle for manipulation would make changes to both portlets on the page rather than just the one the user attempting to interact with.

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, 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.

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

uPortal's greatest need from a Javascript framework is for templating.  A number of current portlets and core libraries in uPortal support the binding of content and event handling to flexibly-structures HTML markup.  For example, an internal portlet browser library is used both to generate the "add content" menu in the uPortal customization interface as well as the portlet administration portlet's list of portlets:

Binding content to multiple flexible templates allows re-use of javascript code, creating a smaller, more stable, more focused codebase.  Allowing flexible markup also allows adopters to customize portlets without deep changes to javascript code.

Examples:

Flexibility and Modularity

best if we can include flexible markup make things flexible via the JSP

Stability and Alignment

The uPortal community values stability and continuity, and the scarcity of UX developers in the community makes it difficult to switch JS frameworks often.  The community would benefit from having a stable, well-documented library likely to continue to be viable for at least a couple years.  Since uPortal and portlets are also separate projects, we'd like a framework whose API is fairly stable, increasing the likelihood that a portlet's library versions might be compatible with those of the portal.

uPortal uses jQuery heavily, and a number of Jasig developers like and have become familiar with the framework.  The mobile view additionally uses jQuery Mobile to produce its mobile views.  Compatibility with jQuery and jQuery Mobile is important to Jasig, and libraries that play nicely with those frameworks would be preferred.

 

Â