skip to content
Podcast cover art for Knowledge Base, Voracious Dev, Octo App
Podcast

Knowledge Base, Voracious Dev, Octo App

David Myers discusses building OctoApp, an open-source markdown knowledge base, covering offline-first architecture, in-browser editors, and data sync challenges.

Open .md

Episode Description

David Myers discusses building OctoApp, an open-source markdown knowledge base, covering offline-first architecture, in-browser editors, and data sync challenges.

Episode Summary

This episode of JavaScript Jam Live features David Myers, creator of OctoApp, an open-source markdown knowledge base built with Vue, TypeScript, and Vite. The conversation opens with Anthony Campolo announcing he's joining Edgio as a developer advocate before transitioning into the main discussion. David explains how frustration with existing note-taking tools led him to build OctoApp, starting as a simple Vue app with a Rails backend on Heroku before evolving into a progressive web app powered by Firebase, IndexedDB, and service workers. He walks through how offline-first architecture works in practice, describing how documents are saved to IndexedDB first and then synced to the cloud, with a "most recently updated" strategy for resolving conflicts across devices. The conversation then shifts to the challenges of building an in-browser markdown editor, where David compares approaches like text areas, content editable divs, and dedicated libraries, ultimately recommending CodeMirror 6 for its incremental parsing and cross-platform support over alternatives like Monaco. Audience member Jason contributes insights on CRDTs and libraries like YJS for real-time collaborative editing, prompting David to discuss how client-side encryption constrains his approach to collaboration features. The episode closes with David sharing his standalone editor library, Ink MDE, and a preview of next week's guest on WebAuthn.

Chapters

00:00:00 - Introduction and Anthony's Announcement

The episode kicks off with host Scott Steinlage welcoming listeners to JavaScript Jam Live, a weekly Wednesday show focused on web development topics. He introduces the guest format and brings co-host Ishan Anand into the conversation to set the stage for the day's discussion.

Before the main topic begins, Anthony Campolo shares breaking news that he's accepted a developer advocate position at Edgio, joining Scott and Ishan. The hosts celebrate the hire, noting Anthony's existing track record with podcasts like FSJam and his new stream, and Anthony reflects on how the opportunity had been in the works for a long time before the timing finally aligned.

00:06:15 - David Myers and the Origins of OctoApp

Ishan introduces David Myers, a senior software engineer at Doximity and creator of OctoApp, an open-source markdown knowledge base. David shares his background as a self-taught developer with roughly a decade of experience and a long history of open-source contributions, noting that every personal project he starts begins as a public GitHub repo.

David explains that OctoApp was born from dissatisfaction with existing note-taking tools. He wanted something open source, cross-platform, and well-designed, and after cycling through options like Bear Notes and Obsidian without finding the right fit, he decided to build his own. What began as a small experiment ended up becoming a multi-year project, which surprised even him given that his previous side projects rarely lasted more than three months.

00:12:00 - Choosing the Tech Stack and Evolving the Architecture

David describes how OctoApp's technology stack evolved organically. He started with plain Vue and JavaScript, using Vue CLI and a free Heroku-hosted Rails API as the backend. Over time he layered on Vue Router, Vuex, and eventually TypeScript, while migrating the backend to Firebase for stability after hitting limitations with Heroku's free tier.

The conversation touches on Vue's identity as a "progressive framework" that allows incremental adoption, which Ishan connects to past JavaScript Jam guests like Evan Yu and Alex Russell. David clarifies that OctoApp hasn't fully migrated to Nuxt yet, explaining the challenges of converting an existing Vue 3 application to Nuxt's opinionated directory structure, and noting the lack of migration-focused resources compared to the abundance of "start from scratch" tutorials.

00:17:15 - Server-Side Rendering and Progressive Web App Benefits

David explains why server-side rendering matters for OctoApp despite being a browser-centric application. SEO is the primary driver, since the current single-page app delivers a minimal experience to crawlers. A secondary motivation is improving initial page load time for first-time visitors and people accessing shared public documents, which currently requires downloading a large JavaScript payload.

The discussion highlights OctoApp's progressive web app capabilities, including how the app continued functioning during major AWS outages because static assets were served from the browser cache. David describes how technologies like IndexedDB and service workers enable a fully offline experience after the first visit, which is especially valuable for a note-taking tool where users might need access regardless of connectivity.

00:25:00 - Offline-First Architecture and Data Synchronization

David breaks down what offline-first means in practice for OctoApp. Every new document is written to IndexedDB on the client before any server sync occurs, treating the browser as the primary data store rather than a cache. If the Firebase sync fails, the app simply retries later, ensuring full functionality regardless of network state.

Ishan raises the thorny problem of conflict resolution when the same document is edited on multiple devices while offline. David explains his current approach uses a simple "most recently updated" timestamp comparison, acknowledging it isn't the most sophisticated strategy but is predictable and consistent. He discusses the eventual goal of implementing a merge UI similar to Git conflict resolution, where users would choose between conflicting versions rather than having the app guess, while noting that in practice these conflicts are rare since most devices stay connected.

00:34:44 - Mid-Show Break and Building an In-Browser Editor

After a brief station break where Scott promotes the JavaScript Jam newsletter and encourages audience participation, the conversation shifts to how OctoApp's in-browser markdown editor was built. David walks through the spectrum of approaches, from simple text areas with styling hacks to content editable divs, explaining why each has significant trade-offs.

David describes his commitment to real-time, in-place markdown rendering rather than the common split edit/preview panel approach. He recounts starting with CodeMirror 5 and eventually upgrading to CodeMirror 6, a complete rewrite that provides consistent cross-browser behavior and incremental parsing. He recommends CodeMirror 6 over Monaco for most use cases, citing Monaco's struggles with large documents and lack of mobile/touchscreen support as key disadvantages.

00:46:27 - CRDTs, Collaboration, and Editor Libraries

Audience member Jason joins the discussion to share his experience with CRDTs and the YJS library for real-time collaborative editing. He explains that CRDTs enable multiplayer applications like Google Docs and Figma by providing a prescribed method for synchronizing shared data across clients, while cautioning that they aren't a silver bullet due to challenges with data size and storage.

David responds that YJS was already on his roadmap for real-time document collaboration in OctoApp but notes a critical constraint: client-side encryption means plain text data cannot flow through a server, limiting him to peer-to-peer connections via WebRTC. The group discusses the architectural distinction between server-owned and client-owned data models, with Jason highlighting tools like Replicache for server-authoritative sync and the trade-offs of storing YJS documents as binary blobs.

00:56:45 - No-Code Editors, CMS Tools, and Closing Remarks

Audience member Bro Nifty asks about how drag-and-drop site builders like Builder.io relate to the text editors discussed. David frames it as adjacent under the umbrella of no-code technology, while Ishan suggests such builders likely contain text editing components internally and face their own unique constraints. The conversation briefly touches on DIY CMS tools like TinaCMS and the broader ecosystem connecting content editing paradigms.

David closes with a shout-out to Ink MDE, a standalone open-source markdown editor library extracted from OctoApp and built on CodeMirror 6, available on his GitHub for anyone to drop into their own projects. Scott wraps up the show by previewing next week's guest, Dan Moore from FusionAuth discussing WebAuthn, and announcing that Anthony will be co-hosting and extending the show by thirty minutes going forward.

Transcript

00:00:00 - Scott Steinlage

Hello. How's it going? All right, David's in the room. Let me bring him up on stage here. And Anthony, I'll bring you up too. There we go. Hey, hey, hey. Thank you all so much for joining us today. Let me invite Ishan up here, the co-host. Boom, sent you the invite there, man. Should see it momentarily. All right, thank you all so much for joining us today. Welcome to JavaScript Jam Live. We do this every Wednesday at 12:00 PM Pacific Standard Time. So if you're a regular, you know you're here, you're on time, you're probably early, you're waiting, your finger is just waiting to click that button to get into the room.

00:00:50 - Jason

It was.

00:00:51 - Anthony Campolo

I'm always standing there just waiting.

00:00:54 - Scott Steinlage

I knew it. All right, thank you all so much for joining us. Whether you're a beginner or you've been doing development for a very long time, we love to hear from everybody on here. We'll give everyone an opportunity to come up and ask questions or state opinions, whatever it might be, so please join us in that. In fact, that's when we get so much value out of these, when others in the audience participate. So feel free to raise your hand or request to come up, and we'll bring you up. No problemo. Today we have David in the house. David Myers is the founder and creator of OctoApp. Super exciting stuff there. We're going to dig into that today with him. I'm really, really, really excited for today. So let's go ahead and kick it off. Let's introduce Ishan in the house as well, our co-host.

00:02:10 - Scott Steinlage

Wonderful co-host.

00:02:10 - Ishan Anand

Hey, Scott.

00:02:11 - Scott Steinlage

Hey. Hey. And he's going to be shooting the questions out there to David.

00:02:18 - Ishan Anand

Yeah, yeah. So, hey, folks, again, great to see a lot of our regulars. Anthony, Brad, Jason, Eric, great to have everyone here. As we've been doing for the last couple weeks, we've been getting more and more guests on the show. Today we have David Myers, the creator of OctoApp. We're going to do the guest format where about the first half will be talking with the guest about their topic, and then the second half of the show we'll make more audience-driven. But it's great to see everyone again, and I really hope you all participate because we like to have this as audience-driven as much as possible.

00:03:02 - Anthony Campolo

Can I make my announcement first?

00:03:03 - Ishan Anand

Oh, okay. Breaking news.

00:03:06 - David Myers

Let's hear it.

00:03:06 - Anthony Campolo

Yes, breaking news. I'm going to be joining Scott and Ishan at Edgio.

00:03:13 - Ishan Anand

Yay. We are so excited. So for those who've been regulars, you obviously know Anthony and you know us. Anthony has accepted a position here as a developer advocate, and we cannot wait for him to get started. I know you wanted a little bit of a break, Anthony, before, and so I reached out like, hey, can we start? We can't wait to ramp you up.

00:03:44 - Anthony Campolo

So, yeah, it'll be a break, but I'm sure I'll be writing a handful of Edgio blog posts in the interim.

00:03:52 - Ishan Anand

Awesome.

00:03:52 - Anthony Campolo

Just to get myself familiar with it.

00:03:55 - Ishan Anand

Yeah. So look, bottom line, expect to hear a lot more from Anthony in this forum and others. We're really excited. I'll tell you, especially those of us who've worked with you here,

00:04:13 - Anthony Campolo

trying to find the right sound effect.

00:04:15 - Ishan Anand

Yeah,

00:04:20 - Anthony Campolo

I'll accept it.

00:04:21 - Ishan Anand

There we go. Thank you. Nicely done.

00:04:24 - Anthony Campolo

Yeah. And just to say real quick, this is a long time in the making. I was actually talking to you about possibly coming on back when I was interviewing for my last job, and it was a very tough decision at the time. I ended up going with a different company and I don't regret it. But at the same time, I think the time is now right for me to accept that I want to work on cool open-source JavaScript stuff and deployment platforms, and this is going to be a really great opportunity to do it.

00:04:54 - Ishan Anand

Yes. And while we're at it, one of the great things about Anthony, when you're looking for somebody, they say look for someone who's already doing the job. Anthony already has, I think, multiple podcasts now at this point. You've got FSJam, which is the one where I first started listening to you. I highly encourage people to check that out. You just have a great level of consistency and quality of guests and quality of interviews. So shout out to that. And I think you started another one as well. What was the name of that one?

00:05:27 - Anthony Campolo

So I have a stream as well now. HHC and the Web. Yeah.

00:05:31 - David Myers

So that's on.

00:05:32 - Anthony Campolo

Yeah. And that'll be coming up next Monday. We'll have Travis Waithmayer on to talk about his cool CSS project, Bedrock Layouts.

00:05:41 - Ishan Anand

Great. So definitely encourage folks to check that out. Thanks for that shout-out, Anthony. Again, we're really excited, so feel free to start co-hosting immediately. And with that, let me introduce David, who's our guest for today's episode. David, as we mentioned, is the creator of OctoApp. OctoApp is an open-source markdown knowledge base built on Vue, Nuxt, TypeScript, and Vite. We wanted to bring David on to share real-world lessons building and launching an app with those technologies and how he architected it for things like serverless, offline-first, and more. With that, David, why don't you first start out by telling us a little bit about yourself and then what got you into OctoApp, and then we'll dive into those topics.

00:06:39 - David Myers

Yeah, thanks for having me on too. I guess to get started, a little bit about myself. I'm currently a senior software engineer at a company called Doximity, based out of San Francisco. I live in Columbus, Ohio, so I'm a remote engineer. I've been remote for like the last three to four years, I'd say. I kind of got started with software development in general, specifically web development, around 10 to 11 years ago. I am fully self-taught, never been through any sort of formal education, and I've been pretty big into open source for most of that time.

00:07:23 - Ishan Anand

Cool. What was the trigger for creating OctoApp?

00:07:29 - David Myers

So, as a developer, it's very easy when we see a gap in tooling to be like, oh, I can just make that thing. And in my experience, that gap was definitely in my note-taking tooling. To be honest, I didn't really have a good note-taking habit at the time. I was working on it. This is about three and a half years ago now, or so. I had an okay note-taking habit, but I was constantly blaming my tooling. I was like, the tooling's not good enough. So that's why I don't take more notes or better notes, and why I don't refine them and share them with people, because the tooling is just bad. There were definitely options, but being someone who's big into open source, I really wanted to find an open-source tool that did what I wanted, something where I understood how it worked behind the scenes, something that I could maybe extend myself if something was missing. And I just didn't find anything that fit what I was looking for.

00:08:32 - David Myers

And part of that is just discoverability, right? There were probably things at that point in time that I would have been happy with, but I just didn't find them. So being a developer, I was like, you know what, I've been jumping from tool to tool to tool. I'm just going to try to make one and see how it goes. And being a web developer more specifically, I wanted to make sure that I could build a tool that would fully operate in the browser, one that could work on any platform. One issue I had was that I found some tools that were platform-specific. Bear Notes was really close to what I was looking for back when I started, but it only works in the Apple ecosystem. It only works on MacBooks, iPhones, and, well, maybe that's it, iPads. There we go. And I didn't know about Notion, if it existed at the time. I kind of knew about Obsidian, but I also have this thing about user interface design where if I don't like the interface, it can be a little bit distracting for me.

00:09:33 - David Myers

And at the time I felt like Obsidian just wasn't quite what I was looking for either because of that. So I started down the path of trying to build a notes app, whatever that meant.

00:09:45 - Ishan Anand

Was a certain element of this also to exercise the development muscle? I know when I talk to a lot of folks who do something open source, it's either to learn a particular technology or they want to just have an open-source thing they can point to. Because very often when you're in a company, I think Doximity is in the medical field, everything you do there is going to stay completely private. Were any of those motivations as well?

00:10:09 - David Myers

A little, I'd say. Being involved in open source, I had little projects that I'd worked on from time to time. It wasn't necessarily that I was looking for something because, as many people do, I have a million ideas of things that I could work on. So I was never at a loss for something to build open source. That's kind of been true even since before I started Octo, building things. When I'm going to start a project, I start it open source immediately. I don't keep things closed source. I don't really work on anything closed source other than the software I work on during my day job. So anything I build starts as an open-source repo on GitHub. That wasn't necessarily a huge part of it, but it was obviously a factor. I wanted it to be open source, and I definitely wanted to find something that resonated with me that I could work on and contribute to. But I'd be lying if I said I knew at the time that Octo was going to be something I'd stick with for years, because up to that point every project I had had a lifespan of at most maybe three months.

00:11:17 - Ishan Anand

Well, oh, we should actually just pause here and tell people how to get to it. You go to OctoApp. You don't even have to create an account. You can go to, I think, docs.new. Just to describe it for folks, or you can follow along, just load it up in your browser and you get an in-browser markdown editor. You can save it. It works offline-first. There's a lot of functionality here. Maybe the first place to start is I described the technologies you've used to build it: Vue, Nuxt, TypeScript, Tailwind, Vite. Let's start with how you decided on the stack. Once you decide on the problem you're trying to solve, how did you pick those? Was it simply familiarity, or were there other decisions?

00:12:04 - David Myers

Yeah, I'd say really familiarity. When I started this, again, not knowing the scope of what I was going to be working on and what I was really doing, because it really was an experiment at first, I just started with Vue by itself, nothing additional. I didn't use TypeScript. It was just JavaScript and Vue. And I didn't use Vite at the time. I think I was using Vue CLI, which if I remember correctly, I think the build tool was webpack. I honestly don't even remember what Vue CLI was using originally. It might have been Rollup at that point, but it started off very basic. I started as a Vue app because I was familiar with Vue. I understood the technology. Then over time I added things like Vue Router for being able to essentially build a multi-page single-page app, Vuex for state management, because those were essentially the go-tos. Then as it progressed, I introduced the backend. Actually, let me say that when I started it, of course I needed a backend. It didn't actually start off as offline-first. So my backend was actually a free Heroku instance, and it was just a basic Rails API, because Rails is something I was familiar with as well.

00:13:25 - David Myers

Oh, interesting. Yeah. But as time progressed, and I got to the point where I needed a backend that was a little more stable, because the free instances of Heroku obviously suffer from things like cold boots, so initial API calls could be slow. They also only allow them to actually run for like X percentage of the entire day, which means if traffic's too heavy, your instance just stops serving traffic. So I ended up deciding that I wanted to start going down the serverless route and chose Firebase as the sort of backend for Octo at that time. Again, not necessarily being offline-first, and so the backend really was required. Over time, though, I realized that the browser is actually capable of a lot more than most apps take advantage of, and I started to learn about and understand technologies like IndexedDB, which is essentially a key-value document store that exists in every modern browser. And I started digging into and learning about service workers, and I realized that you can actually build a web application that, after the first page load, will work entirely offline. It will cache everything, including its own static assets, in the browser so that you can turn off your network connection or just leave your Wi-Fi and everything will continue to function as usual.

00:14:56 - David Myers

Interesting little tangent, or side effect, there about progressive web apps, which is kind of the encompassing technology this is called when you talk about each of these individual pieces, like using IndexedDB and using service workers. The interesting aspect there is that because everything is cached in your browser, and if you have it configured correctly, it uses the browser as the starting point and then tries to perform network hops, when we had a couple of those really big outages, like when AWS went down in the entire US-East region, for example, Octo still worked in the browser. You could go to OctoApp and it would still load up because it loaded directly from your browser's cache. And even though all of DNS resolution was down for US East 1, you could still load Octo up in your browser if you had at least visited it one time.

00:15:51 - Ishan Anand

There are so many things to unpack there, but the things that jump out immediately to me are two past guests on JavaScript Jam Live that I think of that I wish were here to hear this, because it's almost like an ad for them. You were just talking about the dream of PWAs, progressive web apps, being competitive with native apps, but coming from the browser. We've had Alex Russell as a guest in the past on JavaScript Jam Live, and he coined the term progressive web app. He worked on service worker standards inside Chrome, and now he's on the Edge team. So you're basically living the dream there. And the other thing that jumped out that I thought was really interesting is how you progressively used Vue. Evan Yu has been a guest on JavaScript Jam in the past, and one of the things you see in the documentation is they call it the progressive framework. It can be easily adopted in a very minimal way. At the very beginning of what you're talking about, it sounded like exactly a case study in what they describe.

00:16:55 - Ishan Anand

You don't have to bring in this whole big bundler and all this other state management and routing libraries. Just start with the library itself and then gradually adopt various pieces as you need them. It sounded exactly like a case study in that. So that was really great to hear. It's almost textbook, it feels like.

00:17:15 - David Myers

Yeah, I mean, that was.

00:17:16 - Ishan Anand

Yeah.

00:17:18 - David Myers

That was my draw to Vue, actually, because at the time I had worked at places where we were either using ad hoc JavaScript enhancements like jQuery and Lodash, or Underscore before that, or when we were using single-page apps, the go-to, of course, was React. And yeah, I love React. I'll never sit here and be like Vue's the best and React is terrible. That's not the case. They're both great frameworks, and I love both of them, and I still work in both currently. But at the time, React did have kind of a heavier initialization process and it was a bit more prescriptive. I really liked the aspect of Vue where you could just drop it in, either use it for your full app if you want, or just use it for part of your app. And I loved that. I love being able to just drop it in. That was my original draw to it.

00:18:12 - Ishan Anand

So, at Edgio, a slight majority of our customers are in React, but we have a number of customers on Vue or Nuxt. One of the things we help a lot of customers do is go from those legacy stacks to a modern one, either in Vue or React. Vue definitely has that easier, more incremental adoption. But one thing I'm curious about is why you adopted Vue and didn't go directly to Nuxt. I've seen a lot of those folks, in our experience, go directly to Nuxt. Is it simply because it was harder to progressively adopt, like you could with Vue, or you had that existing legacy backend with Rails? Why not jump straight to Nuxt?

00:18:54 - David Myers

Yeah, that is a great question, and I'd say a big, probably the largest, factor there is just the lack of familiarity with Nuxt at the time, personally. In my day job, I was primarily working with Rails and React, and actually not even Next either, just React. I think part of that is, again, more of a corporate setting, legacy infrastructure. Even though our infrastructure was decent, using React with our Rails backend made more sense because we had very small dedication to frontend in general. So even just using React took some initiative and a push from the engineering team, I'd say. But almost everyone was familiar with Rails, so we knew we were going to use Rails as our backend, and React was more like a little enhancement over the typical, hard-to-work-with, in my opinion, server-rendered views, server-served templates. But as for Octo, I wasn't super familiar with Nuxt at the time, and it is a little harder to progressively add on.

00:20:13 - David Myers

Nuxt is a bit opinionated, which isn't a bad thing in my opinion. But it would have been more of an investment at that point in time for sure.

00:20:25 - Ishan Anand

That makes sense. I'm curious on that other... Oh yeah, go ahead.

00:20:30 - David Myers

Sorry. And I was going to actually clarify one thing. Octo is actually not running on Nuxt yet. I have been working on progressively migrating to Nuxt, and so it's actually not running on Nuxt. It's running on just Vue 3 at the moment, Vue 3 and TypeScript, and it's still using Vue Router. It's using Vuex and Pinia, actually, so newer state stores. I've started writing in Pinia and started migrating things from Vuex to Pinia, since Pinia is technically going to be the successor to Vuex 4. But there are still a few areas of the codebase that need to be migrated in order to support server-side rendering, for one, which is a feature I want to take advantage of in Nuxt, but also just the entire directory structure, another opinionated piece of Nuxt. The entire directory structure is very much enforced by the framework, and the Octo directory structure is not quite matching that yet. So I do have Nuxt installed, actually, in the application, but the actual production build that's live right now is not a Nuxt app. Nuxt is installed, some Nuxt dependencies are installed, and I've already migrated some of the directory structure to reflect Nuxt, but if you think about it, there are not a lot of resources out there about taking an existing Vue 3 app and converting it to a Nuxt app, an existing Vue 3 app with a decent amount of dependencies, and converting it to a Nuxt app.

00:22:03 - David Myers

There's a lot out there for just building a new Nuxt app, but not a lot for migrating an existing non-Nuxt codebase.

00:22:11 - Ishan Anand

Yeah, I would say that's in general true for everything. There isn't a lot in terms of migrating in general. Everyone likes to write the net-new TodoMVC example. One thing you brought up, and I'm curious about, is how important server-side rendering is for OctoApp. It's very full, like a Google Docs in the browser type thing. What is the relevance? Is it not as critical and important a thing for Octo?

00:22:40 - Jason

Sure.

00:22:41 - David Myers

There are a number of reasons that it's important to me personally. One, which I think is maybe the most obvious one, is SEO. Right now SEO in Octo is terrible because it's a single-page application. There is no static site served with very useful information. When a crawler hits Octo, it's getting a very basic experience. So SEO is a huge one. Another benefit of server-side rendering, though, is just initial page load time and speed, I'd say, for first-time visitors of the application. Being a larger single-page application, being a progressive web app that also does a lot of precaching in the background, the first-time hit, even though every subsequent visit, every subsequent page load, is technically faster than any sort of server-side-rendered app would typically be able to serve, the initial hit, the initial page load, is a large payload that has to be delivered. So it's a little slow. It really is, and I want to improve that experience for first-time visitors, but not just for first-time visitors that are coming to possibly sign up or not sign up and just use the application.

00:23:54 - David Myers

But one feature of Octo, because it's a web app, is the ability to just make one of your documents public and share a link to someone. When you share that link for someone to view your document, it's a read-only view. At the moment, that initial page load I would love to be faster because there's a lot more opportunity for people to see this one document than for someone to just randomly discover Octo. So if I write up a document that I want to share with my team, for example, I can just make the document public, share a link to like 10 different people, and they can all look at it. The initial page load for them is fairly slow at the moment.

00:24:39 - Ishan Anand

Got it. It's to expand the job to be done from simply note-taking to also publishing, which makes sense in that context. Let's talk about where you think the most interesting, to developers, challenges or technologies you had to deal with were. Whether it was offline-first or you've got client-side encryption, you mentioned service workers and IndexedDB. What were the most interesting or exciting lessons, technically, that we could start diving into?

00:25:12 - David Myers

Yeah, that's a great question. There have definitely been a lot over time. So let's start from offline-first. Let's start there. I feel like the idea of offline-first, and just to simplify it, to give it a definition from my perspective, it's essentially making it so that your web application... Offline-first is actually a strategy that applies to mobile apps too, because not all mobile apps are offline-first. Not all mobile apps, or native applications, fully function without a stable internet connection. But for a web app, offline-first really means, first of all, your page has to be able to be cached in the browser and served in the browser, and that usually happens on the very first visit, although technically you can defer that for some sort of user interaction if you want to. Maybe they sign up and then you cache everything. But really, you have to be able to cache your entire page in the browser so that it can be served when there's no connection.

00:26:14 - David Myers

But going beyond that, think about the core functionality of an application. If the core functionality of an application is real-time communication with a lot of people, offline-first doesn't necessarily make sense or even matter that much. Twitter is probably a good example of that, where being offline-first for Twitter is probably not that important because real-time information is kind of the whole point of the application. But for something like Octo, where you have essentially just text documents that you're creating ad hoc and going back to and editing, being offline-first makes a lot of sense because who knows where you'll be when you need to take notes, right? The idea there is you need to be able to have that data that a user is generating stored in the browser first and then somehow synced to your backend and then ideally synced across that user's various clients. So if you sign up for an account on OctoApp, what happens is you essentially get free syncing. All your documents are synced across the various devices you might be signed into on Octo.

00:27:31 - David Myers

But every time you create a document, the flow is actually, you know, I create a new note, I start typing, that note is now saved first in IndexedDB, which is the client-side database. And then in the background, if I'm signed in, it is synced to Firebase. And then if I have various other clients, it'll be synced to those clients as well. But that is an afterthought. The first thing is that it is written to IndexedDB, and that's all that matters. If it fails the sync to Firebase, not a big deal. We can try again when they're online, or we can try again in a minute or something like that. The biggest thing is making sure that your app's full functionality works even if it's offline.

00:28:45 - David Myers

The technical challenges there are dealing with things like the Vuex centralized state store, right? Nowadays there are a lot of simple plugins that you can use to persist that to something like localStorage. But IndexedDB is more like a traditional database, and so using a basic storage sync plugin doesn't usually work as well, because what ends up happening is it just syncs all of your state into a single document with a single key in IndexedDB, which is not very efficient, as you can imagine. So you kind of have to work around the quirks of typical tooling, which looks at client-side storage or browser storage as a cache rather than an actual source of truth. So that's probably one of the most interesting aspects.

00:29:00 - Ishan Anand

This is exactly where I wanted to go, because I think for a lot of developers, conceptually, it's just the idea, okay, I can write to localStorage or IndexedDB, but the complexity is like, suppose I as a user create a document, it gets synced up, then I lose a connection, I go to another device, I access that document, make a change, and then both of those connect back. Who, out of those three entities? I've got two browsers, one on my computer, one on my phone since I'm out and about, say, and then I've got the version in the cloud. How are you reconciling who is the source of truth when they all reconnect? Are you using the date? Is there a library or tools that you would recommend for developers that handle this for you? Does Firebase handle this for you? I know the old version of Firebase used to handle some of this. Can you just make recommendations for solving this problem, or to simplify it for the developers who are like, I want to have that, but I don't have to think about it?

00:29:59 - David Myers

Yeah, this is something I spent a bit of time on a while back, probably in the earlier stages of building out this offline-first and Firebase functionality. But the strategy I went with currently is not the most intelligent strategy, but it is a very consistent and predictable strategy, and it's just most recently updated. So essentially every time you make a change to a document, it's associated with a timestamp. If you think about a doc, or a document, or a note, whatever you want to call it, as a record in a database table, that's the best way to think about it. Every document has associated with it a unique ID, a text field essentially for the note body, and then a bunch of other metadata fields like created at, updated at, touched at, synced at, and then also some other things like your initialization vector and your symmetric key for encryption if you're using client-side encryption. All of those are stored essentially in that one JSON object so that it is treated as a record, and that record is passed around.

00:31:16 - David Myers

The exact same JSON object is stored in the browser in IndexedDB as is stored in Firebase. Anytime you make a change to a document, it's going to update some of those fields, one of which again being updated at and another being synced at. Those are going to allow me to essentially do a really basic most-recently-updated comparison where I say, okay, a document on my phone was edited first, but then 10 minutes later I went and edited the same document on my laptop. It's just going to take the laptop, that is going to be the new source of truth. The thought process there is it's predictable, it's consistent, and the user probably expects that the last one they touched is going to be the final format that is being saved instead of doing something really weird or special where you end up overriding something they did.

00:32:20 - Ishan Anand

Mostly, yeah, I align to that intuition. I'm wondering if you do any type of merge of the data. As an example, I start writing an email maybe on my desktop, I go to my phone, maybe I happen to make an update to it, and then I go back to the desktop, like I'm going back and forth. I might go back to the phone, the phone doesn't have the most recent state, and it goes and modifies an old version, so to speak, and overwrites things I might have lost. I can get more specific, but imagine you've got two paragraphs and I insert a third one in, and the other one didn't know that got inserted, and then I go back to the old client and it overrides it. I don't know if my question is

00:33:03 - David Myers

making sense, but it absolutely does. It absolutely makes sense. And yes, this is why I said that my strategy wasn't the most intelligent strategy. The intelligent strategy is to perform some merge, whether you do a basic line-based merge or a more custom UI-based merge where you essentially show the user, hey, we have a conflict. You have these two separate documents. You need to decide what to do with them. Personally, I think something more like the latter is going to be better for most users because, again, it's too hard to predict what a person actually wants in terms of behavior. You should just allow them to decide what the behavior should be. I think if I were to implement a merge, which is definitely on the roadmap, it's just not a very highly prioritized piece on the roadmap, I would probably do something more like that where, if it cannot safely merge automatically, think akin to a Git merge, for example, then just present it to the user. Okay, but the biggest piece there is the user experience. You really have to consider the user experience of dealing with this and also the practicality of it, the real-world scenario, and how frequently something like this happens, because in reality it doesn't actually happen that often because most of our devices are connected essentially all the time.

00:34:39 - David Myers

It's very uncommon for this to actually happen in reality.

00:34:44 - Ishan Anand

That makes sense. I've got a couple more questions, but I want to give the audience a chance to participate. So Scott, I'll let you do the station break and then we'll open it up to folks. There's a button on the bottom of your screen where you can raise your hand, and we will bring you up to the stage and ask questions. Scott, I'll let you do the station break and then we'll keep going.

00:35:04 - Scott Steinlage

Awesome. Yeah, it has been such a good conversation here, you guys going back and forth. I knew this was just, you know, I wasn't expecting anything less. Just hearing David on here before, speaking with us in past Spaces and stuff like that, I was just really, really excited for this one. And it's proven to be just that. So thank you so much, David, for joining us today and continuing that throughout the rest of the session here. All right. If you've never been here before, you're crazy. No, I'm kidding. But thank you so much for coming if you haven't been here before. And we do this every Wednesday at 12 PM Pacific Standard Time, and we have some awesome people on here like David and many other folks. If you want to go back and listen to our recordings, you can go to javascriptjam.com and check those out. And by the way, we have this awesome newsletter, so if you don't want to miss out on the latest things having to do with web development and things like that, JavaScript maybe, then hey, go there, sign up for our newsletter, and you will be getting the awesomeness that we put out on that, as well as keeping you updated on what we're doing here on the space too, and in the podcast.

00:36:13 - Scott Steinlage

So go ahead and check that out. All right, thank you all so, so much. By the way, if you are a beginner or you've been doing this for maybe forever, and what I mean by that is developing, it doesn't matter. We want to hear from everybody, okay? So feel free to, like Ishan said, quote-unquote raise your hand or request to come up, and we'll bring you up here and you can ask questions, you can state some opinions. But yeah, get involved. Feel free. Please, please. The more people we have up here talking, the more value that is delivered, typically, because we can't think of all the questions, guys. We don't have all the opinions either, so feel free to share them. We love you all so much. By the way, real quick, last thing here, if you've gotten any value from anybody up here on stage, please click on their face, follow them, because guess what? If you've gotten value from them here, you're probably going to get value from them in other places. All right, thank you all so, so much. Back to you, Ishan.

00:37:13 - Ishan Anand

Yeah, and just a shout-out, if you go to javascriptjam.com, you can also click there and subscribe to our newsletter, where we will give you the schedule of the upcoming speakers. And we send a newsletter out once a week letting you know some topics we'll be talking about, so it's another good way to keep up to date. Again, feel free to raise your hand. Happy to interrupt my line of questioning for your line of questioning. In the meantime, while we're waiting for folks to do that, the next thing I want to talk about is OctoApp has an in-browser editor. I think it's one of those things that a lot of devs, they've used them, like in Google Docs and various... if you're writing a GitHub ticket and things like that. We use it a lot, but I don't think a lot of people have experience with building it, and it almost seems magical. I don't know if developers realize you just turn on contenteditable and you can start using it. Did you have any difficulties with that? Did you use a library or editing library to help you set that up? Just maybe tell us a little bit about what that process was like, building an in-browser editor.

00:38:23 - David Myers

Yeah, sure thing. So the interesting thing about the editor is you can do things as simple as using a textarea. There's a lot of really clever ways people have come up with to tackle in-browser text editing. A textarea is one example where you have a very plain-text text input that someone can type into, and it's multiline. That's a key piece here, a multiline text input. Textareas are nice, but they're really hard to style. If you've never actually messed with one or used one, you're very limited on what aspects of it you can actually style, in terms of coloring. Syntax highlighting, I guess, is one of the most obvious aspects there. Some hacks around that that people have done, which I find really interesting, are making a textarea that is actually behind a div, and the div has the same text as the textarea, but the div is dynamically updated with the same text that's in the textarea, except each piece, each token of text, is wrapped in spans and colored. That's a really interesting hack I've seen people do for syntax highlighting a regular textarea.

00:39:41 - David Myers

The next thing you can do is essentially use contenteditable. Contenteditable is just an attribute you can put on any random HTML element, and it allows you to edit the contents of that element. Unlike a textarea, the contents of a contenteditable div, we'll say, are actually HTML tokens themselves. So they can be targeted and styled and all kinds of things. But the output of contenteditable, on a browser-by-browser basis, is very unpredictable. If you think about text in, let's say, Markdown, Markdown can be parsed into an AST, abstract syntax tree. So if you want to render Markdown, we'll say, directly from the text format to HTML, which a lot of libraries out there do, this is what happens, for example, on GitHub when you're editing a README and you click on the preview tab. What's happening is a one-time pass: you're taking all of the Markdown text, you're essentially building that syntax tree, and then converting that syntax tree into HTML. Each piece of that syntax tree can be converted into a specific HTML element with specific classes, which then have specific styles, like font size for headings or actual font color for things like a code block where you have various tokens there, right?

00:41:16 - David Myers

And so because of that, contenteditable is actually really hard to get right if you use it directly. That's why a lot of in-browser editors, aside from just the overall package size itself being really, really large, will essentially implement the edit view and preview view. That is so common in Markdown. I'm sure everyone here has seen that almost every Markdown input you use in places is going to have a separate edit panel and a preview panel because that real-time rendering of Markdown is hard. It's hard to do. Instead, they just compile the Markdown to the HTML preview when you click on that preview tab. Then you have other editors that do something similar, but what they're doing is essentially compiling it to HTML on the fly. You've probably also seen a lot of synced side-by-side panels where you have the edit panel and the preview panel both visible at the same time, and they're both real-time. That's just because what's happening every time you press a button, every time you edit the text, is it's recompiling the whole document. That's great. That's definitely a solution.

00:42:23 - David Myers

But that was one big aspect of Octo that I cared a lot about, having a real-time, in-place rendered plain-text Markdown editor, not a separate edit panel and preview panel that are both visible or that you switch between. I wanted real-time, in-place, to see generally what this is going to look like, what the final outcome of this document is. Because for me, for note-taking, the plain-text version of the Markdown is actually the final product. I'm not going to compile this to some HTML page that I then host somewhere. I could, and it'd be nice to know that it's going to look similar, but in reality the final format of my document is still just plain-text Markdown. That's what I'm writing in, and this is just for my own personal structuring of notes. And so I originally built the editor using a tool called CodeMirror, CodeMirror 5 to be specific, which is a text editor library.

00:43:39 - David Myers

It's open source. While I liked it, it's meant to be more of a general-purpose library, and doing things like changing font sizes and applying inline previewing of images and things like that was actually really difficult to get working. Since then, I've upgraded to CodeMirror 6, which actually just released earlier this year. Finally, I switched Octo to CodeMirror 6 while it was still in progress back in, I want to say, January-ish of this year. But CodeMirror 6 is essentially a complete rewrite of CodeMirror, the text editor library that uses contenteditable behind the scenes. It performs its own sort of manipulation of that contenteditable DOM to make it 100% consistent across browsers, and it makes it completely consistent with the tokenization of your text and how that gets converted into HTML. CodeMirror is a web-based text editor library, very similar to Monaco, which is the Microsoft text editor that powers VS Code.

00:44:56 - Ishan Anand

Before we wrap up, and I saw that Jason raised his hand and is now up, are there any other libraries you'd recommend people look at as an in-browser editor library?

00:45:09 - David Myers

For the purposes of text editing, it all, of course, like everything, depends. But for the purposes of general text editing, especially if you need things like syntax highlighting and tokenization of your text, CodeMirror is my top pick for sure. Monaco is great, and it obviously is backed, but it's also, I believe, open source, and it's backed by Microsoft, and it powers VS Code, so it obviously has a lot of buy-in. But Monaco struggles a lot with incredibly large documents because it is, and I'm going to butcher the terminology here. What's funny is Nathan in this call actually would know a lot more about the actual parsing aspect of this. But CodeMirror is an incremental parser, which essentially means it can parse pieces of the overall text without having to continually parse the entire text, and Monaco is not, and therefore it can't handle very large documents. Also, Monaco is not built to be touchscreen-friendly, which means it doesn't work very well on mobile applications, which is something I care about again with Octo being a cross-platform web app. So CodeMirror would be my top choice by far, I'd say.

00:46:27 - Ishan Anand

Ah, that's good. Those are good call-outs, especially given that I'm sure people would say, oh, let's use Monaco. If it's good enough for VS Code, it's good enough for anybody. Jason, you came up to the stage. I'll let you ask your question. Go ahead.

00:46:43 - Jason

Well, I think David already answered my question. I was going to ask about the editor piece, but he did an amazing job going through the evolution of his editor inside Octo. Just my two cents: I've gone down fairly deep in the rabbit hole on database synchronization using things like CRDTs. Yjs is a pretty popular library in that space now. And the overlap with editing is Tiptap, which is like a headless wrapper around ProseMirror, also related to CodeMirror. So I was just going to throw in my two cents on a recommendation for more of a text-based editor with collaborative editing, so true offline-online synchronization with multiple editors. I've been going down that rabbit hole recently and found it rather interesting.

00:47:40 - Ishan Anand

This is why I love the audience, when we get these kinds of conversations. Sorry, go ahead, David.

00:47:47 - David Myers

I was just going to say I'm glad that you mentioned Tiptap because it is a great solution for WYSIWYG editors.

00:47:55 - Jason

Absolutely.

00:47:56 - David Myers

And to clarify there, I think it's really important to call that out as well. You talk about a typical end-user product, WYSIWYG is what most people probably want. What that means, it's an acronym, it stands for what you see is what you get, and essentially just means that even though you can use macros and shortcuts and essentially Markdown-ish typing when you're writing your documents, it gets converted into styled text instead of leaving the actual descriptor tokens in the final document. Those get wiped out. So essentially, in a Markdown document where you use a hashtag and then a space to create a header, if you did that in Google Docs with their quote-unquote Markdown mode enabled, it actually strips out that initial hashtag and just converts it into a top-level header because it is a WYSIWYG editor. Tiptap is awesome if you want a WYSIWYG editor. ProseMirror, by the way, is built on top of CodeMirror, so probably a good call-out there. ProseMirror is built on top of CodeMirror 6, the latest version, and Tiptap's built on top of that.

00:49:03 - David Myers

Very similar. You can use a lot of CodeMirror extensions in it, a lot of awesome functionality. But the key takeaway there, I'd say, is make sure you want a WYSIWYG, because removing the WYSIWYG portion of Tiptap, I believe, is a bit more difficult since it's built on top of ProseMirror.

00:49:19 - Jason

Yeah, absolutely. If your target is Markdown.

00:49:22 - David Myers

Yeah.

00:49:22 - Jason

Using something like Tiptap is probably not ideal.

00:49:26 - David Myers

So yeah, the biggest thing for me is plain text. My target for Octo is people in the technical space, and this might be a minority preference, actually, I'm not sure, but at least in the subset of people that I've dealt with, keeping your documents in plain text and not performing the sort of fancy upgrading that a lot of notes apps actually do, like swapping out quotes for fancy quotes, for example, or performing these WYSIWYG updates, is something I definitely wanted to avoid.

00:50:02 - Ishan Anand

Jason, you mentioned CRDTs, conflict-free replicated data types. Do you want to explain for the audience what those are, just for a minute or a couple minutes?

00:50:13 - Jason

Sure. I don't know that I could necessarily provide a technical description of exactly how they work.

00:50:22 - Ishan Anand

Oh no, just the goal. Just because you threw the buzzword around, explain what it is.

00:50:26 - David Myers

Yeah, the goal.

00:50:27 - Jason

Yeah, I guess the goal would be to be able to create applications that allow multiple people to edit the data in real time. So your Google Docs, maybe your Figma, any kind of, what do they call them, multiplayer applications now, where you have a bunch of people with a concurrent set of shared data, whether that be a document or a canvas or maybe even some other kind of application data, that you don't want to have to worry about synchronization. It has a prescribed way of synchronizing the data between different clients, maybe something sort of akin to Git, but in a more real-time manner. So there's a lot of upsides, but there are also some downsides in terms of, because everyone has the entire copy of the repository, so to speak, you have to be very careful about large data sets or your documents getting really, really large. As you know, it's impossible to delete anything in a shared database or shared data set like that. So it's not a silver bullet that can just solve all of your synchronization problems

00:51:42 - Jason

just by sprinkling in a library like Yjs.

00:51:46 - Ishan Anand

Is there, besides that, any libraries or technologies or tools you've been looking at that you'd recommend people, if they just want to learn more, go look at, rather than the academic papers?

00:51:57 - Scott Steinlage

Yeah, go ahead.

00:51:58 - Jason

Yeah, it'd be interesting to see if David has done any digging as well, given you're very articulate with a lot of these things and you've got an app out in public. But I've looked at Replicache. It's another interesting one where it's trying to do data synchronization. I'm trying to think of some other ones. I think the biggest issue is

00:52:22 - Scott Steinlage

where

00:52:22 - Jason

is the single source of truth. Solutions like Replicache, I think, are more that the server owns the master, whereas solutions like CRDTs are technically peer-to-peer. So you kind of have to force one of the clients to be the one that is the single source of truth if you want to have a traditional database store all of your data. So thinking about those kinds of solutions, whether you have the server be your single source of truth or if it is more of a peer-to-peer distributed thing like Git outside of GitHub traditionally, you have to think about those kinds of things. It's not as easy as just shoehorning it into a traditional client-server database-type application.

00:53:12 - David Myers

Yeah, Yjs is actually the tool I had pinned. As with many products, I have a roadmap that is much larger than what I can work through on a day-to-day basis, especially since I have an actual full-time job outside of this. But Yjs is definitely the solution I had looked at for real-time collaboration on documents in Octo, which is a feature that is on the roadmap. But I had not considered using it as a sort of reconciliation tool for cross-clients under the same user. I'll definitely have to look into that. I'm not positive what that would look like. I'm not well-versed in Yjs or its alternatives, but I like that idea.

00:54:00 - Jason

Yeah, I think that's definitely something to look into. There is a WebSocket implementation, so in terms of the protocol to share the document updates with each other, you could do it that way. I think the most common way would most likely be WebSocket-based. So you have to have a WebSocket-capable server platform that could then keep all the clients up to date. That is a little bit more involved. The other thing that I've run into, because Tiptap, the team behind Yjs, and I think Tiptap and Yjs are kind of the same team, I could be wrong on that, but I think that's the case. They also have a WebSocket server called Hocus Pocus that I think you have to be a sponsor to get access to.

00:54:48 - Ishan Anand

I've.

00:54:48 - Jason

I've been using it for about the better part of the year on an internal project. Basically, what you store in your database is a binary, or not a binary, but essentially a binary. You have to store it in a blob, and that's the document. And if you want to get a snapshot of it, you literally have to take a snapshot of the binary, and that can dump out into whatever. Well, in the case of Tiptap, then it would be like a JSON parse of the document. Again, it's not exactly straightforward. You have this table with a bunch of binary blobs in it that you can't look at unless you open them up and parse them with the Yjs client, which is expensive. Again, it's not exactly straightforward.

00:55:37 - David Myers

Yeah. Another aspect on top of that that I have to worry about is the client-side encryption aspect, which means I can't allow any library or third-party tooling, or Yjs for example... The only way I'll be able to use Yjs is peer-to-peer directly using WebRTC because I do not want any plain-text data flowing from the client to the server to another client when a user has that enabled. It's not enabled by default, but it can be enabled, which means I should never be sending plain-text information away from a user's browser unless it's a direct peer-to-peer connection, which Yjs does support. So that's probably the strategy I'd be looking at for that.

00:56:25 - Jason

Yeah, definitely.

00:56:26 - Ishan Anand

That's an interesting constraint. We have only a few minutes left. I have to go pretty much at the top of the hour, but I wanted to give Bro Nifty the last question here. But before I do that, in case I have to jump, just thank you to David and everyone else for joining today. And with that, Bro Nifty, I'll turn it over to you to ask the last question or comment.

00:56:50 - Bro Nifty

Thank you, thank you, Ishan. I'm just here to contribute to the buzzword inflation. These are really wonderful updates. I'm furiously taking notes on everything you guys were saying. I've got to re-listen to this. But I'm just curious whether, and I think this is within the same realm, so Builder.io, which is just an absolutely amazing site, uses drag-and-drop editing. We got Markdown, WYSIWYG, drag-and-drop, three different kinds of concepts. One is more for site building, for content sites, and the others are for straight editing text, different ways of editing text, like Markdown versus the WYSIWYG style, whatever. But I guess my question would be, I don't really have a question. Do you guys have any opinion about how that fits in, or if that's a good idea, or if that has anything to do with Tiptap or CodeMirror or the OctoApp? Does that kind of fit within the realm, or does it have anything to do with it? Or am I just kind of off on the deep end here? What do you guys think?

00:58:02 - David Myers

I think personally, and I'll go since I'm unmuted here, but personally I think that if it's under the realm of no-code technology, which is the idea of essentially being able to create a UI that then gets converted into some underlying codebase, I'd call it a bit different from the text editor frameworks. But in terms of technological uniqueness, or the fact that it's trying to simplify a large amount of complexity via the user experience, I mean it's definitely in the same realm there.

00:58:40 - Ishan Anand

Another way maybe to look at it is I'm sure Builder has some text edit areas that might be contenteditable or something similar within it for some of the components you might edit. Some of them might be just straight textareas, others might be. So it probably has these problems contained within it, and it probably has unique constraints and problems dealing with all of those at once, at least in the editing experience. That would be my guess. But I would consider it a slightly different use case.

00:59:20 - Jason

Yeah, I'd say it is adjacent to what we're talking about, especially if we expand that to talk about data synchronization. Figma, I think, their architecture is the server owns the document and not the clients. So those are the two different... that's like the main architectural difference you have to think about. Where you start with all this is who owns the master copy: is it the client or is it the server? And then your decisions cascade down from there.

00:59:59 - Bro Nifty

Yeah. So as far as I know, this is sort of like a what does the universe look like discussion. But yeah, my notes here for these editors, like CMS, if you want to DIY a CMS or whatever, I'm thinking TinaCMS.

01:00:17 - David Myers

Yeah.

01:00:18 - Bro Nifty

That's the lowest-level thing I can think of is TinaCMS. Anyways, okay, so this is kind of like, I feel like, a DIY CMS discussion, which is similar. I think it fits within the rubric of a drag-and-drop editor. You're drag-and-dropping content, which is CMS. But if you're doing it from Stackbit, which is what Builder.io builds on top of, as well as... who else builds on top of it? Something you really haven't heard of before would be Webflow, things like that. They use that too. So it's the DIY part. It's like the layer that these front-end products are building on top of for doing CMS. So whether you're doing text editing, that's CMS really.

01:01:07 - Scott Steinlage

Right.

01:01:08 - Bro Nifty

It's a tool to build a CMS on top of, I'm thinking. So anyway, yeah. Well, anyways, Octo is very cool. I joined and I'll make some notes. Thanks, guys.

01:01:24 - David Myers

Thank you. I wanted to mention one last thing. I know we probably have to wrap it up. So the core editor of Octo has been something I've been hand-building and crafting over time. It is built on top of CodeMirror 6, but there's actually a core editor that is a separate library built on top of CodeMirror 6. That editor is what Octo uses, and it's called Ink MDE, so ink-mde. That is also an open-source standalone project on my GitHub, which is github.com/voracious. The editor itself can be dropped into any site. If you want the same Markdown editor that powers Octo in any other random text field on any other random site, you can literally just install it and use it.

01:02:22 - Scott Steinlage

Awesome.

01:02:22 - David Myers

Yeah, yeah.

01:02:23 - Jason

I was just looking at that code while we were talking. Great stuff.

01:02:30 - Scott Steinlage

Thank you so much for sharing that. Looks like we lost Ishan here, unfortunately, but that's okay. We are at the top of the hour, bottom of the hour, what are you going to call it? Thank you so much for all of this amazing conversation we had today. I'm really excited about OctoApp. I think there's a big future for it. I think there's definitely a user base there and people are excited about it. Obviously, you just gained another user today. Super cool. Thank you all so, so much. Greatly appreciate everything we do here. Remember, we do this every Wednesday, 12 PM Pacific Standard Time. And if you got value from David, click on him, follow him. You know, probably putting value out in other places too. Super awesome. Oh, and by the way, if you're not on our newsletter yet, go to javascriptjam.com, sign up. You don't want to miss out on the latest and greatest in web dev, JavaScript. Oh, one other thing. Next week, we're going to be having some fun too. We have another guest. You want to know who?

01:03:47 - Anthony Campolo

Yeah.

01:03:47 - Scott Steinlage

Do get the newsletter. I'm kidding. I'll tell you who it is. Okay, okay, you're following me. I can't hold it back anymore. We're having Dan Moore with FusionAuth joining us, talking about WebAuthn, and it could be a good time. And I believe, if I'm not mistaken, Anthony is going to be here again.

01:04:16 - Anthony Campolo

I will be. I'm also going to be staying here for all future episodes. I'll be here for an hour and a half so that we can have this go till 3:30.

01:04:26 - Scott Steinlage

Oh my gosh. You hear that, folks? We just got another half-hour increase in JavaScript Jam Live.

01:04:34 - Anthony Campolo

I bet there'd be more questions if people had them. In future events, people can keep asking the questions that they have.

01:04:40 - Scott Steinlage

Absolutely, absolutely. They shall go on. It'll be good. And Anthony is going to be hosting with me next week. It's gonna be great. So thank y'all so much. Greatly appreciate everything y'all do. Love y'all. Everybody give David some high fives, claps, hearts, some love. You all right? 100. Awesome. Thank y'all so much. Thanks, David, man. Appreciate you.

01:05:13 - Anthony Campolo

Outro music.

01:05:15 - Scott Steinlage

Yeah. Here it comes. Watch out, y'all. Thank you so much, and we'll see you next week. Peace.

On this pageJump to section