add obsidian vault as source for blogging
This commit is contained in:
parent
a6ffa5eab9
commit
cc6c1f46f9
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "content-sources/obsidian-default"]
|
||||||
|
path = content-sources/obsidian-default
|
||||||
|
url = git@git.lindholm.dev:vlindhol/obsidian-default.git
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
# Development
|
||||||
|
|
||||||
You need Hugo to build this site:
|
You need Hugo to build this site:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -5,3 +7,8 @@ $ brew install hugo
|
|||||||
```
|
```
|
||||||
|
|
||||||
then use `hugo server` to run the dev server.
|
then use `hugo server` to run the dev server.
|
||||||
|
|
||||||
|
## Update blog posts from Obsidian
|
||||||
|
|
||||||
|
1. `git submodule update --remote`
|
||||||
|
2. `./scripts/generate-blog-posts.sh`
|
||||||
|
|||||||
1
content-sources/obsidian-default
Submodule
1
content-sources/obsidian-default
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 92c093e38b1e82c51ecd4e22ac22a1303fda3071
|
||||||
@ -1,8 +1,13 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
title: "My experience contributing to Servo"
|
title: "My experience contributing to Servo"
|
||||||
|
|
||||||
date: 2024-12-09T12:14:57+03:00
|
date: 2024-12-09T12:14:57+03:00
|
||||||
tags: ["programming", "rust"]
|
|
||||||
|
tags: \["programming", "rust"\]
|
||||||
|
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
I've been a long-time Rust enthusiast, but haven't worked a lot with Rust in a real way. Thus, as I found myself with some spare time during my sabbatical, I decided to find an open source Rust project to contribute to, and Servo fit that bill perfectly.
|
I've been a long-time Rust enthusiast, but haven't worked a lot with Rust in a real way. Thus, as I found myself with some spare time during my sabbatical, I decided to find an open source Rust project to contribute to, and Servo fit that bill perfectly.
|
||||||
@ -10,8 +15,11 @@ I've been a long-time Rust enthusiast, but haven't worked a lot with Rust in a r
|
|||||||
Why Servo? It's a browser engine written entirely in Rust, started at Mozilla, where Rust was invented. The stated (and unstated) goals tick a lot of boxes for me:
|
Why Servo? It's a browser engine written entirely in Rust, started at Mozilla, where Rust was invented. The stated (and unstated) goals tick a lot of boxes for me:
|
||||||
|
|
||||||
* The browser landscape is practically a Chrome monoculture, I want to help counteract that.
|
* The browser landscape is practically a Chrome monoculture, I want to help counteract that.
|
||||||
|
|
||||||
* The future of UI for most apps will either be a more polished PWA experience (which depends on OS maker support) or less memory and processor intensive desktop web apps á la Electron (which doesn't). Servo is designed to be embeddable, i.e. "used as a library", so it fits nicely into either future.
|
* The future of UI for most apps will either be a more polished PWA experience (which depends on OS maker support) or less memory and processor intensive desktop web apps á la Electron (which doesn't). Servo is designed to be embeddable, i.e. "used as a library", so it fits nicely into either future.
|
||||||
|
|
||||||
* Compared to incumbents, Servo is designed for GPUs and parallel processing from the ground up. It's state of the art in many ways.
|
* Compared to incumbents, Servo is designed for GPUs and parallel processing from the ground up. It's state of the art in many ways.
|
||||||
|
|
||||||
* I like building web apps, so this gives me a deeper appreciation of how the DOM and rendering really works.
|
* I like building web apps, so this gives me a deeper appreciation of how the DOM and rendering really works.
|
||||||
|
|
||||||
## Orienting myself in the project
|
## Orienting myself in the project
|
||||||
@ -47,34 +55,49 @@ At this point I really needed to get my hands dirty with Servo.
|
|||||||
Servo is a Cargo workspace, with the gargantuan `script` module being where all my work needed to take place. This is where everything DOM and JavaScript-related happens. The main things I ended up needing to learn was:
|
Servo is a Cargo workspace, with the gargantuan `script` module being where all my work needed to take place. This is where everything DOM and JavaScript-related happens. The main things I ended up needing to learn was:
|
||||||
|
|
||||||
1. How memory management works (spoiler: the JS runtime does garbage collection)
|
1. How memory management works (spoiler: the JS runtime does garbage collection)
|
||||||
2. WebIDL
|
|
||||||
3. Running WPT tests effectively
|
1. WebIDL
|
||||||
|
|
||||||
|
1. Running WPT tests effectively
|
||||||
|
|
||||||
**Memory management**, which can get tricky in any Rust project, turned out to be quite painless (from my point of view). There's a [detailed writeup](XXX) about it, but the gist of it is:
|
**Memory management**, which can get tricky in any Rust project, turned out to be quite painless (from my point of view). There's a [detailed writeup](XXX) about it, but the gist of it is:
|
||||||
|
|
||||||
1. All structs that correspond to classes in the DOM spec (e.g. `Element`) are marked with `#[dom_struct]`, which among other things is an alias for `#[derive(JSTraceable)]`.
|
1. All structs that correspond to classes in the DOM spec (e.g. `Element`) are marked with `#[dom_struct]`, which among other things is an alias for `#[derive(JSTraceable)]`.
|
||||||
2. Once the JS runtime (called SpiderMonkey) is aware of the existence of such a struct, its garbage collector looks at every field, looking for other `JSTraceable` contents. This type of GC is literally called [tracing garbage collection](XXX).
|
|
||||||
3. Once SpiderMonkey can't trace a `JSTraceable` object, the memory can safely get freed by the garbage collector *i.e. not by Rust logic*.
|
1. Once the JS runtime (called SpiderMonkey) is aware of the existence of such a struct, its garbage collector looks at every field, looking for other `JSTraceable` contents. This type of GC is literally called [tracing garbage collection](XXX).
|
||||||
4. Not every `JSTraceable` struct lives inside another `JSTraceable`, so you can create a new GC "root" by saying `DomRoot::new(&ref_to_a_dom_struct)`. A root is simply one of many "starting points" for the GC's tracing.
|
|
||||||
|
1. Once SpiderMonkey can't trace a `JSTraceable` object, the memory can safely get freed by the garbage collector *i.e. not by Rust logic*.
|
||||||
|
|
||||||
|
1. Not every `JSTraceable` struct lives inside another `JSTraceable`, so you can create a new GC "root" by saying `DomRoot::new(&ref_to_a_dom_struct)`. A root is simply one of many "starting points" for the GC's tracing.
|
||||||
|
|
||||||
From a Rustacean's perspective this means that for complex tree structures like the DOM, one doesn't need to think quite so much about lifetimes, since one rarely stores plain references to anything, put rather an opaque "this value is part of the DOM and thus gets GC'd" type. Like so:
|
From a Rustacean's perspective this means that for complex tree structures like the DOM, one doesn't need to think quite so much about lifetimes, since one rarely stores plain references to anything, put rather an opaque "this value is part of the DOM and thus gets GC'd" type. Like so:
|
||||||
|
|
||||||
```rust
|
````rust
|
||||||
|
|
||||||
// "traditional" Rust
|
// "traditional" Rust
|
||||||
|
|
||||||
struct Node {
|
struct Node {
|
||||||
parent_node: Option<&Node>,
|
|
||||||
|
parent_node: Option<&Node>,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// GC'd by SpiderMonkey
|
// GC'd by SpiderMonkey
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
|
||||||
struct Node {
|
struct Node {
|
||||||
parent_node: Dom<Option<Node>>
|
|
||||||
|
parent_node: Dom<Option<Node>>
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
````
|
||||||
|
|
||||||
`Dom<T>` implement `Deref`, so you can still get ahold of a `&Node` by saying `&some_node.parent_node` etc. And you can at any time safely convert a `&Node` back to a traced `Dom<Node>` with `DomRoot::from_ref(some_node_ref)` (`DomRoot<T>` is a `Root<Dom<T>>`, the `Root` signifies that a new root has been stored for GC).
|
`Dom<T>` implement `Deref`, so you can still get ahold of a `&Node` by saying `&some_node.parent_node` etc. And you can at any time safely convert a `&Node` back to a traced `Dom<Node>` with `DomRoot::from_ref(some_node_ref)` (`DomRoot<T>` is a `Root<Dom<T>>`, the `Root` signifies that a new root has been stored for GC).
|
||||||
|
|
||||||
Are there any drawbacks? The main thing I've noted so far is that there are a lot of roots created "just in case", since it can be quite difficult to determine whether a root should be created or not. Picture a simple document with no JS scripting: optimally there would be only ONE root, which would be the containing `Document`, and all DOM objects can be found through that. But as soon as any type of JS gets involved, it's possible that the same object is reachable from many roots, which makes the garbage collector "double count" the same object. This is harmless, because all we care about is that the count is >0, but it can get wasteful.
|
Are there any drawbacks? The main thing I've noted so far is that there are a lot of roots created "just in case", since it can be quite difficult to determine whether a root should be created or not. Picture a simple document with no JS scripting: optimally there would be only ONE root, which would be the containing `Document`, and all DOM objects can be found through that. But as soon as any type of JS gets involved, it's possible that the same object is reachable from many roots, which makes the garbage collector "double count" the same object. This is harmless, because all we care about is that the count is >0, but it can get wasteful.
|
||||||
|
|
||||||
As a fairly new Rustacean, I was thankful for the option of being able to ignore lifetimes, since an XPath evaluator traverses the DOM tree quite intensely. At first I tried using only pure `&Node` references, but it quickly got messy. Someone more seasoned could probably optimize the code, but now I ended up creating a lot of extraneous roots for simplicity of the implementation.
|
As a fairly new Rustacean, I was thankful for the option of being able to ignore lifetimes, since an XPath evaluator traverses the DOM tree quite intensely. At first I tried using only pure `&Node` references, but it quickly got messy. Someone more seasoned could probably optimize the code, but now I ended up creating a lot of extraneous roots for simplicity of the implementation.
|
||||||
|
|
||||||
BIN
obsidian-export-aarch64-apple-darwin
Executable file
BIN
obsidian-export-aarch64-apple-darwin
Executable file
Binary file not shown.
BIN
obsidian-export-x86_64_unknown-linux-gnu
Executable file
BIN
obsidian-export-x86_64_unknown-linux-gnu
Executable file
Binary file not shown.
31
scripts/generate-blog-posts.sh
Executable file
31
scripts/generate-blog-posts.sh
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Detect the platform
|
||||||
|
PLATFORM="$(uname -s)"
|
||||||
|
ARCH="$(uname -m)"
|
||||||
|
|
||||||
|
# Determine which binary to use
|
||||||
|
if [ "$PLATFORM" = "Darwin" ]; then
|
||||||
|
if [ "$ARCH" = "arm64" ]; then
|
||||||
|
BINARY="obsidian-export-aarch64-apple-darwin"
|
||||||
|
else
|
||||||
|
echo "Unsupported architecture on macOS: $ARCH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
elif [ "$PLATFORM" = "Linux" ]; then
|
||||||
|
if [ "$ARCH" = "x86_64" ]; then
|
||||||
|
BINARY="obsidian-export-x86_64_unknown-linux-gnu"
|
||||||
|
else
|
||||||
|
echo "Unsupported architecture on Linux: $ARCH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Unsupported platform: $PLATFORM"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure the binary is executable
|
||||||
|
chmod +x "$BINARY"
|
||||||
|
|
||||||
|
# Run the appropriate binary
|
||||||
|
./"$BINARY" --start-at content-sources/obsidian-default/Blog content-sources/obsidian-default/ content/blog/
|
||||||
Loading…
x
Reference in New Issue
Block a user