Skip to content

Commit

Permalink
Merge pull request #10 from mashedkeyboard/posts/when-did-we-decide-t…
Browse files Browse the repository at this point in the history
…he-semantic-web-is-too-hard

When did we decide the semantic Web is too hard?
  • Loading branch information
mashedkeyboard authored Nov 11, 2023
2 parents 4b890a1 + 220c53c commit b46c72f
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 8 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@tsconfig/svelte": "^3.0.0",
"@types/mdast": "^4.0.0",
"@types/node": "^20.8.9",
"@types/sanitize-html": "^2",
"directory-tree": "^3.5.1",
"esbuild": "^0.19.3",
"eslint": "^8.50.0",
Expand Down Expand Up @@ -55,7 +56,9 @@
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"microformats-parser": "^1.5.2",
"normalize.css": "^8.0.1"
"normalize.css": "^8.0.1",
"sanitize-html": "^2.11.0",
"tsl-mastodon-api": "^0.4.1"
},
"packageManager": "yarn@4.0.0"
}
Binary file added posts/2023/11/11/laptop.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: When did we decide the semantic Web is too hard?
date: 2023-11-11T18:28:15.400Z
summary: "The whole #Web is based on #HTML. So, why don't we value it being written well and semantically meaningful? MySpace proved anyone can write it - yet now we don't seem to care about writing it well. That's sad."
image: laptop.jpg
imageAlt: "An open laptop, sitting on a desk, on which HTML and CSS are being written in Sublime Text."
toots: https://social.mashed.cloud/@curtispf/111318079457442689
---
<script>
import Toot from '$lib/components/Toot.svelte';
export let toots;
</script>

MySpace has been rattling around in my head for a little while now, not for the platform itself but for the side effects it had. I was too young to actually be there myself(!), but the folks on it at the time were big fans of the idea of being able to customise their homepages - even those who wouldn't normally be interested in the Web. I went out to Mastodon to check I wasn't hallucinating this: sure enough, it wasn't just techy people, it seems.

<aside>
<Toot
url="https://social.mashed.cloud/@curtispf/111318079457442689"
{toots}
/>
</aside>

It's definitely true to say that the Web's moved on a lot since those days. HTML5, CSS3 and modern JavaScript are all substantially more complex than they were at the time. Even so, the fundamental basis on which the Web works hasn't changed - HTML and CSS are still the core of what a web page is. Yet, over the last decade and with the advent of things like React, we've moved increasingly towards a model where the HTML output of web pages is considered by many to be almost as irrelevant as the assembly code that C compiles down to. This... well, this seems <em><strong>bad</strong></em>.

## Why care about the page markup?

I'm not interested in doing the "markup language vs programming language" trope that's been done to death, but importantly, HTML is specifically designed to be parseable and understandable, both by humans and by software tools. With very few exceptions for specific-purpose internal applications, sighted humans at desktop computers are not your only users. HTML on the Web is designed to be interpreted not only by Web browsers to be displayed to a user on a screen (and definitely not only by Chromium-based browsers... sigh), but also by assistive technology, search engine spiders, content parsers and all manner of other Internet users.

Your markup meaning something means something to all of these users. If any of them get cared about at all, search engine spiders are usually the one that people identify - thinking about ensuring that Google will render rich snippets for them - and that is an important use case, but that often leads to a situation where people building apps with a login page in front of them just don't care about their produced markup. [MDN has many examples of why this matters on their page on the subject](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML) - unless you're making extensive use of `aria-role` (and if you are, with a few justifiable exceptions, why not just use the semantic elements to start with?!), a screen reader isn't going to have any idea that your beautifully-styled heading is a heading, and your app behind the login page is going to be made much less accessible to folks who aren't using your standard "sighted access happy path".

## Why don't people seem to care about this anymore?

There's a small-but-significant conjunt of people who consider themselves to be, for instance, "React developers", rather than "web developers". I definitely don't want to impugn the idea of being a subject-matter expert in a particular framework, and I'm not even sure I want to litigate the arguments around whether a good developer should be able to work in multiple languages and paradigms (though I do absolutely think they should!). But, it's really important to be clear that, when you're building a Web application, whatever else you consider yourself to be, you are a Web developer. <strong>Being an [insert favourite frontend framework here] developer doesn't absolve you from the need to understand the markup you're outputting.</strong>

In some senses, though, the problem is the tools we've created that allow people to disconnect themselves from the markup their creations are ultimately generating. When I first started Web development, I was writing inline PHP with no separation of concerns between the view, model, controller, or really anything else - it was a bit of a hodgepodge. Far be it from me to argue in favour of that model in any sense, but the one (practically singular) advantage it did have is that you knew exactly what the markup you're generating looked like - because it was in the page! In a monolithic application, things like erb in Ruby or jinja in Python keep you close to the markup you're writing, too. We have a real tendency to lose that in frontend applications, though: whether you're writing it in React, Preact, Flutter, or even something like Elm to a somewhat lesser extent, you're finding yourself a lot further away from the actual end product that you're producing.

Tools like JSX, in principle, sound like a good solution to this problem, but I'm just not convinced they are: when you hold up your JavaScript as the most important part of your Web application, you inevitably have a culture shift. What you put in your JSX becomes secondary to what you have in the function above it, and that's the wrong way around for things to be: users care about the side effects of your JavaScript, like its performance or how usable the page is without it, but not what your JavaScript looks like in and of itself. <strong>The core of a good Web app is necessarily a good website.</strong> Frameworks like Vue and Svelte, in my view, do an awful lot better at this, by virtue of the fact that they centre HTML in their single-file components; the way that the technology is shaped in turn shapes the development culture, putting high-quality markup first.

## What's this all got to do with MySpace?

I think it would probably be fair to observe that most user MySpace pages weren't exactly held up as an example of how to build a good, accessible, semantic webpage. Yet, what they did very clearly do is offer people some curiosity as to how this whole interwebs thing worked under the bonnet. Clearly, the platform experience that MySpace had is far from universal, and was heavily dependent on their particular user demographics - and yet, at the same time, it did introduce potentially millions of people to the idea that they too could build their own little space on the Web. Of course, this isn't the same as them hosting their own website, but there's definitely [a small Web kind of feel to it](https://ar.al/2020/08/07/what-is-the-small-web) - because if they could do it on MySpace, they could do it anywhere else, or on their own webpage too one day!

MySpace provided the space to prove the hypothesis that "normal people" could write HTML - or at least cobble together something functional. In many ways, then, it seems an oddity that today, we might well suggest to a new Web developer to start with something like React, because it's "what everyone uses", or even because it's "easier than HTML": people tinkering don't need a framework, and when people need a framework, React is rarely the best choice other than from an "everyone uses this" perspective. Sure, it's true to say that perhaps there's a little more complexity in managing your HTML separately to your script that generates or modifies it (though it really is an incredibly small amount!), but that doesn't mean it's not worthwhile - in the same way that most people recognise separation of concerns to be valuable in the backend. Shoving together everything into this massive "view-cum-API-handler-cum-frontend-logic-manager" file is a really unhelpful step backwards - and so long as that's what we show people first, we're losing out on people doing it better in the future.

## We change tech, then tech changes us

Part of the inspiration for writing this was reading [Heather Buchel's excellent blog post "It's 2023, here is why your web design sucks"](https://heather-buchel.com/blog/2023/10/why-your-web-design-sucks), highlighting how much we've lost out by pushing the "Web design" role into either pure UX design or into "front-end engineering" - and I think that's intrinsically linked to all of this. Both problems arise from the idea that what's output to the browser and what's output to the user is totally secondary to what the JavaScript code on the website happens to do - and the idea that somehow it's "smarter" or "more important" (or, as Heather points out quite rightly, "more masculine") to be writing the business logic rather than the presentation details.

As a user of your website, I want to have semantic output my user agent understands, so that I can use the Web how it was intended to be used: using a user agent of my choice, that helps me achieve my tasks in the way that I want it to, and in a way that makes sense for me and the person I am. Making that happen is valuable work that deserves recognition and deserves to be held up in its own right, whether it's done by a Web designer, or a Web developer, or anyone else for that matter.

If MySpace users could manage their page HTML, your team can too.
9 changes: 7 additions & 2 deletions src/lib/blog/Post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class Post {
private image?: BlogPostImage;
private summary?: string;
private mastodon_post?: string;
private toots?: string[];

private plaintext: string;
private body?: SvelteComponent;
Expand All @@ -27,14 +28,16 @@ export class Post {
constructor(
slug: string, title: string, date: Date,
image: BlogPostImage | undefined, summary: string | undefined,
mastodon_post: string | undefined, plaintext: string, body?: SvelteComponent
mastodon_post: string | undefined, toots: string[] | undefined,
plaintext: string, body?: SvelteComponent
) {
this.slug = slug;
this.title = title;
this.date = date;
this.image = image;
this.summary = summary;
this.mastodon_post = mastodon_post;
this.toots = toots;

this.plaintext = plaintext.slice(0, 500);
this.body = body;
Expand All @@ -57,6 +60,7 @@ export class Post {
importedModule.images,
importedModule.metadata.summary,
importedModule.metadata.mastodon_post,
importedModule.metadata.toots?.split(','),
importedModule.metadata.plaintext || 'No text',
importedModule.default
)
Expand All @@ -67,7 +71,7 @@ export class Post {
metadata.slug, metadata.title,
new Date(metadata.date), metadata.image,
metadata.summary, metadata.mastodon_post,
metadata.plaintext
undefined, metadata.plaintext
);
}

Expand Down Expand Up @@ -186,4 +190,5 @@ export class Post {
public getDate() { return this.date; }
public getBody() { return this.body; }
public getMastodonPost() { return this.mastodon_post; }
public getToots() { return this.toots; }
}
81 changes: 81 additions & 0 deletions src/lib/components/Toot.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<script lang="ts">
import type Status from "tsl-mastodon-api/lib/JSON/Status";
import sanitizeHtml from 'sanitize-html';
import FaIcon from "./FAIcon.svelte";
import { faMastodon } from "@fortawesome/free-brands-svg-icons";
export let url: string;
export let toots: Map<string, Status>;
let tootWithEmojis: string;
const toot = toots.get(url);
if (toot) {
tootWithEmojis = toot.emojis.reduce((tootContent, newEmoji) => {
return tootContent.replaceAll(
`:${newEmoji.shortcode}:`,
`<img src="${newEmoji.static_url}" alt="${newEmoji.shortcode} emoji"
referrerpolicy="no-referrer" loading="lazy"
fetchpriority="low" />`
);
}, toot.content)
}
</script>

{#if toot}
<article>
<a href={toot.url} class="masto-icon">
<FaIcon opts={{title: "Toot from Mastodon", classes: "fa-2xl"}} icon={faMastodon} />
</a>

<section class="author">
<a href={toot.account.url}>{toot.account.display_name}</a> <a href={toot.url}>tooted</a>:
</section>
<section class="content">
<p>
{@html sanitizeHtml(tootWithEmojis, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ])
})}
</p>
</section>
{#if toot.poll}
<section>
<h4>Poll responses</h4>
<ol>
{#each toot.poll.options as option}
<li>{option.title}: {option.votes_count || 0 / toot.poll.votes_count}%</li>
{/each}
</ol>
</section>
{/if}
</article>
{/if}

<style lang="scss">
article {
border: 1px solid $light;
@include light-mode {
border: 1px solid $primary_dark;
}
padding: 1em;
ol {
list-style: none;
}
.content p :global(img) {
width: 1em;
}
a.masto-icon {
float: left;
color: $light;
@include light-mode {
color: $primary_dark;
}
margin-right: 1em;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import Mentions from '$lib/components/blog/Mentions.svelte';
import { onMount } from 'svelte';
import { urlForPost } from '$lib/Helpers';
import type Status from 'tsl-mastodon-api/lib/JSON/Status';
const post: Post = $page.data.post;
const toots: Map<string, Status> = $page.data.toots;
let mentionsRequest: Promise<Response> = new Promise(() => {});
Expand Down Expand Up @@ -49,7 +51,7 @@
</div>
{/if}
<div class="e-content" itemprop="articleBody">
<svelte:component this={post.getBody()} />
<svelte:component this={post.getBody()} toots={toots} />
</div>

{#await mentionsRequest}
Expand Down Expand Up @@ -133,4 +135,17 @@
padding-right: 3em;
font-style: italic;
}
.e-content {
:global(aside) {
@media screen and (min-width: $mobile-break) {
float: right;
text-align: right;
max-width: 50%;
margin-left: 1.5em;
}
margin-bottom: 1em;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,39 @@ import { getPost } from '$lib/blog/PostManager.js';
import { resolveSlug } from './SlugResolver.js';
import { error } from '@sveltejs/kit';
import { urlFor } from '$lib/Helpers.js';
import type Status from 'tsl-mastodon-api/lib/JSON/Status';

/** @type {import('./$types').PageLoad} */
export async function load({ params }) {
return getPost(resolveSlug(params)).then((post) => {
return getPost(resolveSlug(params)).then(async (post) => {
let tootsMap;

const toots = post.getToots();
if (toots) {
tootsMap = new Map(await Promise.all(toots.map((tootUrl) => {
return new Promise<[string, Status]>(async (res) => {
const urlObject = new URL(tootUrl);
const pathParts = urlObject.pathname.split('/');

const fetchedPost = await fetch(
`${urlObject.origin}/api/v1/statuses/${pathParts[pathParts.length - 1]}`, {
headers: {
"User-Agent": "site-masto-fetcher@cpf.sh"
}
});

res([tootUrl, await fetchedPost.json() as Status]);
})
})));
}

return {
post: post,
has_own_h1: true,
meta_title: post.getTitle(),
social_image: post.getImage()?.fallbackImage,
description: post.getSummary(),
toots: tootsMap || new Map(),
open_graph_type: 'article',
open_graph: {
"article:author": urlFor(),
Expand Down
Loading

0 comments on commit b46c72f

Please sign in to comment.