We recently needed to navigate the minefield that is modern JavaScript development to implement our new JS stack on our Web Projects. In this blog post we share some of the decisions we made in the interests of sharing our experiences with the community.
Before modern JavaScript
As we are predominantly backend focused, JavaScript was never our priority as a team (in honesty we avoided it where possible).
Before moving to our new stack we would serve unbundled JQuery to the browser or use inline JavaScript in our templates. Unsurprisingly this did not scale, and also caused us issues with reusability, maintenance and testability. We also found that we had no defined standard for code quality.
One of our main problems related to browser incompatibilities. Most JavaScript features we developed required rework to be compatible with older browsers. When fixing these problems we had issues refactoring as JavaScript would be copied and pasted around, mainly due to the lack of any module system.
First step - Transpilation and Bundling
Our first step toward JS implementation was to introduce basic transpilation and bundling, achieved by introducing Webpack to our projects. We configured Webpack to load SASS/Scss and ES6+ JS, for this we used:
With the introduction of Webpack, we could stop worrying about browser incompatibilities and could start reusing JS modules across our applications. Another positive of introducing Webpack was that it gave us access to NPM packages in our projects, this is because it was required to install Webpack.
For production and CI testing we setup a new Docker image for transpiling assets. We took this approach to avoid installing Node.js. The image is set up in a bind mount to the projects directory, and it’s only invoked when there is a webpack.config.js
available in the root of the project.
Second step - Framework
After the initial stack was set up, it was time for us to choose a framework that we would use for bigger portions of our products’ front-end functionality. It was a big decision, as it needed to be something that the whole team was relatively comfortable with and would be used across multiple products in the future. After narrowing it down to Vue.js and React.js, we decided that the best course of action would be to timebox an implementation of a new feature in both frameworks and then compare the experiences at the end. We also made sure that the feature would be big enough to hopefully uncover any issues we might have with the frameworks, and to help us build up a list of pros and cons that we could bring to the rest of the team.
The results of the investigation led us to choose React over Vue. We found that the wider support and use of React.js made the community much larger than that of Vues. This was appealing for us as we are not a JS focused team, so more available training resources and blog posts will assist us when using the framework. Another reason for picking React over Vue was that the members of the team had more previous experience with React than Vue.js so by picking React here we saved time on training staff on Vue. The training issue was an important factor as we found Vue to have a lot of specific proprietary standards and practices. React on the other hand is much more aligned with the direction of ECMAScript as a whole, meaning we would require less framework specific training.
React - Tooling
Because React.js is such a flexible and open view library we needed to pick some other tooling to handle further tasks required, for example AJAX requests. For AJAX requests we decided to go with Axios. We chose Axios due to its wide usage and its active community and the native support for Promises was also big seller.
State management is handled by Redux. Redux as a library has great support for React out of the box which is useful as it minimised the amount of code we have to write to integrate the library into our products. Our chosen pre-compiled language was TypeScript as we find that the static type safety of TypeScript makes JavaScript 10x easier to work with, and the wide adoption means most major libraries have a types package.
Conclusion
After implementing our new stack, we’ve found that feature implementation times have been reduced, and we have produced less bugs. The development team now plans to roll out our JS stack across all of our web projects. We also will be investigating the use of React Native for our mobile products.