gmile
I am looking for a tool to preview contents of a Markdown file, as I edit it. After checking plenty of existing tools, all of them appear to have different shortcomings:
- subjectively, too slow when editing huge .md files (thousands of words; for example, https://stackedit.io and https://hackmd.io),
- some of them need to be installed and are resource hungry (seems they attempt to bring full Electron),
- no longer developed actively (for example, GitHub - pandao/editor.md: The open source embeddable online markdown editor (component). · GitHub),
- not conforming to CommonMark or GFM, and having weird default preview styling (e.g. Obsidian).
(I got to be honest I haven’t check each and every Markdown editor out there)
I’ve also tried using an online “Demo” page for Markedjs, only to have lost a couple of hours of writing when my Chrome crashed
But that’s a lesson for me, I guess.
Instead of using a dedicated “Markdown editor” tool for this, I’d like to use:
- plain text .md files on my hard drive,
- my editor of choice, e.g. neovim or Zed, or even a TextEdit on macOS,
- a “small” server that would notice changes to the file, then render an .html out of it and cue browser to reload the page (see next item),
- a browser, that would render an .html version of the .md file.
I’ve largely achieved this by using a node HTTP server, with a combination of marked, highlight.js and socket.io libraries:
I know this is ugly
const http = require('http');
const fs = require('fs');
const socketIo = require('socket.io');
const { Marked } = require('marked');
const { markedHighlight } = require('marked-highlight');
const hljs = require('highlight.js');
const server = http.createServer((req, res) => {
if (req.url === '/') {
fs.readFile('./index.html', 'utf8', (err, content) => {
if (err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Internal server error');
return;
}
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content);
});
} else if (req.url === '/socket.io/socket.io.js') {
res.writeHead(200, { 'Content-Type': 'application/javascript' });
res.end(socketIo.clientSource);
} else if (req.url === '/highlight.js/styles/github.css') {
res.writeHead(200, { 'Content-Type': 'text/css' });
res.end("node_modules/highlightjs/styles/obsidian.css")
}
});
const io = socketIo(server);
let htmlContent = '';
const updateHtmlContent = () => {
const mdContent = fs.readFileSync('post-1.md', 'utf8');
const marked = new Marked(
markedHighlight({
langPrefix: 'hljs language-',
highlight(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
}
})
);
htmlContent = marked.parse(mdContent);
};
// Initial read
updateHtmlContent();
io.on('connection', (socket) => {
console.log('Client connected');
socket.emit('updateContent', htmlContent);
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
fs.watchFile('article.md', () => {
console.log('article.md changed');
updateHtmlContent();
io.emit('refreshContent');
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000/');
});
With the above, I’m able to edit the file locally and see it’s preview in Safari. This works good enough, but as the length of article grows, there’s a noticeable lag between saving the file and the contents appearing on the web page. Perceivably, the lag comes from 2 sources:
- there’s some kind of delay between when the file is changed, and when the change is “noticed”,
- on top of that, there’s a full page re-render needs to happen every time the new contents is about to appear on page.
Because in Elixir ecosystem there exist tools like earmark, phoenix_live_view and phoenix_live_reload - couldn’t the above script in node be implemented much more optimally? E.g.:
- (server) on start,
- load .md file from disk,
- convert .md to .html, “memoize” it,
- serve .html,
- establish a WebSocket connection with browser,
- (server) listen for changes on .md file; when a change occurs:
- convert .md to .html,
- figure out diff between existing .html by using a previous “memoized” version of .html,
- send diff over the WebSocket connection to browser,
- let JavaScript in browser apply up the diff.
Conceptually, it would look like this:
Or more precisely, like this:
I don’t know a lot about LiveView, and not sure where to start about this one. I’ve noticed that LiveView actually is dependent on Phoenix itself, so actually a full-blown phoenix project is likely be needed here, but I am ok with that.
The benefits of such a server as I see it:
- all .md files are local, so chances of loosing changes is small,
- the preview generation is blazing fast,
- I’d be using tools from Elixir ecosystem, and potentially contribute back (for example if
earcutis lacking support for some things from CommonMark).
Where would one start on something like this? ![]()
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #metaprogramming
- #hex












Showing Posts 1 to 5- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
gmile
https://github.com/nickdichev/markdown-live
The difference appears to be that they offer a on-page editor, as opposed to editing the file on the disk
D4no0
From what I know, the actual html diff is a internal part of the liveview system and it triggers based on the change of the assignments. What I want to say with this is that currently liveview (from what I know) doesn’t have a system to generate html diffs from a full data-source directly, the way it generates them is an internal implementation that laverages on data(assigns).
If my assumption is correct, you will not be able to use liveview directly to patch the frontend html, because the markdown parser generates an entire html document, not some partial changes that liveview would understand how to operate with.
derek-zhou
I send whole markdown from client to server with a small debounce (100ms) after key strokes, and render the whole markdown server side and send everything back. It works reasonably well for:
smathy
Have you seen the MarkdownPreview plugin for nvim? It’s pretty good.
cmo
Logseq is an obsidian alternative.
Editor plugin also works great.