How CodeMirror v6 dev setup retrieves packages without a monorepo

Ramu NarasingaRamu Narasinga
3 min read

In the OSS community, it is quite common to come across monorepo projects where the workspaces and packages are all in a single repository. CodeMirror has a different style to the way packages are managed, each package that is used is a repository on its own. In this article, we analyse what these packages are that CodeMirror uses and how they are installed when you want to setup CodeMirror v6 locally to contribute.

bin/packages.js

Before we analyse the install function, let’s first understand the variours packages that make up the CodeMirror. You
will find these packages listed in bin/packages.js file

These below are the core packages:

exports.core = [
 "state",
 "view",
 "language",
 "commands",
 "search",
 "autocomplete",
 "lint",
 "collab",
 "language-data",
 "codemirror",
]

These below are the non-core packages.

exports.nonCore = [
 "lang-javascript",
 "lang-java",
 "lang-json",
 "lang-cpp",
 "lang-php",
 "lang-python",
 "lang-go",
 "lang-css",
 "lang-sass",
 "lang-html",
 "lang-sql",
 "lang-rust",
 "lang-xml",
 "lang-markdown",
 "lang-lezer",
 "lang-wast",
 "lang-angular",
 "lang-vue",
 "lang-liquid",
 "lang-less",
 "lang-yaml",
 "legacy-modes",
 "theme-one-dark",
 "merge"
]

You will find repositories in the CodeMirror organisation for all these packages shown above. There is no single repository containing all these packages like in a monorepo, instead you have all these repositories that make up the CodeMirror.

exports.core and exports.nonCore

You will find that these packages are accessed via a function named loadPackages.

You might be wondering what exports.all here is in the above image, at line 42. It is interesting how the concat is made on exports.core and exports.nonCore and this you have all these packages merged into one array and assigned to exports.all.

exports.loadPackages

let packages = exports.all.map(n => new Pkg(n))

Using map on exports.all, new Pkg class is instantiated using the Pkg class that’s shown below:

class Pkg {
 constructor(name) {
 this.name = name
 this.dir = join(__dirname, "..", name)
 this.main = null
 if (name != "legacy-modes" && fs.existsSync(this.dir)) {
 let files = fs.readdirSync(join(this.dir, "src")).filter(f => /^[^.]+\.ts$/.test(f))
 let main = files.length == 1 ? files[0] : files.includes("index.ts") ? "index.ts"
 : files.includes(name.replace(/^(theme-|lang-)/, "") + ".ts") ? name.replace(/^(theme-|lang-)/, "") + ".ts" : null
 if (!main) throw new Error("Couldn't find a main script for " + name)
 this.main = join(this.dir, "src", main)
 }
 }
}

It technically sets name, dir and main.

let packageNames = Object.create(null)
for (let p of packages) packageNames[p.name] = p

Object.create(null) creates an empty object, that’s fancy way of creating a obj that would otherwise be just obj = {} and finally below is the return statement.

return {
  packages, 
  packageNames, 
  buildPackages: packages.filter(p => p.main)
}

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

I am open to work on an interesting project. Send me an email at ramu.narasinga@gmail.com

My Github - https://github.com/ramu-narasinga My website - https://ramunarasinga.com My Youtube channel - https://www.youtube.com/@ramu-narasinga Learning platform - https://thinkthroo.com Codebase Architecture - https://app.thinkthroo.com/architecture Best practices - https://app.thinkthroo.com/best-practices Production-grade projects - https://app.thinkthroo.com/production-grade-projects

References

  1. https://github.com/codemirror/dev/blob/main/bin/cm.js#L81

  2. https://github.com/codemirror/dev/blob/main/bin/packages.js

  3. https://github.com/orgs/codemirror/repositories

0
Subscribe to my newsletter

Read articles from Ramu Narasinga directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ramu Narasinga
Ramu Narasinga

I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.