Skip to content

pwr-piisw/oasp-seed

Repository files navigation

devonfw Angular CLI + Spring Boot Project Seed

This is a project seed for Single Page Applications (SPAa) built on top of Spring Boot and Angular CLI / OASP4JS ng2 project seed. To integrate these two parts of a SPA, we make use of frontend-maven-plugin.

Build Status

Getting started

Install prerequisites

You need a Git client and Java 8 installed on your machine.

Install the Project Seed

Clone the oasp-seed repository:

git clone https://github.com/pwr-piisw/oasp-seed.git

Build the application:

cd oasp-seed
mvnw clean package

The above command runs Maven via the Maven Wrapper (which means the necessary version of Maven will be downloaded for the first time). Also, thanks to the frontend-maven-plugin the necessary Node.js / npm / yarn version will be downloaded for the first time. Having the Node.js platform available, the frontend part is built. During the build (in the Maven test phase) JavaScript tests are executed as well. The web application distribution which can be found in src\main\client\dist is then treated as a Java resource available in src\main\resources\static which in turn is served by Spring Boot as static web content.

Run the application

Start the application using the following command:

java -jar target\ng-boot-project-seed-0.0.1-SNAPSHOT.jar

or by simply typing …​ run-backend …​

Open http://localhost:8080 in your browser.

Client application can be launched by running following commands:

cd src/main/client
run start

Client application is served under http://localhost:4200.

Changing server port

When 8080 port is busy by any reason, it can be easily changed by editing src/resources/application.properties file:

#Uncomment below line when standard port 8080 is occupied.
server.port=8090

In addition proxy port must be configured for client application, we do this under src/main/client/proxy.conf.json:

{
  "/services/rest": {
    "target": "http://localhost:8090",
    "secure": false
  }
}

In such case slightly different launching method for client should be used:

cd src/main/client
run start-proxy

How we created the application

First, we added the following scripts to the package.json:

"scripts": {
    ...
    "build4prod": "node ./node_modules/@angular/cli/bin/ng build --prod",
    "test4ci": "node ./node_modules/@angular/cli/bin/ng test --single-run --browsers=PhantomJS"
}

Note that the relative path to the local version of ng script was specified.

Then, we configured the new maven profile jsclient which uses the frontend-maven-plugin to download Node.js / npm / yarn, build the client application (build4prod) and run JavaScript tests (test4ci). The following configuration was added to pom.xml:

...
<profile>
    <id>jsclient</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <build>
        <plugins>
            <plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>${frontend-maven-plugin.version}</version>
                <configuration>
                    <workingDirectory>${js.client.dir}</workingDirectory>
                </configuration>
                <executions>
                    <execution>
                        <id>install node and yarn</id>
                        <goals>
                            <goal>install-node-and-yarn</goal>
                        </goals>
                        <configuration>
                            <nodeVersion>${node.version}</nodeVersion>
                            <yarnVersion>${yarn.version}</yarnVersion>
                        </configuration>
                    </execution>

                    <execution>
                        <id>install node and npm</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                        <configuration>
                            <nodeVersion>${node.version}</nodeVersion>
                            <npmVersion>${npm.version}</npmVersion>
                        </configuration>
                    </execution>

                    <execution>
                        <id>yarn install</id>
                        <goals>
                            <goal>yarn</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>

                    <execution>
                        <id>Build Client (npm run-script build4prod)</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>run-script build4prod</arguments>
                        </configuration>
                    </execution>

                    <execution>
                        <id>JavaScript Tests (npm run-script test4ci)</id>
                        <phase>test</phase>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>run-script test4ci</arguments>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
    </build>
</profile>
...

Create history API fallback

We added the HistoryApiFallbackController in order to handle forwarding to the index.html when bookmarking any client’s dialog (whose path begins with app per convention). Such handling is necessary because the HTML5 history API is used in the client.

@Controller
public class HistoryApiFallbackController {

  @RequestMapping(value = "app/**", method = RequestMethod.GET)
  public String historyApiFallback() {
    return "forward:/";
  }
}

Display build metadata

In order to display in the page the current application version and build time, we added the following meta tags to head section of index.html:

<head>
    ...
    <meta name="version" content="${project.version}">
    <meta name="timestamp" content="${timestamp}">
    ...
</head>

For this to work, we used maven-resources-plugin to filter src/main/client/dist/index.html (the plugin uses Maven Filtering for filtering resources). The following configuration was added to our jsclient profile (pom.xml):

...
<profile>
    <id>jsclient</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <build>
        <plugins>
            ...
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>filter-index.html</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <useDefaultDelimiters>true</useDefaultDelimiters>
                            <outputDirectory>${project.build.directory}/client</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${js.client.dir}/dist</directory>
                                    <filtering>true</filtering>
                                    <includes>
                                        <include>index.html</include>
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                    <execution>
                        <id>copy-index.html</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${js.client.dir}/dist</outputDirectory>
                            <overwrite>true</overwrite>
                            <resources>
                                <resource>
                                    <directory>${project.build.directory}/client</directory>
                                    <filtering>false</filtering>
                                    <includes>
                                        <include>index.html</include>
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>
...

Technically, a copy of index.html is created: first the file is filtered and copied to target/client and then copied to src/main/client/dist overwriting the previous version.