Skip to content

Instantly share code, notes, and snippets.

@TylerK
Last active March 6, 2019 21:03
Show Gist options
  • Save TylerK/f5fbf4178348b32029cc6901e1241943 to your computer and use it in GitHub Desktop.
Save TylerK/f5fbf4178348b32029cc6901e1241943 to your computer and use it in GitHub Desktop.
Fleet App Next™

Fleet App Next™

Table of Contents

Goals

Short term

  • Rename the current working branch to fleet-app-next and start accepting PR's there.
  • Discuss current work and remaining items with whomever wants to help.
  • Test and launch this work ASAP

Medium term

  • Get the modules PR up and running
  • Start converting all existing UI to the new modules format
  • Build out Trips 2.0 and other new UI features

Long term

  • Move towards a GraphQL architecture

Dependencies

It's been almost two years since we settled on a lot of our versions and dependencies. It's time to update these to take advantage of some of the new cool toys out there.

  • TypeScript: Bump to 3.x
    • Too many great features to list here. See: 1, 2, 3, 4
  • React: Bump to 16.8
    • Hooks
    • Improved context API
    • Async rendering performance
  • Yarn: Bump to 1.14.x
    • Better monorepo support
    • Faster, better, stronger
    • Tons of bug fixes since 1.10 (our current version)

There are likely a few other libraries we would like to upgrade, I just haven't done a thourough deep dive in our package.json yet.

back to top 🔺

Modules

Overview

Kevin has done some great work around getting us setup to move to a far more modular UI for our front end applications. Follow along here: https://github.com/nauto/web-apps/pull/924

Reasons for doing this work

  • Decouple and blackbox as much of the UI as possible for maximum re-usability and testabilty
  • ui-kit has grown out of control, and requires testing and publishing everything anytime we need to make minor changes to anything
  • Semvar will make sense again if applied to small, isolated functions
    • Like seriously, what does 2.12.5 even mean in terms of a massive collection of disparate components?
  • Allow us to use Lerna to it's full potential
  • Greatly speeds up change time for small fixes
  • Spin up new projects with greater ease
  • As long as the module outputs React and or es-modules, we have greater flexibility to expiriment with new methods, ie: React Hooks.

What does a module look like?

modules
  └─ widget
    ├─ lib
      ├─ index.d.ts
      └─ index.js
    ├─ src
      ├─ locales                    // All necessary strings
        ├─ en-US
          └─ translation.json
        ├─ ja-JP
          └─ translation.json
      ├─ index.tsx                  // Entry point file
      ├─ index.mdx                  // docz file for UI components
      └─ index.test.tsx             // Entry point unit tests
    ├─ .babelrc
    ├─ i18next.config.js
    ├─ jest.config.js
    ├─ tsconfig.json
    ├─ tslint.json
    ├─ rollup.config.js
    ├─ README.md
    └─ package.json

That is a lot of boilerplate, for sure. However this allows us to build and publish discrete pieces of well tested and documented UI.

Sunsetting UIKit as a repository for UI components

Soon we will be breaking ui-kit down into major modules and seperating them out into individually versioned, namespaced NPM modules.

Before

import Widget from '@nauto/uikit/dist/components/widget';

After

import { Widget } from '@nauto/widget';

Docz

We will start replacing all Storybook files with Docz files. I have a branch where I've done a ton of this work already so we've got a nice headstart here. I believe Docz offers much nicer features, and a better end user experience for developing UI. .mdx files are infinitely nicer to work with than .story.js files.

Check out: https://www.docz.site/

New UIKit project

A new UIKit project will become the public face for our UI. This new project will scan the modules folder for mdx files and correlate them into a single style guide. Since docz allows developers to create themes for displaying their UI, it shouldn't take very long to build a Nauto branded styleguide.

I would love to see this project deployed to https://ui.nauto.systems.

Modular i18n

Problem

All issues with POEditor and our current process aside, we are loading about 36kb (gzipped) of JSON into the browser all at once for each language on inital page load.

Solution

As we move to a more modular arcitecture it stands to reason we should also lazyload translations with each module. This will help to greatly speed up initial page loads.

back to top 🔺

Moving Away From Decorators

I believe we should start making use of components that expose render props, in lieu of relying on our current HoC solution. This will make our code more declarative and allow us to make use of stateless components in future work.

Before

import withFeatureFlags from '@nauto/feature-flags';
import Widget from '@nauto/widget';

@withFeatureFlags
class Foo extends React.Component {
  render() {
    const { flags } = this.props;
    return flags.showWidget ? <Widget /> : null;
  }
}

After

import Feature from '@nauto/feature-flags';
import Widget from '@nauto/widget';

class Foo extends React.Component {
  render() {
    return <Feature flags={flag => flag.showWidget && <Widget />} />;
  }
}

But why not function as a child?

This write up is pretty succinct

back to top 🔺

A Nicer API Interface

Current

import { config } from '@nauto/config-file';
import { path } from '@nauto/utils/path';
import { getFleetId } from '@nauto/utils/fleets';
import { fetchRequest } from '@nauto/utils/request';

const url = path(`${config.api_url}/fleets/${getFleetId()}/events/${endpoint}`, params);

return fetchRequest(url)
  .then(...)
  .catch(...)

Problems:

  • config.api_url is a constant that is imported and repeated in every redux file
  • getFleetId() is also a constant that gets imported and repeated in every redux file
  • Requires a lot of imports from disparate util files to build up a URL string and make a request
  • None of this is typed, even a little bit

Proposal #1

import { match, request } from '@nauto/api';

/**
 * the url function could accept an object
 * to return a fully formed URL:
 * https://api.nauto.systems/v2.2/fleets/f-n2-internal/events/drivers?foo=bar
 */
const url = match({
  path: `fleets/:fleetId/events/${endPoint}`,
  params: {
    foo: 'bar',
  }
});

/**
 * Or a string to return a fully formed URL:
 * returns: "https://api.nauto.systems/v2.2/fleets/f-n2-internal/events"
 */
const url = match('/fleets/:fleetId/events');

return request(url)
  .then(...)
  .catch(...)

"request" would default to get, in order to facilitate other operations we would add methods to the request class, and additionally take an optional data object.

request.post(url, data);
request.put(url, data);
request.delete(url, data);

Proposal #2

Utilizing a fully typed and documented API class.

import { api, request } from '@nauto/api';

// ...

return request(api.fleet.events.drivers)
  .then(...)
  .catch(...)

This would have the benefit of fully abstracting away URL building from the calling function, as well as enabling intellisense.

@TylerK
Copy link
Author

TylerK commented Mar 1, 2019

I'm down for a zIndex enum!

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