Web Development

Deploy Angular 2 Maven WebApp on Tomcat

We can run angular app on tomcat by putting the angular 2 app content ( contents inside target directory when you build, default is ‘dist’ for angular 2 ) directly inside /src/main/webapp directory.

For Maven projects we will do all the things automatically (build, copy etc).

So here is my project structure for maven project.

.
├── angular
│   ├── angular-cli-build.js
│   ├── angular-cli.json
│   ├── config
│   ├── dist
│   │   ├── app
│   │   ├── bundle.js
│   │   ├── favicon.ico
│   │   ├── index.html
│   │   ├── main.js
│   │   ├── system-config.js
│   │   └── vendor
│   ├── e2e
│   ├── package.json
│   ├── public
│   ├── README.md
│   ├── src
│   ├── tmp
│   ├── tslint.json
│   ├── typings
│   └── typings.json
├── cat.txt
├── pom.xml
├── src
│   └── main
│       ├── java
│       ├── resources
│       └── webapp
│           └── WEB-INF
│               └── web.xml
├── target
└── temp

And when I run command mvn clean install, what I want in .war file is

.
├── app
├── cat.txt
├── favicon.ico
├── index.html
├── main.js
├── META-INF
├── system-config.js
├── vendor
└── WEB-INF
    ├── lib
    └── web.xml

So as you can see in the war file I have put all the contents of /angular/dist/ in root of war file.

What we did is

  1. Installed nodejs and npm
  2. Ran the command “npm install” in /angular/ to install dependencies and compile typescript files.
  3. Ran the command “npm run build” in /angular/
  4. Finally copied the contents of /angular/dist/ in root of .war file.

We will not do all these things by ourselves but will the help of two maven plugins. One is frontend-maven-plugin which will install nodejs and build the angular project. Another plugin is maven-resources-plugin which will copy the contents of ‘dist’ directory.

I am writing the code first that you have to add in pom.xml. I will explain after that.

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
    </plugin>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <version>2.6</version>
    </plugin>

    <!-- Plugin to execute command  "npm install" and "npm run build" inside /angular directory -->
    <plugin>
      <groupId>com.github.eirslett</groupId>
      <artifactId>frontend-maven-plugin</artifactId>
      <version>1.0</version>
      <configuration>
        <workingDirectory>angular</workingDirectory>
        <installDirectory>temp</installDirectory>
      </configuration>
      <executions>
        <!-- It will install nodejs and npm -->
        <execution>
          <id>install node and npm</id>
          <goals>
            <goal>install-node-and-npm</goal>
          </goals>
          <configuration>
            <nodeVersion>v6.3.1</nodeVersion>
            <npmVersion>3.9.5</npmVersion>
          </configuration>
        </execution>

        <!-- It will execute command "npm install" inside "/angular" directory -->
        <execution>
          <id>npm install</id>
          <goals>
            <goal>npm</goal>
          </goals>
          <configuration>
            <arguments>install</arguments>
          </configuration>
        </execution>

        <!-- It will execute command "npm build" inside "/angular" directory to clean and create "/dist" directory-->
        <execution>
          <id>npm build</id>
          <goals>
            <goal>npm</goal>
          </goals>
          <configuration>
            <arguments>run build</arguments>
          </configuration>
        </execution>
      </executions>
    </plugin>

    <!-- Plugin to copy the content of /angular/dist/ directory to output directory (ie/ /target/transactionManager-1.0/) -->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-resources-plugin</artifactId>
      <version>2.4.2</version>
      <executions>
        <execution>
          <id>default-copy-resources</id>
          <phase>process-resources</phase>
          <goals>
            <goal>copy-resources</goal>
          </goals>
          <configuration>
            <overwrite>true</overwrite>
            <outputDirectory>${project.build.directory}/${project.artifactId}-${project.version}/</outputDirectory>
            <resources>
              <resource>
                <directory>${project.basedir}/angular/dist</directory>
              </resource>
            </resources>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

When you compare this code with your pom.xml you will these two new plugins frontend-maven-plugin and maven-resources-plugin. So lets explain the frontend-maven-plugin first.

<configuration>
  <workingDirectory>angular</workingDirectory>
  <installDirectory>temp</installDirectory>
</configuration>

In the above code we are telling frontend-maven-plugin that our angular 2 code is in /angular directory and the directory in which we want it to install nodejs is /temp.

<execution>
  <id>install node and npm</id>
  <goals>
    <goal>install-node-and-npm</goal>
  </goals>
  <configuration>
    <nodeVersion>v6.3.1</nodeVersion>
    <npmVersion>3.9.5</npmVersion>
  </configuration>
</execution>

In the above code we are specifying node and npm version to install it on our system automatically.

<execution>
  <id>npm install</id>
  <goals>
    <goal>npm</goal>
  </goals>
  <configuration>
    <arguments>install</arguments>
  </configuration>
</execution>

It will execute command npm install inside the workingDirectory (ie. /angular/)

<execution>
  <id>npm build</id>
  <goals>
    <goal>npm</goal>
  </goals>
  <configuration>
    <arguments>run build</arguments>
  </configuration>
</execution>

It will execute command npm run build inside the workingDirectory (ie. /angular/)

<execution>
  <id>default-copy-resources</id>
  <phase>process-resources</phase>
  <goals>
    <goal>copy-resources</goal>
  </goals>
  <configuration>
    <overwrite>true</overwrite>
    <outputDirectory>${project.build.directory}/${project.artifactId}-${project.version}/</outputDirectory>
    <resources>
      <resource>
  <directory>${project.basedir}/angular/dist</directory>
      </resource>
    </resources>
  </configuration>
</execution>

It will copy the content of /angular/dist/ directory to output directory (${project.basedir}/angular/dist).

Finally run mvn clean install and your .war is ready.

NOTE :
1. Add index.html in your welcome files list in web.xml.
ie. Paste the below code in web.xml

<welcome-file-list>
  <welcome-file>index.html</welcome-file>
</welcome-file-list>

2. Add "build": "ng build" script in your package.json

{
  "name": "angular",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "start": "ng serve",
    	.
    	.
    	.

    "build": "ng build"
  },
  "dependencies": {
   	.
   	.
   	.
  },
  "devDependencies": {
   	.
   	.
  }
}

You can check my projects
BaceDevotees
TransactionManager

Also don’t forget to read this
https://github.com/ashishdoneriya/LittleBlueBird/wiki
It will describe what’s wrong with urls in Angular.

Another Way

After a long time, I’ve realized maven-frontend plugin sometimes doesn’t work for me. Therefore, in this case, remember the manual way that I told you before
“We can run Angular app on Tomcat by putting the angular 2 app content ( contents inside target directory when you build, the default is ‘dist’ for angular 2 ) directly inside /src/main/webapp directory.”

It means, build your angular project (using ‘ng build’ or ‘ng build –prod’). On successful build, it will generate a directory called ‘dist’ inside your angular project directory. Copy all the contents inside that ‘dist’ directory and paste them directly into ‘src/main/webapp’ directory of your maven/war project. After that compile your maven/war project.

My Personal Opinion : Do not use Angular 2, 4 or whatever for production purpose. If you want a framework that is stable, then don’t use Angular 2,4.

49 thoughts on “Deploy Angular 2 Maven WebApp on Tomcat

  1. Hello,

    I would like to ask how do you run npm run build. Where is your build script? Run ng build is not supported from the plugin.

  2. Thank you Evangelos for pointing out the problem. Yes, ng build is not supported from this plugin but it can call any script and we will call build script and build script will run “ng build” command. For this we have to add one script (line) in package.json -> script
    and that is
    “build”: “ng build”

    Thanks for pointing out the error. I have fixed the problem in my github repository and added build script in package.json
    https://github.com/ashishdoneriya/TransactionManager

  3. Your welcome. Are you planning to update at the angular release version your project? Have you tried to support both angular-cli and gulp in any of your projects?

  4. After success build (mvn clean install). A directory “target” will be created. Inside that directory there will be a .war file. Deploy that .war file in web server (like tomcat).

  5. I am able to successfully build the project and deploy it to my local Tomcat Server.
    However I am unable to load index.html as I have getting 404 Resource not found error for following JS files:

    Failed to load resource: the server responded with a status of 404 (Not Found)
    http://localhost:8080/ember-cli-live-reload.js Failed to load resource: the server responded with a status of 404 (Not Found)

    Failed to load resource: the server responded with a status of 404 (Not Found)
    http://localhost:8080/vendor/es6-shim/es6-shim.js Failed to load resource: the server responded with a status of 404 (Not Found)

    Failed to load resource: the server responded with a status of 404 (Not Found)
    http://localhost:8080/vendor/reflect-metadata/Reflect.js Failed to load resource: the server responded with a status of 404 (Not Found)

    Failed to load resource: the server responded with a status of 404 (Not Found)
    http://localhost:8080/vendor/systemjs/dist/system.src.js Failed to load resource: the server responded with a status of 404 (Not Found)

    Failed to load resource: the server responded with a status of 404 (Not Found)
    http://localhost:8080/vendor/zone.js/dist/zone.js Failed to load resource: the server responded with a status of 404 (Not Found)

    Uncaught ReferenceError: System is not defined(…)

    I checked the WAR file and found that everything is there except ember-cli-live-reload.js file.

    Do you have any idea what wrong in here?

  6. It seems you don’t have the same context path. You should point your angular application to the right context path. Probably you deploy an app as /something but your application tries to find the resources from the root. Try something like
    # Sets base tag href to /myUrl/ in your index.html
    ng build –base-href /myUrl/
    ng build –bh /myUrl/

  7. Sorry, but I think you should run a sample angular app (without maven etc.). Also check if you haven’t change the dist-folder path. Also check your context path as suggested by Ungelis Papathanasiou

  8. The solution for broken routes is that in the index.html file in the base property href agren the paht of your project

  9. This article has the name deploy in it but yet, you don’t have any deploy script within it? I get the build a war file, but how do you then deploy this file?

  10. After I ran maven install, I found everything in target/LPA-1.0.0-SNAP SHOT but not in the war file. Anything I left?

    target
    —LPA
    —LPA-1.0.0-SNAP SHOT
    —maven-archiver
    —LPA.war

  11. Hi Ashish,
    I am using angular-cli for creating angular 2 website. I am exposing rest services in springboot using STS and Maven. Now I want to use rest services in my angular 2 website. But I want to run the application on same localhost port. So can I use the same you mentioned. You have any sample project on it.

  12. Thanks for the interesting article. The exact steps helped in deploying the application.
    I had to change the base URL in index.html from “/” to “.” so that the script files are loaded properly, when the target is localhost:8080/xxx/home

  13. Hi Ponni, this didnt help , can you please post your package.json, or put your project on github.
    did use ngbuild ng build –base-href in package.json?
    Appreciate your response

  14. Hi Jagruti,
    I dint do anything at the package.json . Just updated the index.html. What’s the error you get?
    And it is plain ‘ng build’ that I do. I had some trouble in the of ng build through Maven. So I commented out the ‘npm build’ execution in the pom.xml above, and copied the dist folder generated from a direct ‘ng build’ in my app folder.
    Please let me know if that helps.

  15. I got a forbidden message after I deploy to WildFly Server. I guess it is related to index.html.

    I don’t have any index.html inside src/main/webapp/. But I guess the server should find my index.html in my WAR file. My WAR file has an index.html which is from my angular project built.

    But I have a red cross of my WAR file in WildFly Server of eclipse.

    src/main/webapp/WEB-INF/web.xml:

    Archetype Created Web Application

    index.html

  16. Hi Ashish,

    I am trying to run the code as directed by you,my code always gives

    Failed at the [email protected] build script ‘ng build –prod’.

    Failed to execute goal com.github.eirslett:frontend-maven-plugin:1.0:npm (npm build) on project Angular2test1: Failed to run task: ‘npm run build –proxy=http://’ failed.

    I am stuck in this since 3 days,tried various solution by altering build in script:

    can you please help me out on this

  17. Can anyone explain what wrong I am doing in building project

    [INFO] Installing node version v6.3.1
    [INFO] Copying node binary from C:\Users\ayush.goyal\.m2\repository\com\github\eirslett\node\6.3.1\node-6.3.1-windows-x64.exe to C:\Users\ayush.goyal\workspace\angular2-tom\temp\node\node.exe
    [INFO] Installed node locally.
    [INFO] NPM 3.9.5 is already installed.
    [INFO]
    [INFO] — frontend-maven-plugin:1.0:npm (npm install) @ angular2-tom —
    [INFO] Found proxies: [Fiddler{protocol=’http’, host=’indpunsbd6intpxy01.ad.infosys.com’, port=80}]
    [INFO] Running ‘npm install –proxy=http://indpunsbd6intpxy01.ad.infosys.com:80’ in C:\Users\ayush.goyal\workspace\angular2-tom\angular
    [INFO] ————————————————————————
    [INFO] BUILD FAILURE
    [INFO] ————————————————————————
    [INFO] Total time: 5.916 s
    [INFO] Finished at: 2017-02-21T12:16:54+05:30
    [INFO] Final Memory: 10M/113M
    [INFO] ————————————————————————
    [ERROR] Failed to execute goal com.github.eirslett:frontend-maven-plugin:1.0:npm (npm install) on project angular2-tom: Failed to run task: ‘npm install –proxy=http://indpunsbd6intpxy01.ad.infosys.com:80’ failed. java.io.IOException: Cannot run program “C:\Users\ayush.goyal\workspace\angular2-tom\temp\node\node.exe” (in directory “C:\Users\ayush.goyal\workspace\angular2-tom\angular”): CreateProcess error=193, %1 is not a valid Win32 application -> [Help 1]
    [ERROR]

  18. What I need to do? I need to copy whole angular 2 app as it is need to past into src/main/webapp folder or just angular 2 app content?
    I confused here. Please help me

  19. I created “angular” folder in webapp and kept angular 2 app content in this folder with dist folder. I made .war file and deployed on server. But still I unable to access page. I tried with both “localhost:8080” and “localhost:4200”. Please guide me. I’m new in angular 2 and doing this thing first time.

  20. You don’t have to copy things every time (it will be done automatically). But you have to set up your project first time.
    So do these steps.
    1. Create maven project.
    2. In the root of that maven project create folder named as angular.
    3. Put your angular 2 code (package.json, dist whatever) inside that “angular” folder.
    4. Do the changes in pom.xml file as I have described above in the blog.
    5. Compile the project using mvn command (maven).
    6. That’s it.
    You can see my project https://github.com/ashishdoneriya/BaceDevotees and verify the project structure.

  21. For anyone else getting 404 resource not found errors on JS files, try changing ‘/’ to ‘./’ like Ponni mentioned. Worked for me!

  22. Hi Ashish,
    I’m getting this below error after clean .

    Failed to run task (com.github.eirslett:frontend-maven-plugin:1.0:npm:npm install:generate-resources)

    org.apache.maven.plugin.MojoFailureException: Failed to run task
    at com.github.eirslett.maven.plugins.frontend.mojo.AbstractFrontendMojo.execute(AbstractFrontendMojo.java:95)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
    at org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331)
    at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362)
    at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1)
    at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:176)
    at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:112)
    at org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:1360)
    at org.eclipse.m2e.core.project.configurator.MojoExecutionBuildParticipant.build(MojoExecutionBuildParticipant.java:52)
    at org.eclipse.m2e.core.internal.builder.MavenBuilderImpl.build(MavenBuilderImpl.java:137)
    at org.eclipse.m2e.core.internal.builder.MavenBuilder$1.method(MavenBuilder.java:172)
    at org.eclipse.m2e.core.internal.builder.MavenBuilder$1.method(MavenBuilder.java:1)
    at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod$1$1.call(MavenBuilder.java:115)
    at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:176)
    at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:112)
    at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod$1.call(MavenBuilder.java:105)
    at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:176)
    at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:151)
    at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:99)
    at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod.execute(MavenBuilder.java:86)
    at org.eclipse.m2e.core.internal.builder.MavenBuilder.build(MavenBuilder.java:200)
    at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:735)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:206)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:246)
    at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:301)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:304)
    at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:360)
    at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:383)
    at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:144)
    at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:235)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
    Caused by: com.github.eirslett.maven.plugins.frontend.lib.TaskRunnerException: ‘npm install’ failed.
    at com.github.eirslett.maven.plugins.frontend.lib.NodeTaskExecutor.execute(NodeTaskExecutor.java:63)
    at com.github.eirslett.maven.plugins.frontend.mojo.NpmMojo.execute(NpmMojo.java:62)
    at com.github.eirslett.maven.plugins.frontend.mojo.AbstractFrontendMojo.execute(AbstractFrontendMojo.java:89)
    … 32 more
    Caused by: com.github.eirslett.maven.plugins.frontend.lib.ProcessExecutionException: java.io.IOException: Cannot run program “/home/oem/workspace/NeedForBook/temp/node/node” (in directory “/home/oem/workspace/NeedForBook/angular”): error=2, No such file or directory
    at com.github.eirslett.maven.plugins.frontend.lib.ProcessExecutor.executeAndRedirectOutput(ProcessExecutor.java:73)
    at com.github.eirslett.maven.plugins.frontend.lib.NodeExecutor.executeAndRedirectOutput(NodeExecutor.java:29)
    at com.github.eirslett.maven.plugins.frontend.lib.NodeTaskExecutor.execute(NodeTaskExecutor.java:58)
    … 34 more
    Caused by: java.io.IOException: Cannot run program “/home/oem/workspace/NeedForBook/temp/node/node” (in directory “/home/oem/workspace/NeedForBook/angular”): error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at com.github.eirslett.maven.plugins.frontend.lib.ProcessExecutor.executeAndRedirectOutput(ProcessExecutor.java:61)
    … 36 more
    Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    … 37 more

  23. Can you tell me files and directories that are just inside your project (eg. mine have pom.xml file and a directory named as ‘angular’ in which I’ve put my angular 2 source code).

  24. Hi,
    Thank you for sharing your code / knowledge!
    The combination of Maven & Angular 2 seems a good one.
    ? Do you deploy both in 1 WAR file?
    When trying the TransactionManager I tried to deploy the war within Eclipse on a Tomcat server. All went well.
    When trying to browser to http://localhost:8080/transactionManager … I get a 404.
    Also http://localhost:8080 … a 404.
    I tried also to reach the api (…/api/categories) but nothing happens.
    Can you please help?
    Thank you, kind regards,
    Johan

  25. Yes, I deploy both in 1 war file. Angular 2 is nothing but a bunch of Html and Javascript in which it generates as its output when we build it (using ng build command). I just move all those generated Html/Javascript files to the root of war file (using maven pom.xml). And don’t use TransactionManagement Project. Use https://github.com/ashishdoneriya/BaceDevotees. It is maintained. Instructions are given on the link itself.

  26. Hi Ashish
    I’m using weblogic as my app server and I have created a separate module for UI(Angular2) in the existing project. Now made it into 1 war file(Angular2 + Java project) when I am deploying it and giving the local host as http://localhost:7001/gdl-ws/home/( I configured in the router to direct this URL and added component to that. GDL-WS is context route) I’m getting 404 error. Is there any where else that I have to configure for weblogic server. Do you have any sample project with Angular2 using weblogic server.

  27. Hello Ashish !
    thanks for your tutorial. it’s good help for me.
    Just one question … why do you use “copy-resources” instead of “-op” option of “ng” command. this option automatically copy (with replace) your distrib in a specific path.
    my example in my project (with my prompt “[…./webapp-test/webapp-node] $” ):
    […./webapp-test/webapp-node] $ ng build -prod -bh=. -op=../webapp-tomcat/src/main/webapp/ihm

  28. Hi Ashish,

    Thanks for the very neat tutorial it helped me a lot, Like you said in your tutorial maven-frontend plugin didn’t work for me.

    So i thought to build the angular project and copy it manually in webapp folder. I try to build the angular project using npm install and npm build -prod in eclipse terminal I got error [ERROR in Error: Unexpected value ‘MaterialModule ].

    Checked in internet and tried many solution but nothing works.

    Can you tell me what may be the issue, i am using your DevoteeManagement project.

    Thanks in Advance

  29. Hi Ashish,

    Thanks for your reply, it is really good you are answering for everyone’s questions.

    If i found the solution i will update you.

    Thank you once again.

Leave a Reply

Your email address will not be published. Required fields are marked *