# Node.js / Build System
20161011 [<i class="fa fa-github"></i> Elantris](https://github.com/Elantris)
Note: https://hackmd.io/s/H1LliB_p
###### tags: `2016` `javascript` `handout`
## Node.js
[Official Site](https://nodejs.org/)
### Setup
Install Node.js.
* Mac
- [Homebrew](http://brew.sh/)
+ `brew update`
+ `brew upgrade`
+ `brew install node`
- [Homebrew-versions](https://github.com/Homebrew/homebrew-versions)
+ `brew tap homebrew/versions`
+ `brew install node4-lts`
+ `brew install node5`
* Windows
- Download
- Double click
- Next, next, next
- Done
* Linux
- Do It Yourself
Update Node.js.
* Mac
- `brew update` (now with auto-update)
- `brew upgrade`
* Windows
- Download
- Double click
- Next, next, next
- Done
* Linux
- Do It Yourself
Update NPM (Node Package Manager).
```sh
$ npm install --global npm // latest
$ npm install --global npm@2 // v2
```
Check versions.
```sh
$ node -v
v6.7.0
$ npm -v
3.10.8
```
### CLI Commands
```sh
$ npm i -g gulp pnpm
```
* [Gulp](https://github.com/gulpjs/gulp)
The streaming build system http://gulpjs.com
* [pnpm](https://github.com/rstacruz/pnpm)
Performant 'npm install' http://ricostacruz.com/pnpm
* [npm-check-update](https://github.com/tjunnone/npm-check-updates)
Find newer versions of package dependencies than what your package.json or bower.json allows
* [tldr](https://github.com/tldr-pages/tldr)
A collection of simplified and community-driven man pages.
* [Bower](https://github.com/bower/bower)
A package manager for the web http://bower.io
* [PM2](https://github.com/Unitech/pm2)
Production process manager for Node.js apps with a built-in load balancer http://pm2.io
### Module System
Every package in NPM is a module.
Everything in JavaScript is an object.
Export module.
```js
// square.js
function square(x) {
return x * x;
}
module.exports = square;
```
Import module.
```js
// index.js
var square = require('./square.js');
console.log(square(12));
```
### Node.js Project
Find a place to create a folder for a new Node.js project.
```sh
$ mkdir node-project
$ cd node-project
```
Prepare a NPM environment.
> (Keep pressing enter till the end.)
> It will create a file named `package.json`.
```sh
$ npm init
```
Install dependencies.
> https://github.com/jackdcrawford/five
> It will create a folder named `node_modules`.
```sh
$ npm install --save five
```
Write some codes.
```js
// index.js
var five = require('five');
console.log(five());
console.log(five.upHigh());
console.log(five.downLow());
```
Run scripts.
```sh
$ node index.js
```
## Build System
### Front End Tools
* Bower
https://bower.io
* ESLint
http://eslint.org
* Pug
https://pugjs.org
* Sass
http://sass-lang.com
* Babel
https://babeljs.io
* Browserify
http://browserify.org
### Sublime Text Packages
[Package Control](https://packagecontrol.io)
* Bagel
https://packagecontrol.io/packages/Babel
* CSS3
https://packagecontrol.io/packages/CSS3
* Emmet
https://packagecontrol.io/packages/Emmet
* HTML5
https://packagecontrol.io/packages/HTML5
* SCSS
https://packagecontrol.io/packages/SCSS
### Gulp
[Official Site](http://gulpjs.com)
Install packages with prefix of `gulp-`.
* gulp-if
https://github.com/robrich/gulp-if
* gulp-rename
https://github.com/hparra/gulp-rename
* gulp-sourcemaps
https://github.com/floridoo/gulp-sourcemaps
* gulp-cssmin
https://github.com/chilijung/gulp-cssmin
* gulp-uglify
https://github.com/terinjokes/gulp-uglify
* gulp-concat
https://github.com/contra/gulp-concat
* gulp-eslint
https://github.com/adametry/gulp-eslint
* gulp-bower
https://github.com/zont/gulp-bower
* gulp-sass
https://github.com/dlmanning/gulp-sass
* gulp-autoprefixer
https://github.com/sindresorhus/gulp-autoprefixer
```sh
$ git clone https://github.com/Elantris/react-boilerplate.git
```
Load dependencies in `gulpfile.js`.
```js
/*====================================
= Dependencies =
====================================*/
const fs = require('fs')
const clc = require('cli-color') // https://github.com/medikoo/cli-color
const moment = require('moment') // https://github.com/moment/moment/
// gulp
const gulp = require('gulp') // https://github.com/gulpjs/gulp
const gulpif = require('gulp-if') // https://github.com/robrich/gulp-if
const rename = require('gulp-rename') // https://github.com/hparra/gulp-rename
const sourcemaps = require('gulp-sourcemaps') // https://github.com/floridoo/gulp-sourcemaps
const cssmin = require('gulp-cssmin') // https://github.com/chilijung/gulp-cssmin
const uglify = require('gulp-uglify') // https://github.com/terinjokes/gulp-uglify
const concat = require('gulp-concat') // https://github.com/contra/gulp-concat
// tasks
const del = require('del') // https://github.com/sindresorhus/del
const eslint = require('gulp-eslint') // https://github.com/adametry/gulp-eslint
const bower = require('gulp-bower') // https://github.com/zont/gulp-bower
const sass = require('gulp-sass') // https://github.com/dlmanning/gulp-sass
const autoprefixer = require('gulp-autoprefixer') // https://github.com/sindresorhus/gulp-autoprefixer
const browserify = require('browserify') // https://github.com/substack/node-browserify
const watchify = require('watchify') // https://github.com/substack/watchify
const source = require('vinyl-source-stream') // https://github.com/hughsk/vinyl-source-stream
const buffer = require('vinyl-buffer') // https://github.com/hughsk/vinyl-buffer
const babelify = require('babelify') // https://github.com/babel/babelify
const lrload = require('livereactload') // https://github.com/milankinen/livereactload
const browserSync = require('browser-sync') // https://github.com/Browsersync/browser-sync
```
Utility functions.
```js
var env = process.env.NODE_ENV || 'development'
var colorLog = (color, message) => {
console.log(`[${ clc.blackBright(moment().format('HH:mm:ss')) }] ${ clc[color](message) }`)
}
var errorLog = (err) => {
colorLog('redBright', err.stack)
}
```
Configure gulp tasks.
* Clean the production files
```js
gulp.task('clean', () => del([
'./public/**',
'!./public',
]))
```
* Code Lint
```js
gulp.task('lint', () => gulp.src(['./src/react/**/*.jsx'])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
)
```
* Install bower dependencies and bundle all plugins
```js
gulp.task('bower-install', () => bower())
gulp.task('bower', ['bower-install'], () => {
gulp.src([])
.pipe(cssmin())
.pipe(gulpif(env === 'development', sourcemaps.init()))
.pipe(concat('plugins.min.css'))
.pipe(gulpif(env === 'development', sourcemaps.write('./')))
.pipe(gulp.dest('./public/css/'))
gulp.src([])
.pipe(uglify())
.pipe(gulpif(env === 'development', sourcemaps.init()))
.pipe(concat('plugins.min.js'))
.pipe(gulpif(env === 'development', sourcemaps.write('./')))
.pipe(gulp.dest('./public/js/'))
})
```
* Move static assets to public folder
```js
gulp.task('move', () => gulp.src('./assets/**')
.pipe(gulp.dest('./public/'))
.pipe(browserSync.stream())
)
gulp.task('move:watch', ['move'], () => {
gulp.watch(['./assets/**'], (event) => {
gulp.src(event.path)
.pipe(gulp.dest('./public/'))
})
})
```
* Compile sass into css
```js
gulp.task('sass', () => gulp.src('./src/sass/*.scss')
.pipe(gulpif(env === 'development', sourcemaps.init()))
.pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError))
.pipe(autoprefixer({
browsers: ['last 2 versions'],
cascade: false
}))
.pipe(rename({ suffix: '.min' }))
.pipe(gulpif(env === 'development', sourcemaps.write('./')))
.pipe(gulp.dest('./public/css/'))
)
gulp.task('sass:watch', ['sass'], () => {
gulp.watch('./src/sass/**/*.scss', ['sass'])
})
```
* Schedule all tasks
```js
gulp.task('default', ['bower', 'move', 'sass'])
gulp.task('watch', ['browser-sync'])
```
Use gulp.
```sh
$ gulp
$ gulp watch
$ gulp sass # single task
```
### React
[Official Site](https://facebook.github.io/react/)
```auto
// main.jsx
var React = require('react');
var ReactDOM = require('react-dom');
var App = React.createClass({
render: function() {
return (
<div>hello, world</div>
);
}
});
ReactDOM.render(<App />, document.getElementById('main'));
```
### Gulp For React
* Bundling function
```js
var dependencies = Object.keys(require('./package.json').dependencies)
var lib_bundler, app_bundler
var bundle = (b, output, mangle) => {
b.bundle()
.on('error', errorLog)
.pipe(source(output))
.pipe(buffer())
.pipe(gulpif(env === 'production', uglify({ mangle: mangle })))
.on('error', errorLog)
.pipe(gulp.dest('./public/js/'))
}
```
* Bundle jsx file and transform to browser compatible scripts
```js
gulp.task('react:lib', () => {
lib_bundler = browserify({
debug: (env === 'development'),
paths: ['./node_modules/']
})
for (var i in dependencies) lib_bundler.require(dependencies[i])
bundle(lib_bundler, 'main.lib.js', false)
})
gulp.task('react:app', () => {
app_bundler = browserify('./src/react/main.jsx', {
cache: {},
packageCache: {},
debug: (env === 'development'),
paths: ['./node_modules/'],
transform: [
['babelify', { presets: ['es2015', 'react'] }]
],
fullPaths: (env === 'development')
})
for (var i in dependencies) app_bundler.external(dependencies[i])
bundle(app_bundler, 'main.min.js', true)
})
```
* Watch changes
```js
gulp.task('react:watch', ['react:app'], () => {
app_bundler.plugin(lrload)
app_bundler.plugin(watchify)
app_bundler.on('log', (msg) => { colorLog('yellowBright', msg) })
app_bundler.on('update', (ids) => { bundle(app_bundler, 'main.min.js', true) })
})
```
### File Structures
```
./node-project/
├── gulpfile.js
├── package.json
├── assets/
| ├── fonts/
| └── img/
├── node_modules/
├── public/
| ├── index.html
| ├── css/
| ├── fonts/
| ├── img/
| └── js/
└── src/
├── react/
| ├── actions/
| ├── components/
| ├── stores/
| ├── utils/
| └── main.jsx
└── sass/
├── components/
├── layout/
├── plugins/
├── utils/
└── main.scss
```