The CLI does not yet fully support this, but it provides some useful tools to help you with this. I needed this to deploy my Angular app along with WAR, trying to minimize the amount of complexity added through servlet mappings. J2EE is not specifically mentioned in this question, but I think that the principles of this solution can be used in different environments.
Relevant ng build
options:
--deploy-url
: path mapping to be applied to resources. This is probably close since Angular -CLI is currently getting to what you are looking for.--output-path
: assigns the output directory for the Angular assembly (in particular, I used this to indicate unique output directories for different environments, as the application is deployed for several purposes with different configurations).--base-href
: The root URI for the application. For example, /angular-app/
for http://localhost:4200/angular-app/
. This sets the header tag <base href="<uri>">
and is required for non-hash routing. This may be required for other things.
The most interesting thing for you is probably --deploy-url
. For example, if you set the deployment URL /dist/
, then the links to JS files in your embedded application will be prefixed with /dist/
.
Two big tricks to this method:
--deploy-url
does not change the output path for JS files. It only modifies links to JS files. The files themselves will still be placed in the root assembly directory. You will need to add a step to the build process to fix it manually.--deploy-url
does not seem to work for any other assets. I put all my other assets in the assets/
directory, and the constructed output still refers to assets through assets/<path>
(and not dist/assets/<path>
as desired). You can get around this by providing a virtual directory or by rewriting the URL.
For reference, here is my resulting directory structure for WAR:
app/ dist/ <-- Deployed Angular application assets/ (images, CSS, etc) *.js (other assets pulled into the root path, eg *.(svg|eot|woff|woff2|ttf) from Font Awesome) index.html WEB-INF/ ... index.jsp
These are the steps that I take to create this structure:
ng build -pr false --prod --output-path build/node-prod --base-href /angular-app/ --deploy-url /angular-app/dist/
.- Copy the contents of
build/node-prod
to the WAR app/dist
assembly directory using the gradle task. - Point
index.jsp
to index.html
through the contents of <%@include file="dist/index.html"%>
. - Add a servlet mapping for the default servlet (static assets) for the paths
/dist/*
and /assets/*
. - Add a URL mapping through http://tuckey.org/urlrewrite/ for
^/assets/(.*)$
to /dist/assets/$1
(or via httpd, nginx, etc.). This is necessary because of the catch mentioned above for --deploy-url
not working for other assets. - (Optional) add a 301 or 302 redirect for
^/dist/index.html$
to the context root path so that users cannot access the application through the dist
URI.
In the resulting webapp, http://localhost/angular-app/
is the only valid endpoint for my application. This endpoint points to index.jsp
, which includes the contents of index.html
, which loads the appropriate JS using the <script src="/angular-app/dist/<some-file>.js"></script>
.
When some other asset is required, for example, a logo image, the page sends a request to assets/<file-name>
, which is rewritten on the server side via Tuckey to dist/assets/<file-name>
, transparently resolving the requested asset.
The best part about this solution was that we were able to deploy the Angular application in the root context without putting everything that ng build
embedded in the WAR root path. This is especially nice because we don’t want to add global servlet mappings (e.g. *.js
) when they can be avoided.