GithubHelp home page GithubHelp logo

altenfreelance / liferay-javascript-portlet Goto Github PK

View Code? Open in Web Editor NEW

This project forked from hannikkala/liferay-javascript-portlet

0.0 1.0 0.0 12.54 MB

Simple Liferay portlet to create portlets from JavaScript applications (React, Angular, etc)

JavaScript 24.72% Shell 0.59% Batchfile 0.46% CSS 11.74% HTML 6.65% Java 55.85%

liferay-javascript-portlet's Introduction

Liferay Javascript Portlet

Generic purpose portlet to display any application made with any modern JavaScript framework. There's an simple example made with Angular1 and REST backend with Spring Boot. As easily it works with ReactJS and others.

Why?

Short answer: Because Liferay development is very slow and painful (change, build, deploy, pray, restart portal, clear temp & work & webapp and try again...)

Longer answer: ... and there are great new waves on Web development. Namely modern JavaScript libraries like ReactJS, AngularJS as well as frameworks to create REST API services that are very lightweight. Here I use Spring Boot but you may choose whatever you like even made with other languages. I don't judge :)

The development process goes more like change, automatic refresh, change, automatic refresh, .. and this is the way it should go. This project aims to be easy-to-use tool to embed any custom JavaScript software into Liferay portal and taking care of all the heavy lifting. This of course works as long as you don't need any Liferay's internal objects.

Features

  • Fetches index.html from external source as Thymeleaf template or just plain simple HTML file if you don't need parameters.
  • Caches resources from the index page internally for faster accessibility
  • For even faster performance there are support for using CDN (Content Delivery Network)
  • Support for multiple portlets
  • Support for multiple JavaScript applications (as different portlet instances)
  • Support for multiple REST services. Configure application.yml inside the WAR package
  • Support for JWT tokens. Get user token from URL /delegate/rest/me

Quickstart

You must have JavaScript application running somewhere for Liferay to find it. Optionally you may have REST service running as well.

  1. Install portlet. Drop the portlet into Liferay deploy directory.
    • There are application.yml inside the portlet to set REST API addresses by URL patterns
  2. Drag and drop portlet into some page as an administrator. Portlet can be found under JavaScript -> JavaScript Portlet.
  3. Configure portlet. Set the URL where we can fetch index.html (See screen shots below).

Configuring REST services

Find application.yml inside WAR package. There's already configured a single REST API to be used with an example project. It looks like following:

rest:
  - pattern: /rest/api/todo/**
    location: http://localhost:8081

Externalizing REST configuration

You may want to put REST configuration away from web application directory. For this purpose there's a mechanism for that: set system property jsportlet.rest.resource on Spring resource format (default value is classpath:application.yml).

Examples:

  • In Tomcat environment you can modify CATALINA_OPTS-variable in setenv.sh or setenv.bat. Add -Djsportlet.rest.resource=<resource>
  • Resource syntax examples can be found from Spring Framework documentation

Note! Access URL is /delegate/rest/api/ but while requesting proxy through Liferay's Delegate Servlet, /delegate gets stripped off.

Note! Background service sees only /api/todo part of the request.

Configuring portlet

Not configured Portlet Portlet added but not configured.

Portlet configuration Configure Portlet as Administrator.

UI Root configured Write page URL on the input field where we can find index.html.

There are also checkbox to enable/disable so called CDN mode. If you are publishing JavaScript application into a server that can be seen and accessed by your users, you may want to enable this. Basically what it does, is to write resource links (images, JavaScripts and CSS files) to external CDN server instead of proxying them through js-portlet.

On bottom of the configuration page, there is a checkbox for enabling/disabling developer mode. Basically this means that application does not go to cache.

Refreshed Portlet will show up after page is refreshed.

Running example project

There is an example project in example directory. Example project contains two modules: angular-client and rest-service. Naming should be self-explaining :)

Running angular-client

Go to example/angular-client and run npm install && gulp serve:dist. This will install dependencies and run client on port 3000. Angular client runs on NodeJS and BrowserSync.

Running rest-service

Go to example/rest-service and run mvn spring-boot:run. This will run REST API on port 8081.

And install Portlet to your Liferay instance

...Just like above.

TODO

  • Cache fetching for static resources DONE
  • Configurable JWT secret key DONE
  • Way better error communication
  • An actual architecture picture
  • Support for externalized REST configuration
  • CDN support to improve performance. Portlet rewrite paths to external source.

Application development

The main idea is to create portlet that only has to be configured to use with any JavaScript application and REST API.

Fetching index page

First of all portlet has to fetch the index page. Modern JavaScript frameworks come with some kind of container to run, for example NodeJS. The portlet fetches and processes the index page as Thymeleaf template. This way it can be developed as standalone application as well.

Variables that will be processed for index:

Variable Description
ajaxURL Relative URL to REST API proxy. Usually /rest/api
standalone Is application standalone? Will be set to false
authenticatedUser Assigns authenticated user email. For example [email protected]
portletId Assigns full portlet ID and instance ID. Example: p_p_id_jsportlet_WAR_jsportlet_INSTANCE_MVFuHik6CyK0_
portletAppContextPath This variable can be used as prefix to images and any other resources.
Example variables
<script type="text/javascript">
var ajaxURL = /*[[${ajaxURL}]]*/ "http://localhost:8081/";
var isStandalone = /*[[${standalone}]]*/ true;
var authenticatedUser = /*[[${authenticatedUser}]]*/ "anonymous";
var portletId = /*[[${portletId}]]*/ 'pocAngularClient';
var portletAppContextPath = /*[[${portletAppContextPath}]]*/ '';
// Do here whatever you need to use them.
</script>

Using different JavaScript libraries

AngularJS 1
  • Use hash paths:
angular.module('yourModule').config(function($locationProvider) {
    $locationProvider.setHtml5Mode(false);
});
  • angular.bootstrap manually into an element
angular.bootstrap(document.getElementById(rootElementId), ['mymodule']);

Note! Don't use ng-app.

  • Use REST URL as constant
var ajaxURL = /*[[${ajaxURL}]]*/ "http://localhost:8081/";
app.constant('ajaxUrl', ajaxURL);

app.service('MyService', function(ajaxUrl, $http, $q) {
    return {
          list: function() {
            var deferred = $q.defer();
            $http.get(ajaxUrl + "api/todo").then(function(todos) {
              deferred.resolve(todos.data);
            });
            return deferred.promise;
          }
    }
});
ReactJS
  • Use hash URLs

ReactJS Router

The trick is done by using hashHistory instead of browserHistory:

import { Router, Route, hashHistory } from 'react-router';

render((
    <Router history={hashHistory}>
        <Route path="/" component="App" />
        // ... Other routes
    </Router>
), document.getElementById('reactRootElement'));

Tips and tricks

Use dynamic root element

To use multiple portlets on the same page, you might need to dynamically name your root element. Portlet ID that is provided when calling through Portlet will help you. Example:

<div id="myrootelement" th:id="${portletId}></div> 
Use stateless REST services.

It's recommended to use provided JWT tokens to transport user information to REST service. Portlet provides token generation REST endpoint at /delegate/rest/me. To configure JWT secret key, edit file application.properties inside the portlet application directory <LIFERAY_HOME>/tomcat-<VERSION>/webapps/js-portlet/WEB-INF/classes.

Resource paths

All resources from index.html are mapped as /js-portlet/p/<portlet_instance_id>/path. You can use variables set to an index page as stated above.

REST Proxy

Portlet comes with the REST API proxy. REST API's URLs are /delegate/rest/api/<mapping>. This delegate Servlet uses classpath resource application.yml to find out where to forward the request.

Fetching JWT token

When you are logged in to Liferay, you can use /delegate/rest/me to fetch one. The request must go through Liferay Delegate Servlet (very undocumented feature) to gain access to user that's currently logged in. That's why there must be /delegate -prefix on the request.

liferay-javascript-portlet's People

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.