Adding Markdown Support to Safari

I recently created a Safari Extension that renders plain text Markdown files as good looking HTML right in your browser. I also added a context menu item so you can swap between the rendered HTML and the original Markdown text.

Download

http://www.gingerbeardman.com/safari/Doctor.safariextz (25Kb)

To install: double click the file after it has downloaded.

Why?

Recently my buddy and fellow Former Apple Technology Evangelist @TDRBY asked if there was an extension available for rendering Markdown files in Safari. I had a quick look — there wasn’t — and that got me thinking.

On macOS you can use Quick Look plugins to add support for new file types to Finder’s Quick Look preview popup. These plugins are great, I use a bunch of them, but they only apply in Finder and not in Safari. Maybe I could do something similar?

So, knowing that Safari renders plain text files by wrapping them in simple HTML > BODY > PRE markup, I thought that an extension should be able to modify such files. That was enough to pique my interest — so I got to work!

How?

The extension took less than an hour to put together. This blog post took me a lot more time to write! Anyway, here’s how I did it:

  1. Create new extension using Safari > Develop > Extension Builder > + button
  2. Set website access level to All
  3. Confirm extensions run on plain text files in Safari by adding a CSS file containing only body { background-color: red !important; } — success, they do!
  4. Find a suitable JavaScript Markdown to HTML converter showdown.js — this ticks two important boxes: it is easy to use, and is still being actively developed
  5. Write a few lines of JavaScript to run showdown.js on the page text and replace it with the generated HTML
  6. Add github-markdown.css and apply the markdown-body class to make things look better
  7. Configure the extension to run only on URLs ending in common Markdown file extensions
  8. Manually add https:// variations of the Markdown file extensions to the Info.plist (far quicker than using the Extension Builder user interface)
  9. Edit the .map file reference out of the minimised showdown.js to avoid a runtime access warning
  10. Build the release package

At this point I’d like to mention a couple of great open-source projects that made this task so much easier: github-markdown.css by Sindre Sorhus, and showdown.js by Estevão Soares dos Santos — nice work guys!

Testing

There are Markdown files all over the internet, but two notable source stand out.

  • Almost every GitHub project has a README.md file. View the RAW version to have the extension render it as HTML. Here’s the one I used for testing.
  • John Gruber’s excellent daringfireball.net blog is written using Markdown, and the source of each post can be seen by appending .text to the URL. Here are two posts that I used to test. Of course, John is also the creator of Markdown. Thanks, John! 👍

Postmortem

After the initial build, a period of testing revealed some issues:

  • Strikethrough, and some other non-standard but frequently used Markdown, was not being rendered. This was fixed by enabling some options in the showdown.js file.
  • Rendering quirks due to using github-markdown.css outside of the GitHub page structure required few manual CSS tweaks. Mainly this was to make tables look better.
  • Markdown on GitHub that was already rendered as HTML was being processed a second time, resulting in corrupted pages. This was fixed by blacklisting the github.com domain.
  • Sometimes I wanted to see the plain text Markdown. I fixed this by spending an inordinate amount of time adding a context menu item that allows you to Show or Render Markdown. I hope it was worth it! 😬

Safari Wish List

Despite the brief development, I noticed a few quirks to do with Safari that I did not expect to encounter:

  • You can’t open the Web Inspector whilst viewing a plain text file. But if you open the inspector on a blank tab, or an existing HTML page, you can then navigate to the plain text file and the inspector will remain open. Phew!
  • Due to the way Safari Extension access permissions work, I have had to enable the extension for all pages and then reduce its power by whitelisting a range of Markdown file extensions. This feels like cracking a nut with a sledgehammer.
  • Extensions do not run on local file:/// documents. 😩

Please join me in filing enhancement requests with Apple if you’d like to add your support to any of the above points.

Thanks for reading!

If you have any questions feel free to get in touch using twitter or my website. I’m interested to see more extensions that add support for other file formats in Safari. And I’m available to help you make better products!