Skip to content

Commit d29dd6f

Browse files
committed
update font preload
1 parent 2110768 commit d29dd6f

File tree

3 files changed

+102
-55
lines changed

3 files changed

+102
-55
lines changed

src/content/blog/2025-10-08-lets-talk-sample-apps.md

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
date: "2025-10-08T19:44:48+08:00"
33
slug: "lets-talk-sample-apps"
44
og_image: /images/posts/tag-ure-it.jpg
5+
hascodepen: true
56
tags:
67
- javascript
78
- devlife
@@ -10,7 +11,7 @@ title: "Let's talk sample apps"
1011
draft: true
1112
---
1213

13-
I'm back in the Developer Relations profession. But after going through the [migration](/blog/migrating-from-hugo-to-astro) last weekend, it occurred to me that some part of my current job was something that I have been doing over the years I've had this blog. And that is, explaining to others how something is done and how things work.
14+
I'm back in the Developer Relations profession. But after going through the [migration](/blog/migrating-from-hugo-to-astro) last weekend, it occurred to me that some part of my current job was something that I had already been doing over the years I've had this blog. And that is, explaining to others how something is done and how things work.
1415

1516
My only 2 developer relations jobs were at companies that provided SDKs as products to developers (among other things they do to make revenue). And so it was important to show developers how our SDKs were used and what you could do with them. This meant that I needed to know these SDKs really well, especially all the bits that don't work very well.
1617

@@ -25,3 +26,59 @@ What is the point of a sample application? Well, for my context, I would broadly
2526
Such applications are meant to guide a developer on how to implement something and hopefully they can apply what they learned into their own applications
2627
2. **Showcase sample applications**
2728
Such applications are meant to show what a particular technology makes possible
29+
30+
Based on these categorisations, I would say that learning sample apps would end up being flatter in project structure, since the main purpose is to let developers understand how a particular feature is implemented. You wouldn't spend time optimising and modularising everything to be "production-ready", whatever that means.
31+
32+
Personally I think showcase apps can just go wild. I mean, I used to work in [advertising](/resume/#nurun) where sometimes, even things meant for "production" felt like they were just showcase apps held together by duct tape and the hopes and prayers of the account manager. If you know what I mean.
33+
34+
The rest of this post is focused on learning sample apps. Showcase apps can do whatever they want.
35+
36+
## Decisions, decisions…
37+
38+
When I was young and stupid, I was rather opinionated about the "best" way to do things. Now that I'm old and stupid, I'm much less opinionated, and hopefully less stupid as well. The best way to do things is extremely contextual, so the only guiding principle I go by is to assess the situation you're in.
39+
40+
Anywayz, I had been thinking about the best way to structure sample web applications for the purpose of learning. And wanted to keep a record of my thought process.
41+
42+
First and foremost, what is the specific thing you're trying to explain, and what is its **native environment**? For example, if I'm trying to teach someone how Flexbox works, then I would consider the native environment CSS. If I'm trying to teach someone how to use a particular Node.js SDK, then I would consider the native environment JavaScript or Typescript, you get the picture.
43+
44+
Next thing I took into consideration was the **habits and preferences** of the audience I was trying to reach. If you're building in the AI space, odds are the preferred language is going to be Python. A lot of developers building applications on the blockchain seem to default to React and (sadly) Tailwind. I'm still not a big fan of Tailwind but I can see its use-cases.
45+
46+
Also, would there be more sample apps **related to the same topic**. Or are they **individual snowflakes**? If the sample apps are part of a larger theme, do you want to have unified visuals for UI components? For example, if you're building developer documentation for a suite of product SDKs, maybe your sample apps all follow a similar structure and use the same libraries.
47+
48+
Again, there are no hard and fast rules, but a series of trade-offs between how much effort you can afford versus the range of audiences you are trying to reach, I suppose. In a world where unicorns poop rainbows, you could show your developer audience every flavour of how something is done, but sadly, we live here.
49+
50+
## Highlight the critical code
51+
52+
As a bilingual speaker, I honestly wanted by heading for this section to be "讲重点" but I didn't have the language skills to translate that concisely while keeping the gist right.
53+
54+
### CSS
55+
56+
I've built quite a few demos on CodePen as well as standalone sites over the years. A lot of them are about CSS (86 posts on this blog so far). Most of the demos need some form of "unrelated" code just to make the demo look decent so people don't get so distracted by the lack of styling they miss the point altogether.
57+
58+
For those, I've mostly grouped those styles at the bottom (generally safe cascading since they're not touching the actual elements for the demo), and use a comment to indicate they are layout styles. This seems to be a relatively common approach based on what I've seen.
59+
60+
<p class="codepen" data-height="500" data-default-tab="css,result" data-slug-hash="RwvzoRp" data-pen-title="View Transitions API" data-user="huijing" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
61+
<span>See the Pen <a href="https://codepen.io/huijing/pen/RwvzoRp">
62+
View Transitions API</a> by Chen Hui Jing (<a href="https://codepen.io/huijing">@huijing</a>)
63+
on <a href="https://codepen.io">CodePen</a>.</span>
64+
</p>
65+
66+
Another approach that came to mind was to have the unrelated styles as inline styles on the HTML elements themselves, and leave ONLY the relevant CSS in the stylesheet. That way there is no ambiguity and everything in the CSS file is relevant. I feel this approach could make it easier to immediately parse the CSS that is doing the actual work.
67+
68+
I'm still in two minds on whether to extend this to the actual element being styled itself. Say if I'm explaining Flexbox, and I put the border style for the element inline instead, you know? [Share your thoughts](https://bsky.app/profile/huijing.bsky.social) on this with me, if you have any.
69+
70+
### JavaScript
71+
72+
For JavaScript it might be trickier. But I have done 2 (or more) separate JavaScript files, where one only contains the relevant logic and the other ones handle everything else to make the website work. With the [module syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) now pretty much the norm, there are so many levels of abstraction possible, and this is one area I feel warrants a bit more deliberate thought.
73+
74+
When writing tutorials around such sample apps, I always ponder how copy-pastable my code is. Ideally, you're really not supposed to wholesale copy and paste a sample app code into your own application but you know and I know and your cat knows that people tend to do that. I lean more heavily towards leaving the responsibility of modularisation up to the developer themselves.
75+
76+
Or even for frameworks, like React. If you look at the average React project, it's components all the way down, which is sort of the right way to do things. But I've personally spent a lot of time digging through components like a forensics team trying to find a dead body just to locate where the logic lies.
77+
78+
For a learning sample app, I would propose keeping all UI components as dumb as possible, then dump all the relevant logic into a big-ass custom hook. Is this best practice? Probably not, but it sure makes it easier to find feature implementation code. Generally, I'm thinking along the lines of getting the framework code out of the way as much as possible.
79+
80+
## Wrapping up
81+
82+
If you made it this far, thank you reading the words that I wrote. I'm under the impression that most people don't actually read these days. But hey, what do I know? I'm still amazed that this blog has existed for more than 11 years. A couple of years ago, I too had fallen into the category of people who Googled how to do something and landed on their own blog post.
83+
84+
Ah well. Life.

src/layouts/BaseLayout.astro

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,32 @@ const {
4646
<link rel="canonical" href={canonicalURL} />
4747

4848
<link
49-
rel="prefetch"
49+
rel="preload"
5050
href="/fonts/eightbitoperatorplus8-bold-webfont.woff2"
5151
as="font"
5252
type="font/woff2"
53-
crossorigin
53+
crossorigin="anonymous"
5454
/>
5555
<link
56-
rel="prefetch"
56+
rel="preload"
5757
href="/fonts/eightbitoperatorplus-regular-webfont.woff2"
5858
as="font"
5959
type="font/woff2"
60-
crossorigin
60+
crossorigin="anonymous"
6161
/>
6262
<link
63-
rel="prefetch"
63+
rel="preload"
6464
href="/fonts/magnetic-pro-black.woff2"
6565
as="font"
6666
type="font/woff2"
67-
crossorigin
67+
crossorigin="anonymous"
6868
/>
6969
<link
70-
rel="prefetch"
70+
rel="preload"
7171
href="/fonts/magnetic-pro-light.woff2"
7272
as="font"
7373
type="font/woff2"
74-
crossorigin
74+
crossorigin="anonymous"
7575
/>
7676

7777
<meta property="og:title" content={title ? `${title} | ${SITE_TITLE}` : SITE_TITLE} />

src/pages/work.astro

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,26 @@ import "@/styles/pages.css";
66
import projects from "@/data/projects.json" assert { type: "json" };
77
88
const posts = await getCollection("blog");
9-
const clientWorkPosts = posts.filter((post) => (post.data.tags ?? []).includes("client-work"));
9+
const clientWorkPosts = posts
10+
.filter((post) => (post.data.tags ?? []).includes("client-work"))
11+
.sort((a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime());
1012
const sideProjectPosts = posts.filter((post) => (post.data.tags ?? []).includes("side-project"));
13+
const sideProjects = [
14+
...sideProjectPosts.map((p) => ({
15+
id: p.id,
16+
href: p.data.external_url ?? `/blog/${p.id}/`,
17+
imageName: p.data.project_image,
18+
title: p.data.project,
19+
external: !!p.data.external_url,
20+
})),
21+
...projects.map((p) => ({
22+
id: p.id,
23+
href: p.external_url ?? `${GITHUB_URL}/${p.id}/`,
24+
imageName: p.image,
25+
title: p.title,
26+
external: !!p.external_url,
27+
})),
28+
];
1129
1230
const title = "Work";
1331
---
@@ -66,51 +84,23 @@ const title = "Work";
6684
<h2>Side projects</h2>
6785
<div class="grid projects">
6886
{
69-
sideProjectPosts.map((post) => {
70-
const href = post.data.external_url ? post.data.external_url : `/blog/${post.id}/`;
71-
return (
72-
<div class="project">
73-
<a class="no-underline" href={href}>
74-
<img
75-
class="project__image"
76-
srcset={`/images/posts/projects/${post.data.project_image}@2x.png 2x`}
77-
src={`/images/posts/projects/${post.data.project_image}.png`}
78-
alt={post.data.project}
79-
/>
80-
<h3 class="project__title no-margin">{post.data.project}</h3>
81-
</a>
82-
</div>
83-
);
84-
})
85-
}
86-
87-
{
88-
projects.map((project) => {
89-
const href = project.external_url
90-
? project.external_url
91-
: `${GITHUB_URL}/${project.id}/`;
92-
93-
return (
94-
<div class="project">
95-
<a
96-
href={href}
97-
{...(project.external_url && {
98-
target: "_blank",
99-
rel: "noopener noreferrer",
100-
})}
101-
class="no-underline"
102-
>
103-
<img
104-
class="project__image"
105-
srcset={`/images/posts/projects/${project.image}@2x.png 2x`}
106-
src={`/images/posts/projects/${project.image}.png`}
107-
alt={project.title}
108-
/>
109-
<h3 class="project__title no-margin">{project.title}</h3>
110-
</a>
111-
</div>
112-
);
113-
})
87+
sideProjects.map(({ href, imageName, title, external }) => (
88+
<div class="project">
89+
<a
90+
href={href}
91+
{...(external && { target: "_blank", rel: "noopener noreferrer" })}
92+
class="no-underline"
93+
>
94+
<img
95+
class="project__image"
96+
srcset={`/images/posts/projects/${imageName}@2x.png 2x`}
97+
src={`/images/posts/projects/${imageName}.png`}
98+
alt={title}
99+
/>
100+
<h3 class="project__title no-margin">{title}</h3>
101+
</a>
102+
</div>
103+
))
114104
}
115105
</div>
116106
</div>

0 commit comments

Comments
 (0)