PWA

PWA

Progressive web applications (PWAs) are a type of mobile app delivered through the web, built using common web technologies including HTML, CSS and JavaScript
Jacob Banks

Jacob Banks

1668958070

How to Create Progressive Web Applications (PWA) with React

In this tutorial, you'll learn how to create Progressive Web Applications (PWA) using React

A progressive web application is a type of application software delivered through the web, built using common web technologies including HTML, CSS, and JavaScript. It is intended to work on any platform that uses a standards-compliant browser, including both desktop and mobile devices.

Bit of History

  •    In 2015, designer Frances Berriman and Google Chrome engineer Alex Russell coined the term "progressive web apps" to describe apps taking advantage of new features supported by modern browsers, including service workers and web app manifests, that let users upgrade web apps to progressive web applications in their native operating system (OS). Google then put significant efforts into promoting PWA development for Android. Firefox introduced support for service workers in 2016, and Microsoft Edge and Apple Safari followed in 2018, making service workers available on all major systems.
  •    By 2019, PWAs were available on desktop browsers Microsoft Edge[5] (on Windows) and Google Chrome[16] (on Windows, macOS, Chrome OS, and Linux).

React is an open-source front-end JavaScript library for building user interfaces or UI components. It is maintained by Facebook and a community of individual developers and companies. React can be used as a base in the development of single-page or mobile applications

  •        Lecture 1: Introduction to React.Js
  •        Lecture 2: Introduction to PWA - Progressive Web Applications
  •        Lecture 3: Creating PWA - Progressive Web Application
  •        Lecture 4: Exploring Application Structure and Workflow
  •        Lecture 5: Making Use of React Hooks
  •        Lecture 6: Build and Serve Project
  •        Lecture 7: How to use a service worker
  •        Lecture 8: Offline Cache
  •        Lecture 9: Exploring Manifest.json
  •        Lecture 10: Installing Progressive Web App in Chrome Browser

What you’ll learn

  •        Creating Progressive Web Applications

Are there any course requirements or prerequisites?

  •        Basic Programming knowledge
  •        Basic understanding of React

Who this course is for:

  •        Aspiring Web Developers
  •        Web Developers

#progressivewebapps #react #pwa

How to Create Progressive Web Applications (PWA) with React
Lawrence  Lesch

Lawrence Lesch

1668073260

Library Of Dependency-free JavaScript Utilities That Do Just one Thing

Just

A library of zero-dependency npm modules that do just one thing. A guilt-free alternative to those bulkier utility libraries. Ideal for PWA development or whenever bytes are precious.

Try 🍦

A REPL for every utility (powered by RunKit)

Read 📚

ES and CJS modules available for every utility 

All packages support ES module or Common JS syntax without requiring transpilation

// esm (node / bundler)
import clone from 'just-clone'; 

// esm (native browser code)
import clone from './node_modules/just-clone/index.mjs'; 

// cjs
const clone = require('just-clone'); 

TypeScript

We've now added TypeScript definitions and tests for every Just utility

Browser/Platform Support 💻

Most utilities still work with any platform that supports ES5, but these are the earliest versions guranteed to support every utility. For guidance, any platform that supports spread in array literals will work with Just.

ChromeSafariFirefoxEdgeNodeMobile SafariAndroid Chrome
46816126.0846

Collections

just-diff

source

🍦 Try it

npm install just-diff
yarn add just-diff

Return an object representing the difference between two other objects Pass converter to format as http://jsonpatch.com

import {diff} from 'just-diff';

const obj1 = {a: 4, b: 5};
const obj2 = {a: 3, b: 5};
const obj3 = {a: 4, c: 5};

diff(obj1, obj2);
[
  { "op": "replace", "path": ['a'], "value": 3 }
]

diff(obj2, obj3);
[
  { "op": "remove", "path": ['b'] },
  { "op": "replace", "path": ['a'], "value": 4 }
  { "op": "add", "path": ['c'], "value": 5 }
]

// using converter to generate jsPatch standard paths
import {diff, jsonPatchPathConverter} from 'just-diff'
diff(obj1, obj2, jsonPatchPathConverter);
[
  { "op": "replace", "path": '/a', "value": 3 }
]

diff(obj2, obj3, jsonPatchPathConverter);
[
  { "op": "remove", "path": '/b' },
  { "op": "replace", "path": '/a', "value": 4 }
  { "op": "add", "path": '/c', "value": 5 }
]

// arrays
const obj4 = {a: 4, b: [1, 2, 3]};
const obj5 = {a: 3, b: [1, 2, 4]};
const obj6 = {a: 3, b: [1, 2, 4, 5]};

diff(obj4, obj5);
[
  { "op": "replace", "path": ['a'], "value": 3 }
  { "op": "replace", "path": ['b', 2], "value": 4 }
]

diff(obj5, obj6);
[
  { "op": "add", "path": ['b', 3], "value": 5 }
]

// nested paths
const obj7 = {a: 4, b: {c: 3}};
const obj8 = {a: 4, b: {c: 4}};
const obj9 = {a: 5, b: {d: 4}};

diff(obj7, obj8);
[
  { "op": "replace", "path": ['b', 'c'], "value": 4 }
]

diff(obj8, obj9);
[
  { "op": "replace", "path": ['a'], "value": 5 }
  { "op": "remove", "path": ['b', 'c']}
  { "op": "add", "path": ['b', 'd'], "value": 4 }
]

just-diff-apply

source

🍦 Try it

npm install just-diff-apply
yarn add just-diff-apply

Apply a diff object to an object. Pass converter to apply a http://jsonpatch.com standard patch

  import {diffApply} from 'just-diff-apply';

  const obj1 = {a: 3, b: 5};
  diffApply(obj1,
    [
      { "op": "remove", "path": ['b'] },
      { "op": "replace", "path": ['a'], "value": 4 },
      { "op": "add", "path": ['c'], "value": 5 }
    ]
  );
  obj1; // {a: 4, c: 5}

  const obj2 = {a: 3, b: 5};
  diffApply(obj2,
    [
      { "op": "move", "from": ['a'], "path": ['c']},
    ]
  );
  obj2; // {b: 5, c: 3}

  // using converter to apply jsPatch standard paths
  // see http://jsonpatch.com
  import {diffApply, jsonPatchPathConverter} from 'just-diff-apply'
  const obj3 = {a: 3, b: 5};
  diffApply(obj3, [
    { "op": "remove", "path": '/b' },
    { "op": "replace", "path": '/a', "value": 4 }
    { "op": "add", "path": '/c', "value": 5 }
  ], jsonPatchPathConverter);
  obj3; // {a: 4, c: 5}

  // arrays (array key can be string or numeric)
  const obj4 = {a: 4, b: [1, 2, 3]};
  diffApply(obj4, [
    { "op": "replace", "path": ['a'], "value": 3 }
    { "op": "replace", "path": ['b', 2], "value": 4 }
    { "op": "add", "path": ['b', 3], "value": 9 }
  ]);
  obj4; // {a: 3, b: [1, 2, 4, 9]}

  // nested paths
  const obj5 = {a: 4, b: {c: 3}};
  diffApply(obj5, [
    { "op": "replace", "path": ['a'], "value": 5 }
    { "op": "remove", "path": ['b', 'c']}
    { "op": "add", "path": ['b', 'd'], "value": 4 }
  ]);
  obj5; // {a: 5, b: {d: 4}}

just-compare

source

🍦 Try it

npm install just-compare
yarn add just-compare

Compare two collections

import compare from 'just-compare';

// primitives: value1 === value2
// functions: value1.toString == value2.toString
// arrays: if length, sequence and values of properties are identical
// objects: if length, names and values of properties are identical
compare([1, [2, 3]], [1, [2, 3]]); // true
compare([1, [2, 3], 4], [1, [2, 3]]); // false
compare({a: 2, b: 3}, {a: 2, b: 3}); // true
compare({a: 2, b: 3}, {b: 3, a: 2}); // true
compare({a: 2, b: 3, c: 4}, {a: 2, b: 3}); // false
compare({a: 2, b: 3}, {a: 2, b: 3, c: 4}); // false
compare([1, [2, {a: 4}], 4], [1, [2, {a: 4}]]); // false
compare([1, [2, {a: 4}], 4], [1, [2, {a: 4}], 4]); // true
compare(NaN, NaN); // true

just-clone

source

🍦 Try it

npm install just-clone
yarn add just-clone

Deep copies objects, arrays, maps and sets

// Deep copies objects and arrays, doesn't clone functions

import clone from 'just-clone';

var arr = [1, 2, 3];
var subObj = { aa: 1 };
var obj = { a: 3, b: 5, c: arr, d: subObj };
var objClone = clone(obj);
arr.push(4);
objClone.d.bb = 2;
obj; // {a: 3, b: 5, c: [1, 2, 3, 4], d: {aa: 1}}
objClone; // {a: 3, b: 5, c: [1, 2, 3], d: {aa: 1, bb: 2}}

just-pluck-it

source

🍦 Try it

npm install just-pluck-it
yarn add just-pluck-it

Pluck a property from each member of a collection

import pluck from 'just-pluck-it';

pluck([{a:1, b:2}, {a:4, b:3}, {a:2, b:5}], 'a'); // [1, 4, 2]
pluck({x: {a:1, b:2}, y: {a:4, b:3}, z: {a:2, b:5}}, 'a'); // {x: 1, y: 4, z: 2}

just-flush

source

🍦 Try it

npm install just-flush
yarn add just-flush

Returns a copy of an array or object with null/undefined members removed

import flush from 'just-flush';

flush([1, undefined, 2, null, 3, NaN, 0]); // [1, 2, 3, NaN, 0]
flush([true, null, false, true, [null], undefined]); // [true, false, true, [null]]
flush({a: 2, b: null, c: 4, d: undefined}); // {a: 2, c: 4}
flush('something'); // undefined
flush(); // undefined

Objects

just-extend

source

🍦 Try it

npm install just-extend
yarn add just-extend

Extend an object

import extend from 'just-extend';

var obj = {a: 3, b: 5};
extend(obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8}
obj; // {a: 4, b: 5, c: 8}

var obj = {a: 3, b: 5};
extend({}, obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8}
obj; // {a: 3, b: 5}

var arr = [1, 2, 3];
var obj = {a: 3, b: 5};
extend(obj, {c: arr}); // {a: 3, b: 5, c: [1, 2, 3]}
arr.push(4);
obj; // {a: 3, b: 5, c: [1, 2, 3, 4]}

var arr = [1, 2, 3];
var obj = {a: 3, b: 5};
extend(true, obj, {c: arr}); // {a: 3, b: 5, c: [1, 2, 3]}
arr.push(4);
obj; // {a: 3, b: 5, c: [1, 2, 3]}

extend({a: 4, b: 5}); // {a: 4, b: 5}
extend({a: 4, b: 5}, 3); {a: 4, b: 5}
extend({a: 4, b: 5}, true); {a: 4, b: 5}
extend('hello', {a: 4, b: 5}); // throws
extend(3, {a: 4, b: 5}); // throws

just-merge

source

🍦 Try it

npm install just-merge
yarn add just-merge

Shallow assign. Like just-extend but without deep copy option.

import merge from 'just-merge';

let obj = {a: 3, b: 5};
merge(obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8}
obj; // {a: 4, b: 5, c: 8}

let obj = {a: 3, b: 5};
merge({}, obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8}
obj; // {a: 3, b: 5}

let arr = [1, 2, 3];
let obj = {a: 3, b: 5};
merge(obj, {c: arr}); // {a: 3, b: 5, c: [1, 2, 3]}
arr.push[4];
obj; // {a: 3, b: 5, c: [1, 2, 3, 4]}

merge({a: 4, b: 5}); // {a: 4, b: 5}
merge(3, {a: 4, b: 5}); // throws
merge({a: 4, b: 5}, 3); // throws
merge({a: 4, b: 5}, {b: 4, c: 5}, 'c'); // throws

just-values

source

🍦 Try it

npm install just-values
yarn add just-values

Return property values as an array

const values = require('just-values');

values({a: 4, c: 8}); // [4, 8]
values({a: {aa: 2}, b: {bb: 4}}); // [{aa: 2}, {bb: 4}]
values({}); // []
values([1, 2, 3]); // [1, 2, 3]
values(function(a, b) {return a + b;}); // []
values(new String('hello')); // ['h', 'e', 'l', 'l', 'o']
values(1); // throws exception
values(true); // throws exception
values(undefined); // throws exception
values(null); // throws exception

just-entries

source

🍦 Try it

npm install just-entries
yarn add just-entries

Return object entries as an array of [key, value] pairs

import entries from 'just-entries';

// Object:
entries({c: 8, a: 4}); // [['c', 8], ['a', 4]]
entries({b: {bb: 4}, a: {aa: 2}}); // [['b', {bb: 4}], ['a', {aa: 2}]]
entries({}); // []

// Array:
entries([{c: 8}, {a: 4}]); // [[0, {c: 8}], [1, {a: 4}]]
entries(['À', 'mauvais', 'ouvrier', 'point', 'de', 'bon', 'outil'])
// [[0, 'À'], [1, 'mauvais'] ... [6, 'outil']]
entries([]); // []

just-pick

source

🍦 Try it

npm install just-pick
yarn add just-pick

Copy an object but with only the specified keys

import pick from 'just-pick';

var obj = { a: 3, b: 5, c: 9 };
pick(obj, ['a', 'c']); // {a: 3, c: 9}
pick(obj, 'a', 'c'); // {a: 3, c: 9}
pick(obj, ['a', 'b', 'd']); // {a: 3, b: 5}
pick(obj, ['a', 'a']); // {a: 3}

just-omit

source

🍦 Try it

npm install just-omit
yarn add just-omit

Copy an object but omit the specified keys

import omit from 'just-omit';

var obj = {a: 3, b: 5, c: 9};
omit(obj, ['a', 'c']); // {b: 5}
omit(obj, 'a', 'c'); // {b: 5}
omit(obj, ['a', 'b', 'd']); // {c: 9}
omit(obj, ['a', 'a']); // {b: 5, c: 9}

just-is-empty

source

🍦 Try it

npm install just-is-empty
yarn add just-is-empty

Return true if object has no enumerable key values

import isEmpty from 'just-is-empty';
 isEmpty({a: 3, b: 5}) // false
 isEmpty([1, 2]) // false
 isEmpty(new Set([1, 2, 2])) // false
 isEmpty((new Map()).set('a', 2)) // false
 isEmpty({}) // true
 isEmpty([]) // true
 isEmpty(new Set()) // true
 isEmpty(new Map()) // true
 isEmpty('abc') // false
 isEmpty('') // true
 isEmpty(0) // true
 isEmpty(1) // true
 isEmpty(true) // true
 isEmpty(Symbol('abc')); // true
 isEmpty(//); // true
 isEmpty(new String('abc')); // false
 isEmpty(new String('')); // true
 isEmpty(new Boolean(true)); // true
 isEmpty(null) // true
 isEmpty(undefined) // true

just-is-circular

source

🍦 Try it

npm install just-is-circular
yarn add just-is-circular

Return true if object has a circular reference NOTE: not supported in IE or microsoft edge

import isCircular from 'just-is-circular';
const a = {};
a.b = a;
isCircular(a); // true

const a = {};
a.b = {
  c: a
};
isCircular(a); // true

const a = {};
a.b = {
  c: 4
};
isCircular(a); // false

const a = [];
a.push(a);
isCircular(a); // true

isCircular({}); // false
isCircular('hi'); // false
isCircular(undefined); // false

just-is-primitive

source

🍦 Try it

npm install just-is-primitive
yarn add just-is-primitive

Determine if a value is a primitive value

import isPrimitive from 'just-is-primitive';
isPrimitive('hi') // true
isPrimitive(3) // true
isPrimitive(true) // true
isPrimitive(false) // true
isPrimitive(null) // true
isPrimitive(undefined) // true
isPrimitive(Symbol()) // true
isPrimitive({}) // false
isPrimitive([]) // false
isPrimitive(function() {}) // false
isPrimitive(new Date()) // false
isPrimitive(/a/) // false

just-filter-object

source

🍦 Try it

npm install just-filter-object
yarn add just-filter-object

Filter an object

import filter from 'just-filter';

// returns a new object containing those original properties for which the predicate returns truthy
filter({a: 3, b: 5, c: 9}, (key, value) => value < 6); // {a: 3, b: 5}
filter({a1: 3, b1: 5, a2: 9}, (key, value) => key[0] == 'a'); // {a1: 3, a2: 9}
filter({a: 3, b: 5, c: null}, (key, value) => value); // {a: 3, b: 5}

just-map-object

source

🍦 Try it

npm install just-map-object
yarn add just-map-object

Map an object, passing key and value to predicates

import map from 'just-map-object';

// DEPRECATED: use just-map-values
map({a: 3, b: 5, c: 9}, (key, value) => value + 1); // {a: 4, b: 6, c: 10}
map({a: 3, b: 5, c: 9}, (key, value) => key); // {a: 'a', b: 'b', c: 'c'}
map({a: 3, b: 5, c: 9}, (key, value) => key + value); // {a: 'a3', b: 'b5', c: 'c9'}```

just-map-values

source

🍦 Try it

npm install just-map-values
yarn add just-map-values

Map an object, predicate updates values, receives (value, key, object)

import map from 'just-map-values';

// predicate updates values, receives (value, key, obj)
map({a: 3, b: 5, c: 9}, (value) => value + 1); // {a: 4, b: 6, c: 10}
map({a: 3, b: 5, c: 9}, (value, key) => value + key); // {a: 3a, b: 5b, c: 9c}
map({a: 3, b: 5, c: 9}, (value, key, obj) => obj.b); // {a: 5, b: 5, c: 5}

just-map-keys

source

🍦 Try it

npm install just-map-keys
yarn add just-map-keys

Map an object, predicate updates keys, receives (value, key, object)

import map from 'just-map-keys';

// predicate updates keys, receives (value, key, object)
map({a: 'cow', b: 'sheep', c: 'pig'}, (value) => value);
  // {cow: 'cow', sheep: 'sheep', pig: 'pig'}
map([4, 5, 6], (value, key) => key + 1); // {1: 4, 2: 5, 3: 6}
map({a: 3, b: 5, c: 9}, (value, key) => key + value); // {a3: 3, b5: 5, c9: 9}
map({a: 3, b: 5, c: 9}, (value, key, obj) => obj.b + value + key);
  // {'8a': 3, '10b': 5, '14c': 9}

just-deep-map-values

source

🍦 Try it

npm install just-deep-map-values
yarn add just-deep-map-values

Returns an object with values at all depths mapped according to the provided function

import deepMapValues from 'just-deep-map-values';

const squareFn = (number) => number * number;
deepMapValues({ a: 1, b: { c: 2, d: { e: 3 } } }, squareFn); // => { a: 1, b: { c: 4, d: { e: 9 } } }

just-reduce-object

source

🍦 Try it

npm install just-reduce-object
yarn add just-reduce-object

Reduce an object

import reduce from 'just-reduce-object';

// applies a function against an accumulator and each key-value pairs of the object
// to reduce it to a single value
reduce({a: 3, b: 5, c: 9}, (acc, key, value, index, keys) => {
  acc[value] = key;
  return acc;
}, {}); // {3: 'a', 5: 'b', 9: 'c'}

reduce({a: 3, b: 5, c: 9}, (acc, key, value, index, keys) => {
  acc += value;
  return acc;
}); // 17

just-safe-get

source

🍦 Try it

npm install just-safe-get
yarn add just-safe-get

Get value at property, don't throw if parent is undefined

import get from 'just-safe-get';

const obj = {a: {aa: {aaa: 2}}, b: 4};

get(obj, 'a.aa.aaa'); // 2
get(obj, ['a', 'aa', 'aaa']); // 2

get(obj, 'b.bb.bbb'); // undefined
get(obj, ['b', 'bb', 'bbb']); // undefined

get(obj.a, 'aa.aaa'); // 2
get(obj.a, ['aa', 'aaa']); // 2

get(obj.b, 'bb.bbb'); // undefined
get(obj.b, ['bb', 'bbb']); // undefined

get(obj.b, 'bb.bbb', 5); // 5
get(obj.b, ['bb', 'bbb'], true); // true

get(null, 'a'); // undefined
get(undefined, ['a']); // undefined

get(null, 'a', 42); // 42
get(undefined, ['a'], 42); // 42

const obj = {a: {}};
const sym = Symbol();
obj.a[sym] = 4;
get(obj.a, sym); // 4

just-safe-set

source

🍦 Try it

npm install just-safe-set
yarn add just-safe-set

Set value at property, create intermediate properties if necessary

import set from 'just-safe-set';

const obj1 = {};
set(obj1, 'a.aa.aaa', 4); // true
obj1; // {a: {aa: {aaa: 4}}}

const obj2 = {};
set(obj2, ['a', 'aa', 'aaa'], 4); // true
obj2; // {a: {aa: {aaa: 4}}}

const obj3 = {a: {aa: {aaa: 2}}};
set(obj3, 'a.aa.aaa', 3); // true
obj3; // {a: {aa: {aaa: 3}}}

// don't clobber existing
const obj4 = {a: {aa: {aaa: 2}}};
set(obj4, 'a.aa', {bbb: 7}); // false

const obj5 = {a: {}};
const sym = Symbol();
set(obj5.a, sym, 7); // true
obj5; // {a: {Symbol(): 7}}

just-typeof

source

🍦 Try it

npm install just-typeof
yarn add just-typeof

Type inferer

import typeOf from 'just-typeof';

typeOf({}); // 'object'
typeOf([]); // 'array'
typeOf(function() {}); // 'function'
typeOf(/a/); // 'regexp'
typeOf(new Date()); // 'date'
typeOf(null); // 'null'
typeOf(undefined); // 'undefined'
typeOf('a'); // 'string'
typeOf(1); // 'number'
typeOf(true); // 'boolean'

just-flip-object

source

🍦 Try it

npm install just-flip-object
yarn add just-flip-object

Flip the keys and values

import flip from 'just-flip-object';

// flip the key and value
flip({a: 'x', b: 'y', c: 'z'}); // {x: 'a', y: 'b', z: 'c'}
flip({a: 1, b: 2, c: 3}); // {'1': 'a', '2': 'b', '3': 'c'}
flip({a: false, b: true}); // {false: 'a', true: 'b'}

just-has

source

🍦 Try it

npm install just-has
yarn add just-has

Return a boolen indicating the existence of a deep property, don't throw if parent is undefined

import has from 'just-has';

const obj = {a: {aa: {aaa: 2}}, b: 4};

has(obj, 'a.aa.aaa'); // true
has(obj, ['a', 'aa', 'aaa']); // true

has(obj, 'b.bb.bbb'); // false
has(obj, ['b', 'bb', 'bbb']); // false

has(obj.a, 'aa.aaa'); // true
has(obj.a, ['aa', 'aaa']); // true

has(obj.b, 'bb.bbb'); // false
has(obj.b, ['bb', 'bbb']); // false

has(null, 'a'); // false
has(undefined, ['a']); // false

const obj = {a: {}};
const sym = Symbol();
obj.a[sym] = 4;
has(obj.a, sym); // true

Arrays

just-cartesian-product

source

🍦 Try it

npm install just-cartesian-product
yarn add just-cartesian-product

Takes an input of an array of arrays and returns their Cartesian product.

import cartesianProduct from 'just-cartesian-product';

cartesianProduct([[1, 2], ['a', 'b']]); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
cartesianProduct([[1, 2], ['a', 'b', 'c']]); // [[1, 'a'], [1, 'b'], [1, 'c'], [2, 'a'], [2, 'b'], [2, 'c']]
cartesianProduct([]); // []
cartesianProduct(); // throws

just-unique

source

🍦 Try it

npm install just-unique
yarn add just-unique

Dedupes an array

import unique from 'just-unique';

unique([1, 2, 3, 2, 3, 4, 3, 2, 1, 3]); // [1, 2, 3, 4]

var a = {a: 3};
var b = {b: 4};
var c = {c: 5};
unique([a, a, b, c, b]); // [a, b, c]

unique([1, '1', 2, '2', 3, 2]); // [1, '1', 2, '2', 3]

// declaring sorted array for performance
unique([1, 1, '1', 2, 2, 5, '5', '5'], true); // [1, '1', 2, 5, '6']

// declaring strings array for performance
unique(['a', 'c', 'b', 'c', 'a'], false, true); // ['a', 'b', 'c']

just-flatten-it

source

🍦 Try it

npm install just-flatten-it
yarn add just-flatten-it

Return a flattened array

import flatten from 'just-flatten-it';

flatten([[1, [2, 3]], [[4, 5], 6, 7, [8, 9]]]);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

flatten([[1, [2, 3]], [[4, 5], 6, 7, [8, 9]]], 1);
// [1, [2, 3], [[4, 5], 6, 7, [8, 9]]]

just-index

source

🍦 Try it

npm install just-index
yarn add just-index

Return an object from an array, keyed by the value at the given id

import index from 'just-index';

index([{id: 'first', val: 1}, {id: 'second', val: 2}], 'id');
// {first: {id: 'first', val: 1}, second: {id: 'second', val: 2}}
index([{id: 'first', val: 1}, null], 'id'); // {first: {id: 'first', val: 1}}
index([], 'id'); // {}
index([], null); // undefined
index({}, 'id'); // undefined

just-insert

source

🍦 Try it

npm install just-insert
yarn add just-insert

Inserts a sub-array into an array starting at the given index. Returns a copy

import insert from 'just-insert';

insert([1, 2, 5, 6], ['a', 'c', 'e'], 2); // [1, 2, 'a', 'c', 'e', 5, 6]
insert([1, 2, 5, 6], 'a', 2); // [1, 2, 'a', 5, 6]
insert([1, 2, 5, 6], ['a', 'c', 'e'], 0); // ['a', 'c', 'e', 1, 2, 5, 6]
insert([1, 2, 5, 6], ['a', 'c', 'e']); // ['a', 'c', 'e', 1, 2, 5, 6]

just-intersect

source

🍦 Try it

npm install just-intersect
yarn add just-intersect

Return the intersect of two arrays

import intersect from 'just-intersect';

intersect([1, 2, 5, 6], [2, 3, 5, 6]); // [2, 5, 6]
intersect([1, 2, 2, 4, 5], [3, 2, 2, 5, 7]); // [2, 5]  

just-compact

source

🍦 Try it

npm install just-compact
yarn add just-compact

Returns a copy of an array with falsey values removed

import compact from 'just-compact';

compact([1, null, 2, undefined, null, NaN, 3, 4, false, 5]); // [1, 2, 3, 4, 5]
compact([1, 2, [], 4, {}]); // [1, 2, [], 4, {}]
compact([]); // []
compact({}); // throws

just-last

source

🍦 Try it

npm install just-last
yarn add just-last

Return the last member of an array

import last from 'just-last';

last([1, 2, 3, 4, 5]); // 5
last([{a: 1}, {b: 1}, {c: 1}]); // {c: 1}
last([true, false, [true, false]]); // [true, false]
last(); // undefined
last([]); // undefined
last(null); // undefined
last(undefined); // undefined

just-tail

source

🍦 Try it

npm install just-tail
yarn add just-tail

Return all but the first element of an array

import tail from 'just-tail';

tail([1, 2, 3, 4, 5]); // [2, 3, 4, 5]
tail([{a: 1}, {b: 1}, {c: 1}]); // [{b: 1}, {c: 1}]
tail([true, false, [true, false]]); // [false, [true, false]]
tail([]); // []
tail(); // undefined
tail(null); // undefined
tail(undefined); // undefined

just-random

source

🍦 Try it

npm install just-random
yarn add just-random

Return a randomly selected element in an array

import random from 'just-random';

random([1, 2, 3]);
// one of [1, 2, 3], at random

just-shuffle

source

🍦 Try it

npm install just-shuffle
yarn add just-shuffle

Return the elements of an array in random order

import shuffle from 'just-shuffle';

shuffle([1, 2, 3]); 
// array with original elements randomly sorted
shuffle([1, 2, 3], {shuffleAll: true}); 
// array with original elements randomly sorted and all in new postions
shuffle([]); // []
shuffle([1]); // [1]
shuffle(); // throws
shuffle(undefined); // throws
shuffle(null); // throws
shuffle({}); // throws

just-split

source

🍦 Try it

npm install just-split
yarn add just-split

Splits array into groups of n items each

import split from 'just-split';

split([]); // []
split([1, 2, 3, 4, 5]); // [[1, 2, 3, 4, 5]]
split([1, 2, 3, 4, 5, 6, 7, 8, 9], 3); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
split([1, 2, 3, 4, 5, 6, 7, 8, 9], '3'); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
split(['a', 'b', 'c', 'd', 'e'], 2); // [['a', 'b'], ['c', 'd'], ['e']]
split([1, 2, 3, 4, 5, 6, 7, 8], 3); // [[1, 2, 3], [4, 5, 6], [7, 8]]

just-split-at

source

🍦 Try it

npm install just-split-at
yarn add just-split-at

Splits an array into two at a given position

import splitAt from 'just-split-at';

splitAt([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4, 5]]
splitAt([{a: 1}, {b: 1}, {c: 1}], -1); // [[{a: 1}, {b: 1}], [{c: 1}]]
splitAt([], 2); // [[], []]
splitAt(null, 1); // throws
splitAt(undefined, 1); // throws

just-sort-by

source

🍦 Try it

npm install just-sort-by
yarn add just-sort-by

Produces a new array, sorted in ascending order

import sortBy from 'just-sort-by';

sortBy([10, 1, 5, 20, 15, 35, 30, 6, 8]); // [1, 5, 6, 8, 10, 15, 20, 30, 35]

sortBy([
  {user: 'fabio', details: {city: "Milan", age: 34}},
  {user: 'max', details: {city: "Munich", age: 29}},
  {user: 'zacarias', details: {city: "Sao Paulo", age: 44}},
  {user: 'robert', details: {city: "Manchester", age: 28}},
  {user: 'klaus', details: {city: "Zurich", age: 38}},
], function(o) {
  return o.details.age;
});

/*
[
  {user: 'robert', age: 28},
  {user: 'max', age: 29},
  {user: 'fabio', age: 34},
  {user: 'klaus', age: 38},
  {user: 'zacarias', age: 44},
]
*/

sortBy([
  {user: 'fabio', age: 34},
  {user: 'max', age: 29},
  {user: 'zacarias', age: 44},
  {user: 'robert', age: 28},
  {user: 'klaus', age: 38},
], 'user');
/*
[
  {user: 'fabio', age: 34},
  {user: 'klaus', age: 38},
  {user: 'max', age: 29},
  {user: 'robert', age: 28},
  {user: 'zacarias', age: 44},
]
*/

just-partition

source

🍦 Try it

npm install just-partition
yarn add just-partition

Elements satisfying predicate added to first array, remainder added to second

import partition from 'just-partition';

partition([1, 5, 2, 4, 3], n => n > 3); // [[5, 4],[1, 2, 3]]
partition(['a', 2, 3, '3'], x => typeof x == 'string'); // [['a', '3'],[2, 3]]
partition([1, 2, 3, 4], x => typeof x == 'number'); // [[1, 2, 3, 4],[]]
partition([1, 2, 3, 4], x => typeof x == 'string'); // [[], [1, 2, 3, 4]]
partition([], n => n > 3); // [[], []]
partition({a: 1, b: 2}, n => n > 1); // throws
partition(null, n => n > 1); // throws
partition(undefined, n => n > 1); // throws

just-permutations

source

🍦 Try it

npm install just-permutations
yarn add just-permutations

Returns all permutations of the length N of the elements of the given Array

import permutations from 'just-array-permutations;

permutations([1, 2, 3]); // [[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]
permutations([]); // []
permutations(); // throws

just-range

source

🍦 Try it

npm install just-range
yarn add just-range

Generate a range array for numbers

import range from 'just-range';

range(1, 5); // [1, 2, 3, 4]
range(5); // [0, 1, 2, 3, 4]
range(-5); // [0, -1, -2, -3, -4]
range(0, 20, 5) // [0, 5, 10, 15]

just-remove

source

🍦 Try it

npm install just-remove
yarn add just-remove

Removes one array from another

import remove from 'just-remove';

remove([1, 2, 3, 4, 5, 6], [1, 3, 6]); // [2, 4, 5]

just-union

source

🍦 Try it

npm install just-union
yarn add just-union

Returns the union of two arrays

import union from 'just-union';

union([1, 2, 5, 6], [2, 3, 4, 6]); // [1, 2, 3, 4, 5, 6]

just-zip-it

source

🍦 Try it

npm install just-zip-it
yarn add just-zip-it

Returns an array of grouped elements, taking n-th element from every given array

import zip from 'just-zip-it';

zip([1, 2, 3]); // [[1], [2], [3]]
zip([1, 2, 3], ['a', 'b', 'c']); // [[1, 'a'], [2, 'b'], [3, 'c']]
zip([1, 2], ['a', 'b'], [true, false]); //[[1, 'a', true], [2, 'b', false]]

zip(undefined, {}, false, 1, 'foo'); // []
zip([1, 2], ['a', 'b'], undefined, {}, false, 1, 'foo'); // [[1, 'a'], [2, 'b']]

zip([1, 2, 3], ['a', 'b'], [true]); // [[1, 'a', true], [2, 'b', undefined], [3, undefined, undefined]]

just-group-by

source

🍦 Try it

npm install just-group-by
yarn add just-group-by

Return a grouped object from array

import groupBy from 'just-group-by';

groupBy([6.1, 4.2, 6.3], Math.floor); // { '4': [4.2], '6': [6.1, 6.3] }
groupBy([1,2,3,4,5,6,7,8], function(i) { return i % 2}); // { '0': [2, 4, 6, 8], '1': [1, 3, 5, 7] }

Statistics

just-mean

source

🍦 Try it

npm install just-mean
yarn add just-mean

The mean (average) value in an array

import mean from 'just-mean';

mean([1, 2, 3, 2, 4, 1]); // 2.1666666667
mean(3, 2, 1); // 2
mean([4]); // 4
mean(['3', 2]); // throws
mean(); // throws

just-median

source

🍦 Try it

npm install just-median
yarn add just-median

Return the median value of an array of numbers

import median from 'just-median';

median([1, 2, 3, 4, 5]); // 3
median([3, -1, 2]); // 2
median([9, 14, 14, 200, 15]); // 14
median(1, 2, 4, 3); // 2.5
median(['3', 2, 1]); // throws
median(); // throws

just-mode

source

🍦 Try it

npm install just-mode
yarn add just-mode

Return the most frequently occuring number(s)

import mode from 'just-mode';

mode([1, 2, 3, 2]); // 2
mode(4, 4, 1, 4); // 4
mode(100, 100, 101, 101); // [100, 101]
mode(4, 3, 2, 1); // [1, 2, 3, 4]
mode(['1', 2, 2, 1, 2]); // throws
mode(null); // throws

just-percentile

source

🍦 Try it

npm install just-percentile
yarn add just-percentile

Return the value at the given percentile (using linear interpolation)

import percentile from 'just-percentile';

percentile([1, 2, 3], 0); // 1
percentile([1, 2, 3], 50); // 2
percentile([1, 2, 3], 100); // 3

// See https://en.wikipedia.org/wiki/Percentile (linear interpolation method)
percentile([15, 20, 35, 40, 50], 5); // 15
percentile([15, 20, 35, 40, 50], 30); // 20
percentile([15, 20, 35, 40, 50], 40); // 27.5
percentile([15, 20, 35, 40, 50], 95); // 50

percentile(1, 2, 3, 50); // throws
percentile(['1', 2, 3], 50); // throws
percentile([], 50); // throws

just-variance

source

🍦 Try it

npm install just-variance
yarn add just-variance

Return the standard deviation of an array or numeric argument list

import variance from 'just-variance';

variance([1, 2, 3, 2, 4, 1]); // 1.3666666667
variance(3, 2, 1); // 1
variance([100, 100, 100.1, 100]); // 0.0025
variance(1, 2, 3, 4, 5, -6); // 15.5
variance([4]); // throws
variance(['3', 2]); // throws
variance(NaN, NaN); // throws
variance(); // throws

just-standard-deviation

source

🍦 Try it

npm install just-standard-deviation
yarn add just-standard-deviation

Return the standard deviation of an array or numeric argument list

import standardDeviation from "just-standard-deviation";

standardDeviation([1, 2, 3, 2, 4, 1]); // 1.16904519
standardDeviation(3, 2, 1); // 1
standardDeviation([100, 100, 100.1, 100]); // 0.05
standardDeviation(1, 2, 3, 4, 5, -6); // 3.9370039
standardDeviation([4]); // throws
standardDeviation(["3", 2]); // throws
standardDeviation(NaN, NaN); // throws
standardDeviation(); // throws

just-skewness

source

🍦 Try it

npm install just-skewness
yarn add just-skewness

Return the skewness of an array or numeric argument list using Pearson's second skewness coefficient

import skewness from "just-skewness";

// Using Pearson's second skewness coefficient
skewness(3, 2, 1); // 0
skewness([1, 2, 3, 2, 4, 1]); // 0.4276994613841504
skewness(1, 2, 3, 4, 5, -6); // -0.762000762001143
skewness([1, 2, 3, 4, 9]); // 0.7705935588815224
skewness([4]); // throws
skewness(["3", 2]); // throws
skewness(NaN, NaN); // throws
skewness(); // throws

Strings

just-template

source

🍦 Try it

npm install just-template
yarn add just-template

Interpolate a string with variables

import template from 'just-template';

var data = {
  a: {
    aa: {
      aaa: 'apple',
      bbb: 'pear'
    },
    bb: 'orange'
  },
  b: 'plum'
};
template('2 {{a.aa.aaa}}s, a {{a.aa.bbb}}, 3 {{a.bb}}s and a {{b}}. Yes 1 {{a.aa.bbb}}.', data);
// '2 apples, a pear, 3 oranges and a plum. Yes 1 pear.'

just-truncate

source

🍦 Try it

npm install just-truncate
yarn add just-truncate

Truncate a string with a custom suffix

  truncate('when shall we three meet again', 9); // 'when s...'
  truncate('when shall we three meet again', 10, ' (etc)'); // 'when (etc)'
  truncate('when shall we', 15,); // 'when shall we'
  truncate('when shall we', 15, '(more)'); // 'when shall we'
  truncate('when shall we', 10, ' (etc etc etc)'); // ' (etc etc etc)'

just-prune

source

🍦 Try it

npm install just-prune
yarn add just-prune

Prune a string with whole words and a custom suffix

  prune('when shall we three meet again', 7); // 'when...'
  prune('when shall we three meet again', 7, ' (more)'; // 'when (more)'
  prune('when shall we', 15,); // 'when shall we'
  prune('when shall we', 15, ' (etc)'); // 'when shall we'
  prune('when shall we', 7, ' (more)'); // ' (more)'

just-squash

source

🍦 Try it

npm install just-squash
yarn add just-squash

Remove all spaces from a string, optionally remove escape sequences too

  squash('the cat sat on the mat'); // 'thecatsatonthemat'
  squash(' the cat sat on the mat '); // 'thecatsatonthemat'
  squash('\tthe cat\n sat \fon \vthe \rmat '); // '\tthecat\nsat\fon\vthe\rmat'
  squash('\tthe cat\n sat \fon \vthe \rmat ', true); // 'thecatsatonthemat'
  squash(`the cat
sat on the mat`, true); // thecatsatonthemat

just-left-pad

source

🍦 Try it

npm install just-left-pad
yarn add just-left-pad

Add characters to the left of a string such that its total length is n

import leftPad from 'just-left-pad';

leftPad('hello', 9); // '    hello'
leftPad('hello', 3); // 'hello'
leftPad('hello', 9, '.'); // '....hello'
leftPad('hello', 9, '..'); // '....hello'
leftPad('hello', 10, 'ab'); // 'bababhello'
leftPad('hello', 9, '\uD83D\uDC04'); // '🐄🐄🐄🐄hello'
leftPad('hello', 10, '\uD83D\uDC11\uD83D\uDC04'), // '🐄🐑🐄🐑🐄hello'
leftPad('hello', 7, '🐄'), // '🐄🐄hello'
leftPad(null, 7); // throws
leftPad([], 4, '*'); // throws
leftPad('hello', 4, true); // throws
leftPad('hello', -4, true); // throws  
leftPad('hello', 2.3, true); // throws    

just-right-pad

source

🍦 Try it

npm install just-right-pad
yarn add just-right-pad

Add characters to the right of a string such that its total length is n

import rightPad from 'just-right-pad';

rightPad('hello', 9); // 'hello    '
rightPad('hello', 3); // 'hello'
rightPad('hello', 9, '.'); // 'hello....'
rightPad('hello', 9, '..'); // 'hello....'
rightPad('hello', 10, 'ab'); // 'helloababa'
rightPad('hello', 9, '\uD83D\uDC04'); // 'hello🐄🐄🐄🐄'
rightPad('hello', 10, '\uD83D\uDC11\uD83D\uDC04'), // 'hello🐑🐄🐑🐄🐑'
rightPad('hello', 7, '🐄'), // 'hello🐄🐄'
rightPad(null, 7); // throws
rightPad([], 4, '*'); // throws
rightPad('hello', 4, true); // throws
rightPad('hello', -4, true); // throws  
rightPad('hello', 2.3, true); // throws    

just-camel-case

source

🍦 Try it

npm install just-camel-case
yarn add just-camel-case

Convert a string to camel case

  import camelCase from 'just-camel-case';

  camelCase('the quick brown fox'); // 'theQuickBrownFox'
  camelCase('the_quick_brown_fox'); // 'theQuickBrownFox'
  camelCase('the-quick-brown-fox'); // 'theQuickBrownFox'
  camelCase('theQuickBrownFox'); // 'theQuickBrownFox'
  camelCase('thequickbrownfox'); // 'thequickbrownfox'
  camelCase('the - quick * brown# fox'); // 'theQuickBrownFox'
  camelCase('behold theQuickBrownFox'); // 'beholdTheQuickBrownFox'
  camelCase('Behold theQuickBrownFox'); // 'beholdTheQuickBrownFox'
  // all caps words are camel-cased
  camelCase('The quick brown FOX'), 'theQuickBrownFox');
  // all caps substrings >= 4 chars are camel-cased
  camelCase('theQUickBrownFox'); // 'theQUickBrownFox'
  camelCase('theQUIckBrownFox'); // 'theQUIckBrownFox'
  camelCase('theQUICKBrownFox'); // 'theQuickBrownFox'

just-kebab-case

source

🍦 Try it

npm install just-kebab-case
yarn add just-kebab-case

Convert a string to kebab case

  import kebabCase from 'just-kebab-case';

  kebabCase('the quick brown fox'); // 'the-quick-brown-fox'
  kebabCase('the-quick-brown-fox'); // 'the-quick-brown-fox'
  kebabCase('the_quick_brown_fox'); // 'the-quick-brown-fox'
  kebabCase('theQuickBrownFox'); // 'the-quick-brown-fox'
  kebabCase('theQuickBrown Fox'); // 'the-quick-brown-fox'
  kebabCase('thequickbrownfox'); // 'thequickbrownfox'
  kebabCase('the - quick * brown# fox'); // 'the-quick-brown-fox'
  kebabCase('theQUICKBrownFox'); // 'the-q-u-i-c-k-brown-fox'

just-snake-case

source

🍦 Try it

npm install just-snake-case
yarn add just-snake-case

Convert a string to snake case

  import snakeCase from 'just-snake-case';

  snakeCase('the quick brown fox'); // 'the_quick_brown_fox'
  snakeCase('the-quick-brown-fox'); // 'the_quick_brown_fox'
  snakeCase('the_quick_brown_fox'); // 'the_quick_brown_fox'
  snakeCase('theQuickBrownFox'); // 'the_quick_brown_fox'
  snakeCase('thequickbrownfox'); // 'thequickbrownfox'
  snakeCase('the - quick * brown# fox'); // 'the_quick_brown_fox'
  snakeCase('theQUICKBrownFox'); // 'the_q_u_i_c_k_brown_fox'

just-pascal-case

source

🍦 Try it

npm install just-pascal-case
yarn add just-pascal-case

Convert a string to pascal case

  import pascalCase from 'just-pascal-case';

  pascalCase('the quick brown fox'); // 'TheQuickBrownFox'
  pascalCase('the_quick_brown_fox'); // 'TheQuickBrownFox'
  pascalCase('the-quick-brown-fox'); // 'TheQuickBrownFox'
  pascalCase('theQuickBrownFox'); // 'TheQuickBrownFox'
  pascalCase('thequickbrownfox'); // 'Thequickbrownfox'
  pascalCase('the - quick * brown# fox'); // 'TheQuickBrownFox'
  pascalCase('theQUICKBrownFox'); // 'TheQUICKBrownFox'

just-capitalize

source

🍦 Try it

npm install just-capitalize
yarn add just-capitalize

Capitalize the first character of a string

  import capitalize from 'just-capitalize';

/*
  capitalize('capitals'); // 'Capitals'
  capitalize('Capitals'); // 'Capitals'
  capitalize('many words'); // 'Many words'
  capitalize('!exclaim'); // '!exclaim'
*/

just-replace-all

source

🍦 Try it

npm install just-replace-all
yarn add just-replace-all

Replace all occurrences of a string within a string with another string

  import replaceAll from 'just-replace-all';

/*
  replaceAll('hello, world', 'l', 'q'); // 'heqqo, worqd'
  replaceAll('hello, world', 'l', 'qq'); // 'heqqqqo, worqqd'
  replaceAll('hello, world', 'll', 'q'); // 'heqo, world'
  replaceAll('hello, world', '', 'q'); // 'hello, world'
  replaceAll('hello, world', 'l', ''); // 'heo, word'
  replaceAll('hello, world', null, 'q'); // 'hello, world'
  replaceAll('hello, world', 'l'); // throw
  replaceAll('hello, world'); // throw
  replaceAll(); // throw
  replaceAll(null, 'l', 'q'); // throw
  replaceAll('hello, world', null, 'q'); // throw
  replaceAll('hello, world', 'l', null); // throw
*/

Numbers

just-clamp

source

🍦 Try it

npm install just-clamp
yarn add just-clamp

Restrict a number within a range

import clamp from 'just-clamp';

var n = 5;
clamp(1, n, 12); // 5
clamp(3, n, 1); // 3
clamp(8, n, 9); // 8
clamp(0, n, 0); // 0

var n = -5;
clamp(1, n, 12); // 1
clamp(-7, n, -8); // -7

clamp(NaN, n, 8); // NaN
clamp(3, n, NaN); // NaN  
clamp(3, NaN, 8); // NaN    

clamp(undefined, n, 8); // throws
clamp(3, n, 'h'); // throws  
clamp(3, false, 8); // throws 

just-is-prime

source

🍦 Try it

npm install just-is-prime
yarn add just-is-prime

Check if number is prime

  import isPrime from 'just-is-prime;

/*
  isPrime(1); // false
  isPrime(2); // true
  isPrime(17); // true
  isPrime(10); // false
  isPrime(); // throws
  isPrime(null); // throws
  isPrime("js"); // throws
  isPrime({}); // throws
  isPrime(function() {}); // throws
  isPrime([]); // throws
*/

just-modulo

source

🍦 Try it

npm install just-modulo
yarn add just-modulo

Modulo of a number and a divisor

import modulo from 'just-modulo';

modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 1
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN

just-random-integer

source

🍦 Try it

npm install just-random-integer
yarn add just-random-integer

Produces a random integer within a given range

import random from 'just-random-integer';

random();
// Returns either 0 or 1
random(5);
// Returns a random integer between 0 and 5 (inclusively)
random(3, 10);
// Returns a random integer between 3 and 10 (inclusively)
random(-5.8, 10.4);
// Returns a random integer between -5 and 10 (inclusively)

Functions

just-compose

source

🍦 Try it

npm install just-compose
yarn add just-compose

Return a function composed of 2 or more functions

import compose from 'just-compose';

const sqRootBiggest = compose(Math.max, Math.sqrt, Math.trunc);
sqRootBiggest(10, 5); // 3
sqRootBiggest(7, 0, 16); // 4

just-curry-it

source

🍦 Try it

npm install just-curry-it
yarn add just-curry-it

Return a curried function

import curry from 'just-curry-it';

function add(a, b, c) {
  return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9

function add(...args) {
  return args.reduce((sum, n) => sum + n, 0)
}
var curryAdd4 = curry(add, 4)
curryAdd4(1)(2, 3)(4); // 10

function converter(ratio, input) {
  return (input*ratio).toFixed(1);
}
const curriedConverter = curry(converter)
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2

just-demethodize

source

🍦 Try it

npm install just-demethodize
yarn add just-demethodize

Turn a method into a standalone function; the first arg becomes this

import demethodize from 'just-demethodize';

const trimFn = demethodize(''.trim);
['hello ', ' goodbye', 'hello again'].map(trimFn); // ['hello', 'goodbye', 'hello again']

just-flip

source

🍦 Try it

npm install just-flip
yarn add just-flip

Flip first two arguments of a function

import flip from 'just-flip';

flip(console.log)(1, 2, 3) // 2, 1, 3

import map from 'just-map-object';
import partial from 'just-partial';

const numbers = {x: 5, y: 10};
const flippedMap = flip(map);
const double = partial(flippedMap, (undefined, number) => number * 2);
double(numbers) // {x: 10, y: 20];

just-partial-it

source

🍦 Try it

npm install just-partial-it
yarn add just-partial-it

Return a partial function

import partial from 'just-partial-it';

const cubedRoot = partial(Math.pow, _, 1/3);
cubedRoot(64); // 4

const getRoot = partial(Math.pow, 64);
getRoot(1/2); // 8

just-debounce-it

source

🍦 Try it

npm install just-debounce-it
yarn add just-debounce-it

Return a debounced function

import debounce from "just-debounce-it";

const fn1 = debounce(() => console.log("Hello"), 500);
fn1();
fn1();
fn1();
// 500ms later logs 'hello' once

const fn2 = debounce(() => console.log("Hello"), 500, true);
fn2(); // logs hello immediately
fn2();
fn2();
// 500ms later logs 'hello' once

const fn3 = debounce(() => console.log("Hello"), 500);
fn3();
fn3();
fn3();
fn3.cancel();
// function cancelled before 'hello' is logged

const fn4 = debounce(() => console.log("Hello"), 500);
fn4();
fn4();
fn4();
fn4.flush();
// immediately invoke the debounced function

just-memoize

source

🍦 Try it

npm install just-memoize
yarn add just-memoize

An implementation of the memoize technique

import memoize from 'just-memoize';

const sumByOne = memoize(function(value) {
  return value + 1;
});

sumByOne(10); // Returns value returned by the function
sumByOne(10); // Cache hit!

sumByOne(20); // Returns value returned by the function
sumByOne(20); // Cache hit!

// Custom cache key (key defaults to JSON stringified arguments)
var sum = memoize(function(a, b) {
  return a + b;
}, function(a, b) {
  return `${a}-${b}`;
});

sum(10, 10); // Returns value returned by the function
sum(10, 20); // Returns value returned by the function
sum(10, 20); // Cache hit!

just-memoize-last

source

🍦 Try it

npm install just-memoize-last
yarn add just-memoize-last

A memoize implementation that only caches the most recent evaluation

const memoizeLast = require('just-memoize-last')
const compare = require('just-compare')

const maxValue = memoizeLast(function(arr) {
  return Math.max(...arr)
}, function(a, b) {
  return compare(a, b)
});

maxValue([1,2,3]) // 3
maxValue([1,2,3]) // cache hit!
maxValue([1,3,4]) // 4
maxValue([1,2,3]) // 3

just-random

source

🍦 Try it

npm install just-random
yarn add just-random

Return a randomly selected element in an array

import random from 'just-random';

random([1, 2, 3]);
// one of [1, 2, 3], at random

just-throttle

source

🍦 Try it

npm install just-throttle
yarn add just-throttle

Return a throttled function

import throttle from 'just-throttle';

// no matter how many times the function is called, only invoke once within the given interval
// options: 
// `leading`: invoke  before interval
// `trailing`: invoke afer interval

const fn1 = throttle(() => console.log('hello'), 500, {leading: true});
setInterval(fn1, 400);
// logs 'hello' immediately and then every 500ms

const fn2 = throttle(() => console.log('hello'), 500, {trailing: true});
setInterval(fn2, 400);
// logs 'hello' after 500ms and then every 500ms

const fn3 = throttle(() => console.log('hello'), 500, {leading: true, trailing: true});
// forces trailing to false

const fn4 = throttle(() => console.log('hello'), 500, { leading: false });
fn4();
fn4();
fn4();
fn4.cancel();
// function cancelled before 'hello' is logged

const fn5 = throttle(() => console.log("Hello"), 500);
fn5();
fn5();
fn5();
fn5.flush();
// immediately invoke the throttled function

just-once

source

🍦 Try it

npm install just-once
yarn add just-once

Create a function that can only be invoked once

import once from 'just-once';

const fn = once(() => console.log('hello'));

fn();
// logs 'hello'
fn();
// does nothing

Testing

Run all tests as a single test suite with

npm run test

Cross browser tests (via saucelabs) are in the sauce branch

Contribute!

https://github.com/angus-c/just/blob/master/CONTRIBUTING.md

We welcome contributions. Please follow our contribution guidelines.

Download Details:

Author: angus-c
Source Code: https://github.com/angus-c/just 
License: MIT license

#typescript #javascript #library #pwa 

Library Of Dependency-free JavaScript Utilities That Do Just one Thing

Automated Auditing, Performance Metrics, & Best Practices for The Web

Lighthouse

Lighthouse analyzes web apps and web pages, collecting modern performance metrics and insights on developer best practices.

Using Lighthouse in Chrome DevTools

Lighthouse is integrated directly into the Chrome DevTools, under the "Lighthouse" panel.

Installation: install Chrome.

Run it: open Chrome DevTools, select the Lighthouse panel, and hit "Generate report".

Lighthouse integration in Chrome DevTools

Using the Chrome extension

The Chrome extension was available prior to Lighthouse being available in Chrome Developer Tools, and offers similar functionality.

Installation: install the extension from the Chrome Web Store.

Run it: follow the extension quick-start guide.

Using the Node CLI

The Node CLI provides the most flexibility in how Lighthouse runs can be configured and reported. Users who want more advanced usage, or want to run Lighthouse in an automated fashion should use the Node CLI.

Lighthouse requires Node 14 LTS (14.x) or later.

Installation:

npm install -g lighthouse
# or use yarn:
# yarn global add lighthouse

Run it: lighthouse https://airhorner.com/

By default, Lighthouse writes the report to an HTML file. You can control the output format by passing flags.

CLI options

$ lighthouse --help

lighthouse <url> <options>

Logging:
  --verbose  Displays verbose logging  [boolean] [default: false]
  --quiet    Displays no progress, debug logs, or errors  [boolean] [default: false]

Configuration:
  --save-assets                  Save the trace contents & devtools logs to disk  [boolean] [default: false]
  --list-all-audits              Prints a list of all available audits and exits  [boolean] [default: false]
  --list-trace-categories        Prints a list of all required trace categories and exits  [boolean] [default: false]
  --print-config                 Print the normalized config for the given config and options, then exit.  [boolean] [default: false]
  --additional-trace-categories  Additional categories to capture with the trace (comma-delimited).  [string]
  --config-path                  The path to the config JSON.
                                 An example config file: core/config/lr-desktop-config.js  [string]
  --preset                       Use a built-in configuration.
                                 WARNING: If the --config-path flag is provided, this preset will be ignored.  [string] [choices: "perf", "experimental", "desktop"]
  --chrome-flags                 Custom flags to pass to Chrome (space-delimited). For a full list of flags, see https://bit.ly/chrome-flags
                                 Additionally, use the CHROME_PATH environment variable to use a specific Chrome binary. Requires Chromium version 66.0 or later. If omitted, any detected Chrome Canary or Chrome stable will be used.  [string] [default: ""]
  --port                         The port to use for the debugging protocol. Use 0 for a random port  [number] [default: 0]
  --hostname                     The hostname to use for the debugging protocol.  [string] [default: "localhost"]
  --form-factor                  Determines how performance metrics are scored and if mobile-only audits are skipped. For desktop, --preset=desktop instead.  [string] [choices: "mobile", "desktop"]
  --screenEmulation              Sets screen emulation parameters. See also --preset. Use --screenEmulation.disabled to disable. Otherwise set these 4 parameters individually: --screenEmulation.mobile --screenEmulation.width=360 --screenEmulation.height=640 --screenEmulation.deviceScaleFactor=2
  --emulatedUserAgent            Sets useragent emulation  [string]
  --max-wait-for-load            The timeout (in milliseconds) to wait before the page is considered done loading and the run should continue. WARNING: Very high values can lead to large traces and instability  [number]
  --enable-error-reporting       Enables error reporting, overriding any saved preference. --no-enable-error-reporting will do the opposite. More: https://github.com/GoogleChrome/lighthouse/blob/main/docs/error-reporting.md  [boolean]
  --gather-mode, -G              Collect artifacts from a connected browser and save to disk. (Artifacts folder path may optionally be provided). If audit-mode is not also enabled, the run will quit early.
  --audit-mode, -A               Process saved artifacts from disk. (Artifacts folder path may be provided, otherwise defaults to ./latest-run/)
  --only-audits                  Only run the specified audits  [array]
  --only-categories              Only run the specified categories. Available categories: accessibility, best-practices, performance, pwa, seo  [array]
  --skip-audits                  Run everything except these audits  [array]
  --budget-path                  The path to the budget.json file for LightWallet.  [string]

Output:
  --output       Reporter for the results, supports multiple values. choices: "json", "html", "csv"  [array] [default: ["html"]]
  --output-path  The file path to output the results. Use 'stdout' to write to stdout.
                   If using JSON output, default is stdout.
                   If using HTML or CSV output, default is a file in the working directory with a name based on the test URL and date.
                   If using multiple outputs, --output-path is appended with the standard extension for each output type. "reports/my-run" -> "reports/my-run.report.html", "reports/my-run.report.json", etc.
                   Example: --output-path=./lighthouse-results.html  [string]
  --view         Open HTML report in your browser  [boolean] [default: false]

Options:
  --version                            Show version number  [boolean]
  --help                               Show help  [boolean]
  --cli-flags-path                     The path to a JSON file that contains the desired CLI flags to apply. Flags specified at the command line will still override the file-based ones.
  --locale                             The locale/language the report should be formatted in
  --blocked-url-patterns               Block any network requests to the specified URL patterns  [array]
  --disable-storage-reset              Disable clearing the browser cache and other storage APIs before a run  [boolean]
  --throttling-method                  Controls throttling method  [string] [choices: "devtools", "provided", "simulate"]
  --throttling
  --throttling.rttMs                   Controls simulated network RTT (TCP layer)
  --throttling.throughputKbps          Controls simulated network download throughput
  --throttling.requestLatencyMs        Controls emulated network RTT (HTTP layer)
  --throttling.downloadThroughputKbps  Controls emulated network download throughput
  --throttling.uploadThroughputKbps    Controls emulated network upload throughput
  --throttling.cpuSlowdownMultiplier   Controls simulated + emulated CPU throttling
  --extra-headers                      Set extra HTTP Headers to pass with request
  --precomputed-lantern-data-path      Path to the file where lantern simulation data should be read from, overwriting the lantern observed estimates for RTT and server latency.  [string]
  --lantern-data-output-path           Path to the file where lantern simulation data should be written to, can be used in a future run with the `precomputed-lantern-data-path` flag.  [string]
  --plugins                            Run the specified plugins  [array]
  --channel  [string] [default: "cli"]
  --chrome-ignore-default-flags  [boolean] [default: false]

Examples:
  lighthouse <url> --view                                                                          Opens the HTML report in a browser after the run completes
  lighthouse <url> --config-path=./myconfig.js                                                     Runs Lighthouse with your own configuration: custom audits, report generation, etc.
  lighthouse <url> --output=json --output-path=./report.json --save-assets                         Save trace, screenshots, and named JSON report.
  lighthouse <url> --screenEmulation.disabled --throttling-method=provided --no-emulatedUserAgent  Disable device emulation and all throttling
  lighthouse <url> --chrome-flags="--window-size=412,660"                                          Launch Chrome with a specific window size
  lighthouse <url> --quiet --chrome-flags="--headless"                                             Launch Headless Chrome, turn off logging
  lighthouse <url> --extra-headers "{\"Cookie\":\"monster=blue\", \"x-men\":\"wolverine\"}"        Stringify'd JSON HTTP Header key/value pairs to send in requests
  lighthouse <url> --extra-headers=./path/to/file.json                                             Path to JSON file of HTTP Header key/value pairs to send in requests
  lighthouse <url> --only-categories=performance,pwa                                               Only run the specified categories. Available categories: accessibility, best-practices, performance, pwa, seo

For more information on Lighthouse, see https://developers.google.com/web/tools/lighthouse/.

Output Examples

lighthouse
# saves `./<HOST>_<DATE>.report.html`

lighthouse --output json
# json output sent to stdout

lighthouse --output html --output-path ./report.html
# saves `./report.html`

# NOTE: specifying an output path with multiple formats ignores your specified extension for *ALL* formats
lighthouse --output json --output html --output-path ./myfile.json
# saves `./myfile.report.json` and `./myfile.report.html`

lighthouse --output json --output html
# saves `./<HOST>_<DATE>.report.json` and `./<HOST>_<DATE>.report.html`

lighthouse --output-path=~/mydir/foo.out --save-assets
# saves `~/mydir/foo.report.html`
# saves `~/mydir/foo-0.trace.json` and `~/mydir/foo-0.devtoolslog.json`

lighthouse --output-path=./report.json --output json
# saves `./report.json`

Lifecycle Examples

You can run a subset of Lighthouse's lifecycle if desired via the --gather-mode (-G) and --audit-mode (-A) CLI flags.

lighthouse http://example.com -G
# launches browser, collects artifacts, saves them to disk (in `./latest-run/`) and quits

lighthouse http://example.com -A
# skips browser interaction, loads artifacts from disk (in `./latest-run/`), runs audits on them, generates report

lighthouse http://example.com -GA
# Normal gather + audit run, but also saves collected artifacts to disk for subsequent -A runs.


# You can optionally provide a custom folder destination to -G/-A/-GA. Without a value, the default will be `$PWD/latest-run`.
lighthouse -GA=./gmailartifacts https://gmail.com

Notes on Error Reporting

The first time you run the CLI you will be prompted with a message asking you if Lighthouse can anonymously report runtime exceptions. The Lighthouse team uses this information to detect new bugs and avoid regressions. Opting out will not affect your ability to use Lighthouse in any way. Learn more.

Using the Node module

You can also use Lighthouse programmatically with the Node module.

Read Using Lighthouse programmatically for help getting started.
Read Lighthouse Configuration to learn more about the configuration options available.

Viewing a report

Lighthouse can produce a report as JSON or HTML.

HTML report:

Lighthouse example audit

Online Viewer

Running Lighthouse with the --output=json flag generates a JSON dump of the run. You can view this report online by visiting https://googlechrome.github.io/lighthouse/viewer/ and dragging the file onto the app. You can also use the "Export" button from the top of any Lighthouse HTML report and open the report in the Lighthouse Viewer.

In the Viewer, reports can be shared by clicking the share icon in the top right corner and signing in to GitHub.

Note: shared reports are stashed as a secret Gist in GitHub, under your account.

Docs & Recipes

Useful documentation, examples, and recipes to get you started.

Docs

Recipes

Videos

The session from Google I/O 2018 covers the new performance engine, upcoming Lighthouse REST API, and using the Chrome UX report to evaluate real-user data.

Lighthouse @ Google I/O 2018

The session from Google I/O 2017 covers architecture, writing custom audits, GitHub/Travis/CI integration, headless Chrome, and more:

Lighthouse @ Google I/O 2017

click to watch the video

Develop

Read on for the basics of hacking on Lighthouse. Also, see Contributing for detailed information.

Setup

# yarn should be installed first

git clone https://github.com/GoogleChrome/lighthouse

cd lighthouse
yarn
yarn build-all

Run

node cli http://example.com
# append --chrome-flags="--no-sandbox --headless --disable-gpu" if you run into problems connecting to Chrome

Getting started tip: node --inspect-brk cli http://example.com to open up Chrome DevTools and step through the entire app. See Debugging Node.js with Chrome DevTools for more info.

Tests

# lint and test all files
yarn test

# watch for file changes and run tests
#   Requires http://entrproject.org : brew install entr
yarn watch

## run linting, unit, and smoke tests separately
yarn lint
yarn unit
yarn smoke

## run tsc compiler
yarn type-check

Docs

Some of our docs have tests that run only in CI by default. If you end up needing to modify our documentation, you'll need to run yarn build-pack && yarn test-docs locally to make sure they pass.

Additional Dependencies

  • brew install jq

Lighthouse Integrations in Web Perf services

This section details services that have integrated Lighthouse data. If you're working on a cool project integrating Lighthouse and would like to be featured here, file an issue to this repo or tweet at us @_____lighthouse!

Web Page Test — An open source tool for measuring and analyzing the performance of web pages on real devices. Users can choose to produce a Lighthouse report alongside the analysis of WebPageTest results.

HTTPArchive - HTTPArchive tracks how the web is built by crawling 500k pages with Web Page Test, including Lighthouse results, and stores the information in BigQuery where it is publicly available.

Calibre - Calibre is a comprehensive performance monitoring platform running on Lighthouse. See the performance impact of your work before it hits production with GitHub Pull Request Reviews. Track the impact of Third Party scripts. Automate your performance system with a developer-first Node.js API. Try Calibre with a free 15-day trial.

DebugBear - DebugBear is a website monitoring tool based on Lighthouse. See how your scores and metrics changed over time, with a focus on understanding what caused each change. DebugBear is a paid product with a free 30-day trial.

Treo - Treo is Lighthouse as a Service. It provides regression testing, geographical regions, custom networks, and integrations with GitHub & Slack. Treo is a paid product with plans for solo-developers and teams.

Alertdesk - Alertdesk is based on Lighthouse and helps you to keep track of your site’s quality & performance. Run daily quality & performance tests from both Mobile and Desktop and dive into the powerful & intuitive reports. You can also monitor your uptime (every minute - 24/7) & domain health. Alertdesk is a paid product with a free 14-day trial.

Screpy - Screpy is a web analysis tool that can analyze all pages of your websites in one dashboard and monitor them with your team. It's powered by Lighthouse and it also includes some different analysis tools (SERP, W3C, Uptime, etc). Screpy has free and paid plans.

Lighthouse Keeper - Lighthouse Keeper monitors your pages' Lighthouse scores and notifies you if they drop below your thresholds. Lighthouse Keeper is a free service that monitors up to 3 URLs once per day.

Siteimprove Performance — Siteimprove Performance is a web Performance monitoring solution that enables a marketer, manager or decision maker to understand and optimize website load times. Get easy-to-use insights with a focus on quick and impactful wins. Siteimprove Performance is a paid product with a free 14-day trial.

SpeedCurve — SpeedCurve is a tool for continuously monitoring web performance across different browsers, devices, and regions. It can aggregate any metric including Lighthouse scores across multiple pages and sites, and allows you to set performance budgets with Slack or email alerts. SpeedCurve is a paid product with a free 30-day trial.

Speedrank - Speedrank monitors the performance of your website in the background. It displays Lighthouse reports over time and delivers recommendations for improvement. Speedrank is a paid product with 14-day-trial.

Foo - Lighthouse-as-a-service offering free and premium plans. Provides monitoring and historical reporting of Lighthouse audits with CircleCI, GitHub, and other integrations. Features include Slack notifications, PR comment reporting and more.

Apdex - Apdex is a website performance service. The main features are historical Lighthouse report visualizations, mobile/desktop options, alerts, uptime monitoring, and more. There are flexible paid plans and a 30-day free trial.

Websu - Websu is an open source project to provide Lighthouse-as-a-Service through a simple HTTP REST API. The main features are ability to host and deploy in your own environment and historical Lighthouse report summaries.

DTEKT.IO - DTEKT is a website performance and uptime monitoring service. It uses lighthouse to provide visibility into the performance of websites from multiple locations on multiple devices. It offers three months free trial and paid plans.

SpeedVitals - SpeedVitals is a Lighthouse powered tool to measure web performance across multiple devices and locations. It has various features like Layout Shift Visualization, Waterfall Chart, Field Data and Resource Graphs. SpeedVitals offers both free and paid plans.

Lighthouse Metrics - Lighthouse Metrics gives you global performance insights with a single test. You can also monitor your websites on a daily or hourly base. Lighthouse Metrics offers free global one-time tests and performance monitoring as a paid feature with a free 14-day trial.

Auditzy - Auditzy™ is a robust website auditing & monitoring tool which lets you analyze your web page(s) pre-user journey. Analyze the Competitor Health Metric, Core Web Vitals, and Technology. Compare your web pages with your competitors to understand where you are leading or lagging. Real-time notification with Slack. Have Seamless Collaboration with Multiple Teams. Automate your Audits hourly, daily, weekly, and so on. It has a free trial with pay as you go plans.

Lighthouse Integrations in non-Web Perf services

PageWatch — PageWatch is a tool to find problem pages on your website. It provides insights into spelling errors, layout issues, slow pages (powered by Lighthouse) and more. PageWatch is offered via free and paid plans.

SEO Guard — SEO Guard is a website monitoring solution. It provides metrics based on Lighthouse scores. The service is offered via free and paid premium plans.

Fluxguard - Fluxguard provides website DOM change monitoring orchestrated with Google Puppeteer, and audited by Lighthouse. Fluxguard is a freemium product, with monthly monitoring of up to 75 pages for free.

Microlink — Microlink is a cloud browser as API. It offers Lighthouse reports on demand, making it easy to build any service on top. Similar functionality is available via the underlying open-source project named browserless.

Peyk - Peyk is a website change detection & monitoring service. Peyk can detect changes in cookies, network requests, technologies, local & session storage, lighthouse audits, screenshots and so much more. Peyk is offered via free and paid plans.

Wattspeed — Wattspeed is a free tool that generates snapshots - historical captures of your web pages that include Lighthouse scores, a list of technologies, W3C HTML validator results, DOM size, mixed content info, and more.

AwesomeTechStack — AwesomeTechStack is a free to use website tech stack analyzer. AwesomeTechStack provides insights into the security, modernity, and performance of any website's technology stack and guidance to improve performance. Lighthouse insights are a crucial part of a website's tech stack rating.

Plugins

lighthouse-plugin-field-performance - a plugin that adds real-user performance metrics for the URL using the data from Chrome UX Report.

lighthouse-plugin-publisher-ads - a tool to improve ad speed and overall quality through a series of automated audits. At the moment, this is primarily targeted at sites using Google Ad Manager. This tool will aid in resolving discovered problems, providing a tool to be used to evaluate effectiveness of iterative changes while suggesting actionable feedback.

lighthouse-plugin-crux - a plugin that quickly gathers real-user-metrics data from the Chrome UX Report API.

Related Projects

Other awesome open source projects that use Lighthouse.

  • auto-lighthouse - a CLI for crawling a domain and generating mobile and desktop reports for each page.
  • Exthouse - Analyze the impact of a browser extension on web performance.
  • Garie - An open source tool for monitoring performance using Lighthouse, PageSpeed Insights, Prometheus, Grafana and Docker.
  • Gimbal - An open source (MIT licensed) tool used to measure, analyze, and budget aspects of a web application. Gimbal also integrates reports with GitHub pull requests.
  • Gradle Lighthouse Plugin - An open source Gradle plugin that runs Lighthouse tests on multiple URLs and asserts category score thresholds (useful in continuous integration).
  • lightcrawler - Crawl a website and run each page found through Lighthouse.
  • lighthouse-badges - Generate gh-badges (shields.io) based on Lighthouse performance.
  • lighthouse-batch - Run Lighthouse over a number of sites and generate a summary of their metrics/scores.
  • lighthouse-batch-parallel - Run multiple Lighthouse runs in parallel to accelerate the data collecting process, get the result stream (csv, json, js object) in your own process (warning: performance results may be volatile).
  • lighthouse-check-action - A GitHub Action to run Lighthouse in a workflow, featuring Slack notifications and report upload to S3.
  • lighthouse-check-orb - A CircleCI Orb to run Lighthouse in a workflow, featuring Slack notifications and report upload to S3.
  • andreasonny83/lighthouse-ci - Run Lighthouse and assert scores satisfy your custom thresholds.
  • GoogleChrome/lighthouse-ci - (official) Automate running Lighthouse for every commit, viewing the changes, and preventing regressions.
  • lighthouse-ci-action - A GitHub Action that makes it easy to run Lighthouse in CI and keep your pages small using performance budgets.
  • lighthouse-cron - Cron multiple batch Lighthouse audits and emit results for sending to remote server.
  • lighthouse-gh-reporter - Run Lighthouse in CI and report back in a comment on your pull requests
  • lighthouse-hue - Set the color of Philips Hue lights based on a Lighthouse score
  • lighthouse-jest-example - Gather performance metrics via Lighthouse and assert results with Jest; uses Puppeteer to start Chrome with network emulation settings defined by WebPageTest.
  • lighthouse-lambda - Run Lighthouse on AWS Lambda with prebuilt stable desktop Headless Chrome.
  • lighthouse-magic-light - Set the color of the MagicLight Bluetooth Smart Light Bulb based on Lighthouse score
  • lighthouse-mocha-example - Run Lighthouse performance tests with Mocha and chrome-launcher.
  • lighthouse-monitor - Run Lighthouse against all your URLs. Send metrics to any backend you want, save all reports with automatic data retention, and compare any two results in a web UI.
  • lighthouse-persist - Run Lighthouse and upload HTML reports to an AWS S3 bucket.
  • lighthouse-viewer - Render the Lighthouse JSON into a report, using the Lighthouse Report Renderer repackaged as UMD and ESM. Also available with React, Svelte and Vue wrappers.
  • lighthouse4u - LH4U provides Google Lighthouse as a service, surfaced by both a friendly UI+API, and backed by Elastic Search for easy querying and visualization.
  • performance-budgets - Easily assert Lighthouse budgets with Docker.
  • pwmetrics - Gather performance metrics
  • react-lighthouse-viewer - Render a Lighthouse JSON report in a React Component.
  • site-audit-seo - CLI tool for SEO site audit, crawl site, lighthouse each page. Output to console and tables in csv, xlsx, json, web or Google Drive.
  • webpack-lighthouse-plugin - Run Lighthouse from a Webpack build.
  • is-website-vulnerable - An open source Node.js CLI tool that finds publicly known security vulnerabilities in a website's frontend JavaScript libraries.
  • cypress-audit - Run Lighthouse and Pa11y audits directly in your E2E test suites.

FAQ

How does Lighthouse work?

See Lighthouse Architecture.

Why is the performance score so low? It looks fine to me.

Lighthouse reports the performance metrics as they would be experienced by a typical mobile user on a 4G connection and a mid-tier ~$200 phone. Even if it loads quickly on your device and network, users in other environments will experience the site very differently.

Read more in our guide to throttling.

Why does the performance score change so much?

Lighthouse performance scores will change due to inherent variability in web and network technologies, even if there hasn't been a code change. Test in consistent environments, run Lighthouse multiple times, and beware of variability before drawing conclusions about a performance-impacting change.

Read more in our guide to reducing variability.

Can I configure the lighthouse run?

Yes! Details in Lighthouse configuration.

How does Lighthouse use network throttling, and how can I make it better?

Good question. Network and CPU throttling are applied by default in a Lighthouse run. The network attempts to emulate slow 4G connectivity and the CPU is slowed down 4x from your machine's default speed. If you prefer to run Lighthouse without throttling, you'll have to use the CLI and disable it with the --throttling.* flags mentioned above.

Read more in our guide to network throttling.

Are results sent to a remote server?

Nope. Lighthouse runs locally, auditing a page using a local version of the Chrome browser installed on the machine. Report results are never processed or beaconed to a remote server.

How do I get localized Lighthouse results via the CLI?

Starting in Lighthouse 8.0, Lighthouse relies entirely on native Intl support and no longer uses an Intl polyfill. If you're using Node 14 or later, there should be no issue because Node is now built with full-icu by default.

However, if you're using a small-icu Node build, you may see Lighthouse log messages about your locale not being available. To remedy this, you can upgrade to Node 14+ or manually install ICU data by using the full-icu module and the --icu-data-dir node flag at launch.

How do I author custom audits to extend Lighthouse?

Tip: see Lighthouse Architecture for more information on terminology and architecture.

Lighthouse can be extended to run custom audits and gatherers that you author. This is great if you're already tracking performance metrics in your site and want to surface those metrics within a Lighthouse report.

If you're interested in running your own custom audits, check out our Custom Audit Example over in recipes.

How do I contribute?

We'd love help writing audits, fixing bugs, and making the tool more useful! See Contributing to get started.

Download Details:

Author: GoogleChrome
Source Code: https://github.com/GoogleChrome/lighthouse 
License: Apache-2.0 license

#javascript #web #pwa #chrome #devtools 

Automated Auditing, Performance Metrics, & Best Practices for The Web
Dexter  Goodwin

Dexter Goodwin

1661859915

Next.js App Work Offline using Service Workers Via Google's Workbox

next-offline

Use Workbox with Next.js and easily enable offline functionality in your application!

Installation

$ npm install --save next-offline
$ yarn add next-offline

Usage

There are two important things to set up, first we need next-offline to wrap your next config.

If you haven't yet, create a next.config.js in your project.

// next.config.js
const withOffline = require('next-offline')

const nextConfig = {
  ...
}

module.exports = withOffline(nextConfig)

Next we need to make sure our application is properly serving the service worker, this setup depends on how you're hosting your application. There is documentation below. If you're not using Now 2.0, the Now 1.0 example should work in most circumstances.

Serving service worker

Because service workers are so powerful, the API has some restrictions built in. For example, service workers must be served on the domain they're being used on - you can't use a CDN.

Now 1.0

You'll want to use the next.js custom server API. The easiest way to do that is creating a server.js that looks like this:

const { createServer } = require('http')
const { join } = require('path')
const { parse } = require('url')
const next = require('next')

const app = next({ dev: process.env.NODE_ENV !== 'production' })
const handle = app.getRequestHandler()

app.prepare()
  .then(() => {
    createServer((req, res) => {
      const parsedUrl = parse(req.url, true)
      const { pathname } = parsedUrl

      // handle GET request to /service-worker.js
      if (pathname === '/service-worker.js') {
        const filePath = join(__dirname, '.next', pathname)

        app.serveStatic(req, res, filePath)
      } else {
        handle(req, res, parsedUrl)
      }
    })
    .listen(3000, () => {
      console.log(`> Ready on http://localhost:${3000}`)
    })
  })

You can read more about custom servers in the Next.js docs

If you're not hosting with Now, I'd probably follow the Now 1.0 approach because the custom server API can enable a lot of functionality, it just simply doesn't work well with Now 2.0 🙇‍♂️

Now 2.0

Because Now 2.0 works so different than the previous version, so does serving the service worker. There are a few different ways to do this, but I'd recommend checking out this now2 example app. The changes to be aware of are in the now.json and next.config.js.

Registering service worker

Compile-time registration

By default next-offline will register a service worker with the script below, this is automatically added to your client side bundle once withOffline is invoked.

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function () {
    navigator.serviceWorker.register('/service-worker.js', { scope: '/' }).then(function (registration) {
      console.log('SW registered: ', registration)
    }).catch(function (registrationError) {
      console.log('SW registration failed: ', registrationError)
    })
  })
}

Runtime registration

Alternative to compile-time, you can take control of registering/unregistering in your application code by using the next-offline/runtime module.

import { register, unregister } from 'next-offline/runtime'

class App extends React.Component {
  componentDidMount () {
    register()
  }
  componentWillUnmount () {
    unregister()
  }
  ..
}

You can choose to pass the service worker path and scope if needed.

import { register, unregister } from 'next-offline/runtime'

class App extends React.Component {
  componentDidMount () {
    /** 
      * Default service worker path is '/service-worker.js' 
      * Refer https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register for default scope rules
      *
    */
    register('/sub_folder/service-worker.js', {scope: '/sub_folder'}) 
  }
  componentWillUnmount () {
    unregister()
  }
  ..
}

If you're handling registration on your own, pass dontAutoRegisterSw to next-offline.

// next.config.js
const withOffline = require('next-offline')

module.exports = withOffline({ dontAutoRegisterSw: true })

Customizing service worker

Using workbox

If you're new to workbox, I'd recommend reading this quick guide -- anything inside of workboxOpts will be passed to workbox-webpack-plugin.

Define a workboxOpts object in your next.config.js and it will gets passed to workbox-webpack-plugin. Workbox is what next-offline uses under the hood to generate the service worker, you can learn more about it here.

// next.config.js
const withOffline = require('next-offline')

const nextConfig = {
  workboxOpts: {
    ...
  }
}

module.exports = withOffline(nextConfig)

next-offline options

On top of the workbox options, next-offline has some options built in flags to give you finer grain control over how your service worker gets generated.

NameTypeDescriptionDefault
generateSwBooleanIf false, next-offline will not generate a service worker and will instead try to modify the file found in workboxOpts.swSrc using WorkBox's [Inject Plugin](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin#injectmanifest_plugin)true
dontAutoRegisterSwBooleanIf true, next-offline won't automatically push the registration script into the application code. This is required if you're using runtime registration or are handling registration on your own.false
devSwSrcStringPath to be registered by next-offline during development. By default next-offline will register a noop during developmentfalse
generateInDevModeBooleanIf true, the service worker will also be generated in development mode. Otherwise the service worker defined in devSwSrc will be used.false
registerSwPrefixStringIf your service worker isn't at the root level of your application, this can help you prefix the path. This is useful if you'd like your service worker on foobar.com/my/long/path/service-worker.js. This affects the [scope](https://developers.google.com/web/ilt/pwa/introduction-to-service-worker#registration_and_scope) of your service worker.false
scopeStringThis is passed to the automatically registered service worker allowing increase or decrease what the service worker has control of."/"

Cache strategies

By default next-offline has the following blanket runtime caching strategy. If you customize next-offline with workboxOpts, the default behaviour will not be passed into workbox-webpack-plugin. This article is great at breaking down various different cache recipes.

{
  runtimeCaching: [
    {
      urlPattern: /^https?.*/,
      handler: 'NetworkFirst',
      options: {
        cacheName: 'offlineCache',
        expiration: {
          maxEntries: 200
        }
      }
    }
  ]
}
// next.config.js
const withOffline = require('next-offline')

module.exports = withOffline({
  workboxOpts: {
    runtimeCaching: [
      {
        urlPattern: /.png$/,
        handler: 'CacheFirst'
      },
      {
        urlPattern: /api/,
        handler: 'NetworkFirst',
        options: {
          cacheableResponse: {
            statuses: [0, 200],
            headers: {
              'x-test': 'true'
            }
          }
        }
      }
    ]
  }
})

Service worker path

If your application doesn't live on the root of your domain, you can use registerSwPrefix. This is helpful if your application is on domain.com/my/custom/path because by default next-offline assumes your application is on domain.com and will try to register domain.com/service-worker.js. We can't support using assetPrefix because service workers must be served on the root domain. For a technical breakdown on that limitation, see the following link: Is it possible to serve service workers from CDN/remote origin?

By default next-offline will precache all the Next.js webpack emitted files and the user-defined static ones (inside /static) - essentially everything that is exported as well.

If you'd like to include some more or change the origin of your static files use the given workbox options:

workboxOpts: {
  modifyURLPrefix: {
    'app': assetPrefix,
  },
  runtimeCaching: {...}
}

Development mode

By default next-offline will add a no-op service worker in development. If you want to provide your own pass its filepath to devSwSrc option. This is particularly useful if you want to test web push notifications in development, for example.

// next.config.js
const withOffline = require('next-offline')

module.exports = withOffline({
  devSwSrc: '/path/to/my/dev/service-worker.js'
})

You can disable this behavior by setting the generateInDevMode option to true.

next export

In next-offline@3.0.0 we've rewritten the export functionality to work in more cases, more reliably, with less code thanks to some of the additions in Next 7.0.0!

You can read more about exporting at Next.js docs but next offline should Just Work™️.

next offline 5.0

If you're upgrading to the latest version of next-offline I recommend glancing at what's been added/changed inside of Workbox in 5.x releases along with the 4.0 release which included the breaking changes. Next Offline's API hasn't changed, but a core dependency has!


Questions? Feedback? Please let me know

Contributing

next-offline is a lerna monorepo which uses yarn workspaces. After cloning the repo, run the following

$ yarn bootstrap

This will ensure your development version of next-offline is symlinked in the examples & tests which should allow you to quickly make changes!

Download Details:

Author: Hanford
Source Code: https://github.com/hanford/next-offline 
License: MIT

#javascript #next #website #pwa 

Next.js App Work Offline using Service Workers Via Google's Workbox
Hunter  Krajcik

Hunter Krajcik

1661195700

A Library for Detecting If A New PWA Version is Avaiable

pwa_update_listener

A Flutter package for checking if there is a new PWA version, and it is ready to be update.

Screen Shot 2021-08-18 at 22 15 28

Getting Started

Wrap PwaUpdateListener around a widget in the main page. onReady will be called when the child widget is shown (eg. when a page is pop and the main page is shown) or when the app return from background.

Scaffold(
      body: PwaUpdateListener(
        onReady: () {
          /// Show a snackbar to get users to reload into a newer version
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Row(
                children: [
                  Expanded(child: Text('A new update is ready')),
                  TextButton(
                    onPressed: () {
                      reloadPwa();
                    },
                    child: Text('UPDATE'),
                  ),
                ],
              ),
              duration: Duration(days: 365),
              behavior: SnackBarBehavior.floating,
            ),
          );
        },
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
            ],
          ),
        ),
      ),
    );

Installing

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add pwa_update_listener

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  pwa_update_listener: ^0.1.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:pwa_update_listener/pwa_update_listener.dart';

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:pwa_update_listener/pwa_update_listener.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: PwaUpdateListener(
        onReady: () {
          /// Show a snackbar to get users to reload into a newer version
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Row(
                children: [
                  Expanded(child: Text('A new update is ready')),
                  TextButton(
                    onPressed: () {
                      reloadPwa();
                    },
                    child: Text('UPDATE'),
                  ),
                ],
              ),
              duration: Duration(days: 365),
              behavior: SnackBarBehavior.floating,
            ),
          );
        },
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Download Details:

Author: panuavakul
Source Code: https://github.com/panuavakul/pwa_update_listener 
License: MIT license

#flutter #dart #pwa 

A Library for Detecting If A New PWA Version is Avaiable
Best of Crypto

Best of Crypto

1660231320

Fantom PWA Explorer: JavaScript and Vue Based Fantom PWA Explorer

Fantom PWA Explorer

JavaScript and Vue based Fantom pwa explorer.

We are using:

  • Node / NPM
  • ES2015 (and beyond) support.
  • Vue.js
  • Vue Router for routing
  • Vuex for global state management
  • SCSS

Project setup

We use npm to handle dependencies.

npm install

Hot Build

The npm script can be used to serve default implementation.

npm run serve

Production Build

npm run build

Localization

Translations for views and components are located in src/locales directory.

Production notes

You should disable HTTP caching for file dist/service-worker.js.

Download details:

Author: Fantom-foundation
Source code: https://github.com/Fantom-foundation/opera-jet-explorer
License: MIT license

#fantom #blockchain #pwa #vue #javascript

Fantom PWA Explorer: JavaScript and Vue Based Fantom PWA Explorer
Lawrence  Lesch

Lawrence Lesch

1659762960

Hint: A Hinting Engine for The Web

webhint

Quick start user guide

webhint is a customizable linting tool that helps you improve your site's accessibility, speed, cross-browser compatibility, and more by checking your code for best practices and common errors.

It can be run from the command line (CLI), via a browser extension, as a VS Code extension, and from the online service.

To use it from the from the CLI you will need to install Node.js (v10.x or later) on your machine, and you can use npx to test it.

Testing with npx

Run the following command:

npx hint https://example.com

This will analyze https://example.com using the default configuration.

Installing webhint locally

Install webhint as a devDependency of your project:

npm install hint --save-dev

And then add a script task to your package.json:

{
    ...
    "scripts": {
        "webhint": "hint"
    }
}

And run it via:

npm run webhint -- http://localhost:8080

Or if you are using yarn you can skip the step to create a task and run directly:

yarn hint http://localhost:8080

To know more about webhint, how to configure it, etc. see the online user guide, or the local version for the most recent content.

Contributing to webhint

This project follows a monorepo pattern. That means that the code for all the webhint flavors (CLI, browser and VS Code extension, hints, formatters, etc.) are in here and are published as separate npm packages.

To build the project from the source you will need to install a recent version of node and yarn. Once you've done this run the following from the root of your cloned version:

yarn
yarn build

This can take a bit so please be patient.

To learn more about the internals of webhint, the structure of the project, how to create new hints, parsers, formatters, etc, take a look at the online contributor guide (or the local version).

Contributing to the browser and VS Code extensions

To learn about how to build one of the extensions please check the CONTRIBUTING.md files for each of these packages:

Code of Conduct

All projects in the webhintio organization follow this CoC which adheres to the OpenJS Foundation Code of Conduct.

Other important links

Author: Webhintio
Source Code: https://github.com/webhintio/hint 
License: Apache-2.0 license

#javascript #lint #security #pwa 

Hint: A Hinting Engine for The Web

Building MatchUp App for Find A Sports Match using NextJS and AWS

MatchUp

Find a local sports match that fits your skill level. Built with NextJS and AWS.

About The Project

Looking for a fun and easy way to meet up and play sports with locals in your city? MatchUp makes it simple and quick to connect with other sports enthusiasts in your area so you can hit the court, field, or course in no time! By requiring a small commitment deposit of 5€, we make sure that people that signed up to a MatchUp actually appear. If they do, the deposit gets refunded - but if not, it will be automatically donated to a local charity organization.

Product Name Screen Shot

Getting Started

npm run dev
# or
yarn dev

Backend

This app runs on AWS Ampilfy

To set it up follow the instructions at AWS Amplify

Environment Variables

Take these specific variables from the js file generated at src/aws-exports.js and create the env data listed below at /.env.local

aws_appsync_graphqlEndpoint="https://example-endpoint/graphql"
aws_appsync_apiKey="api-key-example"
aws_user_files_s3_bucket="s3-bucket-name-example"

The environment variables and duplicated aws-exports file is for Vercel deployment
These process.env variables are used in the following files: src/exportdata.js and next.config.js

context for aws-exports.js and exportdata.js

If we were to deploy on AWS Amplify, AWS would generate the aws-exports file for its deployment but vercel does not do this. aws-exports contains some sensitive data so we need to duplicate it and provide the process.env data. aws-exports will be regenerated in your repo on every amplify push/pull so better to just duplicate it.

If you deploy on vercel make sure to add these environment variables on that vercel project as well.

Stripe Integration

for stripe integration located at pages/api/checkout_sessions

add the environment variables

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="exmaple-public-key"
STRIPE_SECRET_KEY="example-secret-key"

PWA

This app is deployed as a PWA on Apple App Store and Google Play

To do the same generate the needed packages at PWA Builder and follow their instructions for publishing.

Download details:
Author: MatchUp-Berlin
Source code: https://github.com/MatchUp-Berlin/matchup
License:

#next #nextjs #react #javascript #pwa #aws

Building MatchUp App for Find A Sports Match using NextJS and AWS
Rupert  Beatty

Rupert Beatty

1658196420

Awes.io: Platform for Interactive Business Applications

Awes.io

Platform for Interactive Business Applications

10x faster to create than the traditional way • 3x increase application experiences • 60% decrease in development cost

Features

  • Free and Open-Source
  • 34 ready-to-use dedicated open-source packages
  • Awesome interface with a dark mode as an out-of-the-box feature
  • Easy to customize, based on Laravel & Vue.js
  • Well-designed for CRM, ERP, SaaS, Admin Dashboards, and Startups
  • Simple support of the applications
Awes.io

Introduction

Awes.io is a platform that provides an awesome UI interface and list of packages to build custom interactive web applications.

Quick Start

1. Try It Out

We have developed the Demo for approximately 1 day. It's really a fast presentation what could be created based on the platform.

Go to Live Demo

2. Install Demo to your machine

When you are satisfied with the demo online version and want to start coding, we have prepared for you a docker-compose build for quick installation. Everything is ready for your experiments. 🧪

Go to repository with demo.

3. Build your "Hello World" application

If you have played enough in the demo on your local machine, you can install an empty build and create your first hello world app.

Go to installation guide

Available Packages

All packages from the table are ready to install within Composer. Unfortunately, we have a limit of resources and have not published all list of packages to GitHub yet. Most parts of it located in our private repositories. We are working hard to open them as quickly as possible.

For installation the packages you have to create a project on Package Kit (it's free) and add the packages to your project. Then it will be ready by the Composer.

Package       Version       Downloads         Framework
Auth
The basic and two-factor authentications, as well as the possibility to log in by using a social network account.
Last versionDownloadsLaravel
Auto Captcha
Shows Google reCAPTCHA automatically, depending on API request frequency, to prevents DoS and Brute Force attacks
Last versionDownloadsLaravel
Awes SPA
Transformation of Awes.io to Single-page application.
Last versionDownloadsvue
Base js
A minimalistic bundle, that includes shared JS methods, common event bus, and also provides functionality for other component modules registration
Last versionDownloadsvue
Billing
Simple billing system to use it on the platform.
Last versionDownloadsLaravel
Billing Paypal
Billing integration with PayPal.
Last versionDownloadsLaravel
Billing Stripe
Billing integration with Stripe.
Last versionDownloadsLaravel
Chart Builder
Vue.js module for building Charts based on chart.js
Last versionDownloadsvue
Context Menu
A dropdown menu component with extended functionality, like pushing GET-params in browser query string and sending AJAX requests
Last versionDownloadsvue
Crop Image
Vue.js module for cropping and resizing images on the client.
Last versionDownloadsLaravel
Docs
This package provides an easy way to create beautiful documentation for your product or application inside your Laravel app.
Last versionDownloadsLaravel
Filter Wrapper
The component allows form-builder to send data to the address bar of the browser.
Last versionDownloadsvue
Form Builder
A component that allows creating forms with two-way binding from data object with default HTML fields and custom, like multi-block or AJAX-select
Last versionDownloadsvue
GEO Location
Checking location based on IP user.
Last versionDownloadsLaravel
Google Cloud Images
Image server for Google Cloud App for cropping and delivery images.
Last versionDownloadsLaravel
Indigo Layout
Basic styles and components set for building user interfaces.
Last versionDownloadsvue
Localization Helper
Helper packages for simple translating of the interfaces.
Last versionDownloadsLaravel
Mail
Subscriptions, Blacklist, Logging - everything that you need for mail.
Last versionDownloadsLaravel
Modal Window
Modal window component, with HTML5-history navigation
Last versionDownloadsvue
Navigator
Build any menus in the project.
Last versionDownloadsLaravel
News
The package which enables to create news announcements and to combine them in categories, and etc.
Last versionDownloadsLaravel
Packaginator
Helper Laravel package for building backend structure for the app.
Last versionDownloadsLaravel
Page Map
Automatically creates anchor-links navigation from provided content.
Last versionDownloadsvue
Permission
The package allows to add permissions to roles and roles to users.
Last versionDownloadsLaravel
Reporter
Library with pre-configured reports to build charts on the pages.
Last versionDownloadsLaravel
Repository
The package which implements the repository pattern with the possibility to select data by means of criteria and filters - both basic, initial filters and new one's design by the developer.
Last versionDownloadsLaravel
Sticky Params
Vue.js module to save filter results and reinstall it after reloading the page.
Last versionDownloadsvue
System Notify
4 types of notifications for the Awes.io.
Last versionDownloadsvue
Tab Builder
A component for tabs with responsive navigation
Last versionDownloadsvue
Table Builder
A component that allows creating responsive HTML tables or lists from data object
Last versionDownloadsvue
Tags
Simple packages for building tag system for any models.
Last versionDownloadsLaravel
Theme Switcher
Helper component for setting light or dark theme on a website which stores it is value in Cookie
Last versionDownloadsvue
Virtual Tour
It provides a quick and easy way to guide your users through your application.
Last versionDownloadsvue

Installation

The build inside of the repository does not exist any backend logic. The build is needed if you would like to start a new project.

👽️ if you see this system for the first time, we strongly recommend installing our demo first!

Via Awes.io Installer

Awes.io utilizes Composer to manage its dependencies. So, before using Awes.io, make sure you have Composer installed on your machine.

First, download the installer using Composer:

composer global require awes-io/installer

Make sure to place composer's system-wide vendor bin directory in your $PATH so the awes-io executable can be located by your system. This directory exists in different locations based on your operating system; however, some common locations include:

  • macOS: $HOME/.composer/vendor/bin, command: export PATH=~/.composer/vendor/bin:$PATH
  • GNU / Linux Distributions: $HOME/.config/composer/vendor/bin
  • Windows: %USERPROFILE%\AppData\Roaming\Composer\vendor\bin

Once installed, the awes-io new command will create a fresh Awes.io installation in the directory you specify. For instance, awes-io new crm will create a directory named crm containing a fresh Awes.io installation with all of Awes.io's dependencies already installed:

awes-io new crm

Manual installation

For the fast start, we recommend using AwesIO Installer. If for some reason it's not an option, please follow the instruction:

  1. Clone the repository: git clone git@github.com:awes-io/awes-io.git
  2. Create a project by the link: https://www.pkgkit.com/awes-io/create
  3. Copy project's API key and save it to your composer.json
  4. composer install
  5. Done! 🍺

Documentation

Full documentation please follow to official website of Awes.io.

Author: Awes-io
Source Code: https://github.com/awes-io/awes-io 
License: MIT license

#laravel #pwa #vue #nuxt 

Awes.io: Platform for Interactive Business Applications

Next PWA | Zero Config PWA Plugin for Next.js

Next PWA

Zero Config PWA Plugin for Next.js

This plugin is powered by workbox and other good stuff.

👋 Share your awesome PWA project 👉 here

Features

  • 0️⃣ Zero config for registering and generating service worker
  • ✨ Optimized precache and runtime cache
  • 💯 Maximize lighthouse score
  • 🎈 Easy to understand examples
  • 📴 Completely offline support with fallbacks example 🆕
  • 📦 Use workbox and workbox-window v6
  • 🍪 Work with cookies out of the box
  • 🔉 Default range requests for audios and videos
  • ☕ No custom server needed for Next.js 9+ example
  • 🔧 Handle PWA lifecycle events opt-in example
  • 📐 Custom worker to run extra code with code splitting and typescript support example
  • 📜 Public environment variables available in custom worker as usual
  • 🐞 Debug service worker with confidence in development mode without caching
  • 🌏 Internationalization (a.k.a I18N) with next-i18next example
  • 🛠 Configurable by the same workbox configuration options for GenerateSW and InjectManifest
  • 🚀 Spin up a GitPod and try out examples in rocket speed
  • ⚡ Support blitz.js (simply add to blitz.config.js)
  • 🔩 (Experimental) precaching .module.js when next.config.js has experimental.modern set to true

NOTE 1 - next-pwa version 2.0.0+ should only work with next.js 9.1+, and static files should only be served through public directory. This will make things simpler.

NOTE 2 - If you encounter error TypeError: Cannot read property **'javascript' of undefined** during build, please consider upgrade to webpack5 in next.config.js.

Install

If you are new to next.js or react.js at all, you may want to first checkout learn next.js or next.js document. Then start from a simple example or progressive-web-app example in next.js repository.

yarn add next-pwa

Basic Usage

Step 1: withPWA

Update or create next.config.js with

const withPWA = require('next-pwa')

module.exports = withPWA({
  pwa: {
    dest: 'public'
  }
})

After running next build, this will generate two files in your public: workbox-*.js and sw.js, which will automatically be served statically.

If you are using Next.js version 9 or newer, then skip the options below and move on to Step 2.

If you are using Next.js older than version 9, you'll need to pick an option below before continuing to Step 2.

Option 1: Host Static Files

Copy files to your static file hosting server, so that they are accessible from the following paths: https://yourdomain.com/sw.js and https://yourdomain.com/workbox-*.js.

One example is using Firebase hosting service to host those files statically. You can automate the copy step using scripts in your deployment workflow.

For security reasons, you must host these files directly from your domain. If the content is delivered using a redirect, the browser will refuse to run the service worker.

Option 2: Use Custom Server

When an HTTP request is received, test if those files are requested, then return those static files.

Example server.js

const { createServer } = require('http')
const { join } = require('path')
const { parse } = require('url')
const next = require('next')

const app = next({ dev: process.env.NODE_ENV !== 'production' })
const handle = app.getRequestHandler()

app.prepare()
  .then(() => {
    createServer((req, res) => {
      const parsedUrl = parse(req.url, true)
      const { pathname } = parsedUrl
      
      if (pathname === '/sw.js' || /^\/(workbox|worker|fallback)-\w+\.js$/.test(pathname)) {
        const filePath = join(__dirname, '.next', pathname)
        app.serveStatic(req, res, filePath)
      } else {
        handle(req, res, parsedUrl)
      }
    })
    .listen(3000, () => {
      console.log(`> Ready on http://localhost:${3000}`)
    })
  })

The following setup has nothing to do with next-pwa plugin, and you probably have already set them up. If not, go ahead and set them up.

Step 2: Add Manifest File (Example)

Create a manifest.json file in your public folder:

{
  "name": "PWA App",
  "short_name": "App",
  "icons": [
    {
      "src": "/icons/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/icons/android-chrome-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "theme_color": "#FFFFFF",
  "background_color": "#FFFFFF",
  "start_url": "/",
  "display": "standalone",
  "orientation": "portrait"
}

Step 3: Add Head Meta (Example)

Add the following into _document.jsx or _app.tsx, in <Head>:

<meta name='application-name' content='PWA App' />
<meta name='apple-mobile-web-app-capable' content='yes' />
<meta name='apple-mobile-web-app-status-bar-style' content='default' />
<meta name='apple-mobile-web-app-title' content='PWA App' />
<meta name='description' content='Best PWA App in the world' />
<meta name='format-detection' content='telephone=no' />
<meta name='mobile-web-app-capable' content='yes' />
<meta name='msapplication-config' content='/icons/browserconfig.xml' />
<meta name='msapplication-TileColor' content='#2B5797' />
<meta name='msapplication-tap-highlight' content='no' />
<meta name='theme-color' content='#000000' />

<link rel='apple-touch-icon' href='/icons/touch-icon-iphone.png' />
<link rel='apple-touch-icon' sizes='152x152' href='/icons/touch-icon-ipad.png' />
<link rel='apple-touch-icon' sizes='180x180' href='/icons/touch-icon-iphone-retina.png' />
<link rel='apple-touch-icon' sizes='167x167' href='/icons/touch-icon-ipad-retina.png' />

<link rel='icon' type='image/png' sizes='32x32' href='/icons/favicon-32x32.png' />
<link rel='icon' type='image/png' sizes='16x16' href='/icons/favicon-16x16.png' />
<link rel='manifest' href='/manifest.json' />
<link rel='mask-icon' href='/icons/safari-pinned-tab.svg' color='#5bbad5' />
<link rel='shortcut icon' href='/favicon.ico' />
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:300,400,500' />
     
<meta name='twitter:card' content='summary' />
<meta name='twitter:url' content='https://yourdomain.com' />
<meta name='twitter:title' content='PWA App' />
<meta name='twitter:description' content='Best PWA App in the world' />
<meta name='twitter:image' content='https://yourdomain.com/icons/android-chrome-192x192.png' />
<meta name='twitter:creator' content='@DavidWShadow' />
<meta property='og:type' content='website' />
<meta property='og:title' content='PWA App' />
<meta property='og:description' content='Best PWA App in the world' />
<meta property='og:site_name' content='PWA App' />
<meta property='og:url' content='https://yourdomain.com' />
<meta property='og:image' content='https://yourdomain.com/icons/apple-touch-icon.png' />

<!-- apple splash screen images -->
<!--
<link rel='apple-touch-startup-image' href='/images/apple_splash_2048.png' sizes='2048x2732' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1668.png' sizes='1668x2224' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1536.png' sizes='1536x2048' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1125.png' sizes='1125x2436' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_1242.png' sizes='1242x2208' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_750.png' sizes='750x1334' />
<link rel='apple-touch-startup-image' href='/images/apple_splash_640.png' sizes='640x1136' />
-->

Tip: Put the viewport head meta tag into _app.js rather than in _document.js if you need it.

<meta name='viewport' content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover' />

Offline Fallbacks

Offline fallbacks are useful when the fetch failed from both cache and network, a precached resource is served instead of present an error from browser.

To get started simply add a /_offline page such as pages/_offline.js or pages/_offline.jsx or pages/_offline.ts or pages/_offline.tsx. Then you are all set! When the user is offline, all pages which are not cached will fallback to '/_offline'.

Use this example to see it in action

next-pwa helps you precache those resources on the first load, then inject a fallback handler to handlerDidError plugin to all runtimeCaching configs, so that precached resources are served when fetch failed.

You can also setup precacheFallback.fallbackURL in your runtimeCaching config entry to implement similar functionality. The difference is that above method is based on the resource type, this method is based matched url pattern. If this config is set in the runtimeCaching config entry, resource type based fallback will be disabled automatically for this particular url pattern to avoid conflict.

Configuration

There are options you can use to customize the behavior of this plugin by adding pwa object in the next config in next.config.js:

const withPWA = require('next-pwa')

module.exports = withPWA({
  pwa: {
    dest: 'public',
    // disable: process.env.NODE_ENV === 'development',
    // register: true,
    // scope: '/app',
    // sw: 'service-worker.js',
    //...
  }
})

Available Options

  • disable: boolean - whether to disable pwa feature as a whole
    • default: false
    • set disable: false, so that it will generate service worker in both dev and prod
    • set disable: true to completely disable PWA
    • if you don't need to debug service worker in dev, you can set disable: process.env.NODE_ENV === 'development'
  • register: boolean - whether to let this plugin register service worker for you
    • default to true
    • set to false when you want to handle register service worker yourself, this could be done in componentDidMount of your root app. you can consider the register.js as an example.
  • scope: string - url scope for pwa
    • default: basePath in next.config.js or /
    • set to /app so that path under /app will be PWA while others are not
  • sw: string - service worker script file name
    • default: /sw.js
    • set to another file name if you want to customize the output file name
  • runtimeCaching - caching strategies (array or callback function)
    • default: see the Runtime Caching section for the default configuration
    • accepts an array of cache entry objects, please follow the structure here
    • Note: the order of the array matters. The first rule that matches is effective. Therefore, please ALWAYS put rules with larger scope behind the rules with a smaller and specific scope.
  • publicExcludes - an array of glob pattern strings to exclude files in the public folder from being precached.
    • default: ['!noprecache/**/*'] - this means that the default behavior will precache all the files inside your public folder but files inside /public/noprecache folder. You can simply put files inside that folder to not precache them without config this.
    • example: ['!img/super-large-image.jpg', '!fonts/not-used-fonts.otf']
  • buildExcludes - an array of extra pattern or function to exclude files from being precached in .next/static (or your custom build) folder
    • default: []
    • example: [/chunks\/images\/.*$/] - Don't precache files under .next/static/chunks/images (Highly recommend this to work with next-optimized-images plugin)
    • doc: Array of (string, RegExp, or function()). One or more specifiers used to exclude assets from the precache manifest. This is interpreted following the same rules as Webpack's standard exclude option.
  • cacheStartUrl - whether to cache start url
  • dynamicStartUrl - if your start url returns different HTML document under different state (such as logged in vs. not logged in), this should be set to true.
    • default: true
    • effective when cacheStartUrl set to true
    • recommend: set to false if your start url always returns same HTML document, then start url will be precached, this will help to speed up first load.
  • dynamicStartUrlRedirect - if your start url redirect to another route such as /login, it's recommended to setup this redirected url for the best user experience.
    • default: undefined
    • effective when dynamicStartUrlRedirect set to true
  • fallbacks - config precached routes to fallback when both cache and network not available to serve resources.
    • if you just need a offline fallback page, simply create a /_offline page such as pages/_offline.js and you are all set, no configuration necessary
    • default: object
      • fallbacks.document - fallback route for document (page), default to /_offline if you created that page
      • fallbacks.image - fallback route for image, default to none
      • fallbacks.audio - fallback route for audio, default to none
      • fallbacks.video - fallback route for video, default to none
      • fallbacks.font - fallback route for font, default to none
  • cacheOnFrontEndNav - enable additional route cache when navigate between pages with next/link on front end. Checkout this example for some context about why this is implemented.
    • default: false
    • note: this improve user experience on special use cases but it also adds some overhead because additional network call, I suggest you consider this as a trade off.
  • subdomainPrefix: string - url prefix to allow hosting static files on a subdomain
    • default: "" - i.e. default with no prefix
    • example: /subdomain if the app is hosted on example.com/subdomain
    • deprecated, use basePath instead
  • reloadOnOnline - changes the behaviour of the app when the device detects that it has gone back "online" and has a network connection. Indicate if the app should call location.reload() to refresh the app.
    • default: true
  • customWorkerDir - customize the directory where next-pwa looks for a custom worker implementation to add to the service worker generated by workbox. For more information, check out the custom worker example.
    • default: worker

Other Options

next-pwa uses workbox-webpack-plugin, other options which could also be put in pwa object can be found ON THE DOCUMENTATION for GenerateSW and InjectManifest. If you specify swSrc, InjectManifest plugin will be used, otherwise GenerateSW will be used to generate service worker.

Runtime Caching

next-pwa uses a default runtime cache.js

There is a great chance you may want to customize your own runtime caching rules. Please feel free to copy the default cache.js file and customize the rules as you like. Don't forget to inject the configurations into your pwa config in next.config.js.

Here is the document on how to write runtime caching configurations, including background sync and broadcast update features and more!

Tips

  1. Common UX pattern to ask user to reload when new service worker is installed
  2. Use a convention like {command: 'doSomething', message: ''} object when postMessage to service worker. So that on the listener, it could do multiple different tasks using if...else....
  3. When you are debugging service worker, constantly clean application cache to reduce some flaky errors.
  4. If you are redirecting the user to another route, please note workbox by default only cache response with 200 HTTP status, if you really want to cache redirected page for the route, you can specify it in runtimeCaching such as options.cacheableResponse.statuses=[200,302].
  5. When debugging issues, you may want to format your generated sw.js file to figure out what's really going on.
  6. Force next-pwa to generate worker box production build by specify the option mode: 'production' in your pwa section of next.config.js. Though next-pwa automatically generate the worker box development build during development (by running next) and worker box production build during production (by running next build and next start). You may still want to force it to production build even during development of your web app for following reason:
    1. Reduce logging noise due to production build doesn't include logging.
    2. Improve performance a bit due to production build is optimized and minified.
  7. If you just want to disable worker box logging while keeping development build during development, simply put self.__WB_DISABLE_DEV_LOGS = true in your worker/index.js (create one if you don't have one).
  8. It is common developers have to use userAgent string to determine if users are using Safari/iOS/MacOS or some other platform, ua-parser-js library is a good friend for that purpose.

Reference

  1. Google Workbox
  2. ServiceWorker, MessageChannel, & postMessage by Nicolás Bevacqua
  3. The Service Worker Lifecycle
  4. 6 Tips to make your iOS PWA feel like a native app
  5. Make Your PWA Available on Google Play Store

Fun PWA Projects

  1. Experience SAMSUNG on an iPhone - must open on an iPhone to start
  2. App Scope - like an app store for PWA
  3. PWA Directory
  4. PWA Builder - Alternative way to build awesome PWA

Download Details:
Author: shadowwalker
Source Code: https://github.com/shadowwalker/next-pwa
License: MIT license

#nextjs #react #javascript #pwa

Next PWA | Zero Config PWA Plugin for Next.js
John David

John David

1656995453

Vite Plugin PWA: Zero-config PWA for Vite

Zero-config PWA Framework-agnostic Plugin for Vite

🚀 Features

  • 📖 Documentation & guides
  • 👌 Zero-Config: sensible built-in default configs for common use cases
  • 🔩 Extensible: expose the full ability to customize the behavior of the plugin
  • 🦾 Type Strong: written in TypeScript
  • 🔌 Offline Support: generate service worker with offline support (via Workbox)
  • Fully tree shakable: auto inject Web App Manifest
  • 💬 Prompt for new content: built-in support for Vanilla JavaScript, Vue 3, React, Svelte, SolidJS and Preact
  • ⚙️ Stale-while-revalidate: automatic reload when new content is available
  • Static assets handling: configure static assets for offline support
  • 🐞 Development Support: debug your custom service worker logic as you develop your application

📦 Install

npm i vite-plugin-pwa -D 

# yarn 
yarn add vite-plugin-pwa -D

# pnpm 
pnpm add vite-plugin-pwa -D

🦄 Usage

🎩 From version 0.11.0, workbox has been updated to version 6.2.2 (previous versions were using 6.1.5 version): if you are using advanced configuration like workbox or injectManifest options, you must review the plugin configuration, since this new version of workbox has breaking changes!

🎩 Changes on version 0.12.0:

  • TypeScript updated to 4.6.3 version, client and DevOptions types changed to interface.
  • If you were using shortcuts on the PWA Manifest, there is a breaking change to add correct type for shortcuts icons, you should review all icon declarations.
  • You can change the PWA Manifest File name, which default value is manifest.webmanifest, use manifestFilename plugin option to change it.
  • workbox-build now loads on demand, if you are starting the development server and don't use DevOptions, workbox-build will not be loaded and the development server will boot faster.
  • You can now provide which Vite plugins add to the service worker build: we have added vite:json and commonjs, check defaultInjectManifestVitePlugins on src/constants.ts module. Beware using this option since you can break your project build.

Add VitePWA plugin to vite.config.js / vite.config.ts and configure it:

// vite.config.js / vite.config.ts
import { VitePWA } from 'vite-plugin-pwa'

export default {
  plugins: [
    VitePWA()
  ]
}

Read the 📖 documentation for a complete guide on how to configure and use this plugin.

Check out the client type declarations client.d.ts for built-in frameworks support.

👀 Full config

Check out the type declaration src/types.ts and the following links for more details.

Download Details: 
Author: antfu
Source Code: https://github.com/antfu/vite-plugin-pwa 
License: MIT

#vue #vite #pwa 

Vite Plugin PWA: Zero-config PWA for Vite

Vite Plugin Pwa: Zero-config PWA Framework-agnostic Plugin for Vite

Zero-config PWA Framework-agnostic Plugin for Vite

🚀 Features

  • 📖 Documentation & guides
  • 👌 Zero-Config: sensible built-in default configs for common use cases
  • 🔩 Extensible: expose the full ability to customize the behavior of the plugin
  • 🦾 Type Strong: written in TypeScript
  • 🔌 Offline Support: generate service worker with offline support (via Workbox)
  • Fully tree shakable: auto inject Web App Manifest
  • 💬 Prompt for new content: built-in support for Vanilla JavaScript, Vue 3, React, Svelte, SolidJS and Preact
  • ⚙️ Stale-while-revalidate: automatic reload when new content is available
  • Static assets handling: configure static assets for offline support
  • 🐞 Development Support: debug your custom service worker logic as you develop your application

📦 Install

npm i vite-plugin-pwa -D 

# yarn 
yarn add vite-plugin-pwa -D

# pnpm 
pnpm add vite-plugin-pwa -D

🦄 Usage

🎩 From version 0.11.0, workbox has been updated to version 6.2.2 (previous versions were using 6.1.5 version): if you are using advanced configuration like workbox or injectManifest options, you must review the plugin configuration, since this new version of workbox has breaking changes!

🎩 Changes on version 0.12.0:

  • TypeScript updated to 4.6.3 version, client and DevOptions types changed to interface.
  • If you were using shortcuts on the PWA Manifest, there is a breaking change to add correct type for shortcuts icons, you should review all icon declarations.
  • You can change the PWA Manifest File name, which default value is manifest.webmanifest, use manifestFilename plugin option to change it.
  • workbox-build now loads on demand, if you are starting the development server and don't use DevOptions, workbox-build will not be loaded and the development server will boot faster.
  • You can now provide which Vite plugins add to the service worker build: we have added vite:json and commonjs, check defaultInjectManifestVitePlugins on src/constants.ts module. Beware using this option since you can break your project build.

Add VitePWA plugin to vite.config.js / vite.config.ts and configure it:

// vite.config.js / vite.config.ts
import { VitePWA } from 'vite-plugin-pwa'

export default {
  plugins: [
    VitePWA()
  ]
}

Read the 📖 documentation for a complete guide on how to configure and use this plugin.

Check out the client type declarations client.d.ts for built-in frameworks support.

👀 Full config

Check out the type declaration src/types.ts and the following links for more details.


Author: antfu
Source code: https://github.com/antfu/vite-plugin-pwa
License: MIT license

#vite #pwa #typescript 

Vite Plugin Pwa: Zero-config PWA Framework-agnostic Plugin for Vite

Simple PWA Boilerplate with Next.js and Redux

Getting Started

  • First, run the development server with npm run dev.
  • Navigate to http://localhost:3000 on your browser.
  • Start editing the page by modifying pages/index.js. The page auto-updates as you edit the file.

Learn More

To learn more about Next.js, take a look at the following resources:

Deployment

▲ Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out the Next.js deployment documentation for more details.

Deploy with Vercel

⊚ Deploy on Netlify

  • On Netlify, Click on new site from git.
  • Select Cloned Repository.
  • Choose VCS.
  • Add build command next build && next export.
  • Add publish directory out.

⊚ Deploy on Gitpod

Click here to deploy on Gitpod.

Contribution

I'm open to contributions & suggestions in making this a lot better ✋

Download Details:
Author: ooade
Source Code: https://github.com/ooade/NextSimpleStarter
License: MIT license

#nextjs #react #javascript #pwa 

Simple PWA Boilerplate with Next.js and Redux
Saul  Alaniz

Saul Alaniz

1653401220

Comprender La Mejora Progresiva

En el desarrollo web, existen varios enfoques para la distribución de contenido, pero la mayoría de los desarrolladores simplemente emplean la entrega de contenido estático o dinámico sin tener en cuenta la accesibilidad del usuario. Poner la accesibilidad en primer lugar en el diseño web es imprescindible, porque si el contenido de una aplicación es inaccesible, muchas personas no podrán interactuar con la aplicación, independientemente de si es estática o dinámica.

Muchos desarrolladores crean PWA (aplicaciones web progresivas) para crear experiencias nativas y accesibles para sus usuarios, pero no entienden qué son o por qué se llaman "progresivas". La frase "mejora progresiva", que discutiremos más adelante en este artículo, está inspirada en "progresivo" en PWA. Como desarrollador, es importante saber por qué la mejora progresiva es un conocimiento necesario para tener en su cinturón de herramientas.

En este artículo, repasaremos los principios básicos de la mejora progresiva, así como la relevancia y las críticas de su uso en el desarrollo web.

¿Qué es la mejora progresiva?

La mejora progresiva es una metodología de diseño web que garantiza que el contenido de la aplicación web llegue primero a todos los usuarios, independientemente de su ventaja digital, antes de que aquellos con funciones de navegador más avanzadas y conexión a Internet reciban contenido aumentado.

En la "degradación elegante", el contenido web se diseña para brindar la mejor experiencia y se entrega a los usuarios primero con las versiones más recientes del navegador, luego se degrada para que funcione bien con versiones anteriores del navegador. La mejora progresiva hace lo contrario.

La regla de “separación de presentación y contenido, separación de contenido y estilo, o separación de semántica y presentación” también se conoce como mejora progresiva en los círculos de marcado.

Principios básicos de la mejora progresiva

Hay una serie de pautas que lo ayudarán a cumplir con el enfoque de mejora progresiva del diseño web. Son los siguientes:

En primer lugar, todos los navegadores web deberían poder acceder al contenido básico. Hay una variedad de navegadores web disponibles, cada uno con su propio conjunto de características y capacidades. Puede ser difícil diseñar un sitio web que funcione con todos los diferentes navegadores disponibles. Sin embargo, existen estándares web globales que son aceptados por todos los navegadores.

Antes de implementar nuevas funciones para explorar navegadores específicos, los sitios web deben seguir los estándares web para garantizar que todos puedan acceder a ellos.

En segundo lugar, las funciones básicas y los eventos estándar deben estar disponibles en todos los navegadores web. Antes de implementar eventos personalizados para manejar funcionalidades avanzadas, es vital usar todos los eventos DOM normales para administrar la experiencia del usuario mientras se construyen sitios web.

 

En tercer lugar, todo el contenido debe incluirse en un marcado semántico mínimo. En el diseño web, es fundamental centrarse en la entrega de contenido en lugar de la estética. El contenido del sitio web debe estar correctamente estructurado, como lo permite el HTML semántico estándar. Por ejemplo, en lugar de imágenes de texto, se puede utilizar la semántica HTML de tipografía adecuada para mostrar el texto. Esto mejora la accesibilidad del contenido del sitio web para las personas que no pueden ver las imágenes.

En cuarto lugar, JavaScript conectado externamente debería proporcionar una funcionalidad mejorada. El uso de bibliotecas de JavaScript de terceros para proporcionar una funcionalidad ampliada debe realizarse después de que el sitio haya demostrado que puede proporcionar una funcionalidad básica a los usuarios que no tienen acceso a dichas bibliotecas de terceros. Aunque ciertos navegadores web no habilitan JavaScript, los usuarios aún deberían poder acceder e interactuar con cierta información.

En quinto lugar, el CSS que está conectado externamente debería proporcionar un diseño mejorado. Los usuarios deberían poder ver el sitio web sin ningún estilo CSS y aún estaría presentable. El propósito del estilo CSS es mejorar el diseño de un sitio web y ofrecer algunos diseños adicionales que HTML no puede proporcionar. El uso de CSS no debe abusarse en detrimento de la accesibilidad del sitio web. Para atributos de estilo experimentales o no estándar, CSS también admite prefijos de proveedores .

Por último, se deben respetar las preferencias del navegador web del usuario final. Los usuarios deben poder utilizar el navegador que deseen y no deben verse obligados a utilizar un determinado navegador para acceder al contenido del sitio web.

Ejemplos prácticos de mejora progresiva

¿Alguna vez se ha encontrado con una característica del sitio web que está disponible cuando su computadora está conectada a Internet, pero no está disponible cuando su computadora está desconectada de Internet? Esto es algo habitual en las aplicaciones web progresivas (PWA), que son una demostración perfecta de la mejora progresiva.

Hay otros ejemplos, como contenido alternativo si JavaScript no está habilitado en el navegador del cliente. En marcos como Angular, Vue o React, se requiere un controlador de errores para mostrar contenido alternativo de la aplicación si JavaScript no está habilitado en el navegador del cliente. Esto se debe a que la aplicación no funcionará correctamente si JavaScript está deshabilitado, por lo tanto, en lugar de poner al usuario en el dolor de acceder a una aplicación que no funciona del todo, el desarrollador proporciona contenido alternativo.

Es una práctica común en React agregar una noscriptetiqueta con un mensaje que indica que JavaScript es necesario para que la aplicación se ejecute. Esta etiqueta se puede encontrar en la bodyetiqueta del index.htmlarchivo en la publiccarpeta en aplicaciones producidas con create-react-app. Aparece de la siguiente manera:

<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
</body>

Las fuentes web son otro ejemplo de mejora progresiva. Cuando se utilizan fuentes personalizadas para diseñar un sitio web, es posible que no sean compatibles con todos los navegadores o que tarden mucho tiempo en cargarse. Si la fuente personalizada no se carga, el desarrollador proporciona una fuente alternativa.

Aquí hay un ejemplo de cómo importar una fuente alternativa, pero usando la fuente predeterminada:

@import url(https://fonts.googleapis.com/css?family=Open+Sans);

body{
   font-family: 'Open Sans', sans-serif;
}

Arriba, importamos Open Sansy configuramos el cuerpo font-familyen Open Sans, sans-serif. sans-serif, que se agregó a la lista de fuentes, es un tipo de letra genérico compatible con casi todos los navegadores. Si la fuente importada ( Open Sans) no se carga, font-familyse cambiará a san-serif.

Nuestro último ejemplo de mejora progresiva se refiere a HTML5. Al usar el elemento de video HTML5, puede definir el texto que se mostrará si el navegador no admite videos o el tipo de archivo. A menudo se hace insertando texto entre las etiquetas de apertura y cierre, como se muestra a continuación:

<video width="320" height="240" controls>
  <source src="movie.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>   

Si su navegador no admite el elemento de video, aparecerán las palabras "Su navegador no admite la etiqueta de video" en la sección del video.

Por qué debería aplicar mejoras progresivas a su aplicación web

Cuando se trata de la entrega de contenido en línea, hay una variedad de desafíos que pueden surgir y que pueden ser causados ​​por el usuario o el desarrollador. La mejora progresiva es una solución que se creó para mitigar las consecuencias de estos problemas o, al menos, proporcionar al usuario final parte de la información, si no toda.

Otras razones para considerar practicar la mejora progresiva incluyen:

  • SEO mejorado: el uso correcto de la semántica HTML en un sitio web impulsará el SEO de ese sitio, ya que la información será más accesible para los lectores de pantalla, las arañas web y los motores de búsqueda.
  • Compatibilidad y accesibilidad mejoradas: el contenido del sitio web debe poder cargarse en una variedad de dispositivos, por lo que si el dispositivo o navegador de un usuario no es compatible con el idioma utilizado para desarrollar el sitio web, habrá menos errores.
  • Escalabilidad simple: el sitio web debe llegar a su audiencia más amplia y al mismo tiempo brindar información adecuada. Los programadores deben estar seguros de que pueden aumentar su carga de trabajo sin dejar de entregar información a los usuarios.
  • Velocidad y experiencia de usuario mejoradas: el uso de una semántica adecuada mejora la velocidad a la que se cargan los contenidos, y cuando un sitio web carga sus contenidos rápidamente, la experiencia del usuario mejora

Cómo implementar la mejora progresiva

Los fundamentos de la mejora progresiva en el diseño web son proporcionar al usuario el contenido adecuado que necesita si la capa superior del diseño web no está disponible.

Por ejemplo, supongamos que tenemos un sitio diseñado con JavaScript como tercera capa, CSS como segunda capa y HTML como primera capa. El diseño del sitio debería funcionar bien incluso si JavaScript no está allí, lo que implica que JavaScript es solo un complemento de lo que ya funciona correctamente.

Veamos cómo funciona esto con un botón desplegable de muestra.

Primera capa: HTML

Esta capa es un marcado semántico que permite a los navegadores arcaicos, lectores de pantalla y agentes de usuario basados ​​en texto navegar y acceder correctamente al contenido del sitio web.

Para el botón desplegable, aquí hay un ejemplo de marcado semántico:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dropdown</title>
</head>
<body>
    <button id="dropbtn">Navigation Menu</button>
    <ul id="ul">
        <li><a href="/home"></a>Home</li>
        <li><a href="/about"></a>About</li>
        <li><a href="/contact"></a>Contact</li>
        <li><a href="/signin"></a>Signin</li>
    </ul>
</body>
</html>  

El menú desplegable está organizado en una lista desordenada y el botón no funciona actualmente. Como resultado, la lista del menú permanecerá estática, sin posibilidad de colapsarla o expandirla.

Cuando ejecute el código anterior en su navegador, debería ver lo siguiente:

Segunda capa: CSS

Esta es la capa inicial de funcionalidad adicional. CSS puede o no traer funcionalidad a una página web; se utiliza principalmente para organizar y mejorar el diseño con el fin de dar al sitio web una apariencia visualmente más atractiva.

Un ejemplo de una mejora de CSS es el siguiente:

<style>
    button {
        border-radius: 20px;
        border: none;
        padding: 10px 20px;
        cursor: pointer;
        background: #ccc;
        transition: all ease 0.2s;
    }
    button:hover {
        box-shadow: 2px 2px 4px rgb(90, 90, 90);
        filter: invert(1);
    }
    ul {
        list-style: none;
        padding: 0px;
        width: 250px;
    }
    .active {
        height: 0px;
        overflow-y: auto;
    }
    li {
        height: 25px;
        padding: 10px;
        background-color: #ccc;
    }
    li:hover {
        filter: invert(1);
    }
    li a {
        height: 100%;
        width: 100%;
        color: black;
        text-decoration: none;
    }
</style>

El menú desplegable debería aparecer así después de agregar los estilos CSS entre las etiquetas heady de la página web:body

Tercera capa: JavaScript

Esta capa es la capa de funcionalidad; podemos optar por manipular el DOM de la forma que queramos para generar nuevas experiencias de usuario, pero no es obligatorio.

Sin esta capa de JavaScript, todavía se puede acceder a nuestro menú desplegable. Echemos un vistazo a cómo se verá una vez que hayamos agregado scripts de funcionalidad adicionales.

Aquí hay un ejemplo de la funcionalidad de JavaScript que puede tener nuestro menú desplegable:

<script>
    window.addEventListener('load', () => {
        dropDownMenu = document.querySelector('#ul')
        btn = document.querySelector('#dropbtn')

        dropDownMenu.classList.add('closed')
        btn.addEventListener('click', (e) => {
            e.preventDefault()
            dropDownMenu.classList.toggle('closed')
        })
    })
</script>

En el código anterior, escuchamos el window.onloadevento, luego usamos querySelectorpara seleccionar dropDownMenuy btn. A continuación, agregamos la clase predeterminada closedpara dropDownMenucolapsarla. Luego, la closedclase se alterna cada vez que btnse hace clic en .

Habiendo agregado este script justo antes de la bodyetiqueta de cierre de la página web, el menú desplegable debería verse así cuando la página se cargue en el navegador:

La lista del menú está colapsada; sin embargo, si hace clic en el botón Menú de navegación , la lista del menú debería expandirse de la siguiente manera:

Todavía pudimos ofrecer acceso a la lista de menús antes de agregar cada capa sucesiva de mejora, aunque esta es una experiencia muy fácil de usar.

Críticas a la mejora progresiva

Por atractivo que parezca el concepto, todavía hay muchos puntos de vista opuestos sobre la mejora progresiva.

Algunas personas creen que es una pérdida de tiempo, mientras que otras creen que los usuarios deberían actualizar sus navegadores para que coincidan con los estándares del sitio web. También se cree que la mejora progresiva es para los usuarios que deshabilitan JavaScript en su navegador a propósito, lo cual es incorrecto. Independientemente de si JavaScript está deshabilitado intencionalmente o no, el usuario debería poder ver el contenido del sitio web.

Otros creen que la mejora progresiva solo está disponible en navegadores obsoletos. Pero los usuarios pueden usar el navegador que deseen, independientemente de cuán antiguo o nuevo sea. Es responsabilidad de los desarrolladores asegurarse de que el sitio web sea compatible con cualquier navegador que intente acceder a los contenidos del sitio web.

Pensamientos finales

La mejora progresiva está más preocupada por la viabilidad a largo plazo de un sitio web. Será más fácil expandirse y hacer la transición a mejores marcos y tecnologías en el futuro si utiliza esta metodología.

Espero que los lectores comprendan el concepto de mejora progresiva y empiecen a ponerlo en práctica. Para poner a prueba su conocimiento de la mejora progresiva, cree una aplicación web progresiva (PWA) y evalúe si se ajusta a los estándares de mejora progresiva que se analizan en este artículo.

Fuente: https://blog.logrocket.com/understanding-progressive-enhancement/

#pwa 

Comprender La Mejora Progresiva
伊藤  直子

伊藤 直子

1653401040

プログレッシブエンハンスメントを理解する

Web開発では、コンテンツ配信にいくつかのアプローチがありますが、ほとんどの開発者は、ユーザーのアクセシビリティを考慮せずに、静的または動的なコンテンツ配信を採用しています。アプリケーションのコンテンツにアクセスできない場合、静的か動的かに関係なく、多くの人がアプリケーションを操作できなくなるため、Webデザインでアクセシビリティを最優先する必要があります。

多くの開発者は、ユーザーがアクセスできるネイティブのようなエクスペリエンスを作成するためにPWA(プログレッシブWebアプリケーション)を作成しますが、それらが何であるか、またはなぜ「プログレッシブ」と呼ばれるのかを理解していません。この記事の後半で説明する「プログレッシブエンハンスメント」というフレーズは、PWAの「プログレッシブ」に着想を得ています。開発者として、プログレッシブエンハンスメントがツールベルトに必要な知識である理由を知ることは重要です。

この記事では、プログレッシブエンハンスメントの基本原則と、それをWeb開発で使用することの関連性と批判について説明します。

プログレッシブエンハンスメントとは何ですか?

プログレッシブエンハンスメントは、デジタルアドバンテージに関係なく、より高度なブラウザー機能とインターネット接続を備えたユーザーが拡張コンテンツを受け取る前に、Webアプリのコンテンツが最初にすべてのユーザーに届くようにするWebデザイン手法です。

「グレースフルデグラデーション」では、Webコンテンツは最高のエクスペリエンスを実現するように設計されており、最初に最新のブラウザバージョンを使用してユーザーに配信され、次に古いブラウザバージョンで適切に機能するようにデグレードされます。プログレッシブエンハンスメントはその逆です。

「プレゼンテーションとコンテンツの分離、コンテンツとスタイルの分離、またはセマンティクスとプレゼンテーションの分離」のルールは、マークアップサークルのプログレッシブエンハンスメントとしても知られています。

プログレッシブエンハンスメントのコア原則

Webデザインへのプログレッシブエンハンスメントアプローチに固執するのに役立つガイドラインがいくつかあります。それらは次のとおりです。

まず、すべてのWebブラウザが基本的なコンテンツにアクセスできる必要があります。さまざまなWebブラウザが利用可能であり、それぞれに独自の機能セットがあります。利用可能なすべての異なるブラウザで動作するWebサイトを設計するのは難しいかもしれません。ただし、すべてのブラウザで受け入れられるグローバルWeb標準があります。

特定のブラウザを探索するための新機能を実装する前に、WebサイトはWeb標準に従って、すべての人がアクセスできるようにする必要があります。

次に、基本機能と標準イベントがすべてのWebブラウザーで使用可能である必要があります。高度な機能を処理するカスタムイベントを実装する前に、通常のDOMイベントをすべて使用して、Webサイトを構築する際のユーザーエクスペリエンスを管理することが重要です。

 

第三に、すべてのコンテンツは最小限のセマンティックマークアップに含まれている必要があります。Webデザインでは、美学よりもコンテンツ配信に重点を置くことが重要です。Webサイトのコンテンツは、標準のセマンティックHTMLで許可されているように、正しく構造化されている必要があります。たとえば、テキストの写真の代わりに、適切なタイポグラフィHTMLセマンティクスを使用してテキストを表示できます。これにより、画像を表示できない可能性のあるユーザーがWebサイトのコンテンツにアクセスしやすくなります。

第4に、外部接続されたJavaScriptは拡張機能を提供する必要があります。拡張機能を提供するためのサードパーティのJavaScriptライブラリの使用は、そのようなサードパーティのライブラリにアクセスできないユーザーに基本的な機能を提供できることがサイトで証明された後に行う必要があります。特定のWebブラウザがJavaScriptを有効にしていない場合でも、ユーザーは一部の情報にアクセスして操作できる必要があります。

第5に、外部に接続されているCSSは、レイアウトを改善する必要があります。ユーザーはCSSスタイルなしでWebサイトを表示できるはずであり、それでも見栄えがします。CSSスタイリングの目的は、Webサイトのレイアウトを改善し、HTMLでは提供できない追加のデザインを提供することです。CSSの使用法は、Webサイトのアクセシビリティを損なうために誤用されるべきではありません。実験的または非標準のスタイル属性の場合、CSSはベンダープレフィックスを追加でサポートします。

最後に、エンドユーザーのWebブラウザの設定を尊重する必要があります。ユーザーは、希望するブラウザを使用できる必要があり、Webサイトのコンテンツにアクセスするために特定のブラウザを使用するように強制されるべきではありません。

プログレッシブエンハンスメントの実践例

コンピューターがインターネットに接続されているときは利用できるが、コンピューターがインターネットから切断されているときは利用できないWebサイト機能に出くわしたことがありますか。これは、プログレッシブWebアプリケーション(PWA)で定期的に発生するものであり、プログレッシブエンハンスメントの完璧なデモンストレーションです。

クライアントのブラウザでJavaScriptが有効になっていない場合の代替コンテンツなど、他の例もあります。Angular、Vue、Reactなどのフレームワークでは、JavaScriptがクライアントのブラウザーで有効になっていない場合、アプリケーションからの代替コンテンツを表示するためにエラーハンドラーが必要です。これは、JavaScriptが無効になっているとアプリケーションが正しく動作しないためです。したがって、完全に機能していないアプリケーションにアクセスするという苦痛をユーザーに与えるのではなく、開発者は代替コンテンツを提供します。

Reactnoscriptでは、アプリの実行にJavaScriptが必要であることを示すメッセージを含むタグを追加するのが一般的です。このタグは、で作成されたアプリのフォルダー内のファイルのbodyタグに含まれている場合があります。次のように表示されます。index.htmlpubliccreate-react-app

<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
</body>

Webフォントは、プログレッシブエンハンスメントのもう1つの例です。カスタムフォントを使用してWebサイトのスタイルを設定すると、すべてのブラウザでサポートされていない場合や、読み込みに時間がかかる場合があります。カスタムフォントの読み込みに失敗した場合、開発者はフォールバックフォントを提供します。

代替フォントをインポートする例を次に示しますが、デフォルトのフォントを使用しています。

@import url(https://fonts.googleapis.com/css?family=Open+Sans);

body{
   font-family: 'Open Sans', sans-serif;
}

Open Sans上記では、本体をインポートしてに設定しfont-familyましたOpen Sans, sans-serifsans-serifフォントリストに追加された、は、ほぼすべてのブラウザでサポートされている一般的な書体です。インポートしたフォント(Open Sans)が読み込めない場合は、font-familyに変更されsan-serifます。

プログレッシブエンハンスメントの最後の例はHTML5に関するものです。HTML5ビデオ要素を使用する場合、ブラウザがビデオまたはファイルタイプをサポートしていない場合に表示されるテキストを定義できます。これは、以下に示すように、開始タグと終了タグの間にテキストを挿入することによって行われることがよくあります。

<video width="320" height="240" controls>
  <source src="movie.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>   

お使いのブラウザがビデオ要素をサポートしていない場合、「お使いのブラウザはビデオタグをサポートしていません」という言葉がビデオのセクションに表示されます。

Webアプリにプログレッシブエンハンスメントを適用する必要がある理由

オンラインコンテンツ配信に関しては、ユーザーまたは開発者のいずれかによって引き起こされる可能性のあるさまざまな課題が発生する可能性があります。プログレッシブエンハンスメントは、これらの問題の影響を軽減するため、または少なくともエンドユーザーにすべてではないにしても一部の情報を提供するために作成されたソリューションです。

プログレッシブエンハンスメントの実践を検討するその他の理由は次のとおりです。

  • 改善されたSEO:WebサイトでHTMLセマンティクスを正しく使用すると、スクリーンリーダー、Webスパイダー、および検索エンジンが情報にアクセスしやすくなるため、そのサイトのSEOが向上します。
  • 互換性とアクセシビリティの向上:Webサイトのコンテンツはさまざまなデバイスにロードできる必要があるため、ユーザーのデバイスまたはブラウザーがWebサイトの開発に使用される言語をサポートしていない場合、エラーは少なくなります。
  • 単純なスケーラビリティ:Webサイトは、十分な情報を提供しながら、最も幅広いオーディエンスに到達する必要があります。プログラマーは、ユーザーに情報を提供しながら、ワークロードを上げることができることを確認する必要があります
  • 速度とユーザーエクスペリエンスの向上:適切なセマンティクスを使用すると、コンテンツの読み込み速度が向上し、Webサイトがコンテンツをすばやく読み込むと、ユーザーエクスペリエンスが向上します。

プログレッシブエンハンスメントを実装する方法

Webデザインのプログレッシブエンハンスメントの基本は、Webデザインの上位層が利用できない場合に、必要な適切なコンテンツをユーザーに提供することです。

たとえば、JavaScriptを第3層、CSSを第2層、HTMLを第1層として設計されたサイトがあるとします。JavaScriptがない場合でも、サイトのデザインは正常に機能するはずです。これは、JavaScriptがすでに正しく機能しているものを補足するだけであることを意味します。

これがサンプルのドロップダウンボタンでどのように機能するかを見てみましょう。

最初のレイヤー:HTML

このレイヤーは、テキストベースの古風なブラウザー、スクリーンリーダー、およびユーザーエージェントがWebサイトのコンテンツを正しく参照してアクセスできるようにするセマンティックマークアップです。

ドロップダウンボタンの場合、セマンティックマークアップの例を次に示します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dropdown</title>
</head>
<body>
    <button id="dropbtn">Navigation Menu</button>
    <ul id="ul">
        <li><a href="/home"></a>Home</li>
        <li><a href="/about"></a>About</li>
        <li><a href="/contact"></a>Contact</li>
        <li><a href="/signin"></a>Signin</li>
    </ul>
</body>
</html>  

ドロップダウンメニューは順序付けられていないリストで構成されており、ボタンは現在機能していません。その結果、メニューリストは静的なままになり、折りたたんだり展開したりすることはできません。

上記のコードをブラウザで実行すると、次のように表示されます。

第2層:CSS

これは、追加機能の最初のレイヤーです。CSSは、Webページに機能をもたらす場合ともたらさない場合があります。これは主に、Webサイトをより視覚的に魅力的な外観にするために、レイアウトを整理および強化するために使用されます。

CSS拡張の例は次のとおりです。

<style>
    button {
        border-radius: 20px;
        border: none;
        padding: 10px 20px;
        cursor: pointer;
        background: #ccc;
        transition: all ease 0.2s;
    }
    button:hover {
        box-shadow: 2px 2px 4px rgb(90, 90, 90);
        filter: invert(1);
    }
    ul {
        list-style: none;
        padding: 0px;
        width: 250px;
    }
    .active {
        height: 0px;
        overflow-y: auto;
    }
    li {
        height: 25px;
        padding: 10px;
        background-color: #ccc;
    }
    li:hover {
        filter: invert(1);
    }
    li a {
        height: 100%;
        width: 100%;
        color: black;
        text-decoration: none;
    }
</style>

headWebページのタグとbodyタグの間にCSSスタイルを追加すると、ドロップダウンは次のように表示されます。

第3層:JavaScript

このレイヤーは機能レイヤーです。新しいユーザーエクスペリエンスを生成する方法でDOMを操作することもできますが、必須ではありません。

このJavaScriptレイヤーがなくても、ドロップダウンにアクセスできます。機能スクリプトを追加すると、どのようになるかを見てみましょう。

ドロップダウンに含まれるJavaScript機能の例を次に示します。

<script>
    window.addEventListener('load', () => {
        dropDownMenu = document.querySelector('#ul')
        btn = document.querySelector('#dropbtn')

        dropDownMenu.classList.add('closed')
        btn.addEventListener('click', (e) => {
            e.preventDefault()
            dropDownMenu.classList.toggle('closed')
        })
    })
</script>

window.onload上記のコードでは、イベントをリッスンし、を使用querySelectorしてとを選択しdropDownMenuますbtnclosed次に、デフォルトのクラスをに追加しdropDownMenuて折りたたみます。その後、がクリックさclosedれるたびにクラスが切り替えられます。btn

Webページの終了タグの直前にこのスクリプトを追加するbodyと、ブラウザにページが読み込まれると、ドロップダウンは次のようになります。

メニューリストは折りたたまれています。ただし、[ナビゲーションメニュー]ボタンをクリックすると、メニューリストが次のように展開されます。

これは非常にユーザーフレンドリーなエクスペリエンスですが、拡張の各連続レイヤーを追加する前に、メニューリストへのアクセスを提供することができました。

プログレッシブエンハンスメントへの批判

コンセプトは魅力的に見えるかもしれませんが、プログレッシブエンハンスメントにはまだ多くの反対の見方があります。

時間の無駄だと考える人もいれば、ユーザーがWebサイトの標準に一致するようにブラウザをアップグレードする必要があると考える人もいます。プログレッシブエンハンスメントは、ブラウザでJavaScriptを故意に無効にするユーザー向けでもあると考えられていますが、これは正しくありません。JavaScriptが意図的に無効にされているかどうかに関係なく、ユーザーはWebサイトのコンテンツを表示できる必要があります。

プログレッシブエンハンスメントは古いブラウザでのみ利用できると考える人もいます。ただし、ユーザーは、ブラウザの新旧に関係なく、好きなブラウザを使用できます。Webサイトが、Webサイトのコンテンツにアクセスしようとするすべてのブラウザと互換性があることを確認するのは開発者の責任です。

まとめ

プログレッシブエンハンスメントは、Webサイトの長期的な実行可能性に関係しています。この方法論を使用すると、将来、より優れたフレームワークとテクノロジーへの拡張と移行が容易になります。

読者の皆様には、プログレッシブエンハンスメントの概念を理解し、実践していただきたいと思います。プログレッシブエンハンスメントの知識をテストするには、プログレッシブWebアプリケーション(PWA)を作成し、それがこの記事で説明するプログレッシブエンハンスメント標準に適合するかどうかを評価します。

出典:https ://blog.logrocket.com/understanding-progressive-enhancement/

#pwa 

プログレッシブエンハンスメントを理解する