This is the repo for swyx's blog - Blog content is created in github issues, then posted on swyx.io as blog pages! Comment/watch to follow along my blog within GitHub
Monaco Editor is [the open source editor]
(https://github.com/microsoft/monaco-editor) used in VS Code, which itself is open source. I used to write my blogposts in VS Code, and as I make my own Dev.to CMS, I wanted to have all the familiar trappings of Monaco to help me out while I write.
Problems
However there are some issues we have to deal with:
Monaco is framework agnostic, so it requires writing some React bindings.
Monaco is written for a desktop Electron app, not for a server-side rendered web app.
This is solved by using import dynamic from "next/dynamic" and making Monaco a dynamic import.
Monaco also wants to offload syntax highlighting to web workers, and we need to figure that out
Next.js doesn't want any dependencies importing CSS from within node_modules, as this assumes a bundler and loader setup (e.g. webpack) and can have unintentional global CSS side effects (all global CSS is intended to be in _app.js).
The solution I use is informed by my usage of Tailwind CSS, which requires a recent version of PostCSS, which @zeit/next-css only has at 3.0 (because it is deprecated and not maintained).
I also use TypeScript, which introduces a small wrinkle, because Monaco Editor attaches a MonacoEnvironment global on the window object - I just @ts-ignore it.
// next.config.js
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
const withTM = require("next-transpile-modules")([
// `monaco-editor` isn't published to npm correctly: it includes both CSS
// imports and non-Node friendly syntax, so it needs to be compiled.
"monaco-editor"
]);
module.exports = withTM({
webpack: config => {
const rule = config.module.rules
.find(rule => rule.oneOf)
.oneOf.find(
r =>
// Find the global CSS loader
r.issuer && r.issuer.include && r.issuer.include.includes("_app")
);
if (rule) {
rule.issuer.include = [
rule.issuer.include,
// Allow `monaco-editor` to import global CSS:
/[\\/]node_modules[\\/]monaco-editor[\\/]/
];
}
config.plugins.push(
new MonacoWebpackPlugin({
languages: [
"json",
"markdown",
"css",
"typescript",
"javascript",
"html",
"graphql",
"python",
"scss",
"yaml"
],
filename: "static/[name].worker.js"
})
);
return config;
}
});
source: devto category: tutorial devToUrl: "https://dev.to/swyx/how-to-add-monaco-editor-to-a-next-js-app-ha3" devToReactions: 66 devToReadingTime: 4 devToPublishedAt: "2020-03-30T23:29:25.241Z" devToViewsCount: 8390
Bottom Line Up Front
I use a slightly modified version of the steps mentioned in this GitHub comment. Modifications were necessary because I use TailwindCSS with Next.js.
{% youtube 13UVFrGe80o %}
Motivations
Monaco Editor is [the open source editor] (https://github.com/microsoft/monaco-editor) used in VS Code, which itself is open source. I used to write my blogposts in VS Code, and as I make my own Dev.to CMS, I wanted to have all the familiar trappings of Monaco to help me out while I write.
Problems
However there are some issues we have to deal with:
import dynamic from "next/dynamic"
and making Monaco a dynamic import.node_modules
, as this assumes a bundler and loader setup (e.g. webpack) and can have unintentional global CSS side effects (all global CSS is intended to be in_app.js
).@zeit/next-css
andnext-transpile-modules
We can solve this with a solution worked out by Elliot Hesp on GitHub and a config from Joe Haddad of the Next.js team.
Solution
The solution I use is informed by my usage of Tailwind CSS, which requires a recent version of PostCSS, which
@zeit/next-css
only has at 3.0 (because it is deprecated and not maintained).I also use TypeScript, which introduces a small wrinkle, because Monaco Editor attaches a
MonacoEnvironment
global on thewindow
object - I just@ts-ignore
it.and then in your Next.js app code:
Since I'm using Tailwind, I'm also using PostCSS, which also tries to eliminate Monaco's CSS. You have to tell it to ignore that:
Catch up on the Dev.to CMS LiveStream!