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
...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