Skip navigation
All People > ddraper > Dave Draper's Blog > 2016 > December
2016

Dave Draper's Blog

December 2016 Previous month Next month

My First NPM Package

Posted by ddraper Dec 28, 2016
This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

 

At the end of my last blog post I was looking at ways in which to write better components by abstracting as much non-browser specific code to utility modules. The idea of this was to improve testing so to minimize the amount of code that needed to be tested against multiple browsers. The side-effect of this approach means producing common capabilities that can be easily re-used against multiple web application frameworks such as Vue.js, React, Angular, etc.

 

As I developed my application I found myself pulling in more and more code and configuration that was already available in one of the many Vue.js CLI template projects. Most UI frameworks now come with a CLI that makes it easy to rapidly build out an application. I want to test out other frameworks so I thought it would make sense to abstract the core authentication and routing code into a separate project so that it could be imported into multiple different projects created using a CLI.

 

I followed some of the approach in this blog post and then mostly following these instructions on setting it up as an NPM package. Some useful information on testing the package prior to publication in described here. It was also necessary to follow this information in order to create a package with multiple exports.

 

The end result means that it is now possible to to install this new package with the following command:

npm install alfresco-auth-router --save-dev

 

Or if you prefer Yarn:

yarn add --dev alfresco-auth-router

 

Then it is just a simple case of setting up the Passport.js and Express routing using the following code in the server.js file:

passport.use(alfrescoAuthRouter.passportStrategy());
passport.serializeUser(alfrescoAuthRouter.serializeUser);
passport.deserializeUser(alfrescoAuthRouter.deserializeUser);
server.use('/auth', alfrescoAuthRouter.authRoutes(passport));
server.use('/proxy', alfrescoAuthRouter.apiRoutes());

 

This should make it much simpler to test out lots of different UI frameworks on Node.js against REST APIs provided by an Alfresco Repository. You can view this in my project by checking out this tag.

This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

 

At the end of my last blog post I had got some initial unit tests working using Karma for my Vue.js client running on a Node.js stack. One of the great things about Aikau is the automated testing that we setup in an attempt to prevent us introducing regressions into our code. The main problem that we now have is that a full regression test on 2 browsers takes around an hour to complete. Whilst this is a reasonably manageable amount, it is not ideal for continuous integration testing where ideally you want to capture bugs as soon as they're introduced.

 

The other thing that I wish I had done differently was to create a greater separation between the "pure" JavaScript code and the code that was tied to the working with the browser DOM. In theory it should only be necessary to test web application code on different browsers where the code may actually behave differently - this would typically be when it was working with the DOM to build the interface that is used. It is of course true that different browsers have different JavaScript engines, but typically there shouldn't be a huge amount of difference - especially if you're coding to the lowest common denominator. 

 

There is a good example of this in the breadcrumb component that I am building. In the Vue.js component we are "watching" (i.e. responding to changes on) the relative path attribute. When a change to the value occurs the component builds a new breadcrumb trail from this updated path:

watch: {
   relativePath: function() {
      let lastPathElement = '/';
      this.breadcrumbs = [{
         label: 'Home',
         relativePath: lastPathElement
      }];
      this.relativePath
         .split('/')
         .filter(function(name) {
            return name.trim() !== '';
         })
         .forEach(function(pathElement) {
            let relativePath = lastPathElement + pathElement + '/'
            this.breadcrumbs.push({
               label: pathElement,
               relativePath: relativePath
            });
            lastPathElement = relativePath;
         }, this);
   }
},

 

This function is highly unlikely to behave any differently when run in Chrome, Firefox or Internet Explorer (especially since it's getting transpiled through Babel to ES5). As it is currently written it would have to be tested with multiple permutations on multiple browsers and because it is embedded within a Vue.js component it would also be necessary to drive the tests through the browser and handle all the associated waiting around for the DOM to be updated, etc. 

 

A much better solution would be to abstract this function to a separate module that could be much more easily tested. If it was placed in a module like this:

export default class Breadcrumb {
   static createBreadcrumbs(input) {
      let lastPathElement = '/';
      let breadcrumbs = [{
         label: 'Home',
         relativePath: lastPathElement
      }];
      input.relativePath
         .split('/')
         .filter(function(name) {
            return name.trim() !== '';
         })
         .forEach(function(pathElement) {
            let currRelativePath = lastPathElement + pathElement + '/';
            breadcrumbs.push({
               label: pathElement,
               relativePath: currRelativePath
            });
            lastPathElement = currRelativePath;
         });
      return {
         lastPathElement: lastPathElement,
         breadcrumbs: breadcrumbs
      };
   }
}

 

...it could then be used in the component like this:

watch: {
   relativePath: function() {
      let breadcrumbData = BreadcrumbUtil.createBreadcrumbs({
         relativePath: this.relativePath
      });
      this.breadcrumbs = breadcrumbData.breadcrumbs;
   }
},

 

And have a much simpler tests written for it like this:

describe('Breadcrumb Util', () => {
   it('should generate home breadcrumb for root', () => {
      let breadcrumbs = BreadcrumbUtil.createBreadcrumbs({
         relativePath: '/'
      });
      expect(breadcrumbs.breadcrumbs).to.have.lengthOf(1);
  });
});

 

As well as the tests being faster and more reliable, it has one other major advantage.... this utility function could be easily used by applications built using other UI frameworks such as React or Angular. 

 

I think that this would be a good approach to developing and testing web application components - the tests could be running constantly and incredibly quickly in the background to give you immediate feedback when you make any changes that break a test and the code would be much more easily portable and re-usable between frameworks.

Unit Testing with Karma

Posted by ddraper Dec 22, 2016
This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

 

At the end of my last post I'd got to the point where I had something working. I could quite conceivably have continued developing but it makes sense to get some automated testing in place to ensure that I don't break anything that I've previously implemented. I've also got into the practice of Test Driven Development (TDD) and find it very rewarding.

 

For Aikau we've always used Intern for automated testing but I wanted to investigate other options that were available. On doing some research I found another Vue.js project template that met my needs. Once again thought I didn't want to start over and I also wanted to understand what the project provided so I started to copy across the unit test elements and try them out. Each time I hit a failure (usually the result of a missing NPM package) I would debug and resolve the problem. My once small package.json file is suddenly bloating out of control and I wanted to make sure that I was only pulling in the packages that I really needed.

 

The project template was using Karma for unit testing (I've not looked at end-to-end testing yet) but the template provided was actually much more complex that I wanted to use so I made the effort to just use the pieces I want for the time being.

 

The first thing to do was so update the main List.vue component so that it no longer made XHR requests itself, but instead used a service that was provided for accessing the data. The idea behind this was to avoid needing to setup Sinon.js for mock XHR handling. However, I wasn't able to get the tests working using the approach described in the documentation.

 

This is no bad thing as moving the data handling out to a service makes the List component much more re-usable. Especially as the new V1 REST APIs have a consistent response schema (meaning that it will be easy to add different services for different APIs). 

 

In the end I resorted to setting up a Sinon.js server and used the json-loader for webpack to load some mock a mock response from a file. Since I've only just got started with this testing approach I'm not sure of how to do everything yet - however one immediately problem was in handling asynchronous loading of elements. Intern provides some excellent capabilities through Leadfoot for waiting for elements to appear and disappear.

 

I'm sure there's a better solution but for the time being I've just used a simple timeout, however this approach won't scale as it forces the test to wait for a maximum amount of time before checking the DOM for the object.

 

My single test looks like this thought:

import Vue from 'vue';
import List from '../../../src/components/lists/List.vue';

// Import a fake response...
var nodes = require('json-loader!./Nodes.json');

// Create our mock server...
var server= sinon.fakeServer.create();
server.autoRespond = true;
server.xhr.useFilters = true;
server.respondWith('GET',
                  /(.*)/,
                  [200,
                   {'Content-Type':'application/json;charset=UTF-8'},
                   JSON.stringify(nodes)]);

// Describe the tests...
describe('List.vue', () => {
  it('should render correct contents', (done) => {
    const vm = new Vue({
      el: document.createElement('div'),
      render: (h) => h(List),
    });
    setTimeout(function() {
        expect(vm.$el.querySelector('li.components-lists-ListView__item').textContent).to.equal('Data Dictionary');
        done();
    }, 1500);
   
  });
});

 

...and I've proven that it works:

ESLint "Fun"

Posted by ddraper Dec 22, 2016
This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

At the end of my last blog I'd converted switched from a "Content Distribution" approach to Components to using a single file component approach using vue-loader. I now had a simple Vue.js application that I could use to browse the "Company Home" on an Alfresco Repository. However although I could drill down into folders I was unable to come back out of them. To complete the basic navigation handling I decided to implement a breadcrumb component. 

 

As I started to implement this new component I realised that I was no longer being informed of JavaScript errors by my the trusty JSHint Gutter package that I have been using on Sublime Text. This was because it was unable to validate my new .vue files that contained my component code. 

 

Fortunately the vue-loader documentation provided some useful information on setting up linting for .vue files using ESLint and the eslint-html-plugin. Installing these was pretty straight forward but getting Sublime to make use of them proved difficult because I was using NVM.

 

To cut a long story short it seems that when starting Sublime my bash profile wasn't including the paths set by NVM. I need to fully implement the solution provided here... but the simple workaround is just to launch Sublime from a new terminal.

 

I'm now in the process of tweaking my ESLint configuration in my project specific .eshintrc.js file and am slowly getting it to fit my preferences.

 

At the same time I've added the breadcrumb. You can view the state of my project at the time of writing by checking out this tag.

 

I plan to learn as much as I can about accessibility as I implement this client so did some research on accessible breadcrumbs and found this useful post (which despite being quite old still seems relevant). This means that whilst my breadcrumb trail is functional (and accessible) it looks very strange! I'm more interested in accessibility and function than style at the moment but will return to the visual look later. 

 

The next step now that I have some basic functional components is to both focus on accessibility and figure out the best automated testing strategy.

 

This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

At the end of my last post I had decided to move away from a "Content Distribution" approach for my new Vue.js Alfresco client and move towards a single file component approach. You can view the state of my project at the time of writing by checking out this tag.

 

My original thought was that I would just move my components from the main app.js file into 3 separate files and use ES6 importing and exporting (as now handled by webpack / babel). However as I read through the documentation and various blog posts (including the one I originally started from) I realised that the recommended approach was to use vue-loader either via vueify or the Vue.js CLI.

 

This presented a minor problem in that I already had an established project and didn't want to just start over. Fortunately there are various templates for different build approaches (such webpack as I was using) and it was a relatively simple exercise to install the missing packages defined in the template package.json with yarn and copy across the additional config into my webpack.config.js file.

 

The vue-loader module allows you to write your Vue.js components in files with a .vue extension that are essentially an HTML file containing the following 3 elements:

<style></style>
<template></template>
<script></script>

 

In order to better edit these files I installed a new syntax highlighting package for Sublime Text (which is my editor of choice).

 

I was now able to create a .vue file for each of the 3 components. As an example the smallest is currently ListView.vue:

<style></style>

<template>
   <ul>
      <li v-for="item in list.entries">{{item.entry.name}}</li>
   </ul>
</template>

<script>
   export default {
      props: ['list']
   }
</script>

 

A couple of things that I noticed were that the file name needs to match how I use it as a custom element. I discovered that is is necessary to define your component names in JavaScript  in camel-case (i.e. "ListView") but that you can refer to them in the template as lisp-case (also sometimes referred to as "kebab-case" or "spinal-case") (i.e. "List-View").

 

As predicted I was able to get rid of my global bus (that I had to use with the content distribution approach) so the volume of code actually reduced.

 

The main disadvantage that I can see is that my outer component (List) now directly declares it's sub-components as both dependencies and in it's template:

<template>
   <div>
      <Toolbar :list="list" @pageForward="pageForward" @pageBack="pageBack"></Toolbar>
      <List-View :list="list"></List-View>
   </div>
</template>

 

However, Vue.js does provide a way in which components can be extended (through what they call mixins) which should make it possible to extend List and update the template to use a different view component for example.

This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

 

At the end of my last post I'd got my Node.js based application set up and was accessing data from an Alfresco Repository over axios and rendering it in a simple Vue.js component. I now wanted to explore building out some interaction with the data that was being loaded and I decided to make a start by building some basic pagination controls. You can view the state of my project at the time of writing by checking out this tag.

 

After several years working on Aikau I find it very difficult to break away from the practice of writing small, re-usable and abstract components. I've also spent a lot of time thinking about how I would implement list handling if I had the chance to do it again. I think that I got a lot write with the way I implemented the AlfList widget in Aikau in that it was predominantly used just for managing the list state but I wish that I'd used it to encapsulate all the controls that would update the  list so that I could make better use of event bubbling. Therefore I naturally took this as an opportunity to investigate that approach.

 

In an ideal world I'd love to get to the point where you can just build up a page using custom elements (i.e. Web Components) and Vue.js refers to this as "Content Distribution" (which is called "transclusion" in Angular). It would be great if you could build an Alfresco client directly into an HTML page with custom elements similar to this:

<alf-list>
  <alf-list-toolbar>
    <alf-list-paginator></alf-list-paginator>
  </alf-list-toolbar>
  <alf-list-view>
  </alf-list-view>
</alf-list>

 

However, I've gotten so far (with Vue.js) is what you see in my code currently:

<alf-list>
  <template scope="props" slot="before-view">
    <alf-list-toolbar :list="props.list"></alf-list-toolbar>
  </template>
  <template scope="props" slot="view">
    <alf-list-view :list="props.list"></alf-list-view>
  </template>
</alf-list>

 

The additional template elements act as a way in which properties can be passed from parent component to child component assigned to a slot. Now whilst this does work it feels less intuitive and seems to result in another problem in that custom events can't be emitted from child component to parent component without the aid of a "global event bus".

 

The implementation I currently have does work and the use of one-way data flow works really nicely in that the pagination buttons emit an event to page forwards or backwards and the list component requests new data which when set will automatically cause the pagination controls and view to refresh.

 

 

Despite the current code working I'm going to switch to a more standard development approach where each component simply references another directly in it's template rather than trying to use slots. I might revisit the content distribution option later and investigate how other frameworks address it.

Getting Started with Vue.js

Posted by ddraper Dec 21, 2016
This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

 

At the end of my last post I had got my Node.js server setup so that I could authenticate against a local Alfresco Repository such that it would act as a proxy for making REST API calls. I also had webpack configured to handle building my application code with hot-reloading (using Babel to transpile my JavaScript).

 

You can view the project code at the time of this blog post by checking out this tag.

 

I now wanted to start building out some client-side code. My initial plan is to test out lots of currently available UI frameworks (React, Aurelia, Ember, etc) to see how they compare... but I've become increasingly interested in Vue.js so wanted to initially start with that.

 

I installed Vue.js using yarn, but the the first gotcha I encountered was the issue with standalone vs runtime only versions which just goes to show that it pays to properly read the documentation! This was quick to resolve with the suggested approach of adding an alias - however this will mean that should I wish to ever deploy the application that I would almost certainly need a separate webpack configuration file for production deployment.

 

The next issue was an absence of source maps which meant it was harder to debug my code. This was quickly solved following the documentation here and here. Essentially it was just a case of updating my webpack.config.js file to include:

 

...
devtool: 'source-map',
...

 

...although there are other source map values that can be used.

 

Once I had Vue installed it was relatively simple to just build a simple component to list the contents of Company Home:

 

import Vue from 'vue';
import axios from 'axios';

Vue.component('alf-list', {
   template: `<ul id="example-1">
      <li v-for="item in items">
       {{ item.node.properties["cm:name"] }}
     </li>
   </ul>`,
   data: () => ({
      items: [],
   }),
   beforeMount() {
      axios.get('/proxy/alfresco/slingshot/doclib2/doclist/all/node/alfresco/company/home')
         .then(response => {
            this.items = response.data.items;
         });
   }
});

var vm = new Vue({
   el: '#app'
});

 

This code fragment defines a new component that before being "mounted" (see the life-cycle) uses axios to request the data from the Repository (going via the proxy set up in a previous post). When it mounts it then iterates over the items loaded from the repository and renders the name of each of them as an individual element in a list.

 

 

At the moment this obviously doesn't handle any kind of browsing of the data and it is not sensibly split out into separate files for the components - however, the essential building blocks are now in place - the ability to retrieve and render data.

This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

At the end of my last post I'd got to the point where I'd set up a basic Node.js server that supported authentication via Passport.js and acted as a proxy for authenticated requests to an Alfresco Repository.  I've since update my project to use yarn and webpack (check out this tag for the revision at the time of writing this post).

 

As I did previously I started by doing some research into the various build tools that are available. The blog post that I'd followed to set up authentication was using Browserify, but after reading various blog posts (like this one) I decided to go with webpack.

 

I found this excellent post on webpack 2 (which at the time of writing is not officially released). The example described was using yarn instead of npm and in the spirit of wanting to try out new things (and already being familiar with npm) decided to give it a go.

 

There's not a huge amount to add to the main post on setting up webpack as it is so good, however I did end up using a different version (as is often the way, blog posts date very quickly when specifying versions so I won't even say which version I ended up using!).

 

The other major difference was in setting up the hot-reloading. The blog recommends using webpack-dev-server but this would provide an entirely different server and wouldn't provide me with all the authentication work that I'd previously done. Instead I switched to using webpack-dev-middleware.

 

The difference is that I configure my Express server to use the additional middle-ware for building the source. This required only the following code to setup:

// Setup webpack middleware...
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpack = require('webpack');
const webpackConfig = require('./webpack.config');
const compiler = webpack(webpackConfig);
server.use(webpackDevMiddleware(compiler, {
publicPath: '/'
}));

This then worked with the exact same configuration that the blog post example had setup.

 

The main immediate benefit of setting this up was that I could remove the CDN loading of axios (that I was using for client-side XHR handling) and replace it with a simple import statement in my "app.js" file (of course I needed to ensure that my webpack built "app.bundle.js" was being loaded on my web page instead!)

 

This now means that I can use ES6 code in my JavaScript and don't need to worry about restarting the server between changes.

 

The next stage will be to get some initial components written and set up some testing for them.

This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

Most of the web development work that I've done for Alfresco has been on a Java web-server stack (i.e. Tomcat, Spring, Surf, Aikau) and doesn't give me a lot of practical opportunities to keep up with modern web development. Therefore I've decided to work through the creation of a web client based on Node.js to experiment, learn and hopefully feed that knowledge back into Alfresco.

 

Rather than picking up any of the readily available CLIs or tooling I wanted to go right back to basics to understand how everything works. The first thing I needed to do was get a server up and running that I could use to access data from an Alfresco Repository. 

 

I've created a new personal GitHub repository for this project and will tag it at each stage of the development process. To see the code created at the point at which this post was written you should clone the repository and checkout the Blog1 tag.

 

Before starting I did some research into what authentication modules were available for Node.js and found that the most popular one seemed to be Passport.js. I found a number of useful blog posts during my search such as these:

 

 

...but the one I found most useful was this one: Create an App in VueJS 2 

 

Although predominantly about VueJS it contains some really useful information on using Passport.js.

 

The main problem I had with all of these blog posts is that they were either describing how to setup local authentication (i.e. authenticating against a local database) or using 3rd party authentication (such as Facebook or Google) via redirection.

 

The solution I was looking for was to take the user credentials provided on login and verify them against an Alfresco Repository. There is a login WebScript supporting HTTP POST provided on the Alfresco Repository at /service/api/login that will return a "ticket" attribute that can be appended as a request parameter to all subsequent REST API calls for authentication.

 

The solution I implemented was to use the "LocalStrategy" and use the "http" module for Node to make an XHR request to the Alfresco Repository when authentication is required. The asynchronous nature of the request was not a problem because the LocalStrategy instance provides a "done" callback that is used to provide the authenticated user information.

 

The next important thing to handle was the serialization and de-serialization of this user data. It was important to store the ticket value on the user object so that we would have access to it later so I took the approach of simply creating a map of username to ticket (although to be perfectly honest due to the single threaded nature of Node.js I'm not actually sure that a map is required - perhaps someone can verify this!). 

 

The last thing to implement was a simple proxy for REST API requests. This was achieved by configuring the Express Router. My configuring a URL endpoint of "/proxy/alfresco" (to match what Alfresco Share currently provides) I was then able to create a simple proxy handler that would append the remainder of the requested URL in a call to "/alfresco/service" on the Alfresco Repository (being sure to also append the session ticket!). 

 

It is necessary to define routers for every HTTP method that you want to support (so far I've just added GET, POST, PUT and DELETE) and ensure that request parameters and/or body is passed on to the repository.

 

Essentially this is a hugely simplified implementation of one of the many capabilities that Surf offers. It should also be possible to support multiple endpoints (i.e. for an Activiti server perhaps?) assuming that the user credentials are the same. 

 

I also need to look further into any potential security issues around this implementation (this blog post provides a useful reference) so I wouldn't be rushing to push an approach like this into production. However, for my purposes this is a sufficient first step in building an Node.js based client for Alfresco.

 

Now that I'm able to access data from the Alfresco repository the next step will be to start building out an application using that data.