3

I have an app with REST as Spring Boot Application and client as Angular2.

Earlier, I started apps separately - Spring Boot by starting SpringBootApplication main method (it started to listen on port 8080), Angular2 - running from command line npm start (it usually started on 3000 port).

Now I want Maven to run both apps with one command.

  1. Angular 4.0.0
  2. Spring Boot 1.5.4.RELEASE

I've been trying to apply answer and this tutorial. But in first case starts only Angular app, is second - only REST.

My package.json:

"scripts": {
    "build": "tsc -p src/",
    "build:watch": "tsc -p src/ -w",
    "serve": "lite-server -c=bs-config.json",
    "prestart": "npm run build",
    "start": "concurrently \"npm run build:watch\" \"npm run serve --proxy-config proxy-config.json\" ",
    "lint": "tslint ./src/**/*.ts -t verbose"
  },
  "license": "ISC",
  "dependencies": {
    "@angular/animations": "^4.2.4",
    "@angular/common": "~4.0.0",
    "@angular/compiler": "~4.0.0",
    "@angular/core": "~4.0.0",
    "@angular/forms": "~4.0.0",
    "@angular/http": "~4.0.0",
    "@angular/material": "^2.0.0-beta.7",
    "@angular/platform-browser": "~4.0.0",
    "@angular/platform-browser-dynamic": "~4.0.0",
    "@angular/router": "~4.0.0",
    "@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.26",
    "angular-in-memory-web-api": "~0.3.0",
    "angular2-modal": "^3.0.1",
    "bootstrap": "^3.3.6",
    "core-js": "^2.4.1",
    "hammerjs": "^2.0.8",
    "jsplumb": "^2.4.3",
    "ng2-bs3-modal": "^0.10.4",
    "ng2-popup": "^0.4.0",
    "rxjs": "5.0.1",
    "systemjs": "0.19.40",
    "zone.js": "^0.8.4"
  },
  "devDependencies": {
    "concurrently": "^3.2.0",
    "lite-server": "^2.2.2",
    "typescript": "~2.1.0",
    "canonical-path": "0.0.2",
    "tslint": "^3.15.1",
    "rimraf": "^2.5.4",
    "@types/node": "^6.0.46"
  },
  "repository": {}
Markiza
  • 444
  • 1
  • 5
  • 18

3 Answers3

2

I agree with sinedsem that for dev I would keep the two apps separate. As for managing a production build, I would do things slightly differently. I don't like the idea of having any manual steps involved in the build such as copying the build files from angular to the source of the spring boot app.

Instead, I would manage the whole build under maven with the angular UI and spring boot app built as separate modules. The build would be managed completely by maven, delegating the angular UI build to npm/gulp etc using frontend-maven-plugin. This can either be added as a dependency to the spring boot app of the output of the build can be copied to the target directory of the spring boot module.

Parent POM

Create a new Parent POM

<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example.angularboot</groupId>
<artifactId>boot-ui-parent</artifactId>
<version>0.1</version>
<packaging>pom</packaging>

<modules>
    <module>spring-boot-app</module>
    <module>angular-ui-resources</module>
</modules>

Angular UI Module

Build the Angular UI Module using frontend-maven-plugin to execute any npm/bower/gulp etc build steps. Either set the output of your build to target/classes/static or copy the built angular resources to target/classes/static

e.g. The below plugin installs node/npm and runs the required npm bower and gulp steps to build the Angular app.

<plugin>
                    <groupId>com.github.eirslett</groupId>
                    <artifactId>frontend-maven-plugin</artifactId>
                    <version>1.3</version>
                    <executions>
                        <execution>
                            <id>install node and npm</id>
                            <goals>
                                <goal>install-node-and-npm</goal>
                            </goals>
                            <phase>generate-resources</phase>
                            <configuration>
                                <nodeVersion>v6.10.3</nodeVersion>
                                <npmVersion>4.6.1</npmVersion>
                            </configuration>
                        </execution>
                        <execution>
                            <id>npm install</id>
                            <goals>
                                <goal>npm</goal>
                            </goals>
                            <phase>generate-resources</phase>
                        </execution>
                        <execution>
                            <id>bower install</id>
                            <goals>
                                <goal>bower</goal>
                            </goals>
                            <configuration>
                                <arguments>install --allow-root</arguments>
                            </configuration>
                        </execution>
                        <execution>
                            <id>gulp build</id>
                            <goals>
                                <goal>gulp</goal>
                            </goals>
                            <phase>generate-resources</phase>
                        </execution>
                    </executions>
                </plugin>

Spring Boop App module

This should be the same as the current spring boot module with the addition of the new parent and the dependency for the angular-ui module.

As the built version of the angular UI was packaged under target/classes/static and the angular-ui jar is on the classpath of spring boot, the angular-ui gets packaged into the spring boot application.

Alternatively, you can run the copy resources maven plugin to copy the resources from the build directory of the angular-ui module to the build directory of the spring-boot module. though I don't really like copying resource files from one module to another e.g.

<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
    <execution>
        <id>copy-angular-components</id>
        <phase>process-classes</phase>
        <goals>
            <goal>copy-resources</goal>
        </goals>
        <configuration>
            <outputDirectory>${project.build.outputDirectory}/static</outputDirectory>
            <resources>
                <resource>
                    <directory>${basedir}/../angular-ui/target/classes/static</directory>
                    <filtering>false</filtering>
                </resource>
            </resources>
        </configuration>
    </execution>
</executions>

Adriano
  • 3,788
  • 5
  • 32
  • 53
tprebs
  • 201
  • 2
  • 5
  • yea, of course I meant building bundle and spring app automatically. – sinedsem Jun 30 '17 at 14:38
  • Great, it works, but when I'm manually refreshing page (ex. localhost:8080/welcome) - I'm getting a `Whitelabel Error Page`. When I'm browsing just localhost:8080 - it works fine just to first manual refreshing. In dev tools I see that all sources are gone. – Markiza Jul 03 '17 at 22:36
  • localhost:8080 works as by default spring boot will load index.html. I expect you get the white label error page because you don't have any controllers mapped to `/welcome`. If `/welcome` is mapped in the angular state provider then try the url localhost:8080/#/welcome/. This will load the angular app from the index.html then route to the state mapped to the url '/welcome' – tprebs Jul 04 '17 at 09:10
1

Your package.json is used by npm, which is not the essential tool here.

I recommend you:

  • For development keep running two apps separately.
  • For production:
    • Pack your angular application in bundle. For example, using webpack.
    • Put your bundle to to spring boot project under /src/main/resources/static.
    • Run Spring Boot application, which will serve your Angular app from static resources.
sinedsem
  • 5,413
  • 7
  • 29
  • 46
1

The solution proposed by tprebs makes sense but the two maven modules are strongly coupled (because the angular module deposits files in the spring-boot module, which is not a good practice).

Keep things simple stupid, if it's a single team that develops the front end and the back end, a single maven module is enough. For example :

Single maven module approach (KISS)

Assuming that spring boot source code is in src/main/java folder and angular code is in src/main/js folder.

src/main/js/angular-cli.json file :

Serve Angular app as spring boot static resources.

{
  [...]
  "apps": [
    {
      "root": "src",
      "outDir": "../resources/static",
      [...]
    },
   [...]
  ]
}

pom.xml :

Build Angular part from maven using npm

<plugin>
    <!-- build UI angular -->
    <groupId>com.github.eirslett</groupId>
    <artifactId>frontend-maven-plugin</artifactId>
    <version>1.0</version>
    <executions>
        <execution>
            <id>install node and npm</id>
            <goals>
                <goal>install-node-and-npm</goal>
            </goals>
            <configuration>
                <workingDirectory>src/main/js</workingDirectory>
                <nodeVersion>v6.9.2</nodeVersion>
                <npmVersion>4.1.1</npmVersion>
            </configuration>
        </execution>

        <execution>
            <id>npm install</id>
            <goals>
                <goal>npm</goal>
            </goals>
            <!-- Optional configuration which provides for running any npm command -->
            <configuration>
                <workingDirectory>src/main/js</workingDirectory>
                <arguments>install</arguments>
            </configuration>
        </execution>

        <execution>
            <id>npm build</id>
            <goals>
                <goal>npm</goal>
            </goals>
            <!-- Optional configuration which provides for running any npm command -->
            <configuration>
                <workingDirectory>src/main/js</workingDirectory>
                <arguments>run-script build</arguments>
            </configuration>
        </execution>
    </executions>
</plugin>

On the other hand, if the teams are distinct I would indeed choose two separated maven modules but, in order to limit the coupling between the two modules, I will publish the angular part as webjar (See https://spring.io/guides/gs/spring-boot-cli-and-js).

Sébastien Helbert
  • 2,185
  • 13
  • 22