Table of Contents |
---|
Tapestry and JavaScript
Tapestry 5 has had a interesting mix of characteristics.
...
Many users are perplexed by how Tapestry performs initialization: in a typical bespoke
Wiki Markup |
---|
{footnote}By "bespoke", we mean a non-component-based, manually created page; a standalone static HTML page.{footnote} |
application, the developer will . In typical web page construction, the developer would create a <script>
block at the bottom of the page, and do initializations there. In Tapestry, it can be much more complex:
- A JavaScript library, containing one or more initialization functions, is created
- The initialization functions must be monkey patched into the T5.initializers namespace
{footnote}Prior to 5.3, it was the {{(or older Tapestry.Initializers}} namespace; both names reference the same object, for backwards compatibility.{footnote}) namespace.Wiki Markup - The JavaScriptSupport environmental must be used to invoke the function, by name, passing it a JSONObject to configure itself (the "specification")
- The affected element must have a unique id attribute, used to coordinate the initialization in the client web browser
{footnote}Tapestry assists with unique id allocation, but it would be much better if unique ids were not necessary.{footnote}. (Tapestry assists with unique id allocation, but it would be much better if unique ids were not necessary.)Wiki Markup
This often feels like overkill, but it is necessary for a number of desirable characteristics:
...
- A module may be overriden (for instance, to work around a bug), in which case a specific asset may be used for the module, rather than the default
- A module may need to be converted from one language to another: specifically, a module may be written in CoffeeScript, and need to be compiled down to JavaScript
- A module's content may be aggregated with other related modules (much like a Tapestry 5.3 stack), especially in production
{footnote}A request for any module should provide the aggregated set of modules; RequireJS will not need to send additional requests for the other modules{footnote}. (A request for any module should provide the aggregated set of modules; RequireJS will not need to send additional requests for the other modules.)Wiki Markup - Module content (aggregated or not) should be minimized
In addition, it may be reasonable to have Tapestry automatically (or via some configuration) wrap CommonJS modules as AMD modules {footnote}. (Traditionally, Tapestry has configured this kind of behavior via service contributions, but there is ample evidence that this could be done using external configuration, perhaps using a JSON file in the module package, to control aggregation, wrapping, and other aspects the process. This would be more agile, as it would not require restarts when the configuration changes.{footnote}) Wiki Markup
Modules will be stored on the classpath, in a modulejs
package below each library's root package. Modules within that package are referenced by their name relative to the package
Wiki Markup |
---|
{footnote}A rarely used feature of Tapestry is that a component library name may be mapped to multiple packages; resolving a module name may require a search among the packages. There is the expectation that the developer will ensure that there are no duplications that would lead to ambiguities.{footnote} |
. . (A rarely used feature of Tapestry is that a component library name may be mapped to multiple packages; resolving a module name may require a search among the packages. There is the expectation that the developer will ensure that there are no duplications that would lead to ambiguities.)
Under this system, module core/pubsub
would be the file pubsub.js
in the package org.apache.tapestry5.corelib.modulejs
, since Tapestry's component library 'core' is mapped to package org.apache.tapestry5.corelib
.
...
- require one or more modules
- require a module (that exports a single function) and invoke the function, passing zero or more values
{footnote}Values passed to module functions may be limited to String and [JSONObject|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/json/JSONObject.html].{footnote}. (Values passed to module functions may be limited to String and JSONObject.)Wiki Markup - require a module and a function name and invoke named function exported by the module, passing zero or more values
...
Tapestry currently maintains two global message catalogs; a global server-side catalog (usually named WEB-INF/app.properties
{footnote}{{ Wiki Markup ) and a client-side catalog. (app.properties
}} provides
application-specific
messages,
and
overrides
of
other
messages
provided
by
Tapestry
and
other
third-party
libraries.
The
global
message
catalog
is
actually
a
composite
of
all
of
these
sources.
{footnote})
and a client-side catalog. The client-side catalog is smaller, more limited, and less extensible.
...
- Redirect the entire page to a new URL (on the server, or elsewhere)
- A server-side error to be presented to the user
{footnote}This was greatly enhanced in . (This was greatly enhanced in 5.3 to present the full exception report in a pop-up iframe.{footnote})Wiki Markup - Update the content of an implicit (originating) element; typically the element for the Zone that triggered the request
- Update the content of any number of other elements (identified by their client-side id)
- Inject new JavaScript libraries into the page
- Inject new CSS links into the page
- Peform initializations (using
T5.initializers
) ... but only after all content updates have occurred
The injected JavaScript libraries and CSS links will often duplicate libraries and CSS links already present on the page; when the page is partially rendered, the server has no way to know what full or partial page renders have already occured
Wiki Markup |
---|
{footnote}It might be possible for the request to include a list of what's already loaded in the browser, so that the server can filter what it sends back; however, given factors such as content compression and typical upload vs. download bandwidth, it is almost certainly more effective for the browser to send too much, and let the client filter out duplicates.{footnote} |
.
occurred. (It might be possible for the request to include a list of what's already loaded in the browser, so that the server can filter what it sends back; however, given factors such as content compression and typical upload vs. download bandwidth, it is almost certainly more effective for the browser to send too much, and let the client filter out duplicates.)
Tapestry 5.3 first loads any additional JavaScript (usually by adding new <script>
tags to the page). Once JavaScript libraries and CSS links have been added, and JavaScript libraries have been loaded, the DOM is updated with the new content. Lastly, any initializations are processed.
...
- Tapestry 5.3 style initializations will be a specific application of 5.4 style module requirement and invocation
- IMMEDIATE may occur before DOM changes
- Module requirement/invocation will occur in initialization priority order; for any single priority, initialization will occur in render order
.occur in render order. (Technically, in the order of invocations on JavaScriptSupport.)Wiki Markup {footnote}Technically, in the order of invocations on JavaScriptSupport.{footnote}
- The response will be embeddable inside other JSONObject responses.
...
Determining what assets are available is somewhat problematic as Tapestry mixes server-side only resources (.class files, .tml files, etc.) freely with assets that might be exposed to the browser {footnote}This should never have been the case, but . (This should never have been the case, but that's hindsight.{footnote}. ) Some of those server-side resource may expose details, such as other server hosts and potentially user names and passwords, that should never be exposed to the client. Wiki Markup
...
This is a big undertaking; this document is not a contract, and is certainly not complete, but is only starting point for discussions about what will be forthcoming in Tapestry 5.4. {display-footnotes} Wiki Markup