This uses @timkendrick/monaco-editor
which has support for the combination of WebPack and a node-like browser environment
(that has global variables like process
and module
defined).
Create a next app:
create-next-app myapp
Install the dependencies:
npm install react-monaco-editor @timkendrick/monaco-editor express @zeit/next-css css-loader --save`
components/code-with-monaco.js
window.MonacoEnvironment = { baseUrl: '/monaco-editor-external' };
import * as monaco from '@timkendrick/monaco-editor/dist/external'
import React, { Component } from 'react'
import MonacoEditor from 'react-monaco-editor'
import '../node_modules/@timkendrick/monaco-editor/dist/external/monaco.css'
export default (props) => (
<MonacoEditor
width={500}
height={200}
language="javascript"
theme="vs-dark"
value=""
options={{selectOnLineNumbers: true}}
onChange={() => null}
editorDidMount={() => null}
{...props}
/>
)
const withCSS = require('@zeit/next-css')
module.exports = withCSS({
webpack: (config) => {
// Fixes npm packages that depend on `fs` module
config.node = {
fs: 'empty'
}
return config
}
})
const express = require('express')
const next = require('next')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = express()
server.use(
'/monaco-editor-external',
express.static(`${__dirname}/node_modules/@timkendrick/monaco-editor/dist/external`)
)
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
Change the scripts
in package.json
to use the custom server:
{
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
}
To use this component, use a dynamic import with ssr
set to false
.
These example pages show that Next.js can switch pages relatively cleanly
with these editor components on them, thanks to react-monaco-editor
and
the alternative build of monaco-editor.
import dynamic from 'next/dynamic'
const CodeWithMonaco = dynamic(import('../components/code-with-monaco'), {ssr: false})
import Link from 'next/link'
export default () => {
const someJs = [
"import {myCoolFunc} from './utils'",
'export default async () => {',
' await myCoolFunc()',
'}'
].join("\n")
return (
<div>
<div>
<Link href="/monaco-other-page"><a>Other Page</a></Link>
</div>
<CodeWithMonaco language="javascript" value={someJs} />
</div>
)
}
import dynamic from 'next/dynamic'
const CodeWithMonaco = dynamic(import('../components/code-with-monaco'), {ssr: false})
import Link from 'next/link'
export default () => {
const someCss = [
'.exampleDiv {',
' background-color: #003;',
' color: #ccc;',
'}'
].join("\n")
const someJs = [
"import {myCoolFunc} from './utils'",
'export default async () => {',
' await myCoolFunc()',
'}'
].join("\n")
return (
<div>
<div>
<Link href="/monaco"><a>Home</a></Link>
</div>
<CodeWithMonaco language="css" value={someCss} />
<CodeWithMonaco language="javascript" value={someJs} />
</div>
)
}
Run it with next dev
and go to localhost:3000
.