Combining some related issues concerning the design of our SSR pipeline to make a single branch and !MR. I hope this will be relatively easy to review.
.ts
modules for easier maintenance, features and refactors-> Typesafe functions to prevent undebuggable build-time errors
css.ts
module-> Typesafe css builder -> Cohesion (less indirection, more inlining)
-> Consistent and typesafe colors and spacings -> Singe source of truth
-> Consistent and typesafe widths and heights -> Singe source of truth
Also included in this branch: #103 Fix
element for correct Html outputExternal stylesheets are notorious for falling out of sync with the Html.
With the Grid
component, we had a precedent of typescript-generated CSS that turned out more stable than the external scss files.
We haven't used the full hierarchy of cube
yet, and probably never will.
Each level on the cascade introduces coupling. Current approaches such as tailwind trade extreme verbosity and lots of redundant inline css for the benefit of no more coupling.
As outlined in #102 I propose that we move styling mostly to inline, with typescript-generated primitives (similar to tailwind in approach but not in execution), but keep a minimal and stable subset of styles in a global
and a component-level layer.
Then we can remove all scss files and get rid of lots of dependencies.
Advantages:
Fixed in branch feature/99
Note:
We can use calc(...) in media (and container) queries but no variables.
We have two sets of media queries:
Can we use calc(...) to get rid of all the fluid breakpoints?
Can we use calc(...) to implement Layout breakpoints (2)?
See https://www.typescriptlang.org/docs/handbook/jsx.html for an overview of JSX types.
We want to narrow <style>
tags and style=
attributes.
Inspecting the source code of nightly.ecobytes.net, I notices the <head>
element is not rendered. It might be due to a script tag I put above it inside the Page
component. While HTML5 allows omission of head, it leads to bad things.
Update March 17th
We've learned a lot about the ts typesystem recently through bottom-up experimentation. Now let's go top-down and think about the smalles interface we want to build.
DX
Shipped CSS
ack
roundtrips between server and client. @yala is that still correct these days?Side note: As of now, nightly.ecobytes.net ships more than 100KB before any rendering.
- index with all CSS inlined - 16k
- normalize.css - 11k
- Astro page transition polyfill - 10k
- Kava regular (woff2) - 26k
- Kava heavy (woff) - 30k (it is a bit narrower than Kava regular, why?)
- Astro preload-on-hover functionality - 10k
Question: Does the network carry less than that, thanks to gzipping?
What invariants should the Css
module enforce?
These invariants apply to individual rules and help with reading (low cognitive load) and writing (intellisense suggestions). I don't think we need to enforce any invariants on a higher levels of abstraction.
What Css snippets need to be available to a Component?
(a) Inline CSS (preferred)
(b) <style>
tag to target dynamic Html (markdown)
Css
moduleHow does a Component select a Css rule?
<style>
tag that I put into my page.Note: Astro has several directives for CSS.
<style>
will be scoped to its component through generated[data-astro-...]
attributes and do some preprocessing (scss is an option) and tree-shaking. If styles exceed a certain size, they end up in an external stylesheet. Scoped styles take precedence over other ones. Later imports take precedence; Astro advises to import a globalLayout
component first.
<style is:global>
opts out of preprocessing and ends up in the header
<style is:inline>
opts out of preprocessing and will be included verbatim in-place
Consider: Astro's main use case is with repo-based data or the new astro-db. As we use the directus graphQL API instead, we need to roll a lot of things ourselves. For example, we cannot use any of the
Content Collection
Dx helpers. This is also true for CSS imports and CSS@url
resolvers which we replace with database-derived typescript types.
Do we event want to hand-write CSS outside of modules?
No.
For better cohesion, let's (in the order of the inevitable cascade):
Page
moduleMarkdown
astropub/md
wrapper into our component Markdown
. Later on, we will probably want to replace astropub/md
with our custom remark
flow and add all the good types so that we can finally use something akin to Blocks #20
Css
module's primitives to construct rules.Page
Grid
Article
(I) Note that with every cascade layer, we introduce coupling. I.e. whenever we change some rule, we need to check if any of the lower cascades are affected. Higher cascade layers thus need to be extremely stable and should not contain any volatile rules.
(II) Repeating a style inline (we can use {tyescript} to make it easy) may be preferable over introducing an astro-scoped selector because we don't affect any DOM children.
Restarting the dev container solved the issue.
Maybe cached data?
Problem right now:
The database didn't update.
I added more color field but the data for the additional color fields weren't downloaded...
As a Maintainer or Designer,
I want to be able to inspect and modify the theme at a single place and trust that the build process succeeds and the layout doesn't fall apart
So that we can manage the theme as orthogonal to other components.
Motivation: The theme affects many places in the build code.
A common pattern is to defuntionalize the theme into parameters, i.e. make it declarative:
--color-primary:
, --font-size-small:
... in a theme.css
theme.json
theme
table on the CMSIn accordance with our goal to have data managed by the CMS, and regarding the beauty of the auto-generated typescript, and because directus offers a Color type, I suggest moving the theme there.
Blocks #96
.(s)css
files anywhere<style>
tags and style=
attributes are narrowed (see #note_44584)
--width-unit
, --width-cell
, --width-column
which scale with font size--height-${s|m|l|xl|unit}
which are multiples, 1/3, or 1/2 of line heightcolor-mix(in oklab...)
out of color variablesNote: After hours of research, I still feel I didn't understand the differences between old-style a.k.a. cjs
modules (module.exports
), "fake es modules" and "modern es modules". But there are some bits of information that I want to collect here to get a clearer picture.
Problem: I can't use the library "fp-ts-std". dev
breaks with
I went back to the current fp-ts version. After all, the whole v3 beta never took off. And voil+a, it works now. Apparently, under some circumstances, modules can be imported just fine. No idea why it works now, without the /lib/
shenanigans...
anyways, I'm happy it's very easy to extend fp-ts and the types are great and we'll use their documentation approach to auto-generate excellent docs. And complex css is really best created by typescript, not by hand. I made a theme :-) All WIP :-)
No... the error persists after patching that line...
import { constant, pipe, flow, flip } from "fp-ts/lib/function";
^^^^^^
It's documented in https://github.com/gcanti/fp-ts/issues/1799
Another thing I remember: I had to change the fp-ts imports from fp-ts/function
to fp-ts/lib/function
to work well as a module.
But the stuff imported from fp-ts
worked fine.
Now, the error message underlines
import { constant, pipe, flow, flip } from "fp-ts/function";
^^^^^^
which is a line using no /lib/
in the import path... maybe relevant?