I'm just starting to get into working with ReactJS, Facebook's open source rendering framework. My project uses SpringBoot for annotation-driven dependency injection and MVC. I thought it would be great if I could use a bit of ReactJS to enhance the application.
If you're looking for a basic conceptual intro, I recommend ReactJS for Stupid People and of course the official documentation is quite good. In full disclosure, I still have no idea how to do "flux" yet. As an experienced Java backend developer, I'm pretty decent at hacking Maven builds - which is precisely what this blog post is going to be about.
First, a word about how React likes to be built. Like many front-end tools, there is a toolkit for the node package manager (NPM). From the command prompt, one might run npm install -g react-tools which installs the jsx command. The jsx command provides the ability to transform JSX syntax into ordinary JavaScript, which is precisely what I want. Of course, running NPM at all implies that it has been installed and configured on the system.
Here are my goals for the build process:
Thanks to Google, I found a Maven plugin already available to do much of this. The frontend plugin makes short work of installing NPM. Here's the plugin setup:
Few things to note about this. First, the JSX compilation is in a different phase of the build from the NPM installation. The generate-sources phase is after the initialize phase, so we're guaranteed that all the NPM and JSX goodness is ready to use in the "target" directory tree.
The arguments are specified as an array. This may seem strange at first to developers who have not used the Java Runtime and ProcessBuilder classes, but under the hood the JVM thinks of shell commands as tokenized arrays. This means that we do not have to use quotes around each logical grouping, even if they contain whitespace (which here they don't).
The extension parameter setting of "jsx" means that only files ending in ".jsx" are going to be compiled. This produces ".js" files in the same location in the compiled code. Because we write them to the target directory, those files won't be included in version control or lie around where developers might get confused by having JS and JSX files together.
If you're looking for a basic conceptual intro, I recommend ReactJS for Stupid People and of course the official documentation is quite good. In full disclosure, I still have no idea how to do "flux" yet. As an experienced Java backend developer, I'm pretty decent at hacking Maven builds - which is precisely what this blog post is going to be about.
First, a word about how React likes to be built. Like many front-end tools, there is a toolkit for the node package manager (NPM). From the command prompt, one might run npm install -g react-tools which installs the jsx command. The jsx command provides the ability to transform JSX syntax into ordinary JavaScript, which is precisely what I want. Of course, running NPM at all implies that it has been installed and configured on the system.
Here are my goals for the build process:
- I want to precompile JSX. The templating capabilities of JSX are nifty, but since I have to build the backend code anyway, we might as well provide clean "regular JS" to the browser.
- I don't want to use a global installation of NPM. My build will eventually need to run on a continuous integration server (Jenkins) and I want to be a good neighbor to any other projects that might also use NPM with ReactJS.
- I want to play nice with Maven and avoid writing any shell scripts. Yuck!
Installing NPM
The first thing we need to do is to have the build install a copy of NPM that we can use for installing react tools. We want NPM binaries to be contained within the software project and, ideally, to be someplace where we won't trip over it and it won't get committed to version control by accident. Installing NPM as a subdirectory of "target" during the project initialization phase would be ideal.Thanks to Google, I found a Maven plugin already available to do much of this. The frontend plugin makes short work of installing NPM. Here's the plugin setup:
<plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>0.0.24</version> <configuration> <workingDirectory>${pom.basedir}/target/node</workingDirectory> <installDirectory>${pom.basedir}/target/node</installDirectory> </configuration> <executions> <execution> <id>frontend-step1-install-npm</id> <goals> <goal>install-node-and-npm</goal> </goals> <phase>initialize</phase> <configuration> <nodeVersion>v0.12.7</nodeVersion> <npmVersion>2.11.3</npmVersion> </configuration> </execution>The only gotcha is that the default location of the node stuff is in a "node" directory in the project base directory. I used the install directory argument to configure the build to put node binaries into "target/node" instead. Obviously this is a personal preference you can ignore in your projects....</executions> </plugin>
Installing JSX
The next thing the build needs to accomplish is installing react tools, and of course we want to use the NPM we just installed to do that. We'll add this as a second execution of the frontend plugin:
<execution>
<id>frontend-step2-install-jsx</id>
<goals>
<goal>npm</goal>
</goals>
<phase>initialize</phase>
<configuration>
<arguments>install -g react-tools</arguments>
</configuration>
</execution>
Recall we've already configured the installation directory path as "target/node", and this execution will install the jsx binary as "target/node/bin/jsx". We use this jsx binary in the next section to compile our JSX files down to plain JavaScript.
Compile JSX
With the jsx binary installed, the build should now be able to generate the JavaScript files. Here's where the frontend plugin isn't useful - we need to reach into our Maven toolkit and find another plugin. Fortunately, Maven has an execution plugin that can invoke shell commands.<plugin> <artifactId>exec-maven-plugin</artifactId> <groupId>org.codehaus.mojo</groupId> <executions> <execution> <id>frontend-step3-run-jsx</id> <phase>generate-sources</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>${basedir}/target/node/bin/jsx</executable><environmentVariables> <PATH>${env.PATH}:${pom.basedir}/target/node/node</PATH> </environmentVariables><arguments> <argument>--extension</argument> <argument>jsx</argument> <argument>${basedir}/src/main/resources/static/js</argument> <argument>${basedir}/target/classes/static/js</argument> </arguments> </configuration> </execution> </executions> </plugin>
Few things to note about this. First, the JSX compilation is in a different phase of the build from the NPM installation. The generate-sources phase is after the initialize phase, so we're guaranteed that all the NPM and JSX goodness is ready to use in the "target" directory tree.
The arguments are specified as an array. This may seem strange at first to developers who have not used the Java Runtime and ProcessBuilder classes, but under the hood the JVM thinks of shell commands as tokenized arrays. This means that we do not have to use quotes around each logical grouping, even if they contain whitespace (which here they don't).
The extension parameter setting of "jsx" means that only files ending in ".jsx" are going to be compiled. This produces ".js" files in the same location in the compiled code. Because we write them to the target directory, those files won't be included in version control or lie around where developers might get confused by having JS and JSX files together.
Summary
Using plugins, we were able to set up JSX compilation and meet our other goals. NPM is installed only in the "target" directory and therefore won't interfere with any other projects. Best of all, there was no shell scripting and only one execution of the jsx executable via the Maven execution plugin.
Here's the whole thing put together:
<plugins> <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>0.0.24</version> <configuration> <workingDirectory>${pom.basedir}/target/node</workingDirectory> </configuration> <executions> <execution> <id>frontend-step1-install-npm</id> <goals> <goal>install-node-and-npm</goal> </goals> <phase>initialize</phase> <configuration> <nodeVersion>v0.12.7</nodeVersion> <npmVersion>2.11.3</npmVersion> <installDirectory>${pom.basedir}/target/node</installDirectory> </configuration> </execution> <execution> <id>frontend-step2-install-jsx</id> <goals> <goal>npm</goal> </goals> <phase>initialize</phase> <configuration> <arguments>install -g react-tools</arguments> <installDirectory>${pom.basedir}/target/node</installDirectory> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>exec-maven-plugin</artifactId> <groupId>org.codehaus.mojo</groupId> <executions> <execution> <id>frontend-step3-run-jsx</id> <phase>generate-sources</phase> <goals> <goal>exec</goal> </goals><environmentVariables> <PATH>${env.PATH}:${pom.basedir}/target/node/node</PATH> </environmentVariables><configuration> <executable>${basedir}/target/node/bin/jsx</executable> <arguments> <argument>--extension</argument> <argument>jsx</argument> <argument>${basedir}/src/main/resources/static/js</argument> <argument>${basedir}/target/classes/static/js</argument> </arguments> </configuration> </execution> </executions> </plugin>
...
</plugins>
This is the kind of post I have been dreaming to find! Great work and thanks for sharing! I will try to get babel, web pack, etc install this way as well.
ReplyDeleteLooks a bit of yucky but it's a good try. I was thinking rather than tear your brains out trying to get ReactJS/Angular2 or any gulp, webpack based toolkit working with Maven. I found it was a bit saner to just keep it as a separate build process.
ReplyDeleteIn the end you're building something that should be decoupled anyway so why not?
Another approach that you can incorporate to your Maven build system is to have a webjar building project and then include that jar as a dependency.
Thanks for your comment. I prefer using vanilla build commands because they make packaging the project more intuitive to run. Running "mvn clean install" builds, tests, and packages the entire project. We run a continuous integration process -- using standard build commands means the configuration on Jenkins is very easy for our ops team.
DeleteI have tried with the attached plugin details in eclipse the URL showing an empty page can you please help me out to on this?
ReplyDeleteThanks for sharing this coding.
ReplyDeleteReact JS course
Awesome work and excellent blog for the people who really need the information about this
ReplyDeletetechnology. Keep posting the updates.
JAVA Training in Chennai
Selenium Training in Chennai
Java Training
Java classes in chennai
Best Selenium Training Institute in Chennai
selenium Classes in chennai
Java Training in Adyar
selenium training in velachery
Great blog, I was searching this for a while. Do post more like this.
ReplyDeleteDevOps certification in Chennai
DevOps Training in Chennai
AWS Training in Chennai
AWS course in Chennai
Data Science Course in Chennai
Data Science Training in Chennai
DevOps Training in Velachery
DevOps Training in Tambaram
It was really an interesting blog, Thank you for providing unknown facts.
ReplyDeleteAviation Academy in Chennai
Air hostess training in Chennai
Airport management courses in Chennai
Ground staff training in Chennai
Aviation Courses in Chennai
Air Hostess Training Institute in Chennai
airport courses in Chennai
airport ground staff training courses in Chennai
Well done, every one can have to look at your blog to be good.
ReplyDeletejava training in coimbatore
java classes in coimbatore
java training in bangalore
Java Course in Bangalore
java training in madurai
java course in madurai
Enjoyed your approach to explaining how it works, hope to see more blog posts from you. thank you!
ReplyDeleteeiffeltowerfacts
Article submission sites
Innovative blog...! This is the best explanation about this topic and Really like your post. Kindly updating more post...
ReplyDeleteExcel Training in Chennai
Excel Advanced course
Pega Training in Chennai
corporate training in chennai
Tableau Training in Chennai
Unix Training in Chennai
Oracle Training in Chennai
Spark Training in Chennai
Embedded System Course Chennai
Linux Training in Chennai
This blog is really awesome. I learned lots of informations in your blog. Keep posting like this...
ReplyDeleteTally Course in Chennai
Tally training in coimbatore
Tally course in madurai
Tally Course in Hyderabad
Tally Training in Bangalore
Tally classes in coimbatore
Best tally training institute in bangalore
Tally Course in Bangalore
IELTS Coaching in Bangalore
German Classes in Bangalore
Thanks for sharing the valuable information. This blog contains various good concepts and ideas.
ReplyDeleteDevOps Training in Chennai
DevOps Training in Bangalore
Best DevOps Training in Bangalore
DevOps Course in Bangalore
DevOps Training Bangalore
DevOps Training Institutes in Bangalore
AWS Training in Bangalore
Data Science Courses in Bangalore
DevOps Course in Marathahalli
DevOps Training in btm
Amazing Post. keep update more information.
ReplyDeleteGerman Classes in Chennai
German Classes in Bangalore
German Classes in Coimbatore
German Classes in Madurai
German Language Course in Hyderabad
German Language Course in Bangalore
German Courses in Bangalore
German classes in marathahalli
Tally Course in Bangalore
Ielts coaching in bangalore
Actually I read it yesterday but I had some thoughts about it and today I wanted to read it again because it is very well written. keep update lot
ReplyDeleteAi & Artificial Intelligence Course in Chennai
PHP Training in Chennai
Ethical Hacking Course in Chennai Blue Prism Training in Chennai
UiPath Training in Chennai
my school essay in marathi grat post you can read also marathi school essay
ReplyDelete