Cannot add custom langauge package to work in CodeMirror

I’m trying to include a custom Language Package with Lezer into an CodeMirror 6 editor. However, the editor doesn’t show up so far. Instead, I get this error:

Uncaught Error: Unrecognized extension value in extension set ([object Object]). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.
    inner file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:2020
    inner file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:1995
    inner file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:2021
    inner file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:1995
    inner file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:2021
    inner file://.../CodeMirrorProblems/editor-example/editor.bundle.js:1995
    flatten$1 file://.../CodeMirrorProblems/editor-example/editor.bundle.js:2024
    resolve file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:1932
    create file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:2759
    EditorView file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:10629
    <anonymous> file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:38297
    <anonymous> file:///.../CodeMirrorProblems/editor-example/editor.bundle.js:38302
editor.bundle.js:2020:26

Steps to Produce:

  1. Set up a custom Language Package in the local directory CodeMirrorProblems/lang-example:
    • Clone the Language Package Template from the Git Example Repository.
    • Replace all occurrences of EXAMPLE with Dummy.
    • Bundle with npm run prepare.
  2. Set up an Editor as described in the Bundling Tutorial:
    • Create a new directory, CodeMirrorProblems/editor-example.
    • Add editor.mjs and index.htmlas described.
    • Set up a new Node.js module and add CodeMirror, @codemirror/lang-javascript. and Rollup dev dependencies.
    • Bundle with node_modules/.bin/rollup editor.mjs -f iife -o editor.bundle.js \ -p @rollup/plugin-node-resolve. At this point, the JavaScript Editor works.
  3. Try to include the Language Package:
    • Modify the editor.mjs file to use the Dummy Language Package.
    • Link the Language Package to use in the Editor project.
    • Bundle the Editor with Rollup.

My editor.mjs now:

import {EditorView, basicSetup} from "codemirror"
import {Dummy} from "codemirror-lang-dummy"

let editor = new EditorView({
  extensions: [basicSetup, Dummy()],
  parent: document.body
})

My package.json for the Editor:

{
  "name": "editor-example",
  "version": "1.0.0",
  "description": "CodeMirror example that will use a language example definition.",
  "main": "editor.js",
  "scripts": {
    "prepare": "rollup editor.mjs -f iife -o editor.bundle.js -p @rollup/plugin-node-resolve"
  },
  "author": "bjthehun",
  "license": "ISC",
  "dependencies": {
    "@codemirror/lang-javascript": "^6.1.7",
    "codemirror": "^6.0.1",
    "codemirror-lang-dummy": "file:../lang-example"
  },
  "devDependencies": {
    "@rollup/plugin-node-resolve": "^15.0.2",
    "rollup": "^3.21.0"
  }
}

My package.json for the Language Package:

{
  "name": "codemirror-lang-dummy",
  "version": "0.1.0",
  "description": "Dummy language support for CodeMirror",
  "scripts": {
    "test": "mocha test/test.js",
    "prepare": "rollup -c"
  },
  "type": "module",
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "exports": {
    "import": "./dist/index.js",
    "require": "./dist/index.cjs"
  },
  "types": "dist/index.d.ts",
  "sideEffects": false,
  "dependencies": {
    "@codemirror/language": "^6.0.0",
    "@lezer/highlight": "^1.0.0",
    "@lezer/lr": "^1.0.0"
  },
  "devDependencies": {
    "@lezer/generator": "^1.0.0",
    "mocha": "^9.0.1",
    "rollup": "^2.60.2",
    "rollup-plugin-dts": "^4.0.1",
    "rollup-plugin-ts": "^3.0.2",
    "typescript": "^4.3.4"
  },
  "license": "MIT"
}

1 Like

How are you including codemirror-lang-dummy in your node_modules? By symlink? It likely has its own node_modules with copies of the CodeMirror packages, and will load those, causing multiple instances of the same package to be loaded, which leads to this kind of error.

You can try to use npm workspaces to get a single dependency tree for both your own code and the language-mode, or publish it to npm and install it normally (in a way that deduplicates). Or try to manually put all the files in the right place but that gets annoying.

1 Like

I did previously include codemirror-lang-dummy by symlink, yes. I’ve tried to set up a common workspace for both editor and language, but it still doesn’t work. (I only recently started using npm, so sorry if I’m asking something that should be obvious.)

I’ve set up a common workspace for both packages in the CodeMirrorProblems directory, like so:

{
  "name": "codemirrorproblems",
  "version": "1.0.0",
  "description": "Editor + Language Package I need to work with",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "workspaces": [
    "editor-example",
    "lang-example"
  ],
  "author": "bjthehun",
  "license": "ISC"
}

For consistency, I renamed codemirror-lang-dummy into lang-example.

And I also removed the direct dependencies (plus node_modules folders and package-lock.json) from both modules, and reincluded them for the workspace (npm install -w ...).
However, now the language package doesn’t build anymore:

$ npm run prepare --workspace=lang-example

> lang-example@0.1.0 prepare
> rollup -c

[!] Error: Directory import '.../CodeMirrorProblems/node_modules/@lezer/generator/' is not supported resolving ES modules imported from .../CodeMirrorProblems/node_modules/@lezer/generator/dist/rollup-plugin-lezer.js
file:///.../CodeMirrorProblems/node_modules/@lezer/generator/
    at new NodeError (node:internal/errors:387:5)
    at finalizeResolution (node:internal/modules/esm/resolve:400:17)
    at moduleResolve (node:internal/modules/esm/resolve:965:10)
    at defaultResolve (node:internal/modules/esm/resolve:1173:11)
    at nextResolve (node:internal/modules/esm/loader:173:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:852:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:439:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)
    at link (node:internal/modules/esm/module_job:75:36)


npm ERR! Lifecycle script `prepare` failed with error: 
npm ERR! Error: command failed 
npm ERR!   in workspace: lang-example@0.1.0 
npm ERR!   at location: /.../CodeMirrorProblems/lang-example 

That may have been an issue with @lezer/generator 1.2.2. I’ve tagged 1.2.3 with this patch.

I’ve updated @lezer/generator to this version, and now I can use the language-package in the editor. Thank you!