Skip to content

Use of Vue

Edward Hibbert edited this page Nov 20, 2020 · 5 revisions

This page documents some of the ways in which this codebase uses Vue.

Use from blade templates

We are migrating incrementally from blade templates to Vue.

  • Blade templates may include Vue components.
  • They do this by putting the Vue component inside a <div class="vue">.
  • Only one Vue component may go inside each such div.
  • Each component referenced from a blade template needs to be registered inside resources/assets/js/app.js. Any components included below that don't need to be registered.
  • There is usually a delay between the initial DOM loading on the client, and the (large) monolithic Javascript being parsed and executed, at which point the Vue components kick in. For the first Vue component on a page you should put in a placeholder like this: <div class="vue-placeholder vue-placeholder-large"> <div class="vue-placeholder-content">@lang('partials.loading')...</div> </div>
  • There isn't a full API which would allow the client to get data. Data is typically passed from the controller into the blade template and hence into the Vue component as props, JSON-encoded unless primitive.
  • Top-level Vue page components generally then put the initial data into a suitable Vuex store.

At some point this may result in a complete client-side app - but not yet.

Use of Vuex stores

  • Generally data which may change should go into a store. You often regret it later if you don't.
  • Some data (e.g. flags specific to a page) will be passed down using props.
  • Avoid use of $props as it leads to an unclear component interface.
  • Bear in mind the Law of Demeter. A component can reasonably expect its children or grandchildren to need access to data, and so it makes sense to pass it down through props. But beyond that, all is shrouded in darkness. If there is data which random components might need to access, put it in in a store.

Vuex stores don't support Map (they will in Vue3). This means that you often choose between:

  • An array, where you have an ordered list.
  • An object, where you have objects indexed by id.
  • Avoid rolling your own versions of Map if at all possible. For example it's OK to use a computed property to sort data extracted from the store. They're pretty fast for the amount of data we're dealing with.

When to use another component

Some considerations.

  • It's harder to disentangle things into components later, so if something has significant logic, err on the side of creating a sub-component.
  • If you are using the same logic in two components, then definitely extract that into a sub-component.
  • They're more efficient than you think, and using more components reduces the amount of re-rendering that needs to happen.
  • If something is inside a v-for, the default should be to use a component.
  • If you have shared JS logic, use a mixin.
  • Extending components is rare.

Infinite scroll techniques

Pages which load lots of data can be slow to render. This is usually because of the hit of inserting many elements into the DOM. The cost of passing data from the server and parsing the JSON encoded version is generally OK for the amount of data in this project (hundreds of items).

There are a complete of ways to make pages load faster where they have lots of data.

  1. Use vue-infinite-loading. The data is in memory, but you use a counter which is incremented in the loadMore callback and which determines (via a computed property) how much is used in the template. This means only the data that is needed to be visible is loaded into the DOM. This particularly speeds page load.
  2. Use a background timer. Again use a counter, but run it on a short timer until the all the data is loaded. One example of this is use of Bootstrap's b-table, where in order for the filtering to work all the data has to be passed into the component, even though it may not be visible on screen. This approach means that the page loads rapidly and then sorts itself out in the background without hanging the browser.