Weeknotes #4

Monday

Hmm… guess I missed last week. Stress sunk it’s claws into me.

Sore back. I’m feeling so old. Did some babysitting. Grateful for a big blessing on our family.

Cleaned up inboxes and task lists.

Tuesday

Business development and networking.

Created a “hire-me” page which required further integration of the CMS on systematicui.com as well as creating a twitter card.

Wednesday

Can’t stop reading about inv.tech. What a fascinating company, so completely transparent.

Completely trapped by over a foot of snow. Winter is still here.

Thursday

So, I built an interesting script for generating a Nuxt website from a static HTML file. It’s not that hard but it is interesting. Nuxt will lose any static payload data once it’s done with hydration, assuming that you will make an API call after hydration. That’s a bit of a pain, so you have to write your dynamic generation-time data into a JSON file and then embed it in your output JS with webpack require() assignment.

Friday

🌞🌤❄️🌬☔️cool emoji weather library parses text and picks an emoji.

Started watching https://www.invisionapp.com/design-system-manager/expert-advice/heartache-design-scale

I ordered contacts with an app. Pretty neat experience, but it’s still amazing how often multi-step forms lose state or experience similar bugs.

https://blog.prototypr.io/what-do-you-need-to-know-before-starting-a-design-system-448158acc084

https://medium.com/invisible-reports/why-report-in-public-d4b94306a52f

Weeknotes #3

Over the Weekend I spent quite a bit of time on a side project that could turn into a really interesting service. It’s a tool that’s useful for deploying and testing CSS design systems. Puppeteer + Docker + Node + Typescript + Mongo Stitch. Super exciting.

Monday

Played with my boys in the morning, enjoyed the sun and watched a small avalanche on the mountain nearby.

I’ve been writing docs, and came up with 12 Factors for Enterprise-Level Front-End Code Quality

  1. Linting
  2. TypeScript
  3. Unit Testing
  4. E2E or Integration Testing
  5. Git, PRs and Code reviews
  6. Continuous Integration
  7. Multiple Environments
  8. Dependency Mgmt. & Security Auditing
  9. Visual Regression Testing
  10. Error Monitoring
  11. Performance Monitoring
  12. Documentation

Tuesday

Hey someone started on a new version of Fractal! It even has a Vue demo. 😍

I built a new project boilerplate for design system projects using Parcel for compilation, XO for Linting, even somehow managed to get TypeScript Support working.

Wednesday

Created a project generator script for design systems with different boilerplate options for folder structure and CSS preprocessors. https://github.com/sirtimbly/systematic-ui-scripts

Rebuilt a Nuxt 1.4 site in Nuxt 2.4. Figured out how to get ESLint working with that setup, and typescript again. What a pain. I never realized how easy TSLint was.

Thursday

Posted a new project on my portfolio. Designing a Perfect-fit Soluton for a Niche Industry

Friday

Re-discovered Astrum for design systems. Light weight design systems running on JS in the browser. No build step or dev server. Interesting.

Order some Darn Tough Socks they last a long time and when they do wear out you can get free replacements from the company.

Weeknotes #2

Monday

Fixed design bugs on timbly.com, more responsive, using tachyons.

Had to figure out how to tell if a slot is empty on a Vue component (TS class).

1
2
3
public get hasDefaultSlot() {
return !!this.$slots.default;
}

It’s 2019 and CSS is awesome. But, we still can’t prevent orphan words when wrapping lines of text.

Have you tried Sublime Merge? I opened it again today – I like it, but I think I still prefer fork.

Tuesday

I’m using the AWS Amplify SDK, and it’s pretty decent. Fully featured authentication implementation. Their docs are nice, and they ship Vue and Reat UI components.

Wednesday

A super usefuly way to get basic SVG icons quickly

Thursday

Doing a lot of Git rebase from multiple developers.

Trying to get fontawesome-vue to actually do treeshaking… with limited success.

Friday

An article about running puppeteer automatically

A good startting place for automated chrome screenshots

Lot’s of time automating visual regressing tests.

icon

Weeknotes #1

Saw this “Weeknotes” idea on some other blogs and decided it’s a good idea. For a while I was trying to write an article every week on dev.to – but I missed week 6 and now it’s hard to get back on the habit. Maybe if I’m adding some value to my personal blog again I can be a little more motivated to write.

Monday

Watched too much twitch. Apex Legends looks so awesome.

Set up perforance monitoring of an app through Calibre - It’s really excellent.

Looked at the latest version of UI Engine to see if it’s a good basis for my next design system. It can display plain HTML or handlebars templates like Fractal, but it also supports displaying Vue and React components, so that’s a pretty good option. Latest version has some great improvements in configuration also.

Tuesday

Found uptime robot. Good free plan. Found an interesting blog from Remy Sharp about rebuilding the very first web browser at CERN on the 30th anniversary of the web.

Wednesday

Lot’s of code reviews today. Hunting down the domain registrar for a client to see why their old website hosting dissappeared. Mystery. If it weren’t for the wayback machine we would lose a lot more websites due to neglect.

Thursday

Spent a lot of time building a initial prototype serverless+FRETS app on Zeit Now. Amazing stack. Will have to write more. It is totally possible to deploy serverless functions written in TypeScript without pre-compiling.

Friday

Discussed CSS and HTML with my mentee. Lots of basic rules like when to use position. The concepts of selector specificity, and background images. Saw a really weird thing happen when viewing a flex element on Chrome mobile viewport emulator. The whole flex item shrunk down to fit in the available flexbox space… interesting. Setting a pixel value on the flex item seemed to solve it.

Saw this article about UX and login forms from Brad Frost. Don’t Get Clever with Login Forms.

Routing and Easy Form Fields on FRETS 0.3

Made a few changes to my little web frontend library, FRETS. First of all I updated the online API documentation to clean up old pieces of code and document more funcitons in the main module.

First, one big bug was fixed. We were getting double rendering of the same state change because I wasn’t checking the cache properly. The new cache checking code should prevent double renders and still allow rendering to happen when an async function (like a fetch) calls FRETS.render(newProps).

Here’s an example of the right way to call async functions from an event listener (action).

1
2
3
4
5
6
7
8
9
10
11
F.actions.loadUser = F.registerAction((e: Event, props: AppProps) => {
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => response.json())
.then(json => {
const user = json[(Math.random() * 10).toFixed()];
console.log("recieved fetch");
props.username = user.username,
F.render(props);
});
return props;
})

Fields Registry

On previous apps, for every single field that a user could change I would have to do several steps.

  • Add a property to the main modelProps class
  • Add an empty action function signature to the main actions class.
  • Add a concrete implementation of the action event handler. Usually some variation of this code
1
props.someProperty = (e.currentTarget as HTMLInputElement).value

Writing the same boilerplate is repetitive. I thought about how we as developers want to add functionality to our apps in flexible and composable way. That’s what components in Vue and React are all about. With those libraries you are building an object to fit some sort of component structure so that you can register properties inside of child components that all get rolled up into the master component. But, I want to keep FRETS free of configuration objects and string key conventions that need to be memorized.

So, I added registration methods on FRETS so that you can call a registerField() method from inside of your UI rendering methods. The entire frets App object is expected to be injected into your render methods now. That way you can still extract model props and actions from the app instance for rendering the UI, and now you can add fields to the main registry — and FRETS takes care of the repetetive event handler creation.

1
2
3
4
5
const countField = app.registerField<string>("count", "1");
return $.input.m1.h({
onblur: countField.handler,
value: countField.value,
}),

When you call registerField you get back an object with the handler and the current value, and any validation errors that have been attached to it during the validation step.

This makes it much quicker to add form inputs that are tied into your app state without having to know and declare every single model property up front. Now you can inject functionality to your app from within the render methods themselves increasing decoupling of the main app code and enabling functionality and features to be declared from within js chunks that are loaded asynchronously only when they are needed.

Routing

When I build single page apps I often end up needing to do some sort of routing to different screens based on the URL. I took it on as a challenge to enable this feature in a functional way, not using complicated configuration objects like Vue-router does. So, when you want to register a route in FRETS - what you are really doing is registering a string for matching the current URL value, and a function that will update your app state in some way when the current url matches your decalared pattern. It can be as simple as switching a value from “screen: 0” to “screen: 1”.

1
2
3
4
F.registerRoute(RouteKeys.About, "/about", (name, params, props) => {
props.activeScreen = SampleScreens.About;
return props;
});

Then when it comes time to navigate to a screen programmatically you will call a method on the app instance from within your event handler action.

1
2
3
4
5
6
F.actions.navAbout = F.registerAction((e: Event, props: AppProps): AppProps => {
F.navToRoute(RouteKeys.About);
props.activeScreen = SampleScreens.About;
return props;
});

Performance

The overall library size is a bit larger (15.3kb minified and Gzipped instead of 10.6kb) because I added a second dependency: the path matching library “path-parser”. In addition, the necessary features from Maquette are still included in compiled library.

I still recommend writing your UI rendering methods using atomic CSS library like BassCSS or Tachyons compiled to JS functions using frets-styles-generator. This will make writing UI code much more pleasant but adds a few more KB of javascript to your final bundle.

The updated example app frets-starter builds a final javascript bundle of 36KB minified and gzip. Which I think is very respectable. View that demo app.

Other Changes

I increased unit test coverage to around 75% now.

To support the field registry your actions and props classes should now inherit PropsWithFields and ActionsWithFields

1
2
3
class MyProps extends PropsWithFields {}
class MyActions extends ActionsWithFields {}

As mentioned before, the new UiRendering method that’s passed into FRETS.registerView() should accept the entire frets object, it’s signature should be:

1
renderFn: (app: FRETS<MyProps, MyActions>) => VNode
icon

FRETS 0.2.7 Supports Async Rendering for Performance

I added an important new feature to my TypeScript SAM framework, FRETS - support for async render functions. Just call F.registerViewAsync() instead of F.registerView() (which is still available).

If you use Webpack you may know about the power of code splitting and lazy loading. It can be useful because you don’t have to include all of your rendering code for pieces of the app that the user will never see becaus they haven’t clicked on it. At the most basic you could simply set it so that the render function for each “screen” or page in your SPA is inside of a module that get’s lazy loaded through an async function.

1
2
3
4
if (props.currentScreen === Screens.Customize) {
const RenderCustomizeScreen = await import("./Customize");
return RenderCustomizeScreen(props, actions);
}

All the code inside the Customize module will be in a chunk file that hasn’t been downloaded yet. If the first time your app renders it doesn’t hit that code branch then it won’t be downloaded by webpack. Webpack will take care of loading the customize screen, it’s child includes, and any of it’s custom style classes and CSS, only when that branch of render logic gets executed. Since Typescript now supports async and await we can use this syntax now as long as we make all the functions up the call stack async also (or handle them as promises). Behind the scenes Webpack issues a fetch request to the server for it’s necessary chunk.js file… and FRETS will re-render the app once that async fetch promise resolves.

This means it might be a good idea to start splitting your atomic css into different css files that only get loaded inside certain modules. Don’t forget about the power of combining FRETS with atomic css and generated typescript classes.

This idea was inspired by this article about architecting large javascript applications - and me staring at the results of webpack-bundle-analyze wondering how to make things smaller now that everything is in javascript.

Also, since my last update I ce this sweet logo:

icon

FRETS 0.2.3 - Now With More FP

I wanted to make it easier to get started with a new FRETS app, so I refactored it into one class with a more functional approach to registering the various parts of the app.

What’s new in version 0.2.3?

Primarily, a new way of instantiating applications that is more functional and less dependent on big ugly configuration objects. The idea is to still use the goodness of TypeScript generics while making it more functional and obvious how to set up a new app.

1
import { FRETS } from "frets";

The older class exports are still available, but now all you need to get started is this one FRETS class.

You kick things off by writing a very lightweight actions class for your app.

1
2
3
4
5
6
export class MyActions {
public changeName: (e: Event) => void;
public saveName: (e: Event) => void;
public startOver: (e: Event) => void;
}

Notice there are no actual implementations in this class! We can still get the help of referencing at action by name in our view, but the function will be assigned at runtime. When you write your view rendering function it still looks pretty much the same.

So, here’s how the minimum initialization procedure actually looks.

1
2
3
4
const F = new FRETS<QuizProps, WheelActions>(new QuizProps(), new WheelActions());
F.mountTo("mainapp");

There are default methods for everything, but you will want to set a real render function using registerView().
We still use the generated atomic BaseStyles class to build dom VNodes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const renderRootView = (props: QuizProps, actions: WheelActions): VNode => {
return $$().div.border.p3.m3.h([
$$().label.pr1.h(["Your Name"]),
$$().input.h({
type: "text",
onchange: actions.changeName,
value: props.name
}),
$$().div.p2.h([
$$().button.btn.btnPrimary.h({ onclick: actions.saveName },["Save"]),
]),
]);
}
F.registerView(renderRootView);
F.mountTo("mainapp");

And of course theres no actual implementation for the actions so you will want to set those using the handy dandy registerAction() method.

1
2
3
4
F.actions.changeName = F.registerAction((e: Event, data: QuizProps) => {
data.name = (e.target as HTMLInputElement).value;
return data;
});

And that means we just need to validate our data changes and calculate any other related state variables that need to change. We should override the built in validator and calculator because they are empty passthroughs out of the box.

1
2
3
4
5
6
7
8
9
10
11
F.validator = (newProps: QuizProps, oldProps: QuizProps): QuizProps => {
if (!newProps.name) {
newProps.errors.name = true;
}
return newProps;
};
F.calculator = (newProps: QuizProps, oldProps: QuizProps): QuizProps => {
newProps.answers.reduce((acc, x) => x * 10 + acc);
return newProps
};

I’m reading the excellent book Functional-Light JavaScript: Pragmatic, Balanced FP in JavaScript. As I make it further into this book I expect I will revisit FRETS and make more updates. We shall see. I wonder if I’m willing to give up some of the TypeScript features for a more pure FP approach.

Shortest Drone Flight Yet

Finally had a day with some nice weather. Went to the park to fly my drone with the go-pro attached. Can’t do anything really crazy right now because of one bad motor that freaks out when I give it too much juice. Anyway, that didn’t matter - ninja branch took me out and covered my electronics in snow.