What is it like to do front-end in 2018?

Vyacheslav Koldovskyy
programmingmentor.com

HTTP

HTTPS is a must

more than 65% websites use HTTPS today, expected to be more than 90% in 2018

Why do we should care?

Mixed Content

Blocked Certificates

TLS Handshake

What's wrong here?

HTTP/2 Era

HTTP/2

HTTP/2 Push

HTTP/1.x

  • Requests are slow
  • Domain Sharding
  • Concatenation
  • Spriting
  • Inlining

HTTP/2.x

  • Requests are fast
  • Lazy loading
  • Push
  • Domain Sharding
  • Concatenation
  • Spriting
  • Inlining

HTML

HTML 5.1

<picture>
<picture>
        <source media="(min-width: 650px)" srcset="images/kitten-large.png">
        <source media="(min-width: 465px)" srcset="images/kitten-medium.png">
        <img src="images/kitten-small.png" alt="a cute kitten">
</picture>

zero-width images

<img src="https://stats.com/c?sample.com" width="0" height="0" alt="">
<details>/<summary>
<h2>Error Message</h2>
<details>
    <summary>We couldn't finish downloading this video.</summary>
    <dl>
        <dt>File name:</dt><dd>yourfile.mp4</dd>
        <dt>File size:</dt><dd>100 MB</dd>
        <dt>Duration:</dt><dd>00:05:27</dd>
    </dl>
</details>
<menu>/<menuitem>
<button contextmenu="rightclickmenu">Right click me</button>
<menu type="context" id="rightclickmenu">
    <menuitem type="checkbox" label="I ♥ HTML5.1.">
</menu>

Inline scripts are evil

Good practice: disable inline JS with CSP

Content-Security-Policy: script-src https://example.com/
nonce attribute
<script nonce=EDNnf03nceIOfn39fn3e9h3sdfa>
  //Some inline code I cant remove yet, but need to asap.
</script>

If you absolutely must use it ...

Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'

rel="noopener"

<a href="#" target="_blank" rel="noopener">
  Your link that won't make troubles
</a>
  • When your page links to another page using target="_blank", the new page runs on the same process as your page. 
  • target="_blank" is a security vulnerability.
    The new page has access to your window object via window.opener, and it can navigate your page to a different URL using window.opener.location = newURL.

HTML 5.2

<dialog>
<button id="btnGreet">Greet</button>
<dialog id="greetDialog">
    <p>Greetings!</p>
    <button id="btnClose">Close</button>
</dialog>
btnGreet.addEventListener('click', () => greetDialog.showModal() );
btnClose.addEventListener('click', () => greetDialog.close() );
<script type="module>
<script type="module" src="./app/app.js"></script>
import utils from "./utils.js";

index.html:

app.js:

Note: module specifier must start with either ./, ../ or /

<meta name="theme-color">
<meta name="theme-color" content="red">

CSS

CSS Grid

CSS Grid

Developer Tools

CSS Variables (Custom Properties)

:root {
  --some-property-name: someValue;
}

selector {
  property: var(--some-property-name);
}

Variables: SCSS vs CSS

$color-1: tomato;
$color-2: olive;
$color-3: gold;

:root {
    --body-color: $color-1;
    @media (max-width: 960px){ --body-color: $color-3; }
    @media (max-width: 480px){ --body-color: $color-2; }
}

body { background-color: var(--body-color); }

CSS Modules

How CSS Modules work

CSS Evolution

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">

JavaScript

  1. ES1

  2. ES2

  3. ES3

  4. ES5

  5. ES5.1

Complete list of EcmaScript Editions

  1. ES2015

  2. ES2016

  3. ES2017

  4. ES2018

ES2015

Swap values

var a = 1, b = 2;

// Junior
var tmp = b;
b = a;
a = tmp;

// Intermediate
a ^= b;
b ^= a;
a ^= b;

// Senior
a = [b, b=a][0];

// Architect
b = (function(a){return a})(a, a=b);

ES5

ES2015

let a = 1, b = 2;

[a, b] = [b, a]

Generate array

function seq(n) {
  var result = [];
  for (var i = 0; i < n; i++) {
      result.push(i);
  }
  return result;
}

ES5

ES2015

const seq = n => [...Array(n).keys()];
[0, 1, 2, 3, ..., N-1]

ES2016

[1, 2, 3].includes(1) // true

a ** b // Math.pow(a, b)

ES2017

ES2018

Frameworks

Rubber duck debugging

Technologies

Isomorphic/Universal
JavaScript

Universal JS Architecture

Serverless

Serverless Architecture

Writing JS
modern way

Async code

callbacks

const addOneTo = function(number, callback) {
    const result = number + 1;
    if (callback) {
        callback(result);
    }
}
// 5 + 1 = 6
addOneTo(5, function(res){
    console.log(res);
})
// 5 + 1 + 1 + 1 + 1 + 1 = 10
addOneTo(5, function(res1) {
    addOneTo(res1, function(res2) {
        addOneTo(res2, function(res3) {
            addOneTo(res3, function(res4) {
                addOneTo(res4, function(res5) {
                    console.log(res5);
                });
            });
        });
    });
});

ES2015: promises

const addOneTo = function(number) {
    const result = number + 1;
    return new Promise(function(resolve, reject) {
        resolve(result);
    });
}
// 5 + 1 = 6
addOneTo(5)
    .then( res => console.log(res) );
// 5 + 1 + 1 + 1 + 1 + 1 = 10
addOneTo(5)
    .then(addOneTo)
    .then(addOneTo)
    .then(addOneTo)
    .then(addOneTo)
    .then(console.log)

ES2017: async/await

const addOnTo = function(number){
    const result = number + 1;
    return new Promise(function(resolve, reject) {
        resolve(result);
    });
}
async function calc(){
    const res1 = await addOnTo(5);
    const res2 = await addOnTo(res1);
    const res3 = await addOnTo(res2);
    const res4 = await addOnTo(res3);
    const res5 = await addOnTo(res4);
    console.log(res5);
}
calc();

Observables

<input id="inpt" type="text" >
<h3>You entered:</h3>
<div id="results"></div>
Rx.Observable
  .fromEvent(inpt, 'keyup')
  .map(x => x.currentTarget.value)
  .debounceTime(500) 
  .subscribe(x => result.innerHTML += `<br>${x}`);

RxJS Sample

Functional

Approach

What's wrong with this code?

function seq(n) {
  var result = [];
  for (var i = 0; i < n; i++) {
      result.push(i);
  }
  return result;
}

Simple steps to adopt functional approach in JS

  1. Build pure functions 
  2. Use constants where possible 
  3. Avoid loops
function solve(x, y) {
  let total = 0;
  for (let i = x; i < y; i++) {
    let current = i.toString();
    let final = '';
    let split = current.split('').reverse();
    for (let j = 0; j < split.length; j++) {
      let x = split[j];
      if (x === '0' || x === '1' || x === '8') {
        final += x;
      } else if (x === '6') {
        final += '9';
      } else if (x === '9') {
        final += '6';
      } else {
        break;
      }
    }
    if (final === current) {
      total++;
    }
  }
  return total;
};

Sample: non-functional

Task (codewars): return the count of upside down numbers within that range. 

function solve(x, y) {
 return [...'_'.repeat(y - x + 1)]
    .map( (_,i) => x + i )
    .reduce( (acc, n) => n == rotate(n) ? ++acc : acc, 0 );
};

function rotate(num) {
  const digitsRotated = {'0': '0', '1': '1', '6': '9', '8': '8', '9': '6'};
  return String(num)
    .split('')
    .reverse()
    .map(d => digitsRotated[d])
    .join('');
}

Sample: functional

Task (codewars): return the count of upside down numbers within that range. 

The death of JavaScript 

Thank you!

Vyacheslav Koldovskyy
programmingmentor.com

Links

Made with Slides.com