Trying out front-end - Part 1 - Build & Debug

I stumbled across hyperapp recently. It made me realise it’s been a while since I’ve experimented with front end development so I thought I’d have a go at building a TODO app (as is tradition). I plan to do this as a series of posts with the following rules:

  1. Javascript - I’ve played a bit will elm. But I want to see what’s possible with js right now.
  2. I’ll do some research but not much. So the tools will hopefully be current but not bleeding edge.
  3. If I get stuck in weird frontend bug hacks I’m hitting eject.
  4. I’m not going to css - because reasons.

Getting something to build

So I’d already picked hyperapp as my starting point. I’ve also decided this is a good time to try out jsx. Jsx means I’m going to need to do some transformation. So now we need a build tool to turn my jsx infused javascript in to old javascript.

Hyperapp has instructions for using webpack as a build chain so I’ve now got the following in my stack so far:

So to NPM:

npm init
npm i hyperapp
npm i -D \
  webpack \
  babel-core \
  babel-loader \
  babel-preset-env \
  babel-plugin-transform-react-jsx

One thing to note is I’ve used babel-preset-env instead of babel-preset-es2015. This means I’ll be able to specify an environment in the future that I want to target.

With the above installed I setup

A .babelrc for babel:

{
  "presets": ["env"],
    "plugins": [
      [
        "transform-react-jsx",
        {
          "pragma": "h"
        }
      ]
    ]
}

and webpack.config.js to get webpack building:

module.exports = {
  entry: "./index.js",
  output: {
    path: __dirname + "/dist",
    filename: "bundle.js",
  },
  module: {
    loaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: "babel-loader"
    }]
  }
}

Something to actually build

I started off with a bit of tooling but now I want a skeleton app. Hyperapp is based on the elm architecture so an app has the following pieces:

I started with the state. I created a file src/todolist.js and decided I’d have a list of todos. In addition a nextTodo which is the todo currently being written:

const emptyState = {
    todos: [],
    nextTodo: {text: "", id: 0}
};

With the above state in mind I created two actions. One which takes a string and uses it for the text of the next todo. And a second action which takes the nextTodo pushes it on to the list then prepares a new clean todo.

const actions = {
    setNewTitle(state, _actions, newText) {
        let nextTodo = state.nextTodo;
        nextTodo.text = newText;
        return {
            nextTodo: nextTodo
        }
    },
    addTodo(state) {
        let updatedTodos = state.todos;
        updatedTodos.push(state.nextTodo);
        return {
            todos: updatedTodos,
            nextTodo: {text: "", id: state.nextTodo.Id + 1}
        }
    }
};

Now that I’ve got this basic (and possibly bug ridden - I’m getting to testing in part 2) logic I’ll create a view. For now this can live in the javascript entry point index.js:

'use strict';
import { h, app } from "hyperapp";

import {emptyState, actions} from "./src/todolist";

const view = ({todos, nextTodoTitle}, {addTodo, setNewTitle}) => (
    <div>
        <input type="text" id="new-title" onchange={e => setNewTitle(e.target.value)}/>
        <button onclick={e => addTodo()}>add</button>
        <ul>
            {
                todos.map((todo) => (<li>{todo.text}</li>))
            }
        </ul>
    </div>
);

app({state: emptyState, view, actions});

This doesn’t do too much at the moment:

The final step is to wrap this in some html:

<!doctype html>
<html>

<body>
<script src="dist/bundle.js"></script>
</body>

</html>

Notice I’m using dist/bundle.js as this is what my webpack build is going to output.

Running it.

I’ve created a build script in my package.json file:

  {
    // Rest of the file
    "scripts": {
      "build": "webpack -p",
      "test": "echo \"Error: no test specified\" && exit 1"
    }
    // more stuff
  }

so running npm run build creates everything for me.

I’m using intelij IDEA so I just need to click run index.html and I’m good to go.

Debugging it

Everything looked fine running it but I wanted to get a better idea of what was actually happening. This is where I’d normally fire up a debugger. Since the code has been transformed and minified I needed to buid a source map.

Adding this to webpack was pretty straight forward. I just need to add

module.exports = {
    //stuff
    devtool: 'source-map',
    //more stuff
};

now when I run the build my dist.js file gets a map too. I’ve already got an intelij debug extension installed in chrome so I create a few break points and click debug index.html.

Now that this shell is working I’ll stop for now and reflect on what I’ve got so far.

Questions

Next step(s)

Thoughts? Comments? Contact me on mastodon!