Background
I would like to share my experience using Vue 2 without a build step in my project and the key factors behind this approach. I started experimenting with Vue.js (Vue 2) back in 2020. One of the nice features of Vue is the ability to use the framework directly into HTML page without a build tool (compilation). This particular feature was the deciding factor in selecting this framework in migrating a jQuery-based web application. I also considered how easy it is to learn and train my team.
The project is a multiple page application (MPA), it consists of an HTML part (UI), an inline JavaScript with embedded Vue (UI Handler) and external Vue components.
A Spring Boot page controller handles the HTTP requests, webpages generation, session management and connection to the business services. An API controller handles the data flow between the web server to the web browser via REST API.
Frontend Framework Selection Criteria
| Features / Capabilities | Vue | React | Angular |
|---|---|---|---|
| No Build Step | ✅ | ✅ | |
| Server Side Rendering | ✅ | ||
| Learning curve | ✅ | ✅ | |
| Reuse or retrofit existing jQuery components | ✅ | ✅ | ✅ |
No Build Step
The tasks were to upgrade an existing Spring 4 to Spring Boot 2, replace jQuery with Vue, provide bug fixes and add new business functionalities. It is important that we don’t introduce additional build tools into the development process and focus on the actual tasks of migrating the code and improving the business logic. Angular needed a build step to transpile TypeScript to JavaScript, while Vue and React could be used without a build step, but the latter required coding in JSX.
The sample code below shows how we use Vue directly with HTML and inline Javascript. Of course, we can also separate the Vue code into its own dedicated JavaScript file.
|
|
Server Side Rendering
The existing spring framework application uses Thymeleaf which is responsible for webpage generation (Server Side Rendering). Using Vue in this scenario is not an issue because it can be embedded directly into HTML pages like normal JavaScript. We utilized the server-side conditional statements to redact or hide pieces of JavaScript code inside the generated webpages. The code snippet below shows how Thymeleaf checks if the user has the authority before rendering the specific part of the webpage.
Thymeleaf conditionals inside an inline Javascript
/*[# sec:authorize="hasAnyAuthority('SYSTEM_ADMINISTRATOR', 'OPERATION_ADMINISTRATOR')"]*/
The code from line 4 to 21 will only be rendered if the user has the required authorization.
|
|
Learning curve
My team and I had experience coding in JavaScript, Java and Go. It is only practical to choose a framework where we can reuse existing skill set. We decided to go with Vue because of its neat coding structure and fantastic attribute, event and input binding.
Class and Style binding
<div class="panel" :class="{ active: isActive, 'text-danger': hasError }"></div>
Event binding
<button @click="viewOrder">View Order</button>
Input binding
<input v-model="order.OrderNumber" placeholder="Order Number" />
Reuse or retrofit existing jQuery components
The project used a number of jQuery and JavaScript components from Telerik and other vendors. Reusing and wrapping them into Vue would save us a lot of time. The existing components were already production-tested and the customer didn’t want to replace them. Telerik had Vue components, but we decided to keep using the existing jQuery-based components
Wrapping a jQuery component into Vue 2 (prj-datetime-picker.js)
Vue.component('prj-datetime-picker', {
template: `<input :id="id" :value="value" :format="format" />`,
props: {
id: {type: String},
value: {type: String},
format: {type: String},
callback: {type: Function, default: null},
disabled: {
default: false,
}
},
data() {
return {}
},
watch:
{
disabled(v) {
let x = $("#" + this.id).data("kendoDateTimePicker");
x.enable(!v);
},
value: {
handler(v) {
let x = $("#" + this.id).data("kendoDateTimePicker");
if (x !== undefined) {
x.value(v);
}
},
immediate: true,
deep: true,
},
},
methods: {
onChange() {
this.$emit('change', $("#" + this.id).data("kendoDateTimePicker").value());
if (this.callback !== null) {
this.callback(this.id, $("#" + this.id).data("kendoDateTimePicker").value());
}
}
},
mounted() {
$(this.$el).kendoDateTimePicker({
format: this.format,
value: this.value,
change: this.onChange,
});
let x = $("#" + this.id).data("kendoDateTimePicker");
x.enable(!this.disabled);
},
})
We can then use this wrapped jQuery component like a regular Vue component
<prj-datetime-picker id="orderDateTime"
format="dd/MM/yyyy HH:mm" style="width: 100%"
:value="order.startDateTime"
@change="onOrderDateTimeChange">
</prj-datetime-picker>
Conclusion
We completed the project and the customer were very happy with the final software product. It resulted in more modular code that was easy to maintain, change and extend. Furthermore, we also learned to choose a technology based on existing team skill set and project timeline, use frameworks or libraries to deliver business solutions, reuse or retrofit production-tested components, use both modular monolith and microservices to our advantage and not to blindly follow the latest technology trends and marketing buzz.

