mirror of
https://github.com/facundoolano/jorge.git
synced 2024-12-25 21:58:28 +01:00
start devlog (#18)
* remove sample posts * init first post * try not ignoring file creation events * draft why go section * more why go * why cli * finish first draft * reconnect with server after lost connection * corrections * more corrections * grammarly * remove docs section * update comment * remove doc index
This commit is contained in:
parent
fe42044405
commit
f733c83b1f
9 changed files with 88 additions and 111 deletions
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
@ -69,6 +70,7 @@ func makeServerEventsHandler(broker *EventBroker) http.HandlerFunc {
|
|||
// send an event to the connected client.
|
||||
// data\n\n just means send an empty, unnamed event
|
||||
// since we only need to support the single reload operation.
|
||||
fmt.Fprint(res, "retry: 1000\n")
|
||||
fmt.Fprint(res, "data\n\n")
|
||||
res.(http.Flusher).Flush()
|
||||
case <-req.Context().Done():
|
||||
|
@ -104,9 +106,10 @@ func setupWatcher(config *config.Config) (*fsnotify.Watcher, *EventBroker, error
|
|||
return
|
||||
}
|
||||
|
||||
// chmod events are noisy, ignore them. also skip create events
|
||||
// which we assume meaningless until the write that comes next
|
||||
if event.Has(fsnotify.Chmod) || event.Has(fsnotify.Create) {
|
||||
// chmod events are noisy, ignore them.
|
||||
// Also ignore dot file events, which are usually spurious (e.g .DS_Store, emacs temp files)
|
||||
isDotFile := strings.HasPrefix(filepath.Base(event.Name), ".")
|
||||
if event.Has(fsnotify.Chmod) || isDotFile {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<a href="/">{{ site.config.name }}</a>
|
||||
<a href="/tutorial/">tutorial</a>
|
||||
<a href="/blog/">devlog</a>
|
||||
<a href="/docs/">docs</a>
|
||||
|
||||
<div class="nav-right hidden-mobile">
|
||||
<a href="https://github.com/facundoolano/jorge">github</a>
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
title: Goodbye Markdown...
|
||||
tags: [blog]
|
||||
date: 2024-02-16
|
||||
layout: post
|
||||
---
|
||||
|
||||
## For the record
|
||||
|
||||
For the record, even though it has *org* in the name, jorge can also render markdown,
|
||||
thanks to [goldmark](https://github.com/yuin/goldmark/).
|
||||
|
||||
Let's look at some code:
|
||||
|
||||
``` python
|
||||
import os
|
||||
|
||||
def hello():
|
||||
print("Hello World!")
|
||||
os.exit(0)
|
||||
|
||||
hello()
|
||||
```
|
||||
|
||||
[Next time](./hello-org), I'll talk about org-mode posts.
|
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
title: Hello Org!
|
||||
subtitle: Writing posts with org-mode syntax
|
||||
tags: [blog, emacs]
|
||||
date: 2024-02-17
|
||||
layout: post
|
||||
---
|
||||
#+OPTIONS: toc:nil num:nil
|
||||
|
||||
** Indeed
|
||||
|
||||
This post was originally written with org-mode syntax, instead of [[file:goodbye-markdown][markdown]].
|
||||
|
||||
As you can see, /italics/ and *bold* render as expected, and you can even use footnotes[fn:1].
|
||||
|
||||
All of this is powered by [[https://github.com/niklasfasching/go-org][go-org]], btw[fn:2].
|
||||
|
||||
Let's look at some code:
|
||||
|
||||
#+begin_src python
|
||||
import os
|
||||
|
||||
def hello():
|
||||
print("Hello World!")
|
||||
os.exit(0)
|
||||
|
||||
hello()
|
||||
#+end_src
|
||||
|
||||
** Notes
|
||||
|
||||
[fn:1] See?
|
||||
|
||||
[fn:2] And another one footnote, to stay on the safe side.
|
|
@ -3,12 +3,6 @@ layout: default
|
|||
title: Devlog
|
||||
---
|
||||
|
||||
{% assign posts_by_year = site.posts | group_by_exp:"post", "post.date | date: '%Y'" %}
|
||||
{% for year in posts_by_year %}
|
||||
{% unless forloop.first%}
|
||||
<br/>
|
||||
{% endunless %}
|
||||
{% for post in year.items %}
|
||||
{% include post_preview.html %}
|
||||
{% endfor %}
|
||||
{% for post in site.posts | reverse %}
|
||||
{% include post_preview.html %}
|
||||
{% endfor %}
|
||||
|
|
64
docs/src/blog/why.org
Normal file
64
docs/src/blog/why.org
Normal file
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
title: Why?
|
||||
date: 2024-02-28
|
||||
layout: post
|
||||
lang: en
|
||||
tags: [project, golang]
|
||||
excerpt: I set out to write a little static site generator, but why?
|
||||
---
|
||||
#+OPTIONS: toc:nil num:nil
|
||||
#+LANGUAGE: en
|
||||
|
||||
I set out to write a little static site generator, but why?
|
||||
|
||||
*** Why this project?
|
||||
I wanted to learn the Go programming language, and my preferred way to learn a new language is to use it on some open-source project[fn:1].
|
||||
|
||||
*** Why Go?
|
||||
|
||||
In the past I studied new programming languages to "broaden my programming horizons";
|
||||
to add better, more sophisticated tools to my toolbox: new paradigms, concurrency models, type systems. Because I never used it in college and never needed it for work, and because it seemed to lack this novelty factor, I never got around to trying Go.
|
||||
|
||||
But, over the last few years, there has been a shift in how I assign value to technology. I don't underestimate the value of trying different things and broadening my horizons, but I find the choice of sophisticated technology hard to justify for most real-world projects: in the long term, the complexity they add outweighs the value they bring. In turn, I became less and less enthusiastic about studying technology that I don't expect to ever apply ---that I wouldn't dare to inflict--- to the real world.
|
||||
|
||||
The very reason why I had avoided Go in the past, now compelled me to give it a try:
|
||||
Go seemed to be an unpretentious, boring language ---and I mean that as [[https://mcfunley.com/choose-boring-technology][a compliment]]---, one that combined many of the features I came to value (or miss) in other languages:
|
||||
|
||||
- A powerful concurrency model that's built into the language rather than an afterthought.
|
||||
- A static type system that's neither astonishing nor bureaucratic.
|
||||
- A good balance between high-level programming and performance.
|
||||
- A gentle learning curve.
|
||||
- Compilation to easy to distribute and operate binaries.
|
||||
|
||||
That's the preconception I had about Go, having read about it but never used it. I wanted to spend some time with it because, if these presumptions turned out to be right, Go could become the obvious default for many of my future projects ---and an accurate boring tech radar.
|
||||
|
||||
*** Why a command-line application?
|
||||
Go is famously good for building server-side software, so that was the first space I turned to when looking for project ideas. I briefly considered following the [[https://pragprog.com/titles/tjgo/distributed-services-with-go/][/Distributed Services with Go/ book]], but I felt that I wouldn't get enthusiastic enough about that project to see it through to completion. More generally, I suspected that any backend-only project would turn into a useless toy I wouldn't care for. I needed something user-facing.
|
||||
|
||||
Could I use Go to implement the backend of a web application, instead? That would've made sense, but I was just [[https://olano.dev/2023-12-12-reclaiming-the-web-with-a-personal-reader/][coming out]] of working on a medium-sized web application[fn:2]; I knew too well that much of the effort in such a project would go into the front end, and I needed a break from that.
|
||||
|
||||
What else, then? Other than servers, Go is known to be good at command-line applications. I enjoy working on CLIs; they challenge me to design and reason about the user experience without most of the graphical interface struggle. A CLI app sounded promising.
|
||||
|
||||
*** Why a static site generator?
|
||||
|
||||
I read somewhere that a blog is the ideal learning project for software developers: it can get as simple or as complex as you want, it exposes you to the entire web stack, from server setup to UI design, and when it's working you are encouraged to write about something (most likely about setting up a blog).
|
||||
|
||||
That notion, projected into the CLI application space, yields a static site generator: a command-line tool to set up blogs. For a number of reasons, this seemed like the kind of project I was looking for:
|
||||
|
||||
- I knew static site generators were useful because I'd been using one (Jekyll) for years.
|
||||
- Moreover, since I had recently rewritten my blog from scratch, I knew what I'd like to reproduce and what to change from Jekyll, and I knew that, at least on a first look, it was about the project size I was looking for: not so small as to be boring, not so big as to get out of hand.
|
||||
- I knew that it was a feasible Go project because one of the most popular static site generators, Hugo, is written in Go.
|
||||
|
||||
Assuming I would implement the local serving functionality (i.e. ~jekyll serve~), I could even go beyond the file manipulation tasks and touch on some of the concurrency and HTTP features of Go.
|
||||
|
||||
Working on a site generator also meant that I could use the project to generate its own documentation and potentially to keep a development blog; to "dogfood", using the software myself as I was building it.
|
||||
|
||||
-----
|
||||
|
||||
With that reasoning, I arrived at a project idea that seemed appropriate for my goals, feasible, and interesting. This was enough to give me the first push to start working on it, but I still needed to outline the user interface and the project plan before a few more of the pieces fell into place. I'll get to that next time.
|
||||
|
||||
** Notes
|
||||
|
||||
[fn:1] I've done it before with [[https://github.com/facundoolano/advenjure][Clojure]] and [[https://github.com/facundoolano/rpg-cli][Rust]].
|
||||
|
||||
[fn:2] Incidentally, a project that I felt was ideal for Go, had I already been fluent with it.
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
title: Docs
|
||||
---
|
||||
|
||||
Comming soon!
|
||||
|
||||
<ul>
|
||||
{% for page in site.pages|where:"dir", "/docs"|sort:"index" %}
|
||||
<li>
|
||||
<a class="title" href="{{ page.url }}">{{ page.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
|
@ -51,23 +51,9 @@ $ jorge serve
|
|||
|
||||
<h2><a href="/blog" class="title" id="devlog">Devlog</a></h2>
|
||||
|
||||
Coming soon!
|
||||
|
||||
{% comment %}
|
||||
{% for post in site.posts limit:3 %}
|
||||
{% for post in site.posts | reverse limit:5 %}
|
||||
{% include post_preview.html %}
|
||||
{% endfor %}
|
||||
|
||||
<p>See the full <a href="/blog">blog archive</a> or subscribe to the <a href="/feed.xml">feed</a>.</p>
|
||||
{% endcomment %}
|
||||
|
||||
<h2><a href="/docs" class="title" id="docs">Docs</a></h2>
|
||||
Coming soon!
|
||||
<ul>
|
||||
{% for page in site.pages|where:"dir", "/docs"|sort:"index" %}
|
||||
<li>
|
||||
<a class="title" href="{{ page.url }}">{{ page.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
25
site/site.go
25
site/site.go
|
@ -387,17 +387,22 @@ func (site *Site) injectLiveReload(extension string, contentReader io.Reader) (i
|
|||
|
||||
const JS_SNIPPET = `
|
||||
const url = '%s/_events/'
|
||||
const eventSource = new EventSource(url);
|
||||
|
||||
eventSource.onmessage = function () {
|
||||
location.reload()
|
||||
};
|
||||
window.onbeforeunload = function() {
|
||||
eventSource.close();
|
||||
var eventSource;
|
||||
function newSSE() {
|
||||
console.log("connecting to server events");
|
||||
eventSource = new EventSource(url);
|
||||
eventSource.onmessage = function () {
|
||||
location.reload()
|
||||
};
|
||||
window.onbeforeunload = function() {
|
||||
eventSource.close();
|
||||
}
|
||||
eventSource.onerror = function (event) {
|
||||
console.error('An error occurred:', event);
|
||||
setTimeout(newSSE, 1000)
|
||||
};
|
||||
}
|
||||
eventSource.onerror = function (event) {
|
||||
console.error('An error occurred:', event)
|
||||
};`
|
||||
newSSE();`
|
||||
script := fmt.Sprintf(JS_SNIPPET, site.Config.SiteUrl)
|
||||
return markup.InjectScript(contentReader, script)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue