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 ShardingConcatenationSpritingInlining
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
-
ES1
-
ES2
-
ES3
-
ES5
-
ES5.1
Complete list of EcmaScript Editions
-
ES2015
-
ES2016
-
ES2017
-
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
Stage 4:
Stage 3:
- Function.prototype.toString revision
- global
- Rest/Spread Properties
- Asynchronous Iteration
- import()
- RegExp Lookbehind Assertions
- RegExp Unicode Property Escapes
- RegExp named capture groups
- Promise.prototype.finally()
- BigInt – arbitrary precision integers
- Class fields
- Optional catch binding
- import.meta
- Array.prototype.flatMap/flatten
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
- Build pure functions
- Use constants where possible
- 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
- Ilya Grigorik High Performance Browser Networking
- https://www.hongkiat.com/blog/html-5-1-new-features/
- https://developers.google.com/web/fundamentals/security/csp/
- https://glebbahmutov.com/blog/disable-inline-javascript-for-security/
- https://blog.whatwg.org/js-modules
- https://www.smashingmagazine.com/2017/06/building-production-ready-css-grid-layout/
- https://gridbyexample.com/
- https://www.xanthir.com/blog/b4KT0
- https://developers.google.com/web/updates/2016/02/css-variables-why-should-you-care
- https://m.alphasights.com/css-evolution-from-css-sass-bem-css-modules-to-styled-components-d4c1da3a659b
- https://www.smashingmagazine.com/2016/12/progressive-web-amps/
- https://medium.com/@frontman/how-swap-two-values-without-temporary-variables-using-javascript-8bb28f96b5f6
- http://2ality.com/2017/02/ecmascript-2018.html
- https://medium.com/@mjackson/universal-javascript-4761051b7ae9
- https://github.com/JustServerless/awesome-serverless
- http://blog.spotinst.com/2017/06/07/state-serverless-ecosystem/
front-end-2018
By Programming Mentor (Vyacheslav Koldovskyy)
front-end-2018
- 517