This week, AppFormer.js initiative PRs were merged into KIE master branches. It means that now it's possible to write React componentes and use them inside Business Central! 🎉
In this post, I'll show how we achieved this and what needs to be done to create your own AppFormer.js components using React and integrate them in Business Central.
- The programming model
- Setting up your environment
- Creating a Maven module for your NPM package
- Creating your AppFormer.js component
- Integrating into Business Central
- Running and live-reloading your changes during development
AppFomer.js was created with the goal of being a next generation of the AppFormer programming model. By implenting a well-defined contract, components can be reused by different platforms and abstract their underlying technologies.
If you're familiar with UberFire, you know that Perspectives, Screens, Editors (and others) are what make this programming model consistent. With AppFormer.js, it's no different. We chose Perspectives and Screens as the first two contracts to be defined, but it can be extended to cover more of it, like Editors, for instance.
In this first moment, we built these contracts having React and GWT components in mind so we could end up with an abstraction that covered both bases. We're also going to use TypeScript in order to keep our types explicit and have a good understanding of the programming model.
So what does an AppFormer.js component look like? It's pretty straightforward. Imagine you have a React component like this.
https://gist.github.com/af0f3c7547c756208b2cae1b6af258bc
Turning it into an AppFormer.Screen
or AppFormer.Perspective
is simple:
https://gist.github.com/2b947071f96bc70c694b84e5ea2dd033
https://gist.github.com/9f91a3b9e480ca7a6acfb5c7255e2232
A few things are worth noting in these examples:
this.af_isReact = true
is what indicates that a component is a React component.- the
super
constructor call is what defined the uniqueid
of the component. - AppFormer.js has its own lifecycle. I encourage you to explore the
AppFormer.Screen
definition to see which methods are available. - React components that translate into AppFormer.js components must be class components, so you can integrate it with AppFormer.js lifecycle.
- This prop called
self
is what exposes the React component to AppFormer.js. Although that is an antipattern, it's very useful here. Be aware that you should not abuse this construction and always try and keep the single directional data-flow consistent. AppFormer.register[Screen/Perspective]
is what actually creates your components. Remember to call it!
If you already have the kiegroup repositories set up, you can skip this section.
First, make sure you have these:
Java 8
Maven 3.5.4
Node v11.6.0
Yarn v1.12.3
Now clone this repo https://github.com//tiagobento/kiegroup-all
and follow the instructions on the README.md file. Instead of a normal mvn clean install
, use this command:
mvn clean install -Denforcer.skip -Dgwt.compiler.skip -DskipTests -Dgwt.skipCompilation
It will speed up the compilation a bit.
You should see a BUILD SUCCESS
message.
We're ready to create a new Mavenzied NPM Package integrated with Business Central's build!
We'll be creating a very simple AppFormer.Screen
inside Business Central's Library, just like the new Spaces Screen. But before we start coding, we need to configure our Mavenized NPM package inside Business Central's build. Because Business Central's Library is inside kie-wb-common
, that's where we're going to add our new module.
The first thing we need is an NPM package where our TypeScript code will be, I'll provide an starter NPM package configuration with the tools we encourage you to use, but feel free to make your own configuration. We're gonna call our NPM package kie-wb-common-library-afjs-first-screen
.
Two things are very important, though:
- You must use the same
react
andreact-dom
versions that Business Central provides:16.6.0
React
andReactDOM
themselves must NOT be inside your final component bundle, so if you're using Webpack, make sure that bothreact
andreact-dom
are marked as external.
One other very important thing is that appformer-js
must be fetched using mvn
, not npm
. How does that work? We create a pom.xml
file that will fetch the org.ubefire:appformer-js:[version]
JAR for us and will extract it inside a directory on the root of our NPM package. Then we will alter our NPM package's package.json
to point to appformer-js as a local NPM package instead of a NPM package coming from the NPM registry. Like this:
https://gist.github.com/1639e99f65dd3ffe233a333ac41b2d42
So you if feel more comfortable downloading a starer Mavenized NPM package, click here.
If you want to configure it by yourself, make sure to call your directory kie-wb-common-library-afjs-first-screen
.
Now, move the kie-wb-common-library-afjs-first-screen
directory to kiegroup-all/kie-wb-common/kie-wb-common-screens/kie-wb-common-library
.
We just have to change kiegroup-all/kie-wb-common/kie-wb-common-screens/kie-wb-common-library/pom.xml
to see our new module, so apply this:
https://gist.github.com/ae493bfd318bb17b289388d6e5e2038d
On kiegroup-all
root, run:
mvn clean install -DskipTests -f kie-wb-common/kie-wb-common-screens/kie-wb-common-library/pom.xml
.
You should see a BUILD SUCCESS
message.
We already have our NPM package configured and integrated as a Maven module inside kiegroup/kie-wb-common
build. Now it's time for us to create our AppFormer.js component inside it!
On your favorite editor, open kie-wb-common-library-afjs-first-screen/src/index.tsx
. For the sake of simplicity, we're going to create our AppFormer.Screen
and our sub-components on the same file. You can download the file here.
The first thing we have to do is create a class extending AppFormer.Screen
an make sure to register it. Like so:
https://gist.github.com/627c420f8adf0e63f4a53f2512ae185c
Now, we can get creative and create a React component to go along with our screen. If you're familiar with React tutorials, you know that we're creating a Counter component 🙂
https://gist.github.com/8ae180107d76a087e6e600a9ebd22677
More than just a Counter, this is a CounterCard, as it contains CSS that will match Business Central's look & feel. At last, we can use the CounterCard
component we just created inside our AppFormer.Screen
. So apply these changes to AfjsFirstScreen
https://gist.github.com/0cd8233b54e64d630adbe1d388ba67da
Like the CounterCard
component we just created, these changes also contain CSS to match Business Central's look & feel.
On kiegroup-all
root, run:
mvn clean install -DskipTests -f kie-wb-common/kie-wb-common-screens/kie-wb-common-library/kie-wb-common-library-afjs-first-screen/pom.xml
.
You should see a BUILD SUCCESS
message.
Your first AppFormer.js component is ready to be used in Business Central! Let's do this with some very simple configurations.
For the sake of this tutorial, we're not going to use the full sized Business Central version. Instead, we're going to work with Drools Workbench, which is an application that has some of the features Business Central and is optimized for development. Don't worry! The process of adding an AppFormer.js component on Business Central is exactly the same.
Note that because Business Central and Drools Workbench both already have AppFormer.js components integrated, there's already a line of code to "activate" the AppFormer.js capabilities. It's usually located on an @EntryPoint
class for AppFormer.js to be available at the very beginning of the app. You can take a look at the @PostConstruct
-annotated method on org/drools/workbench/client/DroolsWorkbenchEntryPoint.java
if you want. The argument to AppFormerJsBridge#init
should be the exact same name of the GWT module being compiled because we'll use that to assemble the URL to lazyly load the AppFormer.js components.
The repository where we're going to work now is drools-wb
, and the module is drools-wb-webapp
. Open it on your favorite editor or IDE and apply the changes below.
On kiegroup-all/drools-wb/drools-wb-webapp/pom.xml
, add this execution configuration on the maven-dependency-plugin
executions tag:
https://gist.github.com/c88fafa0a098a7d2bc90e46e81f69a67
On the same file, add this execution configuration on the maven-resources-plugin
executions tag.
https://gist.github.com/91714f3daf245dbe4fffbc3cb8a54356
These togheter will unpack kie-wb-common-library-afjs-first-screen
JAR, which contains our component's bunlded JavaScript and copy this bundle to the application's output directory. It's conventioned that every AppFormer.js component bundle must be under /org/uberfire/jsbridge/public
, or it won't work.
Last configuration we have to do before changing the application to have some way to access our new screen is to pur our component's information on AppFormer.js registry. All AppFormer.js components are lazily loaded, so we have to register it so AppFormer.js knows when and what to fetch.
On kiegroup-all/drools-wb/drools-wb-webapp/src/main/resources/org/uberfire/jsbridge/public/AppFormerComponentsRegistry.js
, add this entry:
https://gist.github.com/a7b7989b5f290f060de1d66a40646465
We're almost there. To make our screen accessible, we're going to add an item to the Menu of the application. Go to org.drools.workbench.client.DroolsWorkbenchEntryPoint
and add these lines on the setupMenu
method.
https://gist.github.com/adf4093de19505160fb146b3079e06c9
Now let's bring the application up so we can (finally! 🎉) see our new screen.
On kiegroup-all
root, run:
mvn clean gwt:run -f drools-wb/drools-wb-webapp
Wait for the "errai bus started." message on your console and go to "http://localhost:8888". Log in with admin/admin
and wait for the compilation to finish. When the application starts, go to Menu > AppFormer.js First Screen
. Voilà! There it is. Click around so you can see that our component actually works.
That's what you should see:
Your AppFormer.js component is up and running inside Business Central! Now let's see how to speed up the development workflow.
This only works on macOS and Linux at the moment.
If we want to change something on our recently created AppFormer.js component without bringing Business Central (or Drools Workbench in this case) down, everything we have to do it to change the bunlded JavaScript file inside the running application. To do that, we can simply execute a "copy" command. With a bit of bash scripting knowledge, we can achieve this:
Go to kiegroup-all/kie-wb-common/kie-wb-common-screens/kie-wb-common-library/kie-wb-common-library-afjs-first-screen
and run:
npx watch 'yarn run live-reload-on ~/redhat/kiegroup-all/drools-wb/drools-wb-webapp' ./src
This will run the watch
command inside /node_modules/.bin
and execute the command yarn run live-reload-on ~/redhat/kiegroup-all/drools-wb/drools-wb-webapp
everytime something on ./src
changes. The argument yo yarn run live-reload-on
is the location of your running application. In my case it was ~/redhat/kiegroup-all/drools-wb/drools-wb-webapp
. Pretty handy!
If you're curious you can see how it's done on kie-wb-common-library-afjs-first-screen/package.json
.
To see that it works, change something on kie-wb-common-library-afjs-first-screen/src/index.tsx
, wait for the build to finish, go to your browser and refresh the page. After navigating to AppFormer.js First Screen, you should see your changes there.
Now you can easily change and see the changes you made inside Business Central!