You may need an additional loader to handle the result of these loaders (upgrading Monaco Editor)

I wanted to upgrade the version of Monaco Editor to v0.31.1. I did npm install [email protected], and the recompilation by sudo PORT=8000 HTTPS=true ./node_modules/.bin/react-app-rewired start gave me the following error:

Failed to compile.

./node_modules/monaco-editor/esm/vs/language/html/monaco.contribution.js 154:11
Module parse failed: Unexpected token (154:11)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|     dispose() {
|       onLanguageListener.dispose();
>       mode?.dispose();
|       mode = void 0;
|     }

Could anyone help?

Edit 1: package.json before the upgrading:

{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@fluentui/react": "^8.33.0",
    "@handsontable/react": "^9.0.2",
    "@material-ui/core": "^4.9.8",
    "@microsoft/office-js-helpers": "^1.0.2",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "@types/react-stripe-elements": "^6.0.4",
    "@uifabric/react-cards": "^0.109.49",
    "axios": "^0.19.2",
    "color": "^3.1.2",
    "copy-to-clipboard": "^3.3.1",
    "cross-storage": "^1.0.0",
    "dva": "^2.4.1",
    "dva-model-creator": "^0.4.3",
    "formik": "^2.1.4",
    "handsontable": "^9.0.2",
    "highcharts": "^7.0.3",
    "highcharts-react-official": "^3.0.0",
    "lodash": "^4.17.15",
    "moment": "^2.24.0",
    "monaco-editor": "^0.20.0",
    "monaco-languageclient": "^0.13.0",
    "node-sass": "^4.14.1",
    "office-ui-fabric-core": "^11.0.0",
    "office-ui-fabric-react": "^7.105.4",
    "query-string": "^6.11.1",
    "react": "^16.13.1",
    "react-app-polyfill": "^1.0.6",
    "react-bootstrap": "^1.0.1",
    "react-dom": "^16.13.1",
    "react-meta-tags": "^1.0.1",
    "react-monaco-editor": "^0.35.0",
    "react-scripts": "3.4.1",
    "react-stripe-elements": "^6.1.1",
    "redux-devtools-extension": "^2.13.8",
    "styled-components": "^5.0.1",
    "typescript": "^3.8.3",
    "yup": "^0.28.3"
  },
  "scripts": {
    "start": "PORT=3000 react-app-rewired start",
    "start:https": "HTTPS=true  react-app-rewired start",
    "build": "react-scripts --max_old_space_size=8096 build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@types/color": "^3.0.1",
    "@types/cross-storage": "^0.8.29",
    "@types/jest": "^25.1.4",
    "@types/lodash": "^4.14.149",
    "@types/node": "^13.9.5",
    "@types/office-js": "^1.0.92",
    "@types/query-string": "^6.3.0",
    "@types/react": "^16.9.27",
    "@types/react-dom": "^16.9.5",
    "@types/react-redux": "^7.1.7",
    "@types/styled-components": "^5.0.1",
    "@types/yup": "^0.26.33",
    "css-loader": "^3.5.3",
    "react-app-rewired": "^2.1.8",
    "style-loader": "^1.2.1"
  }
}

When "monaco-editor": "^0.20.0", npm list monaco-editor returns

$ npm list monaco-editor
npm list monaco-editor
[email protected] /frontend
├── UNMET DEPENDENCY [email protected] 
└─┬ UNMET DEPENDENCY [email protected]
  └── UNMET DEPENDENCY [email protected] 

npm ERR! missing: [email protected], required by [email protected]
npm ERR! missing: [email protected], required by [email protected]
npm ERR! missing: [email protected], required by [email protected]

When "monaco-editor": "^0.31.1", npm list monaco-editor returns

$ npm list monaco-editor
[email protected] /frontend
├── UNMET DEPENDENCY [email protected] 
└─┬ UNMET DEPENDENCY [email protected]
  └── UNMET DEPENDENCY [email protected] 

npm ERR! missing: [email protected], required by [email protected]
npm ERR! missing: [email protected], required by [email protected]
npm ERR! missing: [email protected], required by [email protected]

Edit 2:

Following the anwser of @Bart, I installed @babel/preset-env by yarn add @babel/preset-env --dev and created babel.config.json with {"presets": ["@babel/preset-env"]}, but react-app-rewired start gave the same error.

Then, I realized that I do have a file config-overrides.js, the content is as follows:

module.exports = function override (config, env) { 
    // disable chunks so the index.html won't change during development 
    config.optimization.splitChunks = {
        cacheGroups: {
            default: false,
        },
    };
    config.optimization.runtimeChunk = false;
    return config;
}

I then added the part for config.module.rules, but the compilation returned the same error.

Additionally, it seems that the project can be built with yarn build without this error. But building the project takes time.

module.exports = function override (config, env) {
    config.module.rules = 
        [
          {
            test: /\.m?js$/,
            exclude: /(node_modules|bower_components)/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env']
              }
            }
          }
        ]
    
    // disable chunks so the index.html won't change during development 
    config.optimization.splitChunks = {
        cacheGroups: {
            default: false,
        },
    };
    config.optimization.runtimeChunk = false;
    return config;
}

Solution 1:

The problem seems to be with the optional chaining syntax (the ?. in mode?.dispose();). This is also listed as a breaking change in the changelog of Monaco:

the generated code is now bundled with ESBuild and the generated code makes use of newer browser features, e.g. optional chaining. These features should be available in all browsers, but they might not be parsed correctly by older JS parsers, specifically parcel v1 might have problems parsing the JS.

This syntax can be handled well by the correct Babel plugin. In general, it’s better to use @babel/preset-env instead of separate plugins. This preset takes care of several plugins at once. Do you have a babel config file where you could include this preset? This can be as simple as installing @babel/preset-env as a dev dependency, and creating a babel.config.json file in your project root with the following contents:

{
  "presets": ["@babel/preset-env"]
}

Secondly, it could mean that your Babel config is already working correctly, but that anything inside node_modules is ignored by Webpack (used under the hood by Create React App), as is often done to speed up transpilation times. Then you’ll have to find a way to overrule the Webpack config so that your monaco dependency is not skipped for transpilation.

I see you’re already using react-app-rewired, so updating the Webpack config is done as explained in their documentation:

// config-overrides.js
module.exports = function override (config, env) { 
    // disable chunks so the index.html won't change during development 
    config.optimization.splitChunks = {
        cacheGroups: {
            default: false,
        },
    };
    config.optimization.runtimeChunk = false;
    
    config.module.rules = [
      {
        test: /node_modules\/monaco-editor/,
        use: {
          loader: 'babel-loader',
          // if you include your babel config here,
          // you don’t need the `babel.config.json` file
          options: { presets: ['@babel/preset-env'] }
        }
      },
      ...config.module.rules
    ]
    return config;
}

Integrating Babel can be done via babel-loader, see instructions here.

Solution 2:

I have the same problem as you in my Vue project.

Maybe you can handle it like this:

Download the source code of monaco-editor from GitHub

Modify the function buildESM and the function buildOneAMD in file monaco-editor/build/utils.js

eg: set target to es2015

function buildESM(options) {
    build({
        entryPoints: options.entryPoints,
        bundle: true,
        target: 'es2015',
        format: 'esm',
        define: {
            AMD: 'false'
        },
        banner: {
            js: bundledFileHeader
        },
        external: options.external,
        outbase: `src/${options.base}`,
        outdir: `out/release/${options.base}/esm/`,
        plugins: [
            alias({
                'vscode-nls': path.join(__dirname, 'fillers/vscode-nls.ts')
            })
        ]
    });
}

and then, npm run release and wait until it's done

npm run release

you get the folder monaco-editor/release, copy the contents of the folder release and paste into the folder modules/monaco-editor you created under your project.

in your project, modify the package.json, set monaco-editor to file:modules/monaco-editor, and npm install

{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "monaco-editor": "file:modules/monaco-editor",
  }
}
npm install

It's my way to solve this problem above, if somebody find the better solution, please reply to me here.

Excuse me, my English is bad.