Frontity Design Principles

This is just an outline of the design principles we use for Frontity yet, but is meant to become a document with a full explanation of the design principles we use to guide the framework development. These principles contain a collection of vision, goals and coding guidelines.


Primary characteristics

  • Zero config
  • Simple APIs
  • But Hackable
  • Unconstrained
  • Extensible by default
  • TypeScript first
  • Modern browser first

Frontity framework

  • Zero-config, opinionated stack

    • Webpack/Babel
    • TypeScript
    • State manager
    • CSS-in-JS
    • Code splitting
    • Head manipulation
    • React SSR and hydration
    • Node Server
    • Service Workers (not available yet)

    Because of:

    • Performance.
    • Extensibility.
    • Code scalibity. Promoting proven design patterns:
      • Flux.
      • Debug.
      • Single source of truth.
      • Normalization.
      • Separtion of concerns.
  • Package bundler

    • Feature agnostic. All features are relegated to packages
    • Everything is a package
    • The final app is the merge of all the packages
    • All packages are equal
  • Ultra Extensible

    • Goal: As extensible as WordPress PHP themes, if not more
    • Extensible by default
    • Extensibility patterns
      • frontity.settings.js state overwrite
      • State/Actions/Libraries access
      • State/Action/Libraries mutation
      • DOM access
      • Namespaces
      • Slot and Fill
      • Priorities
    • Upcoming
      • Server middleware
      • Hooks/Filters
      • React components?
      • Child packages?
    • Always keep in mind code cannot be changed by developer
    • Take into account the site builders
  • Unconstrained

    • Surface API: simple (or even unexistent)
      • Use state for configuration
    • Low-level API: hackable, unconstrained
      • Use code for configuration
    • If surface API is not clear, built the low-level first
    • Avoid making asumptions on usage
    • Start without constrains, add them slowly over time
      • Phase 0: No constrains
      • Phase 1: Documentation / TypeScript constrains
      • Phase 2: Code constrains
  • Backward compatibility

    • Avoid breaking changes when possible
    • But deprecate old/improved APIs following SemVer
    • TypeScript: is an exception.
    • Interface the main APIs through Frontity even if they come from other packages.

State Manager (Frontity Connect)

  • Transparent reactive implementation of Flux
  • TypeScript first
  • As close as possible to plain JavaScript
    • Define plain JS objects
    • Avoid immutability
    • Consumers don’t need to differentiate between real and derived state
    • Allow nested derived state
  • Single source of truth
    • Promote normalization
    • Make derived stated and nested derived state first citizens
  • Extensible by default
    • Hooks/Filters
  • Allow overwrites
  • Ready for DevTools
    • Action executions
    • State mutations linked to action executions
    • Component rerenders linked to state mutations

Node Server

  • Koa server
    • Smaller
    • Simpler API
    • Async/await
    • No dynamic dependencies
  • Extensible via middleware
    • Await until a particular step
    • Expose all the pieces of SSR
  • Everything is a package
    • Render packages (AMP, PDF? XML?)
    • Headers

Performance

  • Prioritize for Modern Browsers
    • Don’t sacrifice size and perf of modern browsers
    • Look only for usability in older browsers, not feature parity
  • Prioritize in this order
    1. Final user experience
    2. Performance
    3. Developer experience
    4. Core implementation complexity

WordPress

  • Don’t reimplement WordPress features, integrate them instead
  • Work with core WordPress
    • Avoid extending/hacking WordPress as much as possible
    • Adapt Frontity to WordPress, not the other way around
  • Maintain official plugin implementations for key plugins
  • Follow, as close as possible, the names already defined in WordPress.

Coding Best Practices

  • Look for just-in-time initialization
  • Avoid defining multiple APIs/entry-points for the same purpose/data
  • Use data normalization
  • Prioritize theme DX over other packages DXs
  • Prioritize package extensibility over package DX
  • Avoid abstractions when they obscure of Frontity works
  • Always define default settings
  • Prefer object-based arguments, except for options

Developer Experience Goals

  • Everything should be as easy to learn as possible
  • Frontity should have as fewer concepts as possible
    • Avoid introducing new concepts. Instead, reuse the same concepts
    • Prioritize using the same concept in different areas over having nicer APIs
  • Stay close to the standards
    • NPM vs Yarn

TypeScript

  • A single type should be enough to define a package
  • APIs must have full TypeScript support
    • Avoid separate APIs for JavaScript and TypeScript as much as possible
    • But prioritize for JavaScript themes DX
  • Use TSDocs

Namespaces

  • Contracts between packages
  • Create and maintain official namespaces
  • Shallow dependencies: new dependency system

Roadmap

  • AMP package
  • Server Extensibility
  • Hooks/Filters
  • Frontity PHP plugin
  • Source v2
  • Frontity config file
  • Language support
  • Namespace dependency system
  • DevTools
  • Admin UI
3 Likes

We did a couple of sessions explaining them in more detail:

Session 1

Session 2

We will do another one next week and we will post it here as well :slightly_smiling_face:

2 Likes

We did another session today, this time about the extensibility patterns.

I struggled a bit to explain this. I realized that the outline was not clear enough for this part, so I have to work more on this.

Session 3

I forgot to add last week session :slightly_smiling_face:

Session 4

And this is the session of this week:

Session 5

Another one:

Session 6

Topics talked in this Session

  • State manager of Frontity is @frontity/connect which internally uses react-easy-state (a light version of Mobx).
  • Benefits of interfacing packages through main frontity package.
  • When using useConnect?
  • Examples of using Typescript in mars-theme (actions, derived, …).
  • Immutability (promoted by Redux)
    • Native using spread.
    • Using mutability thanks to Immer.
  • How big and complex a Frontity app (relying on the state) can be
    • It’s as good as MobX that is in the same league than Redux.
    • JS benchmarks
  • So, the state manager used in Frontity
    • Uses internally react-easy-state (which is a light implementation of MobX).
    • It applies Flux pattern (being actions the ones modifying the state)
    • It simplifies the Developer Experience
      • No need to worry about immutability when modifying the state.
      • It works with async functions.
    • Transparent Reactive programming
      • You just use the state in a component and the state manager tracks that (in a tree) so when that property of the state changes the component is re-rendered.

Session 7

Topics talked in this session

  • [08:00] Single source of truth
    • Changes in a single place are reflected in several places (UI)
    • Consumers don’t need to differentiate between real and derived state
    • [19:00] Comparison w/ Redux that uses selectors (different way to get data from real state and from derived state)
    • [22:00] Example of derived state → state.source.api
    • [23:20] Nested derived state → still need to be solved
      • [26:00] [mobx-state-tree](https://github.com/mobxjs/mobx-state-tree) has this solved
      • [28:00] can’t we use prototypes to solve this?
        • serialization constraint
    • [34:00] Promote normalization
    • [36:30] Make derived stated and nested derived state first citizens
  • [38:00] Extensible by default
    • Hooks/Filters → It’s in progress. API to be defined
    • [47:20] Can also be applied to mutations
    • [48:50] Allow overwrites
  • [51:50] Ready for DevTools - It will be inspired by https://overmindjs.org/ - API already prepared for that

Session 8

Another episode of our DevRel OnBoarding talks :slightly_smiling_face:

Topics talked in this session

  • [08:00] Node Server
  • [09:30] Frontity supports serverless applications (req/res functions)
    • The generated build.js is actually a serverless function
    • npx frontity serve creates the server that makes use of this build.js
  • [13:30] req/res functions generated are KOA (compatible w/ express and some others)
  • [16:30] Why Koa?
    • ctxt more user friendly
    • next async
    • mutations
  • [18:00] KOA → No dynamic dependencies
  • [25:00] Serverless vs Node server
    • [28:00] static folder
    • [31:20] static folder managed by serverless
    • [32:00] vercel example (includes static)
    • [35:30] AWS example

Drawings: https://excalidraw.com/#json=5364363678449664,ArhF6-Bm9QjJ0fM6fEAR0A

Session 9

This is the video for this session:

We talked about Frontity’s relation with performance, mainly regarding new browser prioritization, and Frontity’s relation with WordPress, where we try not to reinvent the wheel and to adapt to it instead of vice-versa.

The drawings are: https://excalidraw.com/#json=4989505241088000,3Ju8jsKYvknEELARutyRFQ

1 Like

Session 10

This is the video for this session:

In this session we talked about:

  • Just-in-time initialization
  • Avoid defining multiple APIs/entry-points for the same purpose/data

These are the drawings: Excalidraw | Hand-drawn look & feel • Collaborative • Secure

Session 11

This is the video for this session:

In this session we talked about:

  • Use data normalization
  • Prioritize theme DX over other packages DXs
  • Prioritize package extensibility over package DX
  • Avoid abstractions when they obscure of Frontity works
  • Always define default settings
  • Prefer object-based arguments, except for options

Session 12

We talked about the Developer Experience Goals:

  • Everything should be as easy to learn as possible
  • Frontity should have as fewer concepts as possible
    • Avoid introducing new concepts. Instead, reuse the same concepts
    • Prioritize using the same concept in different areas over having nicer APIs
  • Stay close to the standards
    • NPM vs Yarn

Session 13

Drawings: Excalidraw | Hand-drawn look & feel • Collaborative • Secure

We talked first about how we choose the external libraries/tools.

These are some of the tools:

  • npm
  • fetch (window.fetch node-fetch)
  • @frontity/connect → react-easy-state
  • emotion
  • Koa
  • react-helmet
  • loadable-components
  • webpack
  • babel

And these are some of the consideration that we use to choose them:

  • standard
  • size/performance
  • cover our needs
  • community/popularity/adoption
  • team

After that we started talking about TypeScript, explaining how TypeScript works in Frontity and “the single type per package” mindset.

We didn’t finish that part, we will finish in the next section :slightly_smiling_face:

The respository I was using to explain the types was this one: GitHub - frontity/woocommerce-proof-of-concept: Proof of concept of a possible Frontity integration with WooCommerce.

1 Like