First dive into Vue with Typescript + Lumen + Gitlab CI/CD (Part 1 — Frontend)
The lacking of types and not yet full support of all object oriented principles made it hard to write proper code. Don’t understand me wrong, it got much better with the ES5, ES6 update but still something was missing…
That’s why we have decided to start our next project with a completely new stack and try to write down our experiences in a blog post. It’s written for people who already have experiences with Vue JS and know the basic concepts of components, vuex, vue-router and webservice calls.
The following technologies are included in the new stack:
Frontend (Part 1)
- Vue JS with Typescript
- vue-cli 3.0 alpha(supports now Typescript)
- Bulma CSS Framework
- Cypress (for integration tests)
- Mocha/chai (for unit tests)
Backend (Part 2)
- Lumen 5.6 (Laravel based micro framework)
- Mailgun (For mailing)
- phpunit for testing
Continuous Integration (Part 3)
- Gitlab CI/CD
- Automated Testing
- Automated Deploying
- Monitor tool for all projects
Holy, thats a lot of stuff. So I’ve decided to split this into 3 parts (Frontend, Backend and Continuous Integration).
Lets start with the frontend
As mentioned above we already had 1.5 years experience with Vue JS and implemented around 5 bigger projects with it. The component based approach increased the simplicity and separation of responsibilities a lot. But still there was a lot to improve on the frontend site. I try to show you the setup we came up with and include some lessons learned.
Setup of Vue JS project with Typescript
Luckily the good lads from Vue JS Team recently updated the vue-cli alpha with in-built Typescipt support. This makes it really easy to create your Vue JS SPA with the command line based vue-cli script.
I don’t want to explain how to create your vue-cli based project, you can find all information on the given link: https://github.com/vuejs/vue-cli
Project folder structure
We have used generated folder structure from vue-cli and added some folders.
The interesting folder is src. Here is a short explanation of the subfolders:
Includes all images/sass files
All Vue JS components are stored here. We group them into module based subfolders to keep it tidy.
Helper Classes are stored here.
In my mobile apps I always mapped the API responses (JSON) into an object structure. To manage all these models I’ve created this models folder.
All routes in the frontend are managed by the vue-router package. The main configuration file is stored in here.
Sometimes you have components which have no logic at all. That’s why we have created this folder views. But honestly I’m not sure if this is actually needed.
To store data locally we are using vuex combined with the vuex-persistedstate plugin. We have divided the store file into sub modules. How we did that will be explained in a later section.
All webservice classes are implemented here as Singleton classes and can be used in all the components.
From API to Vue JS component
To give you better understanding of how all is working together I want to show you how an API call from the Webservice class is bound to the model and how the data is later showed in a Vue JS based component.
JSON response and model classes
In earlier projects we have done our axios requests directly in the Vue components. This let to duplicate code. That’s why we have decided to create now separate Webservice classes for each module. In the following code you can see implementation file of the TopicWebservice which is responsible for the endpoint on the api (api/v1/topic).
Vue JS Component
This Vue JS component is displaying the fetched topics and questions.
The nice thing is now that in this Vue JS component we can just include the TopicWebservice class and call the getAllTopics method. The returned Promise includes the mapped topics with the all corresponding options.
In our project we use vuex therefor after fetching the topics we store (commit) them in our local vuex storage. So other components don’t need to refetch this data. I will later explain how we have structured our vuex folder.
The use of getters from vuex is also with Typescript quite easy. We have used the vue-property-decorator and vuex-class decorators to bind the getter variable topics directly to a class variable in Typescript.
In this Vue JS component we pass all topics to a subcomponent (question-box) which is responsible for displaying the topics and the options.
Vuex and using Local Storage
I’ve mentioned above to store our fetched data locally on the client we use vuex and the library vuex-persistedstate. This library is basically just storing the whole vuex data tree in the local storage and does the synchronisation. So when you reload a page or even open/close a tab the data is still there.
We have started to use the following structure for our vuex modules.
We have separated it into modules. Each module has its own store file and is included in the main store file. In earlier projects we had one massive store file which led to some problems.
The benefit of this is also the access by a given namespace. So when you want to commit to a specific module you can use the namespace as prefix. Specially in bigger project this is making it a lot easier to manage all vuex operations.
Here is our current version of the store file in the module topic. It includes the state, mutations, actions and getters. They are grouped in a module which is then included by the main store file. Very important is the namespaced: true, otherwise it won’t work with the separated namespacing.
As internal router of the views we use vue-router which also works out-of-the-box with Typescript. Nothing special here. Just connects the paths with components.
Integration tests with Cypress
I’m honest.. I did many approaches to start TDD and was always at the beginning quite motivated seeing tests getting green. But at some point I realised that the cost/benefit factor was not on our side. It took almost as much as time to write the test than writing the actual code. We are currently a small two man company and we can’t afford to write half of the day tests.
Thats why I was looking for a testing framework which makes it easy and fun to write tests. With cypress we have found a tool which is offering that. In the picture above you can see one of our integration tests. The nice thing about cypress is, that it’s offering you an inspect tool which gives you directly the code to get a certain element and assert conditions on it. I always lost so much time thinking about how to get to which element.
Another benefit is that it does automatically record the tests in a video and it’s possible to specify at what stages it should take screenshots to document these tests.
A little teaser for Part 3..! We have finally managed it to set up Gitlab CI/CD to run our cypress tests on the server and automatically deploy it to our development server when the tests have been succeeded in the master branch. We have now also a little monitor showing the project status of our current git projects.
That’s it for now
I hope you all enjoyed reading this. It would be really nice to hear other stories of people starting to switch to use Vue with Typescript. For now I feel a bit more comfortable in developing in the frontend world.. But yeah, probably tomorrow there will be a new, life changing framework released and we will do our next project completely different. It never gets boring!
Part 2 and 3 will come soon and will be linked here.