Combining the Grails Vue profile client and server projects
Learn how to generate a JAR file which combines Vue and Grails production artefacts.
Authors: Nirav Assar, Zachary Klein
Grails Version: 3.3.8
1 Grails Training
Grails Training - Developed and delivered by the folks who created and actively maintain the Grails framework!.
2 Getting Started
In this guide, you are going to create a combined build of the server
and
client
projects from the Vue profile. By default, the Vue profile sets up
separate frontend and backend apps, which can make for a more efficient development process.
However, this may not fit your deployment needs, particularly if your entire app is
being deployed to a servlet container such as Tomcat, or being executed as a "fat" JAR.
Thanks to the flexibility of Grails and the Gradle build tool, we can configure a
unified build of our Grails/Vue app with only a few changes.
2.1 What you will need
To complete this guide, you will need the following:
-
Some time on your hands
-
A decent text editor or IDE
-
JDK 1.8 or greater installed with
JAVA_HOME
configured appropriately
2.2 How to complete the guide
To get started do the following:
-
Download and unzip the source
or
-
Clone the Git repository:
git clone https://github.com/grails-guides/grails-vue-combined.git
The Grails guides repositories contain two folders:
-
initial
Initial project. Often a simple Grails app with some additional code to give you a head-start. -
complete
A completed example. It is the result of working through the steps presented by the guide and applying those changes to theinitial
folder.
To complete the guide, go to the initial
folder
-
cd
intograils-guides/grails-vue-combined/initial
and follow the instructions in the next sections.
You can go right to the completed example if you cd into grails-guides/grails-vue-combined/complete
|
3 Writing the Application
If you open the initial
project of this guide, you will find a plain project
generated from the Vue profile.
Both the server
Grails app and the client
Vue app have production
build tasks set up - you can run ./gradlew server:assemble
to build a WAR or
JAR file, and you can run yarn build
(or ./gradlew client:build
) to generate
a static Vue/webpack bundle.
Our first step is to create a new build.gradle
file at the top of our project
structure, above the client
and server
sub-projects.
3.1 Configuring Gradle
The initial folder contains a Grails application generated with the vue
profile. The project is a Gradle Multiproject build.
Create a build.gradle
file in the root project, at the same level as settings.gradle
. Add the following content:
task copyClientResources(dependsOn: ':client:build', type: Copy) { (1)
group = 'build'
description = 'Copy client resources into server'
from "${project(':client').projectDir}/dist"
into "${project(':server').buildDir}/resources/main/public"
}
task assembleServerAndClient(type: Copy, dependsOn: ['copyClientResources', ':server:assemble']) { (2)
group = 'build'
description = 'Build combined server & client JAR/WAR'
from fileTree(dir: "${project(':server').buildDir}/libs/") (3)
into "${rootProject.buildDir}"
doLast {
logger.quiet "JAR/WAR generated at ${rootProject.buildDir}. It combines the server and client projects."
}
}
task(":server:assemble").mustRunAfter(copyClientResources) (4)
1 | The copyClientResources task will copy the static files generated by yarn build into the resources directory of the server project. |
2 | The assembleServerAndClient task ties the copy step to the existing Gradle assemble task for the server project. This means that we will get our unified archive only when running this top-level task (running server:assemble ) alone will generate a "plain" WAR/JAR file without the client resources. |
3 | If copyClientResources is to be executed, it must be before :sever:assemble . This ensures client static files will be available when the Grails app is assembled. |
4 | After the combined JAR file has been created, we copy the files to the top-level build directory. |
In this guide, we will be using an executable JAR file as our deployment target.
To enable this open the server
project’s build.gradle
file, and delete the following line:
apply plugin:"war"
Leave the apply plugin: "war" line in server/build.gradle if you wish to generate a WAR file.
|
3.2 Updating our config
Now that we have a unified Gradle build target, we have a couple more configuration changes to make. All of these changes have to do with the URL differences between the separate Grails & Vue apps and our new combined deployment.
By default, static resources in a deployed Grails app are served from the /static
base URL. That will conflict with
what our Vue app expects, but fortunately, this is a very simple change.
Edit server/grails-app/conf/application.yml
:
grails:
resources:
pattern: /**
This simply sets the static resources URL to be set to the root context.
Along similar lines, we need to edit the URL that the Vue app uses to make REST calls against the Grails app.
This can be done within client/config/prod.env.js
in the client
project. This file is used in the production environment and
sets the SERVER_URL to the root context.
'use strict'
module.exports = {
NODE_ENV: '"production"',
SERVER_URL: '""'
}
3.3 URL Mappings
Our final change needs to happen in UrlMappings.groovy
. If you recall, by default the server
Grails app renders some
application metadata at the root context. However, in order for our combined build to work, we need to load our Vue app
at the root context. Fortunately, this is a very simple change as well.
Edit server/grails-app/controllers/demo/UrlMappings.groovy
:
Delete this line:
'/'(controller: 'application', action:'index')
Replace it with this:
if ( Environment.current == Environment.PRODUCTION ) {
'/'(uri: '/index.html')
} else {
'/'(controller: 'application', action:'index')
}
1 | We are using the grails.util.Environment class to determine whether we are running in development mode or in a deployed artefact,
and setting the URL mappings appropriately. |
With this new mapping config, when we build our executable JAR file, the /
URL will be mapped to /index.html
,
which happens to also be the landing page for our Vue application.
4 Running the Application
To generate the unified executable JAR, file, simply run the following command:
~ ./gradlew assembleServerAndClient
...
JAR generated at build. It combines the server and client projects.
To run the application, use the java -jar
command:
~ java -jar build/server-0.1.jar
...
Grails application running at http://localhost:8080 in environment: production
Browse to http://localhost:8080
, and you should see the Vue application.
Make a GET request to http://localhost:8080/application/
, and you should see the application metadata from the Grails application.
Congratulations, you have a unified Grails/Vue production build!
To run the application in development mode: |
- ./gradlew client:start - for the client Vue app
- ./gradlew server:bootRun - for the server Grails app
- ./gradlew bootRun -parallel - to launch them at the same time with one command