Not really a blog, just some stuff that a future me might need to remember one day.
It’s easy to start with good intentions and then get sucked into an unnecessarily complicated toolchain. Maybe it’s best to start with a minimal setup.
When starting a new project in a language or framework that I’m still learning it’s hard to resist the urge to throw a whole load of tools and libraries into the project from the start just in case we might need them later. But YAGNI!
With front-end dev the temptation to overcomplicate things is particularly strong for me partly because the turnover of shiny new tools and JS frameworks is so rapid but also because it’s not something I do every day.
So I’m trying to build a simple TODO list and I want to focus on learning React.js in it’s simplest form to begin with.
All I want to begin with is:
Above all I want the tools that I choose to be easily replaceable in the future when requirements change, I’m pretty sure that I will make some wrong choices at the beginning.
When I’ve done this kind of thing before I’ve been tempted to scaffold my project with Yeoman. This is great for getting up and running but it doesn’t always help me to learn what I was trying to learn. For a start it drags in a lot of different tools. For example, you might end up with something like:
All of these things are great at what they do but I don’t need them all at the start and more importantly perhaps I don’t really understand what Yeoman has generated for me. For example, taking a peek at the Gruntfile I see a lot of stuff that I don’t understand. Without knowing all that stuff it’s hard then for me to customise and extend what I’ve got.
So let’s start by seeing how far I can get just with npm as a package
manager. I already have a reasonable idea of how this works and a
package.json
doesn’t look too scary. And I’ve heard that it is a
perfectly good front-end package manager. So to start with I can just
use npm to declare and install some dependencies starting with React:
$ cat package.json
{
"name": "todo-app",
"version": "0.0.1",
"description": "React.js Todo app",
"dependencies": {
"react": "^0.14.0"
},
"devDependencies": {
"browserify": "^6.2.0",
"envify": "^3.0.0",
"reactify": "^0.15.2",
"uglify-js": "~2.4.15",
"watchify": "^2.1.1"
},
"author": "Steve",
"browserify": {
"transform": [
"reactify",
"envify"
]
}
}
$ npm install
The other thing I need is something to help me integrate my own
JavaScript code with React and other dependencies. So that is why I’ve
got references to Browserify and some associated plugins in the devDependencies
section.
Browserify lets you write browser-side code as though it were running in
node.js. In particular, it lets us use node’s module system so that we
can modularise our own code and require
our dependencies, e.g.:
const React = require('react');
const MyComponent = React.createClass({
...
});
module.exports = MyComponent;
Because we have declared react
as a dependency in our package.json we
can import it using require
and we can export MyComponent
so that it
can in turn be required in other modules.
It’s probably about time I stopped just writing old-school JavaScript so.
Babel is a JavaScript compiler that takes ES6 or more properly ES2015 and converts it to ES5 that even older browsers understand. It’s pluggable and works well with Browserify.
I added the following config to my package.json
. This
sets Browserify up to include Babel transforms as part of the build
process. I’ve also configured Babel itself to use a package of preset
transforms for ES2015 (you can pick and mix which language features you
want to use).
"browserify": {
"transform": [
"babelify",
"envify"
]
},
"babel": {
"presets": [
"es2015"
]
},
By this stage I’ve already got a handful of tasks that I need to run repeatedly. I don’t want to type long commands and I might forget what they are if I revisit the project in a month’s time. I could add Grunt or Gulp to solve these problems but it turns out I already have a tool to do this, npm.
You can add these tasks to the scripts section of package.json
. For
example:
"scripts": {
"start": "watchify -o js/bundle.js -v -d js/app.js",
"build": "browserify . -t [envify --NODE_ENV production] | uglifyjs -cm > js/bundle.min.js",
"serve": "node_modules/.bin/http-server --cors --proxy http://localhost:9292/",
"test": "mocha --compilers js:babel-core/register --recursive"
},
Here I’ve defined scripts for the first four tasks I need:
start
runs watchify continuously so that as I update my
JavaScript source files the bundle.js
is automatically
regenerated.build
creates a minified and uglified version of my bundle.js
for production.serve
runs a tiny development Web server to let me play about
with the front-end. It only serves static content and I’ve got
my dynamic content running in a separate backend API Web server
on port 9292 so that’s why I am proxying unknown requests to
localhost:9292
.test
runs my tests. I’m using mocha here but that’ll need
another post to describe properly.I can run any of these scripts with the npm run
command, e.g.
$ npm run build
The test
and start
tasks are ‘standard’ tasks and can be run
without the run
command, e.g.
$ npm test
I will no doubt need more than this if and when the project gets any more complicated but for now it does the job and I can easily add to this list.
I’m quite happy with the tools I have and I feel I have a reasonable understanding of what I’ve set up. That means I am in a pretty good position to change it going forward. I like simple.