codemirror / dev

Development repository for the CodeMirror editor project
https://codemirror.net/
Other
5.54k stars 350 forks source link

How import Codemirror.Next in NextJS #277

Closed jefer94 closed 3 years ago

jefer94 commented 3 years ago

Next: https://nextjs.org/

My code

import React, { useRef, useEffect, useState, ReactElement } from 'react'
import styled from 'styled-components'
import { EditorView } from '@codemirror/next/view'
import { EditorState } from '@codemirror/next/state'
import { lineNumbers } from '@codemirror/next/gutter'
import { defaultKeymap } from '@codemirror/next/commands'
import { javascript } from '@codemirror/next/lang-javascript'
import { oneDark } from '@codemirror/next/theme-one-dark'
// import { UnControlled as CodeMirror } from 'react-codemirror2'

// const Div = styled.div`
//   & > div {
//     height: ${(v) => v.height};
//     max-height: ${(v) => v.height};
//     outline: 0!important;
//     background-color: ${(v) => v.theme.surface};
//     color: ${(v) => v.theme.white};
//     font-size: ${(v) => v.theme.fontSize};
//     padding-left: 15px;
//   }
// `

type Props = {
  readonly className?: string
  readonly content: string
}

function CodemirrorWrapperBase({ className, content }: Props): ReactElement {
  const [loading, setLoading] = useState(true)
  const div = useRef<HTMLHeadingElement>()
  const editor = useRef<EditorView>()

  useEffect(() => {
    if (loading) {
      // eslint-disable-next-line functional/immutable-data
      editor.current = new EditorView({
        state: EditorState.create({
          doc: content,
          extensions: [lineNumbers(), javascript(), oneDark]
        }),
        dispatch: (v) => console.log('xxxxxxxxxx', v)
        // extensions: [keymap(defaultKeymap)]
        // extensions: []
        // extensions: [keymap(defaultKeymap), new GutterMarker()]
      })
      setLoading(false)
    }

    else if (div && div.current && editor.current) div.current.appendChild(editor.current.dom)
  }, [loading])

  return (
    <div className={className} ref={div} />
    // <CodeMirror
    //   value="<h1>I ♥ react-codemirror2</h1>"
    //   options={{
    //     mode: 'xml',
    //     theme: 'material',
    //     lineNumbers: true
    //   }}
    //   onChange={(editor, data, value) => {
    //     console.log(value)
    //   }}
    // />
  )
}

type CodemirrorWrapperProps = {
  readonly height: string
}

export const CodemirrorWrapper = styled(CodemirrorWrapperBase)`
  & > div {
    height: ${(v: CodemirrorWrapperProps) => v.height};
    max-height: ${(v: CodemirrorWrapperProps) => v.height};
    outline: 0!important;
    background-color: ${(v) => v.theme.surface};
    color: ${(v) => v.theme.white};
    font-size: ${(v) => v.theme.fontSize};
    padding-left: 15px;
  }

Error

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /node_modules/@codemirror/next/view/dist/index.js 
require() of ES modules is not supported.
require() of /node_modules/@codemirror/next/view/dist/index.js from /.next/server/static/development/pages/index.js is an ES module file as it is a .js file whose nearest parent package.
json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename /node_modules/@codemirror/next/view/dist/index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /node_modules/@codemirror/next/view/package.json.

Next internally use Webpack, it only support CommonJS, but the dist folder is ES6, exist one example how use Codemirror.Next with NextJS or Webpack?

curran commented 3 years ago

Greetings,

I did some experiments when this repository was very young and I did manage to server render CodeMirror with syntax highlighting. Here's the code if it might be useful https://github.com/datavis-tech/codemirror-6-experiments/tree/master/packages/experiments/src/pages/pad

Writeup: https://medium.com/@currankelleher/codemirror-6-experiments-a3930bf03781

I'm not sure about the Next-specific details, but this may help. Good luck!

mischnic commented 3 years ago

I think this happens because Next tries to run codemirror in a Node environment, and Node.js's require() function doesn't work with pure ESM packages (so it's not related to Webpack at all).

jefer94 commented 3 years ago

Exist one way that one project with require() can load a pure ESM package? I trie build one CommonJS wrapper ( https://github.com/jefer94/choco/tree/master/packages/codemirror ), one build with ( https://github.com/jefer94/choco/blob/master/services/algorithm/package.json ) ( this horrible script https://github.com/jefer94/choco/blob/master/scripts/development/prepare.js )

I clone my Codemirror in one Yarn Workspace

But this error appear

view/src/inlineview.ts(74,61): error TS2339: Property 'text' does not exist on type 'InlineView'.
view/src/blockview.ts(35,48): error TS2339: Property 'attrs' does not exist on type 'BlockView'.
view/src/blockview.ts(49,59): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
  Type 'ContentView' is missing the following properties from type 'InlineView': merge, match, slice, getSide
view/src/blockview.ts(53,29): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
view/src/blockview.ts(65,46): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
view/src/blockview.ts(68,47): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
view/src/blockview.ts(73,58): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
view/src/blockview.ts(76,115): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
view/src/blockview.ts(82,71): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
view/src/blockview.ts(86,69): error TS2345: Argument of type 'ContentView' is not assignable to parameter of type 'InlineView'.
 // inlineview.ts
export abstract class InlineView extends ContentView {
  ...
  match(_other: InlineView) { return false } // inlineview.ts line 13
}
// contentview.ts
export abstract class ContentView {
  ...
  abstract children: ContentView[] // contentview.ts line 21
  ...
}
export interface BlockView extends ContentView {
   ...
}
// blockview.ts
export class LineView extends ContentView implements BlockView {
  children: InlineView[] = []
  ...
  let elts = source ? source.children : [] // blockview.ts line 37
  ...
  merge(from: number, to: number, source: BlockView | null, takeDeco: boolean): boolean {
    ...
    // Then try to merge any mergeable nodes at the start and end of
    // the changed range
    while (fromI < toI && elts.length && this.children[toI - 1].match(elts[elts.length - 1])) { // blockview.ts line 82
      elts.pop()
      toI--
    }
    ...
  }
}

That is all I collect about this error

interface BlockView extends ContentView { // blockview.ts line 11
  ..
}

class LineView extends ContentView implements BlockView { // blockview.ts line 21
  ///
}
marijnh commented 3 years ago

This package only exposes ES6 modules, which you can import in node 13+, but you can't require. As such, until other tools catch up with the brace new ES6 module world, I guess you'll have to run something like Rollup in between if you want to use CodeMirror with those tools.

jefer94 commented 3 years ago

But ESM support CommonJS modules, why use ESM output instead of CommonJS output? well i still for the NextJS ESM support

MatthewCaseres commented 3 years ago

https://github.com/vercel/next.js/issues/9607 Might want to try some of the workarounds described here.

OriginalEXE commented 3 years ago

I got it working by using the next-transpile-modules package. Here is an example of the next.js config for @codemirror/basic-setup + @codemirror/lang-json:

const withTM = require('next-transpile-modules')([
  '@codemirror/basic-setup',
  '@codemirror/autocomplete',
  '@codemirror/closebrackets',
  '@codemirror/commands',
  '@codemirror/comment',
  '@codemirror/fold',
  '@codemirror/gutter',
  '@codemirror/highlight',
  '@codemirror/history',
  '@codemirror/language',
  '@codemirror/lint',
  '@codemirror/matchbrackets',
  '@codemirror/panel',
  '@codemirror/rangeset',
  '@codemirror/rectangular-selection',
  '@codemirror/search',
  '@codemirror/state',
  '@codemirror/text',
  '@codemirror/tooltip',
  '@codemirror/view',
  '@codemirror/lang-json',
]);

module.exports = withTM();