Search code examples
reactjstypescriptwebpack-dev-servermonaco-editor

monaco-editor in React using TypeScript -> cannot find module 'monaco-editor'


I have been trying to integrate monaco-editor in a React app. I have had success but still facing issues. Below I have provided details of my development setup.

I have tsconfig.json file configured like this:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "CommonJS",
    "lib": ["dom", "es5", "es2015.collection", "es2015.promise", "dom.iterable"],
    "jsx": "react",
    "sourceMap": true,
    "checkJs": false,
    "outDir": "./dist",
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": "./node_modules",
    "typeRoots": ["node_modules/@types"],
    "allowJs": true,
    
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,

    "preserveConstEnums": true,    
    "isolatedModules": true
  },

  "include": ["./src/**/*"],
  "exclude": ["node_modules"]  
}

And my package.json has the scripts configured like this:

"scripts": {
    "test": "jest",
    "start": "webpack serve",
    "server": "nodemon --exec ts-node server.tsx",
    "build": "webpack -w --mode=development"
  }

The start script is using webpack-dev-server and the server is using ts-node to run my server.tsx file.

The monaco-editor is imported in a React component .tsx file as import * as monaco from 'monaco-editor';

When I run this command: npm run start which uses webpack-dev-server all done nicely and I am able to see my app in the browser.

However, when I run this command: npm run server which uses ts-node to execute server.tsx file, I get this error:

Error: Cannot find module 'monaco-editor'
Require stack:
- D:\Development\Workstation\VividCodes.UI_OLD\src\components\TestMonaco.tsx
- D:\Development\Workstation\VividCodes.UI_OLD\src\components\App.tsx       
- D:\Development\Workstation\VividCodes.UI_OLD\server.tsx
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
    at Function.Module._load (internal/modules/cjs/loader.js:725:27)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)

This is a copy of the content of server.tsx file:

import express from 'express';
import * as React from 'react';
import ReactDOMServer from 'react-dom/server';

import App from './src/components/App';

const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config.js');

const webpackHotMiddleware = require('webpack-hot-middleware');

const server = express();
const compiler = webpack(config);
const port = 3000;

server.use(
  webpackDevMiddleware(compiler, {
    publicPath: config.output.publicPath,
  })
);

server.use(webpackHotMiddleware(compiler));

server.get('/', (req: any, res: any) => {
  const initialMarkup = ReactDOMServer.renderToString(<App />);  
  console.log(initialMarkup);

  res.send(`
    <html>
      <head>
        <title>Monaco_Editor</title>
      </head>
      <body>
        <div id="mountNode">${initialMarkup}</div>
        <script src="/app.bundle.js"></script>
        <script src="/editor.worker.bundle.js"></script>
        <script src="/json.worker.bundle.js"></script>
        <script src="/css.worker.bundle.js"></script>
        <script src="/html.worker.bundle.js"></script>
        <script src="/ts.worker.bundle.js"></script>
      </body>
    </html>
  `)
});

server.listen(port, () => console.log(`Server started on port: ${port}`));

My plan was to use a correct custom server to render my components dynamically, than doing so on client-side.


Solution

  • Monaco-editor does not support server-side rendering. It cannot rebind to the existing DOM node. It has to be done on client-side unfortunately. And, there is currently no plans on implementing the server-side rendering functionality.

    However, for those who have the same concern, if Webpack is what you're using for bundling, make sure you set minimising option to 'true'. This way, your bundled JS files will be much smaller. Also, there is a 'min' version of monaco-editor which can be used for production; but it's based on AMD.