March 6, 2019
Hot Module Reloading (HRM) greatly accelerates developing a Single Page Application (SPA) with Vue.js. However, this requires running in the Webpack Dev Server (WDS). If you're developing a WildFly RESTful backend alongside the SPA, you'll need to adjust the WildFly CORS policy so that the WDS can interact with WildFly.
With HRM, saving a source Javascript file produces an immediate change in the browser. Thismeans that the state accrued in the SPA remains. There is no need for a refresh (F5). WildFly doesn't support this type of browser interaction. At best, WildFly will copy out web resource on a save operation to an exploded configuration. A browser refresh is needed to pick up the changes driven from the server side.
This video demonstrates HRM. A Vue.js save operation in VSCode (left) produces an immediate change in the browser (right) without a refresh.
JavaEE apps are packaged and deployed in a structure called a WAR or Web Archive. This is a zip file with a particular layout including optional deployment descriptors. When a JavaEE app server like WildFly sees a WAR file, it unpacks the contents and wires up any of the resources that its components require such as a datasource. Once in the app server, the WAR file can operate as a web application using server side technologies like JSP, Servlets, JSF, or another framework.
The target production deployment of a Vue.js app might be a single WAR. This could include RESTful web services, business logic in the form of Enterprise Java Beans (EJBs), and data access provided by Hibernate. In this deployment, there is no problem with CORS since all of the Vue.js artifacts and communications will involve a single origin and a single destination.
For more about backend development with WildFly, check out the various RESTful, WebSocket, EJB, and JPA tutorials at https://courses.bekwam.net.
To update an app in a single WAR deployment in a development environment, you would use an exploded configuration (unzipped). When you save a file in the IDE, the changed content would be pushed out and eligible to be accesed by a browser refresh. This is a problem for the SPA since you may have built up state (data) in the running SPA that you don't want reset. For instance, say you went through a few pages of a wizard and got an error on one of the next buttons. With HRM, you can retain this state and swap in a new handler for the next button. This can go on until the troubleshooting ends.
To get HRM, you need to run the webpack-dev-server. This diagram shows the expected deployment. A WildFly app server awaits RESTful web service requests on port 8080. A webpack-dev-server awaits static content requests on port 8081. If you make a change to the Vue.js code running under the webpack-dev-server, that will be reflected in the browser without a refresh. Note that if you change the backend code, you'll need to restart the services in WildFly. Because the front-end (Vue.js) and the backend (WildFly) are decoupled, you may not need to refresh the browser.
But the server arrangement in this deployment will produce a CORS violation. The Vue.js code can't contact the RESTful backend using Axios or other web service client. That's because the port origins are different. To get around this, you'll make a configuration change to WildFly.
This screenshot shows what a CORS violation looks like in the browser.
Another type of CORS error you might see comes from authenticated requests. This errors was produced by a WildFly configuration that accepts the different Origin, but not the Authorization HTTP Header.
WildFly Filters are a proprietary feature that can apply outgoing transformations on an HTTP response. This is like the standard Servlet Filters, but the WildFly filters apply to an entire host. This means that the settings described in this section will be applied to all of the deployed WARs. Additionally, the WildFly Filters have a UI for administrators and don't require manipulating an individual WAR file.
After starting WildFly, go to the Filters section of the Undertow configuration. See the following screenshot for the navigation.
Press "View" and select "Response Header". This screenshot shows the Response Header Filters screen.
You'll define two response headers that will be communicated for each and every response across any of the WAR files loaded in this instance of WildFly. The first header, "Access-Control-Allow-Origin" permits the Javascript code loaded from :8081 to submit HTTP via Axios to :8080.
Name: CORS
Header Name: Access-Control-Allow-Origin
Header Value: *
If all of your requests coming from the Vue.js app are unauthenticated, you only need to adjust the Origin setting above. If you need to authenticate, say using Basic Authentication, you'll need to define an additional header approving the use of the Authorization header.
Name: AuthAllowed
Header Name: Access-Control-Allow-Headers
Header Value: Authorization
The previous step create to Response Header Filters. This next step applies them to the Server. In the Undertow subsystem, navigate to the default-server. See the following screenshot for the path.
Next, press "View" and then the "Hosts" tab. Press the Filters button associated with the default-host.
Finally, you'll use the Add button to associate the Filters with default-host.
If you're content to do a browser refresh with each Vue.js change, then you'll only need the WildFly server. However, to take advantage of HRM, you'll need an HRM-equipped server like webpack-dev-server. HRM is most useful in settings where you'd like to change the browser content without needing to refresh the screen. This avoids the second or so of refresh delay, but -- more substantially -- avoids having to manually repeat a sequence of steps to reset the UI. While not needed for the production deployment, tweaking the CORS settings let me put together a best-of-breed solution for developing both ends of the application.
By Carl Walker
President and Principal Consultant of Bekwam, Inc