Monday, March 20, 2017

JavaScript: React Conf 2017

JavaScript: React Conf 2017

I went to REACTCONF17. Here's the schedule. Here are the videos. Here are my notes:

Keynote

Tom Occhino, Jing Chen, and Sebastian Markbage

547,000 users have React DevTools installed.

Facebook has 100s of React Native screens in production.

Facebook uses React for many screens in the Facebook app. You can't tell the difference between what is and isn't using React Native.

He said they're not done with React. They're going to "Innovate in place." There's always going to be an incremental path. You'll never have to rewrite from scratch.

React Native at Facebook

Benefits:

  • Fast iteration
  • Declarative views
  • Cross-platform (and cross application)

They couldn't rewrite the entire Facebook mobile app. Instead, they're incrementally adopting React Native.

Things they focused on:

  • Performance
  • Parity (between iOS and Android)
  • Developer experience

The bundle size of their React Native app is 11MB, uncompressed.

They do API fetches really early, even before all the code has finished loading.

It's now easier to add a new view. You no longer have to rebuild for every platform every time you add a new view.

They build features that are used across apps (across Facebook and Instagram).

During the migration effort:

  • Build relationships
    • Have regular checkins with the teams
    • Give tech talks and hold happy hours
  • Integrate with the native infrastructure
  • Pay attention to the user experience

React Performance End-to-End

The industry has been moving toward client-side technologies.

  • Robust interactivity
  • Sophisticated UX
    • Offline
  • Innovative interface designs

He plugged the "extensible web".

Slow startup time is a problem, both for web and native.

Some people are considering moving more toward the server:

  • AMP
  • Facebook Instant Articles

Some things should be moved server-side.

Only download what you need:

  • Bundle splitting

Cache the last version:

  • Auto app update
  • Service workers

P2P delivery:

  • P2P app updates (really?)
  • WebRTC

Shared distribution:

  • Shared versioning (common set of tools across companies)
  • CDN

Cache artifacts:

  • Bytecode / codegen cache
  • Ahead of time compilation

He said he's going to talk about "another language" (other than JavaScript) tomorrow.

Compile (like Closure compiler):

  • Constant folding
  • Heap snapshotting

Performance:

  • Smarter algorithms / APIs
  • Optimizing compilers

Try to load and render chunks asynchronously. He talked about streaming responses. Let each component be rendered when it's ready.

Just showing UI as soon as possible is not a good UX because it looks janky. Only display a chunk when the whole component is ready.

Responding to user interaction is always more important than showing more UI.

Responsiveness:

  • Gestures / animation: 10ms
  • Tap / click: 100ms
  • Network / timer: 1000ms
  • Off screen / hidden: whenever

Scheduling is a core part of UI engineering. Right now, it's too ad-hoc.

Important: That's why they built React Fiber.

He said something about asynchronous rendering, scheduling primitives, etc.

yarn add react@next
yarn add react-dom@next

They're already using it in production at Facebook.

More stuff from the main speaker

Fiber is a new foundation for React.

They're working on an <ErrorBoundary /> component.

They're making it so that you can return multiple things from the same component ;) You can return arrays or strings from render.

React Fiber is completely written in Flow.

They're trying to make the codebase more approachable.

He plugged create-react-app. This will help stop JavaScript Fatigue.

We shouldn't bifurcate the community based on platform boundaries. "One React Community".

A Cartoon Intro to Fiber

Lin Clark from Mozilla

She has a cartoon to explain Fiber.

Fiber will make rendering a lot less janky.

It improves perceived performance and responsiveness.

There's a new reconciliation algorithm.

React's initial killer feature was its virtual DOM.

They're differentiating the reconciler and the renderer.

There's a renderer called react-pdf for rendering PDFs.

There are high priority updates and low priority updates.

Currently, the main thread gets stuck waiting for all the recursive renders. The idea is to render some of the components, and then give up the main thread.

A fiber is a plain JavaScript object. It has a 1-to-1 relationship with an instance. She said something about a "stateNode".

There's a work in progress tree.

There's a stack reconciler. It takes changes from instances, and updates DOM nodes.

  • Phases:
    • Phase 1:
      • render / reconciliation
    • Phase 2:
      • commit (cannot be interrupted)

It can schedule work later. It uses requestIdleCallback.

There's a work loop. Do a little bit of work. Then come up to let the main thread do its thing. It keeps track of what more works need to be done, and how much time is left in the given frame.

There's an effect list.

React is using double buffering.

Priorities:

  • Synchronous
  • Task
  • Animation
  • High
  • Low
  • Offscreen

Lifecycle methods might not fire in the order you expect. With Fiber, you can't guarantee that componentWillUpdate will be followed with componentDidUpdate right away. It might be called twice before componentDidUpdate gets called.

Focus on using smaller units of work. Higher priority units of work will cut in line.

This is cooperative scheduling.

The React core team explained Fiber to her so that she could explain it to us.

Next.js: Universal React Made Easy and Simple

Guillermo Rauch

Next.js makes universal React.js easy and simple.

It should behave predictably and consistently.

Universal = works on the server and client.

He rebuilt Hacker News as an exercise. His demo uses Firebase.

They're been using it at zeit.co for almost a year.

Minimal convention over configuration.

These are the invariants he expects:

  1. sophisticated apps have many variable entry points
  2. loading more code than necessary is bad
  3. ./pages, ./lib, ./components

Code splitting even makes sense for CLIs.

Having top-level components is good for a UX style guide. It's like Sketch in the browser.

Pre-rendering the layout is a better indicator of progress than waiting for the server to give you a page.

Sometimes you can pull stuff from the client cache.

You can use <link prefetch> to prime the cache when going from one entry point to another.

Hot module reloading (HMR) is a problem if you get too many components.

Next.js improved performance by 10-15X by only watching the things you're working on for HMR.

They have tons of examples, including Redux, MobX, etc.

Inline styles only support a subset of CSS. For instance, you don't have media queries, etc.

They came up with StyleJSX. You can have a style tag in your JSX code near your HTML.

How you use CSS is very variable in the React world. People are doing all sorts of things. If you're building a library, the only universal thing is inline styles, but those are limited.

Next.js has a Babel preset.

Facebook hired the Inferno guy in order to make React better.

React + ES.next = ♥

Ben Ilegbodu from Eventbrite

They're moving from Backbone to React.

Destructuring

let comments = this.state.comments // Duplicated "comments"
let {comments} = this.state // No duplication
let author = this.state.author // Verbose
let text = this.state.text
let {author, text} = this.state // Much shorter

(Note, he's not using semicolons.)

Renaming attributes:

let {author: authorName} = this.state
function MyComponent(props) {
    ...props.style... // Duplicated props
    ...props.children...
}
function MyComponent({children, style}) { // Exactly what you need
    ...style... // No duplication
    ...children...
}

Spread operator

let newComment = comment
newComment.id = Date.now() // Oops, accidentally mutated comment too!

You can maintain immutability with the spread operator. This replaces _.assign.

let newComment = {...comment, id: Date.now()}

You can use it with arrays instead of using concat to append an element and create a new array:

let newComments = [...comments, newComment]

Arrow functions

Replace anonymous functions with arrow functions. This fixes the "this" problem so you don't need to use .bind.

$.ajax({
    ...,
    success: (resJson) => { // Callback with a properly-bound "this"
        ...
    }
})

He covered the various syntactic variations of arrow functions.

const MyComponent = ({children, style}) => (
    <div>...</div>
)

Promises

Replace callback-style programming with promises.

Use the fetch API instead of $.ajax from jQuery.

fetch(this.props.url, {
    method: 'POST',
    ...
})
    .then((res) => res.json())
    .then((resJson) => {
        this.setState(...);
    })
    .catch((ex) => {
        ...
    });

You can convert callback style APIs (like setTimeout) to promise-based APIs.

Promise.all allows you to make simultaneous async requests as a single promise.

Async functions (ES2017)

Use normal control flow with async/await.

async _handleCommentSubmit(comment) {
    try {
        let res = await fetch(this.props.url, {...})
        newComments = await res.json()
    } catch (ex) {
        ...
    }
}

In order to implement this, Babel uses generators, promises, and a lot of magic.

He wrote a tutorial: https://github.com/benmvp/react-esnext

MobX vs Redux: Comparing the Opposing Paradigms

Preethi Kasireddy

She pronounced it Mob-X instead of Mobe-X.

It's all about opinions and tradeoffs.

Both describe UI as a function of state.

Redux:

  • View -> Actions -> Store / Actions / Reducer

MobX:

  • Like a spreadsheet
  • Stores, computed values, reactions, views

Single store vs. multi-store:

  • Redux is single
  • MobX is multiple. How you structure your stores is up to you.

Redux: plain POJOs.

MobX: wraps your objects with observables.

MobX observes references. It keeps track of the data you care about so that it knows when you need to re-render.

Redux: manually tracks updates

MobX: tracks updates; implicit; reactive

Redux is read-only.

MobX lets you read and write to state. It's impure. (Although it has a useStrict feature that she didn't mention.)

Redux: actions required

MobX: actions not required

Redux: you have to normalize your state. You don't want deeply nested data.

MobX: you can keep your state denormalized. You have computed values.

MobX has a much easier learning curve. It's a familiar OO paradigm with magic behind the scenes.

Redux has a functional programming paradigm, and there's no magic behind the covers.

MobX's learning curve doesn't get harder over time.

Redux's learning curve gets much steeper over time.

MobX wins in terms of requiring less boilerplate.

Redux has much better developer tools. Redux's time travel debugging is awesome.

Redux is more debuggable. Understanding what MobX is doing under the covers is harder.

Redux is more predictable.

Redux is (arguably) more testable.

MobX wins in terms of modularity.

Redux wins in terms of scalability and maintainability.

Redux has a lot more community.

She said you should start with setState. Only when you run into problems should you look for something more powerful in order to pull state out.

She felt that Redux was better for bigger teams. (I disagree.)

MobX allows you to use a single domain class to manage all your update logic.

MobX is good at reacting to state changes.

React is good at reacting to actions or events.

Whichever one you choose, it's not an end game. There's no vendor lock in. They're not framework specific.

She experienced moving a project from Redux to MobX.

Type Systems Will Make You a Better JavaScript Developer

Jared Forsyth from Khan Academy (and previously Facebook)

He has experienced both worlds.

JavaScript has a type system, but he says it doesn't give you nearly enough type errors. That inhibits debugging. You get weird type errors late.

Type errors: when you try to use a thing in a context where it doesn't belong.

Here are some of the ways to get more more type errors:

Linters can catch things that you're trying to use that are undeclared.

Custom runtime type checking (i.e. writing type checks manually in your code) is sometimes useful but frequently annoying. It's powerful, but it requires lots of extra boilerplate-y code, and it can only catch things at runtime.

React propTypes provide runtime type checking, but they're less annoying than doing it by hand.

Flow provides static type checking. In a lot of cases, Flow can infer types. It's much simpler than custom runtime checking.

Flow:

  • Runs ahead of time
  • Doesn't require much boilerplate
  • Applies to everything (not just components)
  • Is great for documentation

He likes Flow. He said TypeScript is similar.

Adding Flow to code will help you find bugs.

Flow's editor integration is confusing.

Code that's too clever is hard to debug.

It's painful to deal with functions that are super flexible and treat the arguments differently based on how many arguments there are.

If it's hard to typecheck, it's probably hard to understand.

Flow helps with implicit invariants.

Sometimes, the best thing to do is to create a child component.

He talked about how to represent a state machine in a way that reduces complexity; try to structure the data to make it impossible to represent illegal states.

Flow has something like algebraic types.

If you're making a ton of things optional, you're probably trying to represent a state machine poorly.

Thinking about the types first sometimes makes things cleaner.

These are the times when you should think about types first:

  • State machines
  • Remote data types

These are the times when you should think about types later:

  • Simple data
  • Complex interactions

Lightning talks

Moving Fast with Nuclide and Flow

Andres Suarez

Nuclide is Facebook's IDE based on Atom.

It has good integration with Flow.

It has:

  • autocomplete
  • type hints
  • jump to definition
  • outline view
  • highlight references
  • push diagnostics

Links:

AWS Lambda + AWS Gateway + React = AWEsome

Sophia Shoemaker

http://fullstackreact.com

With Lambda, you don't have to worry about a lot of the things you had to worry about with servers.

Lambda currently supports JavaScript, Python, and Java.

ServerLess goes hand-in-hand with create-react-app.

http://github.com/serverless/examples

React to Code

Merrick Christensen

The idea is to look at changes to code over time and recommend further improvements based on recognized patterns.

He created react-sourcerer.

It responds to changes to your source code.

It works with ASTs.

state = parse(source)

Do something if the code is importing from lodash:

<Import from='lodash'>

The Road to Styled Components

Max Stoiber

It's another system to tie CSS to components.

CSS sucks.

It sucks for building component-based UIs.

"Colocate and isolate."

Remove the mapping between styles and components:

  • Write actual CSS
  • Have the power of JavaScript
  • Theming
  • React Native support

Building Applications for a Studio in the Cloud at Netflix

Feather Knee

She's working on an internal application built using React at Netflix. She wasn't able to show a screenshot.

Netflix was one of the earlier users of React.

Goal: pick the best content (e.g. movies, etc.), given the constraints.

They know what you will probably watch, based on statistical models. The models are often wrong, but they still manage to have good content.

They have to deal with picking content world wide.

She mentioned a lot of libraries they use.

React Native in the "Brown Field"

Leland Richardson from Airbnb

He talked about integrating React Native into large, existing native codebases.

React Native was launched 2 years ago.

Airbnb started playing around with it about a year ago.

460k LOC (native), 70k LOC (JavaScript)

Brownfield projects are the opposite of greenfield projects.

For React Native: don't reinvent everything in JavaScript. Take advantage of the underlying platform where it makes the most sense.

React Native is only 40% JavaScript.

Some of React Native is in C++.

Yoga is React Native's layout engine. It's written in C++.

React Native things usually have JavaScript APIs, but they are often implemented in native code.

You can write your own native libraries that are usable via JavaScript.

He talked about infrastructure code vs. product code.

There's still no clear answer for navigation in React Native.

  • NavigatorIOS
  • Navigator
  • NavigationExperimental

react-native-navigation is another such library.

Brownfield apps have unique constraints.

Airbnb had to build their own solution for navigation since some of their screens are native, and some of their screens are built using React Native.

One bridge, many React root views.

Two modes of navigating: pushing and presenting.

Render-time configuration: Navigator.config.

He talked about header components that show / hide when scrolling.

Shared element transitions: see a picture on the page, click on it, and the whole view zooms into it.

Leverage native APIs to create even better JavaScript APIs.

Important: They just open sourced their work:

Moving Beyond Animations to User Interactions at 60 FPS in React Native

Tal Kol from Wix

React Native really improves productivity.

Can React Native cross the last mile? The first 95% was really easy; it's about 4X more productive. The last 5% is much harder.

What makes great apps? Smooth transitions, animations, etc.

"animated" is part of the core, and it fixed the slow animations.

UIs are more persuasive when they matches the physical world.

He talked about dynamic user interactions that mimic reality. Swipe an email row, and it shows you actions you can do.

He talked about lots of features in apps where you swipe things out, and they have gravity, velocity, acceleration, etc.

react-native has a SwipeableRow.js library.

He talked about "traffic over the bridge" (between JavaScript and native code) where the animation is mostly implemented in JavaScript.

One way to improve performance is to reduce bridge traffic.

At Wix, only 10% of their engineers are native engineers.

Important: Declarative API are how we cross the last mile.

They're building a declarative API for user interactions.

He showed a bunch of nice looking animations for drawers, cards, swipeable rows, etc.

He talked about springs, friction, and snapping points.

He talked about implementing this kind of stuff using UIKit Dynamics which is a fully fledged physics engine in iOS. However, it's not available in Android.

He talked about reimplementing UIKit Dynamics, i.e. his own physics engine.

He started with Physics 101 on Wikipedia.

They're writing a declarative physics engine for views for React Native.

Search the app store for "React Native Interactions" to play with his examples.

http://github.com/wix/react-native-interactable

Lightning talks

You Don't Need a Fancy Framework to Use GraphQL with React

Samer Buna

https://bit.ly/graphql-react

GraphQL is a replacement for REST for the sake of performance.

graphfront generates a GraphQL schema for your DB.

graphfront-ui generates an admin for your DB.

Cross-Platform Data Visualization with React and React Native

Peggy Rayzis

She's from Major League Soccer.

Victory: a modular charting library for React and React Native.

Using React for Anything but Websites

Ken Wheeler from Formidable

This was a talk about building "strange things" using React.

Spectacle is a JSX-based presentation library.

Victory is for building CLIs.

React-Game-Kit uses MatterJS.

He talked about react-music.

There are other custom renderers like react-hardware.

With Fiber, renderers are first class instead of total hacks.

React Everything, Render Everywhere

Dustan Kasten

In 2013, they introduced React and said HTML was only the beginning. Now we can even do VR with React.

There are lots of different rendering engines.

Fiber changes everything. There's a renderer API.

We own our output.

React motion for drag and drop.

Learn once render everywhere.

Create React Native App: 5 Minutes to "Hello, World!"

Adam Perry

create-react-native-app

You only need to have node installed.

It installs your app into the Expo app (???).

Testing works with Jest.

It doesn't support custom, native modules. But there are a bunch of libraries Expo gives you out of the box.

You can "eject" in order to generate the code and build under XCode and Android Studio.

Goodbye Flatland! An introduction to ReactVR and what it means for web developers

Michaela Lehr

VR concepts

She talked about stereoscopic images.

She talked about tracking sensors.

Here's what the stack looks like:

* Browser
* WebGL
* WebVR
* three.js
* ReactVR

There's a react-vr-cli tool. It can scaffold a project.

How do we present content to the user in this new environment where the user is "in" the environment?

react-native-interactable

There are components for all sorts of VR concepts.

In WebGL, you can think of X as pointing to the right, Y as pointing up, and Z points away from the user, with the user looking in the -Z direction. You can think of 1 unit = 1 meter.

There's a flexbox layout system.

There's an "Animated" API.

There's also sound; you can tie sound to a location.

UX Design and VR

There's a UX hierarchy:

  • Delight
  • Usefulness
  • Interpretability
  • Comfort (most important)

When sitting, you have a 70% cone of viewing. You can turn your head to see an additional 30% to each side (80% max).

Things should be further than 0.5m away and closer than 20m.

The devices have pretty low DPIs, so you should use fonts that are 20px or larger.

PPD = pixels per degree

Current devices have 10-12PPD. To get to the point where you can't see pixels anymore would require 60PPD.

More tips:

  • avoid eyestrain; use darker colors
  • avoid focusing on different depths
  • do not trigger phobias
  • use correct scales
  • do not move things too quickly towards the camera
  • do not attach things near the camera

Avoiding simulation sickness:

It happens when your senses are not in sync. For instance, when what you see doesn't match what you feel.

  • no acceleration
  • do not move the horizon or the camera
  • always keep a low latency and a high frame rate
  • avoid flicker and blur
  • add a stable point of focus
  • support short usage
  • abstract design is better than realistic

You are responsible for the well-being of your users. It's more serious in 3D.

Here are the slides.

Realtime React Apps with GraphQL

Robert Zhu from Facebook

Realtime apps are harder to build, but they give us a sense of connection.

You can no longer think of a client making a request and the server making a response. It's more of a conversation.

Doing realtime with React really comes down to having really good client-side state management and having a nice API.

You can use Relay, Redux, etc. for managing the client-side state. He's going to focus on the API.

Realtime APIs:

  • Pull
    • Polling
  • Push
    • Live queries
    • Subscriptions

Polling has a number of drawbacks, but it's simple, stateless, and intuitive.

With a live query, the server just tells you whenever there's an update to the data you're watching. However, this requires a reactive backend which is difficult to integrate and scale.

With subscriptions, you only get notified of state changes when the state change is something that's really important. Furthermore, you'll be notified about why you're getting this new state.

He talked about how much data the server should give to the client when a state change occurs.

The client should be able to specify the data that they need. That's what GraphQL is about. It's a query language for your API. "It's an elegant idea for a more civilized age." It's a "declarative data query language that lets clients specify exactly the data that they need."

"Wish driven design" = "when I'm building the client, I like to imagine the shape of the data that I wish I had."

"I'm extremely lazy, so the shape of the data should match exactly the shape of the data that I can pass into my React component as props."

GraphQL query:

 query {
     emails {
         from
         subject
         isRead
     }
 }

Response:

{
    "emails": [{
        "from": "carl@gmail.com",
        "subject": "hey",
        "isRead": false,
    }]
}

Subscription:

subscription {
    importantEmail {
        from
        subject
        isRead
    }
}

On the client, he's using React and Relay.

GraphiQL is the GraphQL IDE. It lets you explore a GraphQL schema.

When you run a subscription, it doesn't respond immediately. It waits for events to come in.

The third type in GraphQL is mutation.

There's something else that's like Relay called Apollo.

In his example code, he's using await.

He's using web sockets to talk to the server.

Facebook has been operating GraphQL subscriptions at scale for over two years.

It powers live likes, live comments, and streaming reactions on live videos.

GraphQL is evolving incrementally.

http://github.com/facebook/graphql

Once things are more standardized, he expects the community to build a variety of clients and servers across transports and backends.

Partners:

Jest Snapshots and Beyond

Rogelio Guzman

He doesn't like tests as much as he likes the idea of testing.

They had a problem where it took a lot of effort for fewer tests, instead of less effort for more tests.

Moving to Jest was easy. Tests were 6X faster. Runs were instant.

He mentioned snapshot tests.

yarn add -D jest
yarn jest -- --watch
it('Adds up two numbers', () => {
    ...
});

Sample code: http://github.com/rogeliog/jest-snapshot-talk

There's a problem with running code, and then just copying the results into the test.

Jest has an approach called snapshot testing.

expect(sum(1, 2)).toMatchSnapshot();

It saves the output of the function to a .snap file.

If the output of the function suddenly changes, the test will fail.

Jest takes care of managing the snapshots for you. It adapts to changes. It's easy to maintain. It's much easier than doing this process by hand.

If the snapshot doesn't match the output of the test, you can recognize that it's a bug, or you can have it update the snapshot automatically.

Snapshot serializers let you customize what the snapshots look like:

expect.addSnapshotSerializer({
    test: …,
    print: …
})

You can use snapshots to test the output of components.

const component = renderer.create(
    <MovieList query="f" />
);

Jest has a serializer for the output of components.

There's a enzyme-to-json/serializer library. It works with shallow, mount, etc.

You can use expect(...).toMatchSnapshot() in a loop. Adding more snapshots lets you test more things without increasing the complexity of the tests.

jest-movie: think of a movie where each snapshot is a frame. I think he's still working on this library.

Jest isn't just a testing framework; it's a testing platform.

Jest: jest-snapshot, pretty-format, jest-validate, etc.

Prettier is using jest-validate to validate CLI invocations.

A Beginner's Guide to Code Splitting Your React App

Neehar Venugopal

Facebook has been doing code splitting since 2008. They're working with the Chrome team.

Code splitting is really easy.

70% of our traffic comes from mobile in India. We have to be mobile first.

The nice thing about mobile is that we have evergreen browsers. (I think he's overlooking Facebook webviews.)

Think about long term caching. Split out the third-party libraries into their own bundle. Put a hash in the filename. Tell it to cache the file forever in the CDN and in the browser.

Next, split the code into per-functional-area bundles. Send only the minimum amount of JavaScript required.

ES6 provides built in async loading of modules.

Before, we used to use require.ensure.

Now, we use import(...) to load code asynchronously. It's stage 3. It's in Webpack 2. It returns a promise. It accepts dynamic module names. Webpack implements this by adding an asynchronous script tag to the head.

Components can be: functions, classes, etc., but they can't be promises. Fiber may support this.

Loading components vs. loading data: they can be treated the same. Hence, you can have a component that uses componentWillMount to fetch code. Async modules are promises. Treat them as any other type of data that you fetch dynamically.

Route-level splitting is almost always the best place to start.

Beware of code duplication across multiple bundles.

In React Router v3, there's a getComponent attribute so that you can asynchronously load your code.

Split within top-level routes. Each async route is a distinct output file.

They've been experimenting with the idea of responsive components. Load the mobile JavaScript code first, and upgrade to desktop if necessary. He's thinking of mobile-first JavaScript.

Conditional imports are easy.

In practice, server side rendering gets tricky when you're loading things dynamically on the client.

Always profile on real devices.

Avoid network waterfalls. Try to load all the things you need in parallel rather than serially.

Use link preload and prefetch when appropriate.

Remember, import() is always async and that promises always resolve asynchronously.

"If you can write a component that makes an API call, you can write a component that is lazily loaded."

Web-Like Development and Release Agility for React Native

Parashuram N from Microsoft

React Native: The JavaScript VM sends actions to the native UI and receives events from the native UI.

The packager is something that runs on your local machine, bundles your code, and sends it to the JavaScript VM.

You could run the packager in the cloud, and then update the device in real time. This is how code push works.

People do use code push in production. It doesn't violate iOS's terms of service since they have a specific exception for JavaScript.

Mobile Center: https://mobile.azure.com

It's like a DevOps pipeline. You can upload your certificates. It will take care of CI for your mobile app. It has a pretty UI.

They have a feature where you can test your app on real world devices. All the devices will work together in sync even though you're using manual testing. Pretty neat!

mobile-center-crashes and mobile-center-analytics.

He's using VS Code.

If you shake your phone really hard, you can get your phone to debug JavaScript remotely in Chrome.

You can tell React Native to run the code in Node, and then debug it with VS Code. You can even replace Node with Node Chakra.

Chakra has a Step Back feature where you can rewind the entire JavaScript context of the app.

He said, use TypeScript or Flow to avoid type errors.

You can use code-push to quickly push updates to your phone.

The Step Back feature is like time traveling debugging, but encompasses even more. You can even replay events like you can in Redux.

You can push a fix to your code even without waiting for Apple to approve your new version.

This guy is really talented :)

They're working on code signing.

VSCode:

  • Has excellent Flow and TypeScript support
  • Has an extension named "ReactNative tools" that's pretty helpful
  • Can deploy directly to Exponent
  • Lets you debug Exponent apps
  • Has Node-Chakra code and time travel debugging

He said that time travel debugging is always an experiment.

His slides: http://bit.ly/reactconf17

His demos were amazing.

React-Storybook: Design, Develop, Document and Debug your React UI components

Marie-Laure Thuret

A UI component relies on several states.

How do you make sure your UI components are well documented, tested, etc. in a standalone manner?

http://github.com/storybooks/react-storybook

React Story Book: an isolated environment to quickly design and build your UI components.

Develop, design, document, debug, discuss.

It's a standalone UI to work on your component. Neat!

(She's using VS Code.)

It lets you build documentation in a nice way.

It creates UI to play with your component.

Working on your component in an isolated way helps you think of the API first.

It's a nice thing to link to in your docs.

It can help with testing too.

"Storyshots" is a feature where you can test your markup using snapshot testing.

The Specs add-on lets you write explicit tests near your component.

You can link to a storybook in your GitHub PR.

  • Hot reloading
  • Isolated environment
  • Iterate quickly
  • Create a style guide
  • Live docs
  • Add specs through tests
  • Expose props
  • Entry points for debugging
  • Isolate bugs
  • Share stories

It has an add-on API.

Extensible React

Cameron Westland from Autodesk

Autocad is extensible.

How do you make your app more extensible?

  • 1st party - you working on your own product
  • 2nd party - customers adding to your product
  • 3rd party - an ecosystem of addons to a platform

He's going to just focus on the architecture of your thing that needs to be extensible.

"Lifting state up" works only if you own a common ancestor.

A portal is when you have a component nested in your code, but it actually creates the DOM markup at the end of the body. React modal does this.

He talked about using slots and fills as a way of providing extensibility. There's a react-slot-fill library. You can expose a global extension point, and you can render children into the slot.

He's using VS Code.

Everyone loves extensible apps.

http://github.com/camwest/react-slot-fill

Lightning talks

Building React Communities Outside of Your Circle

Troy Connor

He said he was a diversity candidate last year. This year, he's a speaker.

Mentor. Empower others. Promote diversity.

A Prettier Printer

James Long

Our current tooling is not enough. ESLint is not a formatter.

"We are the knights of nit." I.e. we send each other a lot of "nit:" comments in our PRs.

We need to stop dealing with nits manually.

Hence, he came up with Prettier. Its an opinionated JavaScript formatter.

A bunch of big projects such as Babel are either using it already or plan on using it.

It'll restructure your code depending on your max line length.

It understands Flow types, JSX, etc.

Benefits:

  • Consistency
  • Teachability
  • Freedom (not to worry about reformatting code)

He showed an example where leaving out a semicolon resulted in a bug. They're thinking of adding a feature to support people who prefer not to use semicolons, but they don't have that feature yet. Brendan Eich apparently likes people to use semicolons.

Neat: During the talk, the React guys let him merge a pull request to integrate Prettier :)

How to React in the Slow Lane

Nicole Chung

She talked about progressive web apps. You'll get more users.

She talked about code splitting. She talked about link rel preload.

She talked about caching, and then service workers.

She talked about the Lighthouse plugin--very useful.

She said your page should be responsive in 5 seconds on a 3G connection.

The Great Convergence with React

Aditya Punjani

They've used both progressive web apps and React Native.

When you add a progressive web app (PWA) to your homescreen, an actual APK gets created and installed on your phone.

React PWA best practices:

  • Aggressive caching
  • Extensive code splitting
  • Bypass React for animations

React Native best practices:

  • Pre-parse JavaScript
  • Recycler List View
  • Incremental JavaScript download

React is a platform. The same React engineers can work on both web and native.

Web benefits:

  • Instant load
  • Always up to date
  • No storage requirements

Native benefits:

  • Smooth and fluid
  • Service and hardware APIs
  • Discovery, reviews, and ratings

"Always bet on React" :)

Learn Once, Route Anywhere

Michael Jackson and Ryan Florence from React Training!

They built React Router.

60% of people using ReactDOM also use React Router.

64 people contributed to React Router v4. It finally shipped last week.

V4 is almost entirely "just components".

The API is so small, you can memorize it. He went through it.

https://reacttraining.com/react-router

They built a library called "history" for managing the browser history.

Native apps do have URLs, and you can link to any document in your app. You have a bit more control since the user doesn't have a URL bar.

They support React Native and deep linking.

They can handle the Android back button just fine.

The web is actually the most hostile environment.

One of them was using MacVim.

They have nice animations during navigation.

They did a fun thing where Michael kept saying they were going to work on something for their next talk and Ryan would say that he already built it and whip out the demo. This was particularly cool when they had a demo for React VR since they must have thrown it together using code from the earlier React VR talk.

Taming the Meta-Language

Cheng Lou

Brendan Eich is apparently in the crowd.

Reason is a new programming language from Facebook. It has a friendly syntax and toolchain. It's built on top of OCaml. It was built by the creator of React.

There's so much stuff aside from the language itself that you need to build in order to make a language successful. He calls this stuff "meta code".

How do we express higher level concepts without the need of a library?

Facebook was using OCaml already for Hack and Flow. React was originally prototyped in SML by Jordan Walke. People weren't ready for an ML then. Hence, he rewrote it in JavaScript.

There are ReactJS bindings for Reason. You can interoperate with your existing code.

propTypes become just part of the language using normal types.

The syntax of Reason is meant to look very familiar to JavaScript developers.

Reason has an option type: option (array string)

It supports JSX if you want.

It has label arguments setCoordinates x::10 y::200;

You can swap the argument order since they're named.

Theme of the talk: drag things down into the language.

Classes -> modules. It's a language level concept. It's a big concept.

Modules map to files in OCaml. Modules are first class, which means they can be passed to functions.

He talked about throwing away code--you're throwing away bad code, but you're also throwing away important lessons that were learned.

Less is more.

The problem with JavaScript is that just because you know JavaScript doesn't mean you'll be immediately productive in a radically different JavaScript community.

Instead of using cloneElement, you can just use currying.

You no longer need setState most of the time. Instead, you return a Some {...state, newText: "Hello" }.

There's a syntax formatter. In fact, Prettier was inspired by Reason's formatter.

There's a linter, but no one uses it.

It has per-library, pluggable error reporting.

Types kill a category of tests, but not all tests. Once you have types, you can test more important things.

Reason puts comments into the AST. Comments are even type checked.

Macros could potentially also work on comments.

Documentation becomes easier with types.

They have a sensible way of dealing with deprecation messages.

He used phrases such as "taking the metalanguage". By this, he meant bringing things that weren't in the metalanguage (proptypes, comments, etc.) and putting them into the language.

Some things don't get built into the language; some should get baked into the build tool.

Messenger.com is 25% converted to Reason.

It's not just an academic oddity. You can actually use it in production.

Reason compiles to JavaScript because there's an OCaml to JavaScript compiler.

OCaml itself also compiles to native, of course.

Inspirations: Elm (inspired by Haskell), F# (also inspired by OCaml), Clojure

Informal Panel Q&A

They're not live streaming this.

  • Ben: works on React (including Fiber) at Facebook
  • Sebastian works on React at Facebook
  • Spencer works on React Native at Facebook
  • Leland works at Airbnb on their Native Infra team (using React Native)
  • Lin works at Mozilla on emerging tech (WebAssembly, Rust, Servo)

Fiber is really a new foundation for a lot of work to come in the future.

Mobile simulators aren't nearly as good as using the real device. This is even more important for React Native compared to normal web development.

With React Native, there are some cases where that last 5% is really hard to make it as nice as developing a native app.

componentWillReceiveProps should only be used to call setState.

Dominic (???) said that React might get better than Inferno in terms of speed.

Preact and Inferno have been inspiring. Preact's number one goal is size. Inferno's number one goal is performance. The Facebook team has put serious effort into bundle size as well as performance. They're playing and learning.

Stateful, functional components are an idea that they've thought about. They're not really pure. The problem is that if they do provide such an API, they can't guarantee certain invariants that they need to ensure.

Closing Remarks

"Optimism is the catalyst for human progress."

Being nice is more important than the tech.


Friday, March 03, 2017

Progressive Web Apps

I went to an all day tutorial on Progressive Web Apps (PWAs). Here are my notes:

The tutorial was by Maximiliano Firtman, @firt.

Here are the slides.

Wow, he's written a lot of books!

He's not going to stick to Google's party line.

He mentioned the 10 year history of the web vs. native.

Funny: https://www.wired.com/2016/04/wait-web-isnt-really-dead-google-made-sure/

Web sites are instantly available. You don't have to install them.

Google is the one pushing PWAs. They were followed by Firefox, Opera, and Samsung. Microsoft is coming.

Apple isn't there, but you can still do some stuff on iOS. They created some stuff about 6 years ago that's still pretty useful. Apple hasn't announced any plans to implement various Progressive Web App features.

On iOS, Safari can save a bookmark to the homescreen, but you can't in Chrome on iOS.

Remember, Chrome on iOS is not Chrome. The rendering engine is WebKit, not Blink. Even the UserAgent has "CriOS" instead of "Chrome" in it.

His definition: A Progressive Web App is a model for creating app-like experiences using the latest web technologies progressively.

Important: These are the features of a Progressive Web App, per Google:

  1. Instant loading
  2. Discoverable
  3. Network indepedent
  4. Responsive (although he's not a fan of using exactly the same code for mobile and non-mobile)
  5. Installable (although Chrome doesn't let you do this on desktop by default, except on ChromeOS)
  6. Secure (you must use HTTPS, but you can use HTTP for localhost)
  7. Linkable
  8. Re-engageable (i.e. push notifications)
  9. Works everywhere (???)
  10. Fast

Progressive enhancement: don't design your website for only the latest browsers. Start with a core, and then add features for more advanced browsers and situations. He called this a design pattern.

  1. It's a website!
  2. Add native installation
  3. Add web push notifications
  4. Add hardware and platform access

PWAs vs. hybrid applications:

Hybrids are things built on Apache Cordova, PhoneGap, etc.

  1. There are big differences
  2. A PWA doesn't have distribution via the app store
  3. A PWA doesn't require packaging and signing like a native app
  4. A PWA can't access native plugins

Some people think that hybrids (like PhoneGap) will go away over time and be replaced by PWAs.

He doesn't consider React Native a hybrid. It's a native app that borrows some things from the web platform.

He wrote a book 7 years ago for O'Reilly called "Programming the Mobile Web". Hence, trying to build apps for mobile using web technologies is not a new idea. There have been numerous attempts to build what we are now trying to achieve with PWAs.

iOS came out with Home Screen Web Apps about 8 years ago. He said that this kind of inspired Google.

Firefox had Open Web Apps for WebOS. The project was cancelled, and they're now promoting PWAs.

Chrome had Chrome Home Screen Web Apps. These were inspired by iOS.

He talked about The Extensible Web Manifeso. The idea is to give web developers powerful, low-level APIs so that developers can extend the platform by themselves.

He's using Vysor in order to show his phone through his laptop.

He talked about flipkart.com, which is the poster child of PWAs. You can add the app to your homescreen. Once you re-open it, it is full-screen. It doesn't have the browser navigation bar, etc. It can run offline. It switches to grayscale as a hint that you're offline.

The Washington Post also has a PWA.

Instead of "Add to home screen", the newest Chrome has "Install web app" in the menu. The browser can invite the user to install the app using a banner.

Opera has something called "ambient badging" that they're working on. There will be an icon near the URL that's a hint to the user that you can install the web app.

Twitter built a PWA as well.

So did aliexpress.com. Their PWA has a banner that tells you to install their native app.

On iOS, in Safari, you can click "Add to homescreen". If you do so, and then click on the icon, there won't be any UI from the browser. It's treated more like an app.

https://pwa.rocks has a list of PWAs.

PWA compatibility:

  • Chrome on Android (not on iOS and not fully on desktop)
  • Opera Mobile
  • Samsung Internet Browser
  • Firefox (partial)
  • Edge (in the future; they'll be the first to support desktop)

Chrome on desktop has service workers, but it doesn't let you add an icon to the user's desktop.

Whether you are a PWA or not is not a boolean. It's an open definition with a lot of features that you could or could not be using.

Best of the web:

  1. Linkable
  2. Discoverable
  3. Easy to deploy
  4. Easy to update
  5. Web standards

But also with the best of native:

  1. Offline access
  2. Installed icon
  3. Push notifications
  4. Full screen experience
  5. Fast UI

Flipkart saw users spending 3x more time on their web experience since implementing a PWA. They saw a 40% increase in their re-engagement rate. They saw a 70% increase in their conversion rate for home screen users.

AliExpress saw a 104% increase in users, 2x increase in page loads, and 74% longer web sessions.

Interesting: Note that Flipkart and AliExpress both have native apps as well. No one big is building a PWA instead of a native app.

User acquisition is much, much cheaper for PWAs compared to native apps. Selio found that it was 10x cheaper to acquire users for their PWA compared to their native app.

Abilities:

  • HTML5
  • Works under any network situation
  • Access to sensors and hardware (USB, bluetooth, VR, etc.)
  • Multimedia
  • Icon on the home screen (on Android)

Android came out with Android Instant Apps, which kind of made the Chrome team angry. Android Instant Apps give you a native app without the installation.

Limitations that PWAs have compared to native apps:

  • They don't work on every platform
  • Responsive design is painful
  • They're not first class citizen
  • You don't have access to Android intents
  • You can't distribute your app in the app store

Interesting: Google is working on something called a Web APK. It's currently in Chrome beta under a flag. It will create an APK on the fly on Google's servers and then let you install it. The app will now be a first class citizen. He thinks this will be launched in 6 months.

Right now, you have to enable unsigned sources, but this restriction is going away.

I kind of think of this as an on-the-fly, less powerful version of PhoneGap. Although, keep in mind that PWAs are based on Chrome, whereas PhoneGap is based on webviews.

Brand new article: The New and Improved Add to Home screen

This is for Chrome and Android only. It's not for Opera, Samsung Browser, iOS, etc.--at least not yet.

Microsoft said that PWAs will also be available in the Microsoft store.

Web App Manifest (WAM)

It's a standard from the W3C. It's not new.

Without a manifest, you're not a PWA.

Ideally, you should serve it as application/manifest+json.

Basics:

  • name
  • short_name
  • start_url
  • lang
  • dir (language direction: rtl, ltr, auto)
  • orientation (any, portrait, landscape, natural, etc.)
  • display (required; browser, minimal-ui, standalone, fullscreen)
  • background_color (used for the splash screen)
  • theme_color (the color of the status bar)
  • icons (an array of icon objects)
    • src (32 bit PNGs with an alpha channel)
    • sizes (do a search for Android icon sizes)
    • type

There are several online web app manifest generators that you can use, such as: https://app-manifest.firebaseapp.com/

Article: Don’t use iOS meta tags irresponsibly in your Progressive Web Apps

He's using Visual Studio Code.

(I talked with him about this during a break. He said that he's using it because it's free and easy. He couldn't think of any killer features it has compared to IntelliJ Ultimate.)

index.html

<!doctype html>
<title>My first PWA</title>
<link rel="manifest" href="/manifest.json">
 
<h1>First PWA!</h1>

manifest.json

He used the generator mentioned above.

{
    "name": "...",
    ...
}

If you want to see flipkart's manifest.json, configure your Chrome DevTools to simulate a mobile device. Then, load https://www.flipkart.com/manifest.json.

You can tell it's working if you load Chrome DevTools, and there's an "Application" tab near the "Sources" tab.

Part of the magic is just having a manifest file.

Advanced techniques

Advanced manifest options:

  • related_applications (an array of app objects)
    • platform
    • url (URL of the Play store app)
    • id
  • prefer_related_applications
  • scope (e.g. "/"; not very useful today; what's owned by the PWA instead of by the browser)
<script>
window.addEventListener("install", function(e) {...});
</script>

You can use the display-mode media query to do something different if you were launched as a standalone app vs. if you were launched within the browser:

@media(display-mode: standalone) { /* vs. browser */
    body () /* The user is using the icon. */
}

Architecture

It's just web development. HTML, CSS, JavaScript, etc. You can use things like React, Angular, Polymer, Ionic, etc.

Ionic is a UI framework based on Angular 2 and TypeScript, but it also has a useful command line tool as well. Ionic tries to mimic the UI in Android or iOS.

Material design is just an approach to design. It's not just for Android.

Polymer apps don't try to mimic the native UI like Ionic apps do.

For the data layer:

  • Web storage
  • IndexDB
  • Web sockets
  • Server sent events
  • XHR
  • The fetch API
  • Service workers
  • Background sync

Device APIs:

  • Geolocation
  • Sensors
  • Multimedia
  • Bluetooth

You have to keep web performance in mind.

You must use TLS. HTTP/2 is recommended for performance reasons, but not required.

You can use service workers.

A Web App Install Banner is a little popup from the browser to prompt the user to install your app.

How to discover PWAs:

  • SEO techniques
  • Social networks
  • Etc.

Danger: If you open up a URL from within Facebook, you're stuck with a webview instead of actual Chrome. Hence, distributing a link to your PWA via social networks just doesn't work that well.

Chrome Custom Tabs let you send the user to Chrome with some arguments, etc. to control the experience. You can use this instead of using a webview. Service workers will work. However, Facebook and Twitter don't use these.

Since Android 5, the webview is based on Chromium. Remember that Chromium is open source, whereas Chrome is commercial. You can upgrade your webview, but no one does.

iOS has SFSafariViewController. Flipboard uses it. Facebook and Twitter don't.

A bluetooth beacon with 2 AAA batteries can stream a URL for about a year on a single set of batteries. It only costs about $20. This is the basis of the "Physical Web".

Right now, the web Bluetooth API won't let you automatically connect to Bluetooth beacons.

On iOS, you can add the Chrome widget, and it can scan for Physical Web widgets.

To get a Web App Install Banner, you need:

  1. A service worker
  2. A web app manifest
  3. The user to visit multiple times

On Android, there are no Chrome extensions.

There's a vibration API so that you can vibrate the user's phone.

You can't trigger the Web App Install Banner to happen exacty when you want, but you can customize how it appears once the requirements have been met. See the beforeinstallprompt event.

Ambient badging is the idea of having an icon near the URL in the location bar that shows you that the site is a PWA that can be installed. Opera has proposed this idea. However, no one has implemented it.

There's a downside to running full screen: if you've configured your PWA to run full screen, how can the user share the URL?

A lot of the big PWAs are in Africa or India. PWAs use less storage. They don't require a big download. Users in those places can't install too many apps, and they routinely uninstall apps.

The promise is that one day, users will install your app, and they won't know or care whether it's native or a PWA.

If you uninstall Chrome, it'll also uninstall all the shortcuts on your homescreen that Chrome created. However, on most phones, you can't actually uninstall Chrome because it comes with the device.

Remember, Google might be telling everyone to build PWAs, but their own big apps aren't PWAs.

Global browser stats: http://gs.statcounter.com/

In Asia:

  • Chrome: 44%
  • UC Browser (a Chinese browser): 27%
  • Safari: 10%
  • Opera: 6%
  • Samsung Internet Browser: 6%

UC Browser is a proxy-based browser built for performance. It runs through China. It runs partially in the cloud in order to make the experience better for people with crappy phones and network connections.

UC Browser has 50% market share in India.

In Africa, Chrome finally just passed up Opera.

api.fixer.io is an API for getting current currency rates.

This creates a number keypad:

<input placeholder="Value in USD" type="number" pattern="[0-9]*">

Interesting: By default, mobile browsers emulate desktop browsers that are 980px wide. iOS was the first to do this, and everyone else followed suit. To turn this off, add this to the head:

<meta name="viewport" content="width=device-width">

You could also pick an actual width instead of using device-width. The default, as I mentioned above, is 980px. However, using device-width is probably what you want. You need this in a PWA.

You used to have to add initial-scale=1, but as of later versions of iOS, this is ignored.

You'll also want:

<meta charset="utf-8">

The mobile-optimized frameworks like Ionic take care of a lot of CSS stuff for you to make it more mobile friendly.

This is CSS to turn off copy-and-paste:

user-select: none;

Although, I hate it when people do this.

-webkit-tap-highlight-color: red;

In HTML, there's an <output> tag to represent the output of a calculation.

Let's just use ES6 for now:

document.querySelector("input[type=button]").addEventListener("click", () => {
});

Service Workers

Important: Code snippets (I won't bother copying them all).

It's a little like a web worker, but it's detached from any tab. It's specific to your origin.

It can intercept network requests and replace them with something else. It can respond with a fake response or return something from a cache.

From your main HTML file:

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js');
}

It has no window, no document, etc.

self.addEventListener("install", e => {});

Remember, in Chrome DevTools, in the Application tab, there's a Service Workers section in the left-hand navigation.

If you go to the Console, there's a drop down that lets you switch from top to sw.js to switch from the main context to the service worker context. In the service worker context, you don't have a window, but you do have self.

chrome://serviceworker-internals/

You can prefetch URLs upon install.

From the Application tab, you can unregister your service worker. You'll probably also want to click "Update on reload".

You can also access your cache. During development, you may need to delete things from the cache.

You can also tell it to simulate being offline.

You can communicate between the service worker and the window. You can tell the window that there might be an updated version of the content that was requested earlier. However, you kind of have to implement that yourself.

Within the main window, you have access to the same caches:

caches.match("/")

The service worker can raise an exception after a timeout and return something from the cache.

When you're serving the service worker, you can use caching headers to control how the browser caches it.

The browser will cache a service worker for at most 24 hours. After that, it'll try to download it again. If it's exactly the same, it'll let the previous copy keep running. Otherwise, it'll start shutting it down and run the new version for new page loads.

In a service worker, you can use:

importScripts(["...", "..."]);

This is a web workers API. Alternatively, you can use a something like Webpack to generate a JavaScript bundle.

If you change an importScript, but you don't change the main service worker, the browser won't know that you have a new version of it. You might want to add a version comment at the top of the file. Hence, everytime you change the import script, you should change the version comment.

Data storage:

  • Web Storage:
    • It's a key/value store.
    • localStorage and sessionStorage are not available from SW because they're synchronous.
    • You're limited to 5MB, but in reality, since they use UTF-16, you probably only have 2.5MB to work with.
  • Cookies:
    • You can see the cookies in the requests and responses, but since you're not connected to any particular tab, you don't have access to global cookies.
  • IndexDB:
    • NoSQL.
    • It's an awful API.
    • Stores objects.
    • This is what we should be using.
    • It takes a lot of code to do anything.
  • Web SQL:
    • Deprecated a very long time ago.
    • It's in Chrome and iOS.
  • Cache storage:
    • Cache HTTP responses.

Funny: http://filldisk.com. It fills your disk with images of cats. It uses DNS aliases (SOME_NUM.example.com). Each subdomain is a different origin, and each has their own 5MB.

A service worker can see a request to another origin. You can cache the response, but you can't see it, and you can't generate it on the fly.

localStorage.setItem("data", JSON.stringify(d));

localStorage is easy, but you can't use it from the service worker. IndexDB is really painful to use.

If you want an easy-to-use wrapper for IndexDB, see localForage.

Web workers are available almost everywhere, but they're basically just like processes. They're attached to a tab.

Interesting: There's a new background sync API. It's in Chrome. Not in Opera. Not in Samsung Browser. Will be in Edge. Works even if the user doesn't come back to the tab.

navigator.onLine lets you know if you're offline. If it's false, you know you're offline. However, if it's true, you may be in an area where it's not working. You may be on a hotel network and unable to get outside of it.

Offline.js can help you with more advanced network detection.

Alternatively, you can just try to do a fetch and catch the exception.

This is how to make your website gray if you're offline:

window.addEventListener("offline", function() {
    document.documentElement.style.filter = "grayscale()";
}

You need a manifest and a service worker to get a web app install banner, and you need the user to access your site a second time (1 hr < 2nd visit < 30 days).

Push notifications

Web Push is a new API on top of Service Workers.

Remember, see the code snippets link above.

You need to generate a public key so that you can confirm with the server who you are. There's a code snippet to show you how to generate such a key.

Use pushSubscribeUser() to subscribe the user to pushes. It returns you an endpoint URL that you can use to push messages to the user.

In the service worker, you can register for push events. Imagine, the user isn't even using your site right now. However, your service worker can receive the event.

Within Chrome DevTools, in the Application tab, there's a Push link that you can use to simulate pushes.

It works even better on phones than on desktop. On desktop, if you close the browser, you can't receive messages. On Android, if the message is received, it'll wake up the browser--even if you just turned on your phone and never even started Chrome.

You can query all your client tabs in a service worker.

You can receive a notification in a service worker, updated IndexDB, and then use the client API to tell all the tabs that you have new data.

The notification can only be 1.5k. However, you can do a fetch in response to a notification.

Important: You cannot have silent notifications. You must notify the user:

self.registration.showNotification('Push title', { body: event.data.text() })

If you don't this, the user will get a generic notification.

Facebook and Twitter use this.

They're working on another API that, with the user's permission, you'll be able to update data in the background.

With Web APK, notifications will look like they're from your app, not necessarily from Chrome. It'll look "more native".

Lighthouse

Lighthouse is a Chrome extension that you can use to see how well you've built your app, including the PWA features of your app.

It's available as a Chrome extension or as a command line tool via npm.

iOS Home Screen Web Apps

Here's what's available on iOS:

  1. You can use a meta tag that lets users create an app launcher icon.
  2. You can use AppCache, which is an older, somewhat crappy API for offline apps.
  3. There's no way to do push notifications.
<meta name="app-mobile-webapp-capable" content="yes">
<link rel="apple-touch-icon" href="...">

This will add an "Add to Homescreen" icon somewhere in the menus. Then, you'll have an icon on the homescreen.

https://github.com/firtman/iWAM is an experiment he threw together to take the web manifest file and translate it into meta tags for Apple.

Here's an article he wrote: Don’t use iOS meta tags irresponsibly in your Progressive Web Apps

AppCache is available all over the place. It's terrible. However, it's the only thing you have on iOS.

In closing

  1. Instant loading
  2. Discoverable
  3. Network indepedent
  4. Responsive
  5. Installable
  6. Secure
  7. Linkable
  8. Re-engageable
  9. Works everywhere (???)
  10. Fast

He doesn't think there are good resources / references for Service Workers. This is probably the best he can offer: The Service Worker Cookbook.

The best practices haven't really shaken out yet. It's new. The API is changing. The best practices are changing.

We've only covered a small part of the service workers and web push APIs.