This article was sent via Craft Extension

✍🏼 Written on Dec 8, 2021    💡 Updated on Feb 28, 2022
❗️ Note: it has been days since this article was written, please be aware of its timeliness

Some of the workflow solutions described in this article are outdated. The new workflow logic can be found here: https://www.xheldon.com/tech/my-blog-ci-in-2022.html

Spent two days figuring out a simple way to write content in Craft, sync it to a Github repository via a custom plugin, and have the Github repository automatically build and deploy to Github Pages.

Repository address: https://github.com/craft-extension/craft-github-extension

Changes to the Blog Update Process

Previous Workflow

Write in VSCode → Commit to x_blog_src repository → Trigger Github Action → Build and commit to x_blog repository → Success

However, this process had some pain points:

  1. You might not finish an article in one sitting but write intermittently. If you wrote part of it on your work computer, you’d need to commit to Github first, then continue writing on your home computer. Each commit would trigger the Github Action. My solution was to check the commit message for a specific prefix—commits with the prefix would trigger a build, while those without would be ignored. Still, this wasn’t very elegant.

  2. Another approach was to write in the _draft directory first, allowing free commits, and then move the article to _post once finished. But as mentioned earlier, this still wasn’t elegant.

  3. A third option was to configure Jekyll to exclude future-dated posts. You could set the meta date to something like 2099 while drafting, and Jekyll wouldn’t build it. However, this would still trigger the Github Action and update files—again, not elegant.

  4. Sometimes, I was tempted by Craft’s beauty (great aesthetics) and functionality (editing anytime, anywhere, and multi-device sync). I’d write articles in Craft first, export them as Markdown, manually upload images to the x_blog-static repository, update the image links in the Markdown, and then commit to Github. This process was way too long.

Current Workflow

Write in Craft → Commit to x_blog_src repository → Trigger Github Action → Build and commit to x_blog repository → Success

The key difference from before is switching from writing in VSCode to writing directly in Craft. As mentioned in the fourth point of the previous workflow, this lets me enjoy Craft’s benefits while eliminating the hassle of syncing to Github. Aside from images (more on that below), syncing text content alone is a perfect solution. Now, I might update the blog more frequently (previously, the complexity slowed me down) and focus more on content. Awesome!

Notes

Here are the usage settings:

  1. This plugin is currently for personal use only, so some configurations are hardcoded for individual needs. For example, it only supports uploading files to the _posts directory. If there are more users, we may invest more time to make it more generic. For now, since it’s just for personal use, it’s not as refined.

  2. A Github Personal Token is required to sync Markdown content to a specified Github repository via Github’s Rest API.

  3. When sending content to the repository, the Github API compares the SHA values of the source and target repositories. If they are identical, the updated file won’t display commit information, and checking the commit log will show “0 files changed.”

  4. The first block of an article must be a two-column table serving as Jekyll’s meta information. Currently, the meta includes all content except the path.

  5. The article title serves as the blog post title and doesn’t need to be included in the meta.

  6. As of December 9, 2021, testing shows that the Markdown output from Craft’s API craftBlockToMarkdown fails to render Blockquote styles (called “Focus” under Decorations in Craft Blocks—officially acknowledged as a bug to be fixed in a later version). If you want custom Markdown, you’ll need to traverse the Blocks yourself. Other features remain untested.

  7. Currently, the plugin’s configuration options aren’t very user-friendly and will be optimized later.

  8. Craft’s Markdown formatting is visually appealing—for example, you can embed a paragraph or image under a list to align with the list content. However, standard Markdown doesn’t support this, so the output styling may look less polished.

  9. If meta contains multi-line information like tags, you can separate them with -:, e.g., -:test-:server.

  10. For Craft’s Markdown API, it’s recommended to use the common format (default, currently non-configurable in this plugin). If you use the bear format, images won’t be prefixed with !, causing Github to treat them as links instead of images.

  11. Some Craft features like “Deep Markdown Links” aren’t part of standard Markdown syntax, so support for them hasn’t been tested here.

  12. According to the official documentation, the storageApi is not encrypted on the Web side, so users should be reminded to be cautious when storing data. See here. This issue does not exist on Mac. Analysis revealed that the storageApi on the Web was stored in SessionStorage. Upon further review, it was later changed to IndexedDB (after all, it’s a developer preview version, and changes are made quickly…), specifically in a DB named plugindata-storage. As for the Mac version, because I switched the user workspace, the Storage was also lost. I reported this issue, but the official team has not responded yet :-(.

  13. The storageApi on Mac has a race condition issue. Therefore, if you attempt to read data using storageApi immediately upon loading, it will fail. To address this, the logic in my plugin is to delay plugin initialization by 3 seconds for Mac, while the Web version has no such restriction.

  14. More configuration support coming soon…

About Image Issues

  1. Whether on the Web or desktop, images uploaded to Craft are displayed in .jpg format when inspected via element inspection on the Web side. However, after generating the content using Craft’s Markdown API, it was mistakenly thought to change to .png format. This was a misunderstanding—the image extension remains consistent with the format at upload time; Craft does not convert the format.

  2. Although the image URLs displayed in the documentation’s element inspection use the domain res.craft.do, and the source files in the Github repository also show this address, when previewing images in Github (i.e., directly opening the repository’s md file), the address changes to https://camo.githubusercontent.com. Initially, it might seem that Github kindly hosts your md images on its servers, but in reality, Github temporarily caches third-party images for security reasons during rendering.

  3. Without relying on a server, images uploaded to Craft cannot be fetched using frontend methods like fetch when retrieved via the Craft API, as it will result in CORS errors. Therefore, if you want to extract images from an article when uploading it to Github and host them on your own image bed/COS/Github repository, a pure frontend solution is insufficient. You need to use a server to pull and rehost the images. Additionally, Craft imageBlock image URLs are hosted on AWS S3. Pulling them from domestic servers like Tencent Cloud may time out or be slow, but pushing from overseas servers to domestic ones seems relatively fast. Thus, it’s recommended to use AWS services for image rehosting (Update: I currently use Vercel; details can be found in this article).


Here’s an image to test the speed:

Image

More

  1. Planning to develop a template plugin, available at: https://github.com/craft-extension/craft-template-extension

  2. All plugins are developed based on this tool: https://github.com/craft-extension/craft-dev-toolkit Added some configurations like using antd for UI on top of the official examples. If there are users in the future, I’ll consider adding more configurations, such as supporting scaffold generation for plugin development environments.

  3. Stay tuned for more plugins…

Update 2022.01.24

Regarding the image issue, one idea is to stop backing up images on Github (since images in Craft essentially serve as backups) and directly upload them to Tencent Cloud COS. However, Tencent Cloud COS requires sending requests using the request library, which is wrapped with additional layers to include signatures and other information. After examining the COS source code, I found it allows configuration of the request tool. Currently, I have two approaches to achieve this:

  1. Override the request library methods used by COS.

  2. Rewrite the request code within COS.

  3. Construct signatures manually according to the documented examples to make requests.

Obviously, the third method was ultimately chosen for its simplicity.

Update 2022.02.28

The 01.24 solution has been abandoned due to high costs. The final approach is to stop uploading images to Github and instead use Vercel’s service to store them on Tencent Cloud. This resolves the image issue, allowing for seamless article writing in Craft.

- EOF -
Originally published at: This article was sent via Craft Extension - Xheldon Blog