Zombo Reloaded

Using Modern Technologies:
Webpack, ES6, and SASS

Created by Jonathan Petitcolas (@sethpolma)

www.zombo.com

Pink fluffy unicorn addicted developer

Jonathan Petitcolas

marmelab developer:
Node.js, Angular, React, [any exciting technology]

Open-source contributor

ng-admin: add an AngularJS admin GUI to any RESTful API

ng-admin: https://github.com/marmelab/ng-admin

Open-source contributor

EventDrops: A time based / event series interactive visualization using d3.js

EventDrops: https://github.com/marmelab/EventDrops

Organizer of Apéros Web Nancy

Apéros Web Nancy: a monthly tech meetup

Twitter: @AperoWebNancy

Social Networks

FriendFace, a discrete reference to IT Crowd

Twitter: @Sethpolma | GitHub: jpetitcolas

Webpack
Webpack

Bootstraping Webpack


$ npm init
$ npm install --save-dev webpack


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Zombo Reloaded</title>
</head>
<body>
    <h1>Zombo.com</h1>
    <script src="build/js/zombo.js"></script>
</body>
</html>
// js/copyright.js
var year = new Date().getFullYear();
console.log('© Zombo.com • All rights reserved • 1999-' + year);
// js/sound.js
setInterval(function () {
    console.log('Zombo.com... The Only Limit is Yourself!');
}, 1000);
// webpack.config.js
module.exports = {
    entry: {
        zombo: [
            './js/copyright.js',
            './js/sound.js'
        ]
    },
    output: {
        path: 'build/',
        filename: 'js/[name].js'
    }
};
$ ./node_modules/.bin/webpack
$ gnome-open index.html
Webpack bootstrapped

Transpiling ES6 to ES5

(aka Babel)


$ npm install --save-dev [email protected] [email protected]
// webpack.config.js
module.export = {
     // ...
     module: {
          loaders: [
               {
                    test: /\.js$/,
                    loader: 'babel',
                    include: __dirname + '/js'
               }
          ]
     }
}
// js/copyright.js
const year = new Date().getFullYear();
console.log(`
	© Zombo.com
	All rights reserved
	1999-${year}
`);
// js/sound.js
setInterval(() => {
    console.log('Zombo.com... The Only Limit is Yourself!');
}, 1000);
// build/js/zombo.js
function(module, exports) {
  "use strict";
  var year = new Date().getFullYear();
  console.log("© Zombo.com\n 1999-" + year + "\n");
},

// ...

function(module, exports) {
  'use strict';
  setInterval(function () {
    console.log('Zombo.com... The Only Limit is Yourself!');
  }, 1000);
}

Use Webpack with Style!


$ npm install --save-dev style-loader css-loader
// webpack.config.js
entry: {
    zombo: [
        // ...
        './style/style.css'
    ]
},

module: {
    loaders: [/* ... */ {
        test: /\.css$/, loader: 'style!css',
	include: __dirname + '/style'
    }]
}

Dare Webpack with SASS!


$ npm install --save-dev sass-loader compass-mixins
// webpack.config.js

var sassOptions = [
    'includePaths[]=./node_modules/compass-mixins/lib/',
].join("\n");

module: {
    loaders: [{
        test: /\.scss$/,
        loader: 'style!css!sass?' + sassOptions,
        include: __dirname + '/style'
    }]
}
// style/style.scss

@import "compass/css3";

html, body {
    height: 100%;
}

body {
    @include background-image(
        linear-gradient(to bottom right, green, yellow)
    );
}
Zombo Reloaded with SASS

Live Reload

Smart setup for lazy developers

Webpack Dev Server

  • Links to the browser using Socket.io
  • Serves content through a Web server: no more AJAX issues
  • All updates are done in RAM: that's blazing fast!

$ npm install --save-dev webpack-dev-server

$ ./node_modules/.bin/webpack-dev-server --inline --hot

Zombo Reloaded

Serious matters start here!

Header

<!-- index.html -->

<header>
    <h1>
        <a href="/">
            <img src="img/zombo.png"
                alt="Zombo Reloaded"
                title="The only limit is yourself!" />
        </a>
    </h1>
</header>
// style/style.scss
$green: #3DB871;

header {
    @include background-image(
        linear-gradient(to bottom, $green, #fff)
    );
    padding: 2rem;
    height: 8rem; line-height: 6rem;
    h1 {
        text-align: center;
        img {
            max-width: 100%;
        }
    }
}
Zombo Reloaded header

Central animation

Header

<!-- index.html -->
<article>
    <img src="img/circles.png"
        alt="Circles"
        title="Circles" />
</article>
// style/style.scss
@include keyframes(spin) {
    100% { @include transform(rotate(360deg)); }
}

@include keyframes(fade) {
    0% { @include opacity(1); }
   50% { @include opacity(0); }
  100% { @include opacity(1); }
}

article {
    text-align: center;
    padding-top: 5rem;
    img {
        width: 30%;
        @include animation(
            spin 1s linear infinite,
            fade 0.3s linear infinite
        );
    }
}

Audio

<!-- index.html -->
<audio loop="true" autoplay="true">
	<source src="zombo.ogg" type="audio/ogg">
	Your browser does not support audio. What a pity!
</audio>

Thanks to JuJu2Cast Network for sound track!

Deploying to Production

HTML Plugin

$ npm install --save-dev html-webpack-plugin
// webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    // ...
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: __dirname + '/index.html',
            hash: true, // enable cache busters
        })
    ]
};
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>{%=o.htmlWebpackPlugin.options.title || 'Zombo'%}</title>
    <link href="{%=o.htmlWebpackPlugin.files.css %}" rel="stylesheet">
</head>
<body>
	<!-- Previous body content -->
	<script src="{%=o.htmlWebpackPlugin.files.js %}"></script>
</body>
</html>

Move style into external file

$ npm install --save-dev extract-text-webpack-plugin
// webpack.config.js
var ExtractText = require('extract-text-webpack-plugin');

module.exports = {
    loaders: [{
        test: /\.scss$/, include: __dirname + '/style',
        loader: ExtractText.extract('css!sass?' + sassOptions)
    }],
    plugins: [
        // ...
        new ExtractTextPlugin('style.css', {
            allChunks: true,
        })
    ]
};

Optimizing build

$ ./node_modules/.bin/webpack -p

File loader

$ npm install --save-dev file-loader
// webpack.config.js
var images = function (path) {
    return fs.readdirSync(path).map(function (i) {
        return path + '/' + i;
    });
};

module.exports = {
    entry: [
        // ...
    ].concat(images(__dirname + '/img')),
    loaders: [{
        test: /\.png$/, include: __dirname + '/img',
        loader: 'file?name=[path][name].[ext]'
    }]
};

Any questions?

THE END