Skip to content

Instantly share code, notes, and snippets.

@just-boris
Last active April 27, 2019 10:41
Show Gist options
  • Save just-boris/2080a0595464c1554ea8b03005984f09 to your computer and use it in GitHub Desktop.
Save just-boris/2080a0595464c1554ea8b03005984f09 to your computer and use it in GitHub Desktop.

React Everywhere — Rick Hanlon

Building a Community Around Ignite — Jamon Holmgren

Toolchain for building modular React Native plugins — Ville Immonen

No notes :(

Custom CSS is the path to inconsistent UI — Artem Sapegin

There are many ways to do the same thing in CSS. When different developers try to build the same thing independently, they might get a slightly different result.

The way to unify styles is to create a design system, that will specify colors, font sizes. These elements are called design tokens. Using limited number of design tokes enforces consistency.

Tokens should also make sense, for example when defining colors, you should define text and background colors together, in order to maintain contrast ratio and keep the text readable.

The number of tokens should be minimal to reduce number of unwanted deviation.

On the higher level we have components. But they should be configurable

Configuration via boolean flags:

<Text primary />
<Text secondary />
<Text primary secondary /> // an impossible state!

Rigidity and complexity:

<Text variant="primary" />

Configuring an underlying html tag

<Text /> // renders <p/>
<Text inline/> // <span />

<Text as="label" /> // allows to specify any tag
<Heading level={2} />

With these tokens it is still hard to achieve consistency.

Spacing

  • Linear progression
  • Geometric progression - preferable, since it reduces number of choices to very different

Naming

  • x-small small medium large - full names
  • sa s m l xl - short names
  • 1 2 3 4 5 - numbers

Definition

  • pixes
  • rem
<Box space="m"></Box>
<Flexbox />
<Grid gridGap="m" layout="..." />

Implementation

Why primitive tokens as components

  • Consistency
  • Discoverable API
  • Faster development
  • Code reuse
  • Code reviews
  • Documentation
  • Accessibility
  • Common language with designers

With a good design system you should be able to create a good design even on a napkin.

Creating layouts that last — Artem Zakharchenko

How to build a maintainable interface

  • How fast can I understand?
  • How easy to make a change
  • How can I predict future iterations?

Spacing is important to build maintainable layout. Even on a small piece of interface there can be various spacings.

Spacing declaration

  • padding/margin directly
  • via abstractions
  • css grid – allows to describe a complex layout in a single place (grid template areas)

Atomic layout

CSS-grid + react components

import { Composition } from "atomic-layout";

function Header() {
  return (
    <Composition areas="logo menu actions">
      {(Logo, Menu, Actions) => (
        <div>
          <Logo />
          <Menu />
          <Actions />
        </div>
      )}
    </Composition>
  );
}

Responsive components

<Box padding={10} paddingSm={20} />

<Only from="sm" to="lg" />
<Only except for="md"  />

Same for composition

<Composition
  areas={`
    logo
    menu
  `}
  areasMd={`
    logo menu
    search search
  `}
/>

This approach allows you to compose complex layouts from simple and explicit levels that are easy to maintain and join together.

Composition exposes you an API very close to the actuall CSS-grid properties. It should help you to learn the approach, not just a tool.

Composition component will own spacing, and then you will be using other components to define visuals:

<Card>
  <Composition areas={areas}>
    <Thumbnail>
      <Image />
    </Thumbnail>
    <Header>
      <h1>{title}</h1>
    </Header>
    <Actions>
      <Button />
    </Actions>
  </Composition>
</Card>

We can also use advanced properties from css-grid, like auto-fit or minmax to have nice responsive layouts.

Using extra props like paddingMd or gridGapLg we can add overrides for a certain viewport size.

https://github.com/kettanaito/atomic-layout

Scalable (Design) Systems with TypeScript — Tejas Kumar

Typescript adoption is growing in JS community accroding to the State of JS survey.

Why typescript?

  • It enforces contracts in your code
  • Confidence when making changes
  • Helps your code to scale fast. You can easily add things

We define an interface and make all our code to follow that. When we need to make a change, we update the interface and Typescript shows us places that need to be updated upon the interface change.

Design system is similar to Typescript. It also give you a contract. A contract for UI components, if you have a Button, you know that this is a button and works as you expect. With design system you can build UI with confidence.

There are many design system building tools, like react-styleguidist. What if we will give them a power of Typescript?

Monaco editor – the core part of VSCode. We can bring it into Styleguidist and make code examples editable with autocomplete based on our types information.

How is this built? We use transpile to convert TS to JS and then evaluate it inside of the error boundary:

import { transpile } from "typescript";

<ErrorBoundary>{transpile(eval(example))}</ErrorBoundary>;

Monaco editor component. It does not have ready-to-use react component so we will build one:

  • receive a ref and render the editor inside
  • receive changes and adjust the editor size
  • handle triggerSuggest event, rendering the suggest UI

Monaco has an abstraction to work with file system, where we can provide a custom adapter to have auto-complete for import paths in the browser.

Monaco is an awesome library, very easy to get started, they have good getting started guide in their docs: https://github.com/Microsoft/monaco-editor/blob/master/docs/integrate-esm.md

We can create virtual modules for auto-completion via

monaco.editor.createModel(
  `module content`,
  "typescript",
  "file:///node_modules/my-lib/index.d.ts"
);
  1. Static types analysis is valuable
  2. Working with Monaco editor is facinating
  3. Hacks lead to new ideas

Codecrumbs in React — Bohdan Liashenko

How can we get started with a big legacy code base very quickly?

StackOverflow survey says that average time to be efficient with a code base is ~6 months

React? Does not really help. You still have many components that do not have clear relationship. Where is this component actually used?

Usage: codecrumbs -d project-src-dir and you will get visualization for the code in project-src-dir.

We can add special comments to our code to annotate certain product features to simplify navigation. We can see user flows and how they are represented in different parts of the source.

Codecrumbs can also build multi-project charts.

We can add extra information to our chart that should help contributors to get started with the codebase.

Live demo: https://codecrumbs.io/#showcase=todo-react-redux

React Union: Write once, plug anywhere — Tomáš Konrády

Headless CMS – new generation of CMS:

Content edit APP –> CMS API -> client app

Example: Gatsby + Wordpress

User -> publishes content to -> WP -> triggers a build -> Gatsby -> deploy -> static side

This approach is also called JAM Stack – JavaScript, APIs, and Markup

Cons of this approach

  • Not possible to use huge ecosystem of WP plugins
  • Content editing is limited (can't change layout or colors in CMS)
  • No live preview, because it requires a build
  • Not applicable to legacy CMS

Pros: We own the frontend and can use all modern techs and approaches (React!)

For people who are not able to use JAM stack due to some special requirements, we offer a solution. We can build react widgets and then embed them into a classic CMS.

React union: https://github.com/lundegaard/react-union

<main>
  <p>Static content produced by your favorite CMS.</p>

  <div id="hero-container"></div>

  <p>More static content produced by your favorite CMS.</p>

  <!-- A widget descriptor – configuration of your React widget.  -->
  <script
    data-union-widget="hero"
    data-union-container="hero-container"
    type="application/json"
  ></script>
</main>

We provide a script with configuration via data-attributes that will be picked up by React-union runtime. Initializing the root union component:

import React from "react";
import { Union } from "react-union";

import { route } from "./Hero";

// `Union` renders found widgets into their containers
// but retains a single virtual DOM. Yes, it uses React portals :)

const Root = () => <Union routes={[route]} />;

export default Root;

All your widgets will have a shared react context where you can store theming, localization and other config.

We have adapter for popular CMSes so our widgets can be added to pages using standard CMS mechanisms, for example drag-n-drop or Gutenberg widgets in new WordPress.

React-Union widgets use the same Redux store. If we want, we can scope our data using namespace that is injected into our widget. React-union gives you helpers to register reducers into the global store.

Releasing a library written in TypeScript on NPM — Christoffer Niska

Tooling

Rollup config

  • We import both formats: commonjs and esm
  • Do not forget to configure externals
  • Terser plugin for minification

Typescript config

  • "declaration": true to emit d.ts files for consumers
  • "module": "esnext" to delegate import/export resolution to Rollup or other bundler
  • "moduleResolution": "node" – the other options are legacy in TS

Package.json

  • main – for node.js
  • module – for tools that understand es-modules (Webpack and other bundlers)
  • jsnext:main – same as above but for some older tools
  • types – for typescript
  • files – whitelist of files to publish

We publish files processed via rollup. Rollup is more recommended for libraries, since it does not produce extra runtime, just builds modules together.

Practical Performance for React (Native) — Anna Doubková

Issues that identify performance problems

  • Slow loading time
  • Slow interactions

React native basics

  • UI Thread
  • RN Bridge
  • JS Thread

React Native developer menu has "Performance monitor" feature. Using this monitor we have found that our bottleneck was in the JS thread. We looked into flamechart provided by RN Dev tools (custom version of Chrome dev tools). We have found unnecessary full-renders that took ~5s of JS execution.

Rendering in React

  • Change -> call render functions -> build new vdom tree -> reconciliation -> rendering

Possible optimization: shouldComponentUpdate. Leads to possible bugs, because it is out of sync with the state of the render method.

Optimize reconciliation: react detects changes by shallow properties compare. We can optimize it by not producing new objects if content does not change.

Sources of new instances when nothing changes:

  • Inline arrow functions
  • Redux. When store changes, all connected components will change. mapDispatchToProps produces you new instances. Use only static object form to avoid extra updates
  • Redux selectors. Use special helpers to memoize data
  • Props-dependent state. running an extra re-render from componentDidUpdate is an anti-pattern. You can move stuff to the parent component, redux store or getDerivedStateFromProps
  • Prefer local state over the Redux. Changing it will produce a smaller re-render
  • Avoid dispatching multiple actions. Unify actions to get it done with only one
  • You can try using MobX that has smarter updating logic

React native specific optimization

  • React native built-in animation engine
  • Inline requires. Avoid loading all modules at start, place require call into components to make them called when component is rendered
<Image src={require('./heavy-pic.jpg')}>
  • Use low-level profiler
  • React router native – wastes re-renders. We stopped using it
  • React navigation – the recommended library

WebAssembly - The Next Big Platform — Sven Sauleau

Loading time is important and using framework like React has a cost there.

In the modern era Javascript is also a very popular compilation target for other languages. Compiling from one language to another very high-level lang is not a good idea. We need a more low-level API. This should be solved by WebAssembly.

Will WASM kill Javascript?

No. JS already plays important role in front-end. WASM is mostly built to make languages more suitable to be run in browsers.

Should we all use WASM?

WASM does not support any arbitrary JS object. Work with DOM still should be done in JS.

Rust in WebAssembly

Rust supports WebAssembly as a first-class compilation target. They also provide bindings to Javascript to call Rust code from Javascript and Javascript code from Rust

It is very easy: shows a demo

Webpack has support for WASM. You can just import .wasm files into your javascript and call functions from there

Building resilient frontend architecture — Monica Lent

Reasons to rewrite existing code:

  • Inexperience with the current implementation
  • It is fun
  • Better solution available
  • Technical debt

The definition of tech debt is very vague

  • Code I did not write
  • Code before I knew what I was doing
  • Old libraries
  • Features that no one uses
  • Code that negatively and repeatedly affects your development efficiency

Recurring technical debt

IMG_9907

Second system effecthttps://en.wikipedia.org/wiki/Second-system_effect

The real cost of a software is not an initial development, but the cost of maintaining it over the time.

How to write a system that does not require a rewrite

  • "Good architecture"
  • Architecture as enabling constraints
    • Example in real life: autobahn – no speed limit, but side-barriers

Paradigms are also enabled constraints

  • OOP – classes – for independently deployable components
  • Functional – immutable data – to eliminate race conditions
  • var->const – no re-assign – predictable data
  • jQuery->React – no direct access to DOM – predictable UI and testing
  • CSS->CSS-in-JS – not using explicit class names – no conflicts

Another good set of constraints

Constraint: code dependencies must point inward

Module approaches

  • big ball of mud (chaotic dependencies)
  • layered dependencies
  • modular (huge blocks with very few connections)

Enables: predictable impart of changing a thing, avoidable cross-team conflicts In frontend it means that a single page should work independently, like other pages do not exist. Shared components should go into design system layer or you can copy-paste them otherwise (DRY is overrated).

Constraint: be conservative about code reuse

Code-reuse sometimes leads to brittle and over-engineered code. It also impacts the time to develop, because new requirements affect shared components if they were not truly reusable. When you have half-full and half-empty glasses, sometimes you just really need to glasses.

https://twitter.com/rakyll/status/1088586877072887809

Enables: lower coupling of the code, faster changes

Constraint: enforce your boundaries.

Not every similarly looking code should be merged for reuse. There is a forbidden dependencies tests. They check the structure of the modules and check for unwanted dependencies to ensure clean architecture.

https://github.com/sverweij/dependency-cruiser

Enables: preserves architecture over time

Every time you create a function or add a feature, they all are architecture decisions that affect maintainability of your code. Make these decisions wisely and consider constraints above.

"Intuitive" Tooling — Carolyn Stransky

There are many technologies that people are struggling with.

Typescript – typed superset of Javascript. Or maybe not?

  • has many new constructs
  • has a special compiler
  • new set of challenges
  • number of new file types – ts, tsx, d.ts

Redux – confusing at the first look

  • Can be learned via Elm architecture documentation – not a simple way
  • Many new words to learn
  • Middlewares that are very different from each other

GraphQL – "I use it, but I do not get it"

Gatsby

  • Has too much prerequisites to know
    • react
    • graphql
    • frontend tooling

Flexbox

the list can continue...

There is a common pattern to explain everything as "simple". We mistake familiarity for simplicity. After some time spent with a technology you are loosing tracking what is technology specific and what is a general knowledge.

https://www.youtube.com/watch?v=1vvjiJFsT-Y&t=2367s

Spiral of silence – people have a fear of isolation. People are afraid of saying unpopular opinion in a fear of being excluded from a community.

https://wir-sprechen-online.com/2011/11/25/spiral-of-silence/

Increased Empathy. It is especially important in education.

  • Take ownership of communities, make people feel comfortable to express an opinion

  • Make learning exciting, but showing on your example that mistakes are natural part of learning

  • Start an internal mentorship program. It should be someone out of your organization to avoid bias (definitely not your manager)

  • Try out empathy driven teaching

  • Relate your own experiences. "I have felt the same way, when ..."

  • Ban words like "easy" from your vocabulary, be more specific

  • Be absolute. Show, don't tell

  • Deconstruct our biases. Do not assume previous knowledge

  • Keep a learning journal. This will help you to recap

  • If you understand something it does not mean that everyone does

  • People learn at different speed

  • Brains are weird

  • Everyone is a beginner at some point

  • It is ok if the things are hard

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment