Prototype toolkit

A collection of tools for rapid prototyping.

Web

Use Web, unless native features are required. Web presents the lowest barrier to entry in terms of development (across client and server), and deployment.

Build

Use watchify. It’s simple and stable.

Watch Rollup. Its dependency on ES6 syntax simplifies things, and its API is a balance of browserify’s simplicity and webpack’s configurability. Additionally, it uses a proactive form of dead code elimination, which may be more efficient.

NPM boilerplate:

{
  "scripts": {
    "start": "watchify main.js -o demo/bundle.js -v",
    "serve": "serve"
  },
   "devDependencies": {
    "serve": "^6.2.0",
    "watchify": "^3.9.0"
  }
}

Language

Use ES6 (for concision and to simplify client and server dev)

Type safety is helpful for non-trivial code bases, but the goal in prototyping is to get customer feedback for the lowest cost; we can refactor to something type-safe once we’ve found product-market fit.

HTML diffing

Use diffhtml. Dodson enthusiastically recommends it and it’s worked well for me.

Custom elements

Use web components with ES6 classes. Dodson describes the benefits well.

Web components are well-supported natively and via polyfills.

Example widget:

import {html, innerHTML} from 'diffhtml'

class Widget extends HTMLElement {
  static get is() { return 'x-widget' }
  connectedCallback(){
    this.emojis = {
      smile: '🙂',
      grin: '😁'
    }
    this.filter = ''
    this.render()
  }
  render(){
    const options = Object.keys(this.emojis)
      .filter(name => name.startsWith(this.filter))
      .map(name => {
        const emoji = this.emojis[name]
        return html<span data-name="${name}">${emoji}</span>
      })
    innerHTML(this, html<div class="options"> ${options} </div>)
  }
}
export default Widget

Registration boilerplate:

[Widget].forEach(el => {
  if (!window.customElements.get(el.is)) {
	window.customElements.define(el.is, el);
  }
})

Note is naming convention consistent with Polymer.

Note event listeners bound externally to separate behavior from markup, and to survive template inlining, eg via Babel:

connectedCallback(){
  this.render()
  this.composer = this.querySelector('textarea')
  this.composer.addEventListener('keyup', this.onKeyUp.bind(this))
}

Services

Bias towards HTTP, REST and a widely-used, terse framework: Express JS.

File upload

const app = express()
const storage = {}
const upload = multer()

// $ curl -v -F 'value=@val1.txt' http://localhost:3000/key1
app.post('/:key', upload.single('value'), (req, res) => {
  storage\[req.params.key\] = req.file.buffer.toString() res.end()
})

app.get('/:key', (req, res) => {
  res.send(storage\[key\])
  res.end()
})

Custom browser headers

Use ModHeader to set custom headers, eg:

Feedback

Thoughts? Suggestions? Hit me up @erikeldridge

License

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 International License, and code samples are licensed under the MIT license.