True Collaboration vs. Shoving Work

Caleb Lummer and Michael Snead

Cross platform node.js team collaboration (we're calling it Product Environment Shell)

Sharing back to Citrus

Sharing across Product teams

Sharing across frameworks

Static Analysis / CSS Modules

Caveats, Take Aways

Talking Points.

A Node.js local environment enabling UX Developers to work inside their respective Product team's stack on a Mac and not inside of a virtual machine. This new environment shell helps us iteratively build out prototypes and features collaboratively and quickly.

 

- Work on parts of the site in isolation using enough Product data to reproduce real world scenarios (i.e. : validation)

- Work across platforms without having to VM into .Net via Window (i.e. : work on your Mac in your IDE of choice)

- Work against an accurate representation of code inside the application

- Prevents repetitive refactoring of HTML into Product specific language (i.e. : Kendo / framework / library specific templates)

Product Environment Shell

Product Environment Shell, continued

and voilà (running locally on a Mac)

Markup from master page / layout

Other scripts that would be loaded

React / Angular 2 / Aurelia application

Doesn't need to change

The part we're working on

Shell

AJAX calls and static assets served by a lightweight node.js server

Product Environment Shell, continued.

Other styles that would be loaded

Product Environment Shell, continued.

MVP quick experiment recipe

- Node + Express + view engine

- "FakeLayout": looked at markup at runtime, copied the bits that don't change often      (top menu, <link> and <script> tags, etc.) - for Supreme these change rarely

- "CreateJob": copied the markup from razor with minor tweaks - even this wont  change much, since templates, etc. are driven by React

- Our React build process is cross platform (webpack + gulp + etc.)

- Node router returns "OK" / "true" so operations like "Save" can be tested / modified    in client

Alternative approaches?

- Could've tried mono (host with xsp? we're not quite ready for vnext)

- Could've used raw HTML (no AJAX, routing might not match, oddities with file:///)

- All the code for this lives isolated in its own "ux" folder
- Non-invasive, doesn't clutter with "debug" code

- This was a quick experiment (ie: <60 lines of code to get started.)

- UX/Citrus development already depends on Node, Gulp, etc.
- Most of the requirements + JS language already installed and familiar.

Product Environment Shell, continued

Our React Editor...

- When you type a snippet keyword or phrase it auto highlighted

- Can copy/paste snippet keywords/phrases

- If you delete part of a snippet keyword/phrase the whole thing deletes

- Can insert snippets using dropdown at cursor location

- Replaces snippets/keywords on server with real values

- All without any kind of special character the user needed to see or type with a styled box

(what we needed it to do and what Kendo couldn't deliver)

Sharing back to Citrus

- Define what is being contributed back (vanilla HTML / JS / CSS or platform specific complete features?)
- Is it platform specific? If so, it may be a better fit for one of the platform specific repositories.

- Create documentation for the component (Citrus 2 - Developers will have author access to provide all that’s needed.)

- Reach out to UI leadership and focus groups for sign off / to analyze from UX perspective

- Provide guidelines for usage

(How do we do it?)

Sharing Components

Our internal NPM

  1. npm init (follow prompts to setup your project)
  2. Set registry to the internal NPM
    npm set registry=http://qa-npm-01.paylocity.com
    "npm get registry" to confirm
  3. npm adduser (for your first time per machine)
    Username and Password are for NPM (not your NT)
    When it says public e-mail, it means on our NPM.
  4. npm publish

...and you can go to the URL above in your browser to see the internal module!

Thanks to Jose Basilio for setting this up!

Sharing Components

Platform-Specific Repositories

If your component is specific to a platform / framework / library, our current strategy is to foster an open source community and create a repository for specific to it.

Sharing Across Frameworks

Approach #1: Share styles, rewrite component

My App

ng
Component

Sharing Across Frameworks

Approach #2: Use an adapter

jQuery 29.8kb

React 43.2kb

ngReact 1.7kb

This is how Supreme was able to use the same Kendo components across Kendo MVVM, Angular 2 and React.

Use React inside anything...

Use Kendo inside React

Adapter

My App

React
Component

Sharing Across Frameworks

Approach #3: Framework agnostic code

ng
Adapter/ Template

My App

Component

Component logic is agnostic.

Decide whether templating is per framework or independent.

I can't write an adapter to include "any jQuery component", because there is no convention.

Citrus 02/16

JavaScript 122k LOC

CSS 113k LOC

HTML 51k LOC

Code Metrics (raw)

Citrus 06/16

JavaScript 125k LOC

CSS 166k LOC

HTML 70k LOC

Supreme / ATS

JavaScript 508k LOC
CSS 35k
HTML 5k~

Modular CSS

- Explicit dependencies

- Build-time errors

- Only what you need

The exciting concept of "CSS modules"

Widget V1

.widget-class-one

.widget-class-two


  import { widgetClassOne, widgetClassTwo } from '../styles/widgetstyles.css'
  import classnames from 'classnames';

  var template = `<div class="${classnames(widgetClassOne, widgetClassTwo)}">Hello</div>`;

My App

Modular CSS

Widget V2

.widget-class-one

.widget-class-three

My App

Modular CSS

.widget-class-two

How do you know which CSS class is missing?

Still need to check for visual anomalies.

.widget-size {
  width: 200px;
  height: 200px;
  font-size: 32px;
  display: flex;
}

.alert-box {
  background-color: grey;
}

.widget-font {
  font-size: 12px;
  display: flex;
}
._widgetSize_19zjc {
  width: 200px;
  height: 200px;
  font-size: 32px;
  display: -ms-flexbox;
  display: flex; }

._alertBox_19zjc {
  background-color: grey; }

You can keep the original class names if you want to and more complex selectors work, so long as a class name matches something imported (ie: across media queries).

Less to download, less to process, less to render.

Modular CSS

Other approaches to including 'only what you need'...

uncss

purify-css

- Analyze applied styles at runtime

- May not catch dynamic styling (ie: toggled classes)

- Requires the entire app to be running

Analyzes all code (rather than dependency tree) including JS and HTML

Modular CSS

 

- How might this affect QA testing?
- Legacy pages?
- Performance?

Caveats / Takeaways

Shared Modular UI Components

By Michael Snead

Shared Modular UI Components

  • 2,106