Getting started with ReactJS and eXo Platform portlet development

Getting started with #ReactJS and @exoplatform #portlet development

  • The React lifecycle will initiate the state, mount the component to the DOM, fetch data from the API, and render it.
  • We could replace the Activity class with the react stateless function pattern to get rid of the useless lifecycle.
  • Because Exo uses AMD modules, it will automatically adapt them.
  • The modules will be automatically loaded by eXo Platform when you load the portlet.
  • Discover eXo Platform 4 in a production environment

In this article, you’ll learn how to set up a simple ReactJS and node.js development stack, build a standalone app, and package it all to a portlet.

@eXoPlatform: Getting started with #ReactJS and @exoplatform #portlet development

Tech Lead on a collaborative portal at a French Ministry, and web development passionate

Here is the first post of what I hope will be many posts dedicated to web development!

In this article, I would like to share some information about the eXo Platform portal and ReactJS. You’ll learn how to set up a simple ReactJS and node.js development stack, build a standalone app, and package it all to a portlet.

How did we get to React? eXo Platform comes with a portlet framework called Juzu that lets developers build interactive client-side UIs. While many developers in my organization have mastered several frameworks, they were not very comfortable with Juzu. At that time, my office was heavily promoting ReactJS. In addition, the eXo Platform portlet does not require any specific technology to build portlets, and you can even use your own! If you don’t know anything about ReactJS, take a look at the site first.

To efficiently manage JS library dependencies, we will use node.js and npm. We’ll then use Maven to build and package the portlet.

Though JavaScript is cool for simple projects, it’s not Java. It’s more painful to build robust JavaScript mainly because it lacks a static, strong system. Fortunately, some standards have emerged from the mess over the last few years! You can now use languages like CoffeeScript, TypeScript, and ES2015, which also come with syntax improvements. However, these languages will not execute in the browser, except for ES2015 which is the next version of javascript but still only partially supported. ReactJS also comes with a syntax called JSX, which mixes JS and HTML tags, so we’ll have to transpile it as well. Babel will be good for that task, and we’ll use this time with ES2015.

It’s time to open your IDE. If you do not have one, try Atom. It is lightweight and open source, and it works well with JS. Don’t forget to install the JSX plugin!

The source code is available here. Please follow the instructions for building and deploying in the portlet section.

As I said before, the stack is based on node.js. First, install it on your system. It will come with npm, which you can use to install the JS dependencies (this works like Maven).

Create a directory named “react-portlet” and generate an initial package.json file:

npm init

Let the default values for this time be:

Next, install the React and Moment libraries to deal with the date format later:

Note: React has a core part and a specific lib to render to DOM.

Install the Babel transpilers as a dev dependency:

We will need the webpack library to gather all the JS modules into a bundle file and do some “hot rebuilding.” We’ll also install the express HTTP server to quickly test our app in standalone mode.

At this point, package.json has been updated (with the –save argument), and the node dependencies have been installed in the “node_modules” directory. package.json must be added to version control so anyone can build your project.

The project structure has to be Maven-compliant (keep in mind that we have to build a portlet!):

Now we can create the first React component, “Activities,” to fetch the user’s activities from the server and transform them into HTML. To use the modularity of React, we will also create a child component to render a single activity. First, create the “Activities.jsx” file in /src/main/js:

The “Activity.jsx” file in /src/main/js will be:

We are using the ES6/ES2015 syntax with class inheritance. In short, the React lifecycle will initiate the state, mount the component to the DOM, fetch data from the API, and render it. There’s a method for each lifecycle step. For example, using fetch for componentDidMount is the safest way due to the asynchronous updates.

Whenever the state is modified, the render method is called, and it checks which part of the DOM has to be updated. In this example, we won’t take any actions, so the state will not be modified. A good React pattern to use whenever possible is to manage the state at the highest-level component (which is Activities here) and pass the data to the child components (which is Activity here) via the “props.” Thus, we could replace the Activity class with the react stateless function pattern to get rid of the useless lifecycle.

Did you notice the weird attribute “dangerouslySetInnerHTML”? React is XSS-proof, but sometimes you have to inject preformed HTML code. You should do this it the HTML has been sanitized on the server side.

Now we create index.html in /src/static and declare the React mount tag as a simple div:

Note: We include the “bundle.js” script that will be generated with webpack.

To generate the bundle, we create a “/src/main/js/index.js” file that will import the root component of our app (which is Activities here):

import Activities from ‘./Activities.jsx’;

Note: Webpack will use this file as an entry point to pack all the imports.

Then create “/webpack.config.js”:

Here we use the “index.js” file that we just created. Then we define the output folder for bundle.js. This folder corresponds to the Maven target directory (it will be useful later). Then we define the Babel loader, which takes over transpilation. The define plugin just transmits the NODE_ENV variable to the loader parser to prune the dev code in the React lib at build time.

Before we run the app, our static files need to be copied to the target directory as well. This can be done with scripts in “/package.json”:

“scripts”: { “copy”: “cp -R src/static/* target/static & cp -R src/main/webapp/css target/static” }

Note: In a real project, you should consider using a library like Gulp to externalize complex build tasks and become OS independent!

Call the script:

npm run copy

Next, we create the express HTTP server in the /server.js file.

The express server will manage our standalone mode and serve static files (CSS, JS, HTML) and proxy API requests to static files.

Note: You have to record real API responses in static files before (look at the source code for an example).

Before starting the server, we also want to start webpack in “watch mode” to be able to build again on any change. Add a “watch” script with the following commands in /package.json:

Now just type:

npm run watch

You should see something like this:

Look at the size. Don’t worry though because it is not optimized yet!

The map file will map source lines from the generated bundle code to the original ES2015 file. It will be downloaded by the browser only when you open the debugger. Note: Static files are not watched; you have to restart the server. We could improve that by writing a simple Gulp script and adding it to the start script.

Now start the server:

npm start

and enjoy the results at http://localhost:3000. It should look like this:

When you’re ready for release, you can add the following script in /package.json:

“scripts”: { … “release”: “export NODE_ENV=production && webpack -p” }

We set NODE_ENV equal to production to disable the React dev mode (it helps a lot since it’s a lot slower) and started webpack with the optimizers.

After optimization, the bundle will be three times smaller:

Note: Did you notice a few warnings from the optimizer? They occur because the library is not always cleaned.

Important: The optimized bundle should not be too big (< 1 Mo), so for large apps, you can look at webpack’s code-splitting feature. Note: You can still debug the original files in production since the map file is also updated. Now you’re done with this part! You could use this app outside eXo Platform, but you’ll have to adapt the proxy routes in server.js to the eXo backend (which is easy!) and deal with SSO authentication (which is actually the hard part!). To get started, you can pick some resources from the sample available at https://github.com/exo-samples/docs-samples/tree/4.3.x/portlet/js. It’s a simple javax.portlet that forwards to an index.jsp (the view part of the portlet). Modify index.jsp and only declare an HTML fragment with the “app” mount point: Open webapp/WEB-INF/gatein-resources.xml to declare both the bunderle.js, as a JS module, and the main.css stylesheet: Note: These modules will be automatically loaded by eXo Platform when you load the portlet. There are two main module styles in JavaScript: AMD and CommonJS. When transpiling ES2015 to ES5, Babel replaces imports with the CommonJS style. Because Exo uses AMD modules, it will automatically adapt them. However, some libraries require manual adaptation. This would be the case with React if we had to load it separately from bundle.js. Now we get to the the build part. When we build the portlet, it would be interesting to 1) install JS dependencies and 2) do a webpack release. The Maven exec plugin will do the job. In “/pom.xml”: Then simply type: This will build in dev mode (webpack.release=release-debug) Just add a profile to build in production mode (set webpack.release=release), so: You’ll quickly notice that the non-minified version of React can’t deal with the GateIn minifier (uses the Google Closure minifier)! Actually, the only way to disable the GateIn minifier is to run eXo in dev mode, which is not great. But there’s weird thing: When you minify your bundle with “webpack -p,” the GateIn minifier works! So the simplest solution is to use the minified version of our bundle.js with eXo’s normal mode and use the non-minified version in eXo’s dev mode! There is some bad news though: You will lose the source mapping because of the double minification. Another solution is to disable the minifier on some libs and build and supply the minified and map files. Actually, you can override the UIPortalApplication.gtmpl script in the portal module, filter the JS paths, and remove the “-min” when you need to but it’s tricky. It would be great if eXo and GateIn could come up with a parameter for module definition! I’ve heard about webjars, and they’re probably a more elegant way to do all this. I’ll have to look at them in the future. Those who are used to eXo can skip this part. You must have an exo account and JDK 8 installed. Then download the latest community edition of eXo (4.3+), unzip it, and launch the start_eXo script. Simply copy the target/react-portlet.war in the webapps directory and wait for deployment. Log into eXo and create a “test” site. Go to the site, edit the page layout, and add the portlet. You should see something very similar to standalone mode, but it should be dynamic (for this, you must have created some activities before). Sorry—it doesn’t work in an eXo container unless you start it in debug mode. I’ll have to look into this. When you’re developing several portlets, it’s okay to reuse some libs (like React). You may already know that GateIn allows you to share modules. Before we edit webpack.config.js, we have to tell webpack to gather the React, ReactDOM, and moment libs in another bundle, which we’ll call the “vendor” bundle: Note: Take a look at chunking. It’s a powerful way to optimize web apps when they first load! After rebuilding, you’ll see the new size of your bundle! Set vendor-bundle.js as a shared module. To keep things simple, we set it in our portlet. Otherwise, you could package it into another war: Now when you look at the reactsample.js resource downloaded by the portlet, it will depend on the shared module: We learned how to set up a standalone JS app based on React and built with a node.js/npm/ES2015/Babel/webpack stack. There’s a lot of choices here, and you could replace some of elements of the stack, e.g., bower instead of npm, typescript instead of ES2015, browserify instead of webpack. Each has some pros and cons that you should be aware of when you are choosing. We learned how to simply integrate npm and Maven to build a portlet on top of a standalone app. Unfortunately, the eXo GateIn minifier hates your React code. Even if there’s a workaround, GateIn should really permit lib exclusions from the minifier. Last words: On a real project, you’ll have to deal with unit testing. For the record, we’re currently using Mocha to write tests, Phantomjs as a runtime platform, and Istanbul as a coverage tool. To manage complex build tasks, you should use a lib like Gulp or Grunt. comments

Getting started with ReactJS and eXo Platform portlet development