🖼️ Notion + Jekyll images synchronization
Recently, I successfully set up Notion + Jekyll synchronization using the jekyll-fetch-notion plugin. It has been meeting all my needs until my previous post, where I needed to attach some images. Images must be fetched from Notion and stored under git conrol, so here is a recipe for appeared problem.
What is the problem
I will remind you how our synchronization works. So, we have a pipeline called .gitlab-ci.yml
, which (briefly):
- Runs the
jekyll fetch_notion
command, which pulls everything from Notion, converts it to.md
, and places everything inside your repository. - Stages all the newly pulled
.md
files, performs agit-commit
for any new changes, andgit-push
them. - A new commit in the repository then triggers another pipeline, which builds and deploys the site.
It works great when our posts don’t have any images. The problem with images is that Notion generates a unique short-lived URL for them every time, and after a few minutes, these URLs stop working. This problem is relevant not only to the git-based Notion synchronization approach.
You can solve it without any additional code just by embedding images via a direct URL. Then, Notion won’t save them on their servers, and the output will always be the same. By doing so, you will always need to manually publish images to your site before posting. Well, it sounds uncomfortable, but at least it works.
How to solve it right
I prefer to follow a git-based approach here as well and save images to the repository using the fetch_notion
command. All we need to do is monkey-patch the handling of the image
block. Here is an example of how to work with block handling in general and how to handle custom blocks that are not handled by default: Embedding videos with jekyll-notion.
So, we are overriding the image
block handling like this:
require 'open-uri'
module NotionToMd
module Blocks
class Types
class << self
def image(block)
type = block[:type].to_sym
url = URI.parse(block.dig(type, :url))
# we can also retrieve a caption here like this:
# caption = convert_caption(block)
# https://example.com/filename.jpg?queryParams -> filename.jpg
filename = "assets/#{url.to_s.split('/')[-1].split('?')[0]}"
IO.copy_stream(url.open, filename)
Jekyll.logger.info("Image #{File.absolute_path(filename)} #{"OK".green}")
return "![](#{filename})"
# or you can use jekyll_picture_tag plugin and return liquid
# tag "picture" here, which automatically generates responsive
# images for you.
end
end
end
end
end
You should put it into _plugins/notion_to_md/blocks/types.rb
(or any other .rb
file inside _plugins
directory) to make it works. Also you must include the following lines to Gemfile
:
# Fetching files easily
gem 'open-uri'
# if you are going to use responsive images plugin
group :jekyll_plugins do
# ...
# github.com/rbuchberger/jekyll_picture_tag
gem 'jekyll_picture_tag', '2.0.4'
end
That’s it! Now your images will be stored in a repository during the fetch_notion
command.
Side note: How to make monkey-patching available for jekyll commands
One more thing to note is that monkey-patching is not available for every single Jekyll command by default. To make it work, your command must initialize a Jekyll::Site
object during the processing; otherwise, your .rb
won’t be loaded. That’s how I did it for the fetch_notion
command:
module JekyllNotion
class FetchCommand < Jekyll::Command
def self.init_with_program(p)
p.command(:fetch_notion) do |c|
# ...
c.action do |args, options|
process(args, options)
end
end
end
def self.process(args = [], options = {})
@config = configuration_from_options(options)
# ...
# requires plugins (and _plugins/ directory) to be able to
# define custom notion_to_md blocks via monkey-patching
site = Jekyll::Site.new(@config)
# ...
end
end
Just left this note here because actually, it was hard to find this out as long as it isn’t documented anywhere.
Conclusion
Thank you for reading this little article, I hope it will be useful to someone. Feel free to reach me if you have something to say.
And also take a look on the posts on similar topics: