DEV Community

loading...

Building a web app in 2018, part 1: frontend

rhymes profile image rhymes ・7 min read

This post is more or less a follow up of this post I made in November 2017:

The app, or at least a MVP of it, is now alive and kicking (with its flaws) and it has been in production for week now.

In the previous post I was asking a lot of questions, in this one I will try to provide some answers. Bear in mind that a couple of months of me doing "modern" frontend development do not an expert make :D.

What is this app?

Unfortunately I can't disclose many details about the "what" but it's pretty much a web app to publish static HTML pages on AWS S3. The (company) user inputs data, some magic happen and the customer on its mobile app sees the mini website inside a mobile app. Nothing glorious but there are some moving parts and more will appear in the future that are going to be controlled or integrated in the app itself, which now are handled by separate tools or apps.

How is this app structured?

In the previous post, after ingesting an insane amount of content on the web, which got me definitely confused, I had asked if the app should have been a SPA. I'm here to tell you that my first and only SPA is working :-)

Generally speaking it's a SPA built with VueJS and whose backend is a Python/Flask web server.

Both parts live in the same repository, they just are in two separate directories:

$ ls -1 */
backend/:
README.md
TODO.md
app
business
config
coverage
docs
forms
jobs.py
migrations
models.py
package.json
services
setup.cfg
tests

frontend/:
README.md
TODO.md
build
config
dist
index.html
node_modules
package.json
src
static
test
yarn.lock
Enter fullscreen mode Exit fullscreen mode

In development mode the frontend talks to the backend using webpack's DevServer proxy, in production the frontend is built in the frontend/dist folder which the backend knows to serve as its static folder.

I'm not sure the latter is the greatest idea but for now it's working well, though sometimes I'm tempted to move the frontend inside the backend because they are technically the same app. I haven't decided yet.

Everything is deployed on Heroku.

Something about the frontend

As you might imagine the frontend is the part that worried me the most because it was a novelty for me not to build a traditional server side app and slap some jQuery whenever I needed JavaScript. Even when you try to properly structure jQuery code it still feels like it's an aftertought.

I gravitated towards Vue probably for the same reason I gravitated towards Python many years ago: I don't like complicated things. I like simple technologies that can handle complexity. React didn't attract me much (I have a thing for the underdogs, in life too :D), JSX didn't make sense to me and I fell in love with the "Single File Component" style in Vue and I was sure it could do everything I needed.

After some trial and error I created my frontend folder the right way using
vue "webpack" template.

This template does all you need: sets up the basic app structure, the basic commands, configures babel and its plugins, eslint, all the webpack build tooling, integration with the backend is super easy to setup, and it also sets up unit and e2e testing.

You just need to work with it and not against it especially if, like me, you balk at the amount of generated code when you first create the app. Generated code you have no idea what it is there for. I hope Webpack 4 and the zero configuration approach will improve things in this department in the future.

Frameworks and libraries to build the frontend

First and foremost I was trying to decide which UI framework to use. Vue has so many and it's not very easy for a newcomer to decide. The client giving me total technology freedom didn't really help (constraints are useful). My final indecision was between Boostrap Vue and Buefy, a framework based on CSS framework Bulma.

I honestly chose Buefy because my eyes were tired of seeing photocopied Bootstrap-based websites (including my own) and not being the frontend artist I could be I choose the novelty. Not very rational of me but don't worry, I checked if the project was alive and if they had the main components I needed.

The other UI libraries I'm using are mdi for Buefy's Material Design Icons, uppy which is an amazing file uploader, v-clipboard to copy text to the user's clipboard, vee-validate for form validation, vue-color for color pickers.

I'm also using axios to make calls to the backend, luxon to manipulate time, js-file-download to trigger file downloads and sentry's JS client to collect and report errors.

Last but not least: vue-router to handle routing in the frontend.

As you can imagine it's not the most nimble of apps but it's an internal one, it's used only on the desktop and I'm not optimising anything right now, just building and learning :-)

Frameworks and libraries helping the human build the frontend

Apart from VSCode and the obvious webpack I'm using other tools:

  • vue test-utils, axios mock adapter and flush promises are helping me write the unit tests in Jest

  • eslint and stylelint are helping keeping the code clean. For JS I use an airbnb style with semi colons but you can also choose "standard" during the initial template creation. For CSS I use both CSS and SASS/SCSS so stylelint knows about the latter.

A peek in the frontend's package.json

This is the scripts section of my package.json:

  "scripts": {
    "analyze": "webpack --config build/webpack.prod.conf.js --profile --json > /tmp/stats.json && webpack-bundle-analyzer /tmp/stats.json",
    "build": "node build/build.js",
    "dev": "SERVER_ENV=development webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "e2e": "node test/e2e/runner.js",
    "lint-css": "stylelint 'src/**/*.vue'",
    "lint-fix": "yarn run lint-js-fix",
    "lint-js-fix": "eslint --report-unused-disable-directives --color --ext .js,.vue src test/unit/specs test/e2e/specs --fix",
    "lint-js": "eslint --report-unused-disable-directives --color --ext .js,.vue src test/unit/specs test/e2e/specs",
    "lint": "yarn run lint-css && yarn run lint-js",
    "start-dashboard": "SERVER_ENV=development webpack-dashboard -- webpack-dev-server --config build/webpack.dev.conf.js",
    "start": "yarn run dev",
    "test": "yarn run unit",
    "unit": "jest --config test/unit/jest.conf.js --coverage"
  },
Enter fullscreen mode Exit fullscreen mode

Some have been setup by the template, some are mine, some like start-dashboard I'm not sure why are still there :-D

What I've learned (and not learned) in building this frontend

If you are still with me I would like to share a few general things I've learned:

  • Webpack it's not the easiest thing to configure. Sometimes you end up reading comments on issues on Github to see how to solve this or that thing.

  • Modern frontend development is definitely easier than in the past. Yes, learning Vue has a bit of a learning curve but the tooling it's amazing and webpack's hot reloader is magic (I really have no idea how all this stuff works and I'm not 100% sure I care)

  • Modern frontend development is faster for the developer. You introduce a bug, fix it in the editor, press ⌘-tab and the fix it's already there on the page (VSCode is configured to save upon loss of focus). Same thing for the interactions with the backend: I save a form in the frontend, the backend breaks because it has a bug in some function, I write the server side unit test, fix the code, press save again on the frontend and that's it. No refreshing, no re-inputing data in the form, no nothing.

  • Modern frontend development might not be faster for the user. The user doesn't know or care how you build your app and all of this JavaScript is scaring me a little. Not because of the technology itself but for the sheer size of it. Loading components at runtime with code splitting helps a bit but I haven't mastered everything yet.

  • Building reusable components in Vue is super easy: you basically just need to accept a value and emit an input event and you can send data from the child to the parent using v-model. I'll talk about it more in a future article.

  • I still haven't mastered code reuse in Vue. I have a few reusable components, a few mix-ins (mainly for validation) but I still have a lot of code duplication between the various components. I'm not worried, I'm sure it's going to disappear the more I learn (especially about slots)

  • I still haven't understood how nested routes work. My routes now are all logically flat inside the router, just the paths are nested.

  • I'm not using vuex. It's not like I don't know what it is for and I'll probably need it at some point but for now each component has its own state, the reusable ones talk to their parent using v-model and the main components state come from the backend on creation. Each component it's responsible for initialising itself, either through its own state (think about the "create new something" form) or through an API call.

Conclusions

I honestly think it would have taken me more time to ship this app if I had gone the "safe and paved way" without Vue.

I'm going to stop here because this article is already pretty long. I haven't talked about reusable components, tests and the backend. Expect more articles in the future :D

Discussion (0)

pic
Editor guide