Liferay polymer integration

This is a guideline for Polymer 3 PWA integration as microapplication into Liferay Portlet. The npm module code is a part of portlet and deployed within its JAR. Sample has been build with Vaadin template.

Methods described in this article is applicable to any framework from Angular to Ionic. I am focusing on Polymer 3 as most compatible and smallest base. Other frameworks need extra level of compatibility coding in order to be Liferay (or any CMS) friendly.


Modern JS frameworks in Liferay 7.1 CMS are the pain to deal with.

The internal CDN publishing of NPM modules have promised to be an great helper. The build tool uses the package.json and node_modules content to publish module and dependencies version into Liferay URL. This way same package version could be shared among applications.

This brilliant idea had not been implemented sufficiently to be suitable for high-level frameworks like PolymerJS(native web components) or Quasar( VueJs ). Such libraries use dependencies in es6 source format which meant to be compiled and bundled depend of target platform into es5 or es6 bundles. Liferay JS toolkit unfortunately treats all dependencies as pre-build to es5 AMD format. Kicking off most of modern JS libs which use ES6 'import' capabilities. Bug.


Is to use selected platform bundled build capabilities. I would suggest to use legacy (es5/AMD) and modern(ES6) browsers build profiles, both as bundles with dynamic code load. This way in majority of browsers only minimal set of  JS will be used during page load still keeping page responsive to user actions when on-demand code is loaded.

The reference implementation also gives extra perks like

  • debug mode support to use unbundled JS sources on page load
  • build profile enforcing via URL parameter
  • JS project integrated and deployed withing portlet JAR.

Design notes

  • Portlet have to be published in fixed osgi path.
    I.e. for CSS /o/my-custom-portlet/my-custom.css deployment path defined by bnd.bnd is:
        Web-ContextPath: /my-custom-portlet
  • Legacy and es6 builds have to set own root path in index.html by build.sh
  • Browser compatibility recognition done on server side by BrowserSnifferUtil and uses the build profile matching browser.
    esm-bundled, es5-bundled profiles are made for modern and legacy browsers respectively.
  • Server-side inclusion of build/${profile}/index.html is done by jsp:include
  • the top-level component included by view.jsp after as tag with data passed as html element parameters. In sample the URL for ajax call is passed from jsp to portlet.
  • <script type="module"... > during navigation into page with PolymerPortlet is ignored by Liferay SPA implementation. view.jsp has a workaround by re-injecting script tag into page. Processed script tags are marked by `injected` property.
  • es5-unbundled generates document.write("<!--") which clears the page. Fix is removing code from generated index.html

Sample Code

Happy coding!