Greg Hurrell [Wed, 17 Aug 2022 06:39:02 +0000 (08:39 +0200)]
docs: update Synergy version support info
Just got an email from somebody who thought from the "and above" and "or
later" text that Synergy would work on later versions of macOS. That
text was written years ago (in some cases, over a decade ago), so it is
sorely out of date and wasn't written in a future-proof way. Update it
for clarity.
and the consensus seems to be it's a bad idea, but only for some
non-English languages, and all my content is in English.
This will stop pages like:
https://wincent.com/wiki/macOS_%22must_haves%22
which have long URLs visible inside `a` tags from looking like crap on
mobile (where they overflow the width and make the page too wide,
creating a horizontal scroll).
Greg Hurrell [Thu, 16 Dec 2021 08:11:34 +0000 (09:11 +0100)]
chore: switch license to MIT
Had only been using CC-BY-NC-SA-4 because Corporate Overlords at
previous job had recommended it for use in personal projects. Left there
some years ago, and MIT is a better fit in the JS ecosystem.
Greg Hurrell [Mon, 13 Dec 2021 22:16:17 +0000 (23:16 +0100)]
feat: implement retry/reconnect on Redis client
At the moment I am just catching the two most obvious possible errors;
EPIPE and ECONNREFUSED, but the truth is there are others that might
conceivably occur — from:
maybe ECONNRESET and ETIMEDOUT (even though Node sockets don't time out
by default) are obvious candidates... I might end up just doing a
blanket retry, too... not sure.
Greg Hurrell [Mon, 13 Dec 2021 17:57:45 +0000 (18:57 +0100)]
chore: remove express-graphql
I was only using it as a shortcut to getting GraphiQL in dev, but the
schema is basically "finished" at this point and I don't think I'm going
to need to troubleshoot it again (if I'm wrong about that, I can easily
revert this change). In the meantime, killing this is a small step
towards reducing the dependency footprint.
Greg Hurrell [Sun, 12 Dec 2021 22:25:55 +0000 (23:25 +0100)]
chore: remove dead code
I initially thought I might use these, which correspond to the commands
that I actually use, but in reality, I only use `get()`, and all the
others get used via `multi()`.
Now, when I start rewriting stuff in TypeScript, there will be some
value in having named methods like this, although I will probably want
to expose them on `multi()` like this:
multi()
.zrange(...)
.zcard(...)
.exec();
as opposed to calling them individually (but having said that, I kind of
like the way the array calling convention mirrors the array result, so I
might see how far I can get with static types using that approach...)
Greg Hurrell [Sun, 12 Dec 2021 14:10:03 +0000 (15:10 +0100)]
fix: add back PropTypes import
I was moving quickly and not paying attention, but I _think_ the LSP
told me this was unused so I just deleted it. Or perhaps I blew it away
by accident while trying to delete the comment right above it.
Greg Hurrell [Sun, 12 Dec 2021 13:55:26 +0000 (14:55 +0100)]
fix: don't leak event listeners
Because we were setting up an `on('line')` listener for every command
we ran, we were leaking these quite badly. Wouldn't be a problem if
the clients were short-lived (because when the client is GC'd, the
emitter/listener would go away, because the emitter and the listeners
are all the same object), but the clients live for as long as the server
process runs.
Greg Hurrell [Sun, 12 Dec 2021 10:16:26 +0000 (11:16 +0100)]
chore: clean up additional Flow loose ends
Some stuff that didn't get covered in the last commit, which I made
with:
yarn global add flow-remove-types
flow-remove-types --pretty src -d lib
cp -R lib/* src/
yarn run pretty
Then I backed out the changes to `**/__generated__/*` files.
Now I've swept through, cleaning up empty comments, removing lint
suppressions etc, as well as converting the `scripts/` directory that I
had neglected, and removing some type-only imports.
Greg Hurrell [Sun, 12 Dec 2021 10:09:57 +0000 (11:09 +0100)]
chore: remove unused Flow types
I stopped using Flow a while ago, and have a pending ticket open for
porting to TypeScript[^1], and another in-progress rewrite anyway[^2]...
so for now these are mostly just noise (at best, you can consider them
as inline documentation that might go stale).
[^1]: https://github.com/wincent/masochist/issues/142
[^2]: https://github.com/wincent/masochist/issues/140 — although note
the ticket is nominally about updating the Relay version, which is way
behind, but which is tantamount to doing a full rewrite anyway because
so much is going to have to change.
Greg Hurrell [Sun, 12 Dec 2021 09:55:16 +0000 (10:55 +0100)]
refactor: switch `then()` to use `async`/`await` instead
Micro-refactoring that collapses 4 lines into 3 in a couple of places.
(Places, BTW, that I could DRY up by extracting out the common
functionality, but I don't won't to because the dumb and simple
duplicated version is easier to read.)
Greg Hurrell [Sun, 12 Dec 2021 09:51:41 +0000 (10:51 +0100)]
refactor: turn lines into a property
As all we ever do is pass it around unconditionally without changing it.
I originally had it as a param because I wasn't sure whether it was
going to be needed everywhere.
Greg Hurrell [Sat, 11 Dec 2021 23:36:57 +0000 (00:36 +0100)]
refactor: make redis client more robust
I tried a few things here but eventually "settled" on this design; that
is to say, I wanted to make the async handling a bit more
robust/idiomatic, so I explored using an async generator, then switched
to using an async iterator. The problem should fix is that when we are
pipelining a bunch of commands and executing them with MULTI + EXEC, we
may get several data payloads back with the responses. In the parent
commit, I could run the little test case multiple times, and my MULTI
request would sometimes get 4 `undefined` responses, or 1, or none.
I think I've fixed that now, and just need to add in error handling
everywhere, but we don't actually expect too many errors as Redis should
pretty reliably return exactly what I'm asking it for.
How does this work? Basically, we want to be able to `await` one line at
a time until we've got everything we need, hence the async iterator.
This ended up being a bit more useful than the generator because we can
pass it around (eg. to parse bulk strings in a subroutine) or into a
recursive call (which we need in order to parse maps, sets, arrays etc).
Greg Hurrell [Fri, 10 Dec 2021 23:36:11 +0000 (00:36 +0100)]
refactor: cut over to WIP Redis client
As noted in parent commit, it has some problems, but it still works well
enough to render the blog index in the local development environment
(this is the only page I've tested so far, and I only tested it once, so
you _know_ this is good).
Split up big file into smaller files so that I can keep things tidy as I
slowly refactor this into something robust.
Greg Hurrell [Fri, 10 Dec 2021 22:16:21 +0000 (23:16 +0100)]
feat: add more stuff to WIP redis client
As noted from the TODOs inline, still lots of missing pieces, and it's
not totally robust. Oh, and also, it's ugly. But it is pretty much
"feature complete" at this point and just needs to be fixed up, cleaned
up, and redesigned a bit. Ha.
So something crude like this is probably going to be enough. It is
definitely not going to be efficient, but the payloads we are talking
about here are miniscule, so it really won't matter.
Still to do:
- Implement error handling.
- Add `multi` support.
- Address missing features and "TODOs" noted inline (for example, we
aren't bailing early if we get an incomplete response).
- Add reconnect.
- Maybe write some tests.
Adding this as a .txt file just to show that it's not intended for
actual execution yet, but I do want it in version control in case my
machine dies.
Greg Hurrell [Wed, 8 Dec 2021 18:13:54 +0000 (19:13 +0100)]
chore: back out redis "upgrade"
Because it's not worth it.
The `ZREVRANGE` command is not implemented, which breaks things for us.
Note that we can get the same with `ZRANGE` and passing a `REV` option:
https://github.com/redis/node-redis/issues/1705
but that still leaves headaches elsewhere, where we were using
`ZREVRANGE` with the `WITHSCORES` option. This isn't supported by the
npm package, even though Redis itself supports it:
https://redis.io/commands/zrange
The suggestion is to switch overt to `ZRANGEBYSCORE` instead, but that
is starting to sound awfully like a hassle.
Greg Hurrell [Wed, 8 Dec 2021 17:57:53 +0000 (18:57 +0100)]
refactor: switch multi invocation to v4 style
As documented here:
https://github.com/redis/node-redis
But here's the interesting thing about it — it doesn't work for all
Redis commands. So, for example, we can hit a blog permalink page just
fine but not a page using a reverse-sorted index, like the blog index
page.
This shows up as a server crash:
TypeError: Cannot read property 'posts' of null
at PostsIndex.render (/Users/wincent/code/masochist/src/client/components/PostsIndex.js:64:35)
Dicking around in the console I established that the API works for some
commands but not others; for example, `ZREVRANGE` is missing, but
`ZCARD` is not:
in loop ZREVRANGE masochist:6:blog-index [ 0, 2 ]
command undefined
in loop ZCARD masochist:6:blog-index []
command [Function (anonymous)]
So, if I can't find a way to work around this I may just have to
"downgrade" (that is, "upgrade") to the previously working version of
the software.
Now that I've got the production site back up by "rolling back" to the
prior rev, I'm doing this revert (to the bad rev) in the hope of
reproducing locally and finding out what's going on.
This reverts the last 13 commits because something isn't liking the
changes in prod, where the server serves up the top part of the document
and then nothing.
"Rolling back" in order to do some troubleshooting.
Greg Hurrell [Wed, 8 Dec 2021 16:34:20 +0000 (17:34 +0100)]
chore: update Prettier
Although note that we still have an old duplicate copy lying around
because:
=> Found "graphql-relay#prettier@1.19.1"
info This module exists because "graphql-relay" depends on it.
I don't know/recall why it has it as a non-dev dependency; all its other
deps are under `devDependencies`... looking, seems it is unintended and
was fixed in:
Greg Hurrell [Wed, 8 Dec 2021 16:04:38 +0000 (17:04 +0100)]
chore: update webpack-dev-server
Note that I had to go through a few tweak-restart loops to flush out all
the problems:
ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options has an unknown property 'noInfo'. These properties are valid:
ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options has an unknown property 'publicPath'. These properties are valid:
(node:46306) [DEP_WEBPACK_DEV_SERVER_CONSTRUCTOR] DeprecationWarning: Using 'compiler' as the first argument is deprecated. Please use 'options' as the first argument and 'compiler' as the second argument.
(node:46332) [DEP_WEBPACK_DEV_SERVER_LISTEN] DeprecationWarning: 'listen' is deprecated. Please use async 'start' or 'startCallback' methods.
<w> [webpack-dev-server] "hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.
Greg Hurrell [Wed, 8 Dec 2021 15:07:45 +0000 (16:07 +0100)]
chore: update to webpack
This is the minimal set of changes specified in:
https://webpack.js.org/migrate/5/
with tweaks to make `yarn start` and `yarn build` complete without
errors.
Note I had to get rid of the `!` chaining syntax, as noted here:
Error: Compiling RuleSet failed: Exclamation mark separated
loader lists has been removed in favor of the 'use'
property with arrays (at ruleSet[1].rules[2].loader:
style-loader!css-loader!postcss-loader)
`yarn build` spews out a lot of deprecation notices and other warnings
(edited for readability):
(node:33331) [DEP_WEBPACK_MAIN_TEMPLATE_RENDER_MANIFEST] DeprecationWarning: MainTemplate.hooks.renderManifest is deprecated (use Compilation.hooks.renderManifest instead)
(Use `node --trace-deprecation ...` to show where the warning was created)
(node:33331) [DEP_WEBPACK_CHUNK_TEMPLATE_RENDER_MANIFEST] DeprecationWarning: ChunkTemplate.hooks.renderManifest is deprecated (use Compilation.hooks.renderManifest instead)
(node:33331) [DEP_WEBPACK_MAIN_TEMPLATE_HASH_FOR_CHUNK] DeprecationWarning: MainTemplate.hooks.hashForChunk is deprecated (use JavascriptModulesPlugin.getCompilationHooks().chunkHash instead)
(node:33331) [DEP_WEBPACK_COMPILATION_OPTIMIZE_CHUNK_ASSETS] DeprecationWarning: optimizeChunkAssets is deprecated (use Compilation.hooks.processAssets instead and use one of Compilation.PROCESS_ASSETS_STAGE_* as stage option)
(node:33331) [DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK] DeprecationWarning: Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader
[16:06:38] Finished 'graphql' after 2.18 s
(node:33331) [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning: Compilation.assets will be frozen in future, all modifications are deprecated.
BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation.
Do changes to assets earlier, e. g. in Compilation.hooks.processAssets.
Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.
(node:33331) [DEP_WEBPACK_MODULE_ID] DeprecationWarning: Module.id: Use new ChunkGraph API
(node:33331) [DEP_WEBPACK_MODULE_UPDATE_HASH] DeprecationWarning: Module.updateHash: Use new ChunkGraph API
(node:33331) [DEP_WEBPACK_CHUNK_MODULES_ITERABLE] DeprecationWarning: Chunk.modulesIterable: Use new ChunkGraph API
(node:33331) [DEP_WEBPACK_CHUNK_GROUP_GET_MODULE_INDEX_2] DeprecationWarning: ChunkGroup.getModuleIndex2 was renamed to getModulePostOrderIndex
(node:33331) [DEP_WEBPACK_COMPILATION_CACHE] DeprecationWarning: Compilation.cache was removed in favor of Compilation.getCache()
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
bundle-45d526449584b2234f04.js (525 KiB)
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
main (541 KiB)
styles-a5a8105f24841352a5be.css
bundle-45d526449584b2234f04.js
WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
main (425 KiB)
styles-a5a8105f24841352a5be.css
bundle-8ff3e30a9a2750cb82ed.mjs
WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Greg Hurrell [Wed, 8 Dec 2021 14:33:44 +0000 (15:33 +0100)]
chore: update some CSS dependencies
To avoid this deprecation warning caused by a transitive dep,
es-abstract, as seen on the machine I'm currently on, which happens to
have NodeJS v16.8.0:
(node:25719) [DEP0148] DeprecationWarning: Use of deprecated folder mapping "./" in the "exports" field module resolution of the package at $HOME/code/masochist/node_modules/es-abstract/package.json.
Update this package.json to use a subpath pattern like "./*".
at emitFolderMapDeprecation (node:internal/modules/esm/resolve:88:11)
at packageExportsResolve (node:internal/modules/esm/resolve:648:7)
at resolveExports (node:internal/modules/cjs/loader:482:36)
at Function.Module._findPath (node:internal/modules/cjs/loader:522:31)
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:919:27)
at Function.Module._load (node:internal/modules/cjs/loader:778:27)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:94:18)
at Object.<anonymous> ($HOME/code/masochist/node_modules/object.values/implementation.js:3:10)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
So, updated cssnano from 4.1.10 to 5.0.12, because that's the one that
was pulling in es-abstract. That, in turn, required a couple of other
updates. postcss got bumped to 8.4.4 (we still have some duplicate
divergent versions hiding away in various places though), as per `yarn
why postcss`:
=> Found "postcss@8.4.4"
info Has been hoisted to "postcss"
info This module exists because it's specified in "dependencies".
=> Found "css-loader#postcss@7.0.27"
info This module exists because "css-loader" depends on it.
=> Found "autoprefixer#postcss@7.0.27"
info This module exists because "autoprefixer" depends on it.
=> Found "icss-utils#postcss@7.0.27"
info This module exists because "css-loader#icss-utils" depends on it.
=> Found "postcss-modules-local-by-default#postcss@7.0.27"
info This module exists because "css-loader#postcss-modules-local-by-default" depends on it.
=> Found "postcss-modules-extract-imports#postcss@7.0.27"
info This module exists because "css-loader#postcss-modules-extract-imports" depends on it.
=> Found "postcss-modules-scope#postcss@7.0.27"
info This module exists because "css-loader#postcss-modules-scope" depends on it.
=> Found "postcss-modules-values#postcss@7.0.27"
info This module exists because "css-loader#postcss-modules-values" depends on it.
and postcss-loader went from 3.0.0 to 4.2.0; I couldn't go all the way
to the latest (6.2.1), because that depends on webpack v5, and I'm on
v4:
I'll look at doing some more updates in separate commits, as these
things tend to be such a cluster that it is best to approach them
incrementally and check that things are still working along the way.
Greg Hurrell [Sat, 4 Dec 2021 11:56:57 +0000 (12:56 +0100)]
refactor: change overflow-wrap from "anywhere" to "break-word"
Because "anywhere" is considered an invalid value by Safari, which means
that long `<code>` spans in my blog posts look crap on iOS (even in
Chrome, which is really a thin skin over WebKit on iOS), causing
unwanted horizontal scrolling.
I think this should be adequate. Should work in Chrome and Firefox too.
As described in:
> **normal**
> Lines may only break at normal word break points (such as a space
> between two words).
>
> **anywhere**
> To prevent overflow, an otherwise unbreakable string of characters
> — like a long word or URL — may be broken at any point if
> there are no otherwise-acceptable break points in the line. No
> hyphenation character is inserted at the break point. Soft wrap
> opportunities introduced by the word break are considered when
> calculating min-content intrinsic sizes.
>
> **break-word**
> The same as the anywhere value, with normally unbreakable words
> allowed to be broken at arbitrary points if there are no otherwise
> acceptable break points in the line, but soft wrap opportunities
> introduced by the word break are NOT considered when calculating
> min-content intrinsic sizes.
Looking back over the history, I don't think I've tried this before.
See the output of `git log -Goverflow-wrap -p`, and specifically some
interesting commits like:
Greg Hurrell [Fri, 3 Dec 2021 23:51:49 +0000 (00:51 +0100)]
chore: update React 16.13.0 → 17.0.2
Was hoping this would fix some bugs I'm seeing around how click events
are handled (specifically, jump to and back from footnotes is only
working on the first click, or when JS is disabled), but it didn't.
Doesn't hurt to update though, as far as I can tell, so may as well keep
the change.
Greg Hurrell [Fri, 3 Dec 2021 21:33:40 +0000 (22:33 +0100)]
refactor: start using CSS custom properties
The copy-pasted hex values have long been getting on my nerves. There
are still lots of hard-coded values to be migrated, but I just want to
port a few to serve as a reminder of the direction I want to head in.
Greg Hurrell [Fri, 3 Dec 2021 20:37:18 +0000 (21:37 +0100)]
feat: add support for footnotes
Now that GitHub supports footnotes, I find myself in the habit of using
them there pretty often and therefore wanting to use them here too.
I am not sure if I am fully sold on the design here, but I'm passing in
a DOM identifier so that the `id` attributes in the generated markup can
be unique. One question, for example, is should this field be nullable?
Another is is "DOMIdentifier" the right name? (I wanted to avoid
confusion with GraphQL "id" fields.) Should I be doing more with these
IDs, like using them on title anchor tags? (probably not). Should I
tighten up the schema documentation, where it misleadingly talks of
"prefix"? (As you can see from the link below, the "DOMIdentifier" ends
up being embedded somewhere in the middle of an ID.)
Anyway, all this is possible by setting `docId`, which you can see being
used to construct the anchor names here:
Possible follow-ups: want to check the contrast levels for accessibility
because I eye-balled these and they are probably horrible. May in
general want to do a pass on the styles to make sure they look as pretty
as they should be.
Deprecated as of 10.7.0. highlight(lang, code, ...args) has been deprecated.
Deprecated as of 10.7.0. Please use highlight(code, options) instead.
https://github.com/highlightjs/highlight.js/issues/2277
By running `yarn`. It always seems to want to make changes after
`yarn-deduplicate` has run. As you can see, it also removed a bunch of
dead(?) pages from the cache.
fix: don't break words in <code> elements quite so aggressively
The recent addition of `overflow-wrap: anywhere` was breaking my lovely
tag lozenges, which probably shouldn't be using `<code>` anyway because
they aren't code...
Chrome seems pretty flaky with `box-decoration-break`. ie. in order to
see the difference between "clone" and "slice" I need to toggle the
border on and off again. Whatever; I think the wrapped spans look better
without borders or rounded corners anyway, so removing those. Also
experimented with bold but it is too heavyweight for my taste.
Greg Hurrell [Sun, 13 Jun 2021 21:17:15 +0000 (23:17 +0200)]
fix: remove bad index.php
Whoops. I had this formerly harmless file in here, but when we added
`index.php` to our nginx `try_files` directive, it started getting
served up to visitors hitting the root. :facepalm:
So let's kill it, and if anybody goes to https://wincent.com/index.php
they'll just get a 404, which is fine.
Greg Hurrell [Sat, 12 Jun 2021 23:50:23 +0000 (01:50 +0200)]
refactor: clean up links
Motivation is to avoid broken images caused by CSP violations (eg.
images hosted on www from non-www pages), but there are too many files
to do this in a non-automated way so this is just the dumbest of dumb
changes:
Greg Hurrell [Sat, 12 Jun 2021 22:17:25 +0000 (00:17 +0200)]
chore: add some static files from old hosts
I want to "decommission" the hosts running at www.wincent.com and
secure.wincent.com without breaking any links, if I can help it. They
contain a bunch of PHP pages that do some very simple stuff like
composing a header and a footer and so on. There are only two (basically
dead) pages that handle POST requests.
So, I made this simple Ruby script that runs on the hosts and `curl`s
the pages (and other resources), taking a snapshot of everything. I
normally don't like leaking internal paths like this, but like I said,
the machines are going off the net forever shortly, so it's ok.
The directories that are guarded by .htaccess files all return 403s as
intended, so I haven't included those files in the dump.
As follow up I am going to have to tweak DNS records and SSL
certificates (SAN entries). But then I'll be able to kill off the old
servers.
require 'fileutils'
require 'shellwords'
def escape(word)
Shellwords.shellescape word
end
# Note: we don't have to worry about simlinks over here;
# both directories contain only directories and regular files
#
# find /var/www/secure.wincent.com/public_html -type l
# find /var/www/www.wincent.com/public_html -type l
#
%w[
/var/www/secure.wincent.com/public_html
/var/www/www.wincent.com/public_html
].each do |base|
puts "Scraping from: #{base}"
# Note that `Dir.[]` won't return dot-files, so we miss out on:
#
# $ find /var/www/www.wincent.com/public_html -name '.*'
# /var/www/www.wincent.com/public_html/.well-known
#
# and:
#
# $ find /var/www/secure.wincent.com/public_html -name '.*'
# /var/www/secure.wincent.com/public_html/a/products/install/licensees/binary-only/.htaccess
# /var/www/secure.wincent.com/public_html/a/products/install/licensees/full-source/.htaccess
# /var/www/secure.wincent.com/public_html/a/products/install/licensees/binary+framework/.htaccess
# /var/www/secure.wincent.com/public_html/a/products/install/licensees/.htaccess
# /var/www/secure.wincent.com/public_html/codegen/.htaccess
# /var/www/secure.wincent.com/public_html/.well-known
#
Dir["#{base}/**/*"].each do |source|
host = "#{source}".split(%r{/})[3]
path = "#{source}".split(%r{/})[5..-1].join('/')
destination = File.join(__dir__, 'output', source)
if File.file? source
if system "curl --silent https://#{host}/#{escape path} -o #{escape destination}"
puts " OK : #{host}/#{path}"
else
puts "FAIL: #{host}/#{path}"
end
else
FileUtils.mkdir_p destination
end
end
end