We held our second dedicated foodsharing hackweek at the start of July. The location was the same as our previous hackweek, in the lovely Kanthaus project.

Again, we were mostly the regular people (Matthias, Tilmann, and me), but Chandi also joined again with a pleasing burst of motivation, and we had a new contributor, Theo, come down from Berlin for a few days.

We got some really good things done, including:

  • getting all site JavaScript moved over to the new webpack environment
  • creating the first VueJS component
  • adding the first RESTful API endpoint
  • removing one whole layer of the database hierarchy
  • a shiny new and sleek README.md page

Matthias and Tilmann ponder for a while

Theo Symfony-wrangling in vim

Moving JavaScript to webpack

The existing site used JavaScript heavily for dynamic parts of the page, and this was added to the page via a few seperate approaches:

  • site-wide application and library code was built and minified and served up on every page
  • page-specific code could be added via:
    • specifying extra paths with a script tag
    • including chunks of JavaScript directly in the page
    • evaling scripts returned in XHR responses

All the page-specific scripts could be added via any kind of logic during the request (access permissions, page parameters, etc).

It meant a lot of areas of code with a combination of php/html/css/js which could be confusing to understand - the editor would have no idea how to make sense of the JavaScript and so could provide no assistance (e.g. for missing variables, undefined functions, etc).

The new approach was to use webpack to handle JavaScript. The more common use-case for webpack is for a Single Page Application (SPA) where there is one main entry point.

In the case of foodsharing most of the pages are rendered on the server, with JavaScript used to add extra functionality on the client. So, we decided to have one webpack entry per page, and that would be responsible for loading anything else required for that page (including libraries).

This way we remove the distinction between site-wide and page-specific scripts.

In some ways this was less flexible than the existing approach as we could no longer use backend logic to conditionally include some JavaScript, but gave us the advantage that we now had one tool that had oversight of all the JavaScript for each page.

… well, with one little catch, the site still makes use of global JavaScript references (inside click handlers, some of the leftover dynamically included JavaScript, and XHR response scripts) so we needed a way to expose some functions from the new wepack land back into the global scope.

This was achieved with a small utility function that can be used like this:

import { expose } from '@/utils'

function doSomething () {
  return 'hello'
}

expose({
  doSomething,
})

Here the code is:

  • importing the expose() utility function
  • defining a function inside this modules scope
  • exposing it globally via expose()

The expose() function is nothing clever, here is the full implementation:

export function expose (data) {
  Object.assign(window, data)
}

One of the benefits of the webpack approach is to seperate the concerns of the source code from the files that actually get loaded by the browser, we trust in the webpack asset optimization to cleverly manage the sharing of JavaScript between pages, which we can visualize with the Webpack Bundle Analyzer:

You can view the live interactive version too

The first VueJS component

I did the first experiments with adding VueJS to the site way back in October 2016, but it didn’t progress, partly as there were more pressing things to be doing, and also we didn’t have much other JavaScript infrastructure to support it nicely (no build system or npm libaries available).

In 2018 we are in a much better place! Chandi was able to add the first VueJS component for the store list with BootstrapVue providing the handy table sorter.

Since then he has enthusiastically been working on various other UI tasks.

One of the things we really liked about BootstrapVue is that we could import single components without dragging in the entire libary:

import bTable from '@b/components/table/table'
import bPagination from '@b/components/pagination/pagination'
import bFormSelect from '@b/components/form-select/form-select'
import bTooltip from '@b/directives/tooltip/tooltip'

We could also selectively import the styles from the standard Bootstrap 4 library in such a way that we can use them for regular server-rendered HTML too.

Say hello to the new VueJS rendered filterable store list!

RESTful API Endpoint

One of our newest contributors, Theo, was able to wrestle with mountains of Symfony yaml configuration to get the first RESTful API endpoint up and running!

The shiny new conversation API endpoint

This marks the start of a cleaner implementation for the XHR requests, using HTTP as God intended - the JavaScript conversations API helper looks nice and clean like this:

import { get } from './base'

export function getConversation (conversationId) {
  return get(`/conversations/${conversationId}`)
}

… which can be simply used in the code like this:

const { conversation, member, messages } = await api.getConversation(id)

You might notice we also get to use modern JavaScript features like import/export, async/await, and destructuring assignment.

Removing database class hierarchy

Previously the Model classes had a lot of hierarchy, for example:

MessageModel <- Model <- ManualDb <- Db

Where each of these parent classes often had unrelated or deuplicated methods.

The new approach is to move these into non-hierarchical Gateway classes, and then use composition (via DI) instead of inheritance. So the new ManualDb class looks like this:

<?php

namespace Foodsharing\Lib\Db;

class ManualDb extends Db
{
}

I guess it can be removed entirely soon…

Last but not least… a shiny README!

There is a current trend to have very pretty README pages with logos, screenshots, pictures, contributor lists, and emojis.

We were lacking in that department, but no longer!

You can see it at gitlab.com/foodsharing-dev/foodsharing (if you have access)

You might wonder where all the useful content has gone, that’s over at devdocs.foodsharing.network now. It needs some work still.

What next?

We normally have a burst of activity during the hackweek, then it goes quieter afterwards. I expect this will be no different.

In the short term there is some work to do to get some of the changes made during the hackweek ready for production deployment next week.

Chandi has continued his UI focus by working on a new responsive navbar, but he will leave soon to enjoy the summer festival season.

There are talks of having an Autumn hackweek hosted by Peter in Zürich, and then another back in kanthaus again next January or February.

You?

If this is the kind of thing you think you’d like to work on, come and chat to us in the #foodsharing-dev channel in yunity slack!