Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for JSX #264

Open
Raathigesh opened this issue Nov 14, 2016 · 59 comments
Open

Add support for JSX #264

Raathigesh opened this issue Nov 14, 2016 · 59 comments
Labels
feature-request Request for new features or functionality help wanted Issues identified as good community contribution opportunities typescript
Milestone

Comments

@Raathigesh
Copy link

Does monaco support Jsx? I couldn't find any reference or samples. Any pointers would be appreciated.

@ChrisFan
Copy link

Looks like Monaco doesn't support JSX right now.

I'm a little bit confusing cause Monaco support Typescript and Javascript Syntax,and they both came from monaco-typescript;But if now I want to implement JSX Support based on Monaco API, seems like I have to write those tokenize provider and auto complete things again(include Javascript support) ? Looks like a bit duplicate works.

I don't know if I get wrong with something...
Maybe It would be better that monaco-typescript support JSX?

@alexdima alexdima added the feature-request Request for new features or functionality label Jan 17, 2017
@alexdima alexdima added this to the Backlog milestone Jan 17, 2017
@Flux159
Copy link

Flux159 commented Mar 13, 2017

Spent some time trying to get this working and it seems like monaco-typescript doesn't expose a few options that might enable JSX support. Don't have enough experience with the codebase to create a pull request, but I'll document what I found incase it helps someone else - or if @alexandrudima or someone else who regularly works on monaco could give some help, I could give this a shot later in the week.

Looking through monaco-typescript, it seems like https://github.com/Microsoft/monaco-typescript/blob/master/src/monaco.contribution.ts has a ScriptKind enum defined for JSX and TSX support, but it doesn't look like diagnostic or compiler options takes ScriptKind as a parameter.

According to https://github.com/Microsoft/monaco-typescript/blob/master/lib/typescriptServices.d.ts , there seems to be a ScriptKind and a LanguageVariant which could be set to support JSX files. LanguageVariant is used by a Scanner class which doesn't seem to be exposed via monaco-typescript.

Using the existing API, I could at least disable the warnings that the diagnostics were displaying on JSX, but couldn't get syntax highlighting support (and this isn't a great solution):

monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
  noSemanticValidation: true,
  noSyntaxValidation: true, // This line disables errors in jsx tags like <div>, etc.
});

// I don't think the following makes any difference
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
  // jsx: 'react',
  jsx: monaco.languages.typescript.JsxEmit.React,
  jsxFactory: 'React.createElement',
  reactNamespace: 'React',
  allowNonTsExtensions: true,
  allowJs: true,
  target: monaco.languages.typescript.ScriptTarget.Latest,
});

Similarly, setting for monaco.languages.typescript.javascriptDefaults didn't get very far either.

The other (admittedly bad) option would be to update a monarch syntax definition to add JSX support, then use that instead of using monaco-typescript: https://microsoft.github.io/monaco-editor/monarch.html (essentially start with javascript or typescript and add jsx support).

I didn't even bother pursuing that since I think it would be far better to get proper react support from monaco-typescript.

I think this would be a great feature to have to support editing react components in a browser. It would be great to get some support on getting it implemented - or if its already being worked on, some timeframe on implementation / testing / release (I'm not sure when monaco-editor is updated with respect to vs-code).

@abhishiv
Copy link

@Flux159 Any Idea how VSCode does it?

@abhishiv
Copy link

This seems to suggest with extensions we can do it, but I can't find how to add extensions in Monaco.

https://github.com/Microsoft/vscode/blob/7c633148b3111022ab5e114f21adbede041b7ea3/extensions/javascript/package.json

@Raathigesh
Copy link
Author

Basarat got JSX/TSX working with Alm.tools. Looking into it might help. https://twitter.com/Raathigesh/status/798145470803701760

@Flux159
Copy link

Flux159 commented Mar 25, 2017

Had some time to look a bit more into this... unfortunately it seems like this would require some significant changes to monaco-typescript's tokenization.ts which would be better done by a maintainer of monaco-typescript.

@abhishiv VSCode probably uses a typescript compiler API that monaco editor doesn't expose (look at the createScanner function in the typescript compiler - one of the arguments is languageVariant which is usually passed via a ts.sourceFile object). In monaco-typescript's tokenization.ts, the classifier internally calls createScanner but doesn't expose anything around the a sourceFile object (I don't think that monaco-typescript has a concept of a sourceFile since its based in a browser).

For more info, have a look at createClassifier and createScanner in (warning: large text file) https://raw.githubusercontent.com/Microsoft/monaco-typescript/master/lib/typescriptServices.js which I believe is a single js file that contains the entire typescript compiler.

Monaco doesn't support extensions as far as I know since its a subset of the code in vscode that removes things like local file handling, electron support, and extension support.

@Raathigesh Basarat ended up forking monaco-typescript to get JSX support in ALM but didn't make a pull request into monaco-typescript:
https://github.com/alm-tools/alm/blob/c77c89c5efb3b6ef6f978df2b9f5b76540cb25e0/src/app/monaco/languages/typescript/tokenization.ts

Looking through @basarat code, I don't think he's setting anything related to sourceFile.languageVariant anywhere and is manually parsing the JSX tokens.

@joewood
Copy link

joewood commented Mar 28, 2017

I think i have this working. It was simply a matter of ensuring there's a .tsx in the URI to the createModel function. The same I assume would apply to JSX.

model: monaco.editor.createModel(myCode, "typescript", monaco.Uri.parse("file:///main.tsx"));

@abhishiv
Copy link

Hey @joewood

Awesome, thanks! Seems to working! But now I'm getting this

a_pen_by_abhishiv_saxena

Did you encounter it as well?

@joewood
Copy link

joewood commented Mar 28, 2017

Remember to set Jsx to react in the compiler options. And I did not set these two options (I left them as the default):

  jsxFactory: 'React.createElement',
  reactNamespace: 'React',

Also, I had to wrap the react declaration file with an ambient module definition. e.g.:

declare module "react" {
<react.d.ts goes here>
}

At least until somebody answers this: http://stackoverflow.com/questions/43058191/how-to-use-addextralib-in-monaco-with-an-external-type-definition

One thing that I haven't tried is to set-up file URIs like a typescript project. That may solve the ambient/external module import issue.

@joewood
Copy link

joewood commented Mar 28, 2017

I worked out the solution to the external declaration file issue. The File URI solves that problem too. Here's an example that works in the playground. This should work equally well with the react.d.ts file, and therefore enable full JSX/TSX:


// compiler options
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
    target: monaco.languages.typescript.ScriptTarget.ES2016,
    allowNonTsExtensions: true,
    moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
    module: monaco.languages.typescript.ModuleKind.CommonJS,
    noEmit: true,
    typeRoots: ["node_modules/@types"]
});

// extra libraries
monaco.languages.typescript.typescriptDefaults.addExtraLib(
    `export declare function next() : string`,
    'node_modules/@types/external/index.d.ts');

monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
    noSemanticValidation: false,
    noSyntaxValidation: false
})

var jsCode = `import * as x from "external"
    const tt : string = x.dnext();`;

monaco.editor.create(document.getElementById("container"), {
    model: monaco.editor.createModel(jsCode,"typescript",new monaco.Uri("file:///main.tsx")), 
});

@jasonHzq
Copy link

is there any progress?

@joewood
Copy link

joewood commented Apr 17, 2017

@jasonHzq - did you not manage to get it working?

@dandingol03
Copy link

@joewood if i want to set the value of a new component in jsx syntax,how can i make it work?
this is my screenshoot:

image

@joewood
Copy link

joewood commented May 13, 2017

Hi @dandingol03. Those squiggles look like it's parsing that file as JavaScript and not JSX. Did you set the filename URL as per my comment above, when you create the model?

@dandingol03
Copy link

@joewood
my operate system is mac,so i use monaco.Uri.file instead.here is my code:

  editor=monaco.editor.create(containerElement, {
       model: monaco.editor.createModel(jsCode,"javascript",new monaco.Uri.file("./Containre.jsx")), 
  });

it works well,thanks.By the way,do you have any idea about navigating between modules when i click the module name.For example,there is a statement like import React from 'react',and when i click the react,it will navigate to the {workspace}/node_modules/react/react.js

@barak007
Copy link

Are there any official docs or references on how to implement this?

@luminaxster
Copy link
Contributor

luminaxster commented Feb 3, 2018

In the meanwhile...

TL;DR:

For syntax recognition:

monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
          jsx: "react"
      });


function isApplePlatform() {
  return (window && window.navigator && window.navigator.platform) ?
    window.navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i) ? true : false
    : true;
}

monaco.editor.create(DOMElement, {
model: monaco.editor.createModel(text, "javascript",
    isApplePlatform() ?
      new monaco.Uri.file('./editor_name.jsx')
      : new monaco.Uri('./editor_name.jsx')
  );
});

For syntax highlighting: alm-tools/alm#421

@supnate
Copy link

supnate commented Mar 10, 2018

I've worked out the solution by using prismjs as a tokenlizer to support jsx syntax highlight, see the live demo at: http://demo.rekit.org/element/src%2Ffeatures%2Fhome%2FElementPage.js/code

And here is the web worker to do tokenlize:
http://demo.rekit.org/element/src%2Ffeatures%2Fcommon%2Fmonaco%2Fworkers%2FsyntaxHighlighter.js/code

@jamesplease
Copy link

@supnate that second link that you posted is a 404. Do you have another link to the source code? (Also, is that project open source / on GitHub?)

@Raathigesh
Copy link
Author

Satya wrote a blog that shows how they got JSX syntax highlighting working for snack. https://blog.expo.io/building-a-code-editor-with-monaco-f84b3a06deaf

@cancerberoSgx
Copy link
Contributor

cancerberoSgx commented Mar 8, 2019

Besides syntax highlighting I was able to make it work perfectly, 100% type checked thanks to comments in this issue and make a HOWTO document here: https://github.com/cancerberoSgx/jsx-alone/blob/master/jsx-explorer/HOWTO_JSX_MONACO.md

Thanks!

@alexdima alexdima modified the milestones: Backlog, Backlog Candidates Dec 10, 2019
@alexdima alexdima changed the title Does monaco support JSX ? Add support for JSX Dec 11, 2019
@Jorenm
Copy link

Jorenm commented Nov 25, 2020

For new comers who want to add JSX. Monaco already support JSX out of the box (minus commenting bug above) , and for TSX you need right configuration (but no external dependencies).

My setup code:

monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
    target: monaco.languages.typescript.ScriptTarget.Latest,
    allowNonTsExtensions: true,
    moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
    module: monaco.languages.typescript.ModuleKind.CommonJS,
    noEmit: true,
    esModuleInterop: true,
    jsx: monaco.languages.typescript.JsxEmit.React,
    reactNamespace: "React",
    allowJs: true,
    typeRoots: ["node_modules/@types"],
  });

monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
   noSemanticValidation: false,
   noSyntaxValidation: false,
});

monaco.languages.typescript.typescriptDefaults.addExtraLib(
   '<<react-definition-file>>',
   `file:///node_modules/@react/types/index.d.ts`
);

The last line is important, <<react-definition-file>> not a file path, it is a string.

Replace <<react-definition-file>> with content from https://cdn.jsdelivr.net/npm/@types/[email protected]/index.d.ts, you can fetch them first and then put the content string to replace <<react-definition-file>>.

I can't get this working, but I'm not sure what I'm doing wrong. I copied your code example. I'm using webpack to replace <> with the contents of https://cdn.jsdelivr.net/npm/@types/[email protected]/index.d.ts

I get this error: "Error in event handler: ReferenceError: Component is not defined" from this code ${Component.displayName||Component.name} that's in the index.d.ts file.

I don't have any file at file:///node_modules/@react/types/index.d.ts this location, but don't know if that matters. There is no @react package that I can tell, so I'm not sure where that would be from.

Update: Just manually created the file path with that file in it, but that didn't seem to do anything.

Any help on how to get this working?

Update: Got it working by including Component from React in the file in which I was creating the editor.

@steveruizok
Copy link

So strange that the JSX support is partial, given how close it is to full support. From what I can tell, only the child content of a JSX block is mistakenly styled with standard language keys (e.g. the "for" here is the same as in a for loop). The rest of the highlighting works as expected.

image

@iray100200
Copy link

iray100200 commented Feb 25, 2021

Monaco-editor can use monaco-textmate to highlight jsx

import cssGrammar from 'raw-loader!./grammars/css.json.tmLanguage'
import htmlGrammar from 'raw-loader!./grammars/html.json.tmLanguage'
import tsGrammar from 'raw-loader!./grammars/TypeScriptReact.tmLanguage'
import { loadWASM } from 'onigasm'
import { Registry } from 'monaco-textmate'
import { wireTmGrammars } from './set-gammars'

let grammarsLoaded = false

export async function liftOff(monaco) {
  if (grammarsLoaded) {
    return
  }
  grammarsLoaded = true
  await loadWASM(`/onigasm.wasm`) // See https://www.npmjs.com/package/onigasm#light-it-up

  const registry = new Registry({
    getGrammarDefinition: async (scopeName) => {
      if (scopeName === 'source.css') {
        return {
          format: 'json',
          content: cssGrammar,
        }
      }
      if (scopeName === 'text.html.basic') {
        return {
          format: 'json',
          content: htmlGrammar,
        }
      }

      return {
        format: 'plist',
        content: tsGrammar,
      }
    }
  })

  const grammars = new Map()
  grammars.set('css', 'source.css')
  grammars.set('html', 'text.html.basic')
  grammars.set('vue', 'text.html.basic')
  grammars.set('typescript', 'source.tsx')
  grammars.set('javascript', 'source.js')

  await wireTmGrammars(monaco, registry, grammars)
}```

@x-glorious
Copy link

Use this package https://www.npmjs.com/package/monaco-jsx-syntax-highlight

@jeffscottward
Copy link

This missing JSX lang support issue has been ongoing for 7 years

I would like to hear from @microsoft proper to address why this hasn't/can't be done.

It seems everyone wants this, and now more than ever with WebXR VR coding exploding with all the pushes for headsets. Why is this such an issue?

@kagankan
Copy link

FYI, my solution was @shikijs/monaco
https://shiki.style/packages/monaco

It supports languages other than JSX as well.

@jeffscottward
Copy link

FYI, my solution was @shikijs/monaco

https://shiki.style/packages/monaco

It supports languages other than JSX as well.

Love open source for this exact reason thank you!

@kachurun
Copy link

kachurun commented Jul 9, 2024

https://shiki.style/packages/monaco

That guys just made my day

@ansh
Copy link

ansh commented Aug 17, 2024

How did you use Shiki in monaco-react? @kagankan

@thesoftwarephilosopher
Copy link
Contributor

Maybe I'm missing something, but why is everyone in this thread trying to implement this either by hacking textmate parsers into this, or by hacking the ast in the web workers? I definitely implemented this a few years ago using nothing but the vanilla Monaco tokenizer (#1609), although I don't know where the code for that is, so I'll have to do it again this week. Is there a reason to need to go beyond this method?

@ansh
Copy link

ansh commented Aug 20, 2024

@sdegutis Could you share the code if you figure it out?

I think the issue is none of us have figured it out.

@thesoftwarephilosopher
Copy link
Contributor

@ansh it was a few years ago, and I don't have the code anymore, but I'm working on relearning Monarch and rewriting it based on the clues I left myself in that issue. Maybe this time MS will accept a PR in VS Code proper for out of the box JSX support, who knows.

@thesoftwarephilosopher
Copy link
Contributor

I got JSX working in Monaco, you can try it out at https://vanillajsx.com/

Please try to break it everyone, and let me know what looks weird, so that it's battle proofed before the PR. Thanks.

@ansh
Copy link

ansh commented Aug 23, 2024

@sdegutis how did you get it to work? mind sharing the code?

@thesoftwarephilosopher
Copy link
Contributor

@QingShan-Xu
Copy link

@sdegutis Your code example runs successfully, would you mind sharing the following code?

@QingShan-Xu
Copy link

@sdegutis thanks

@thesoftwarephilosopher
Copy link
Contributor

Sent a Highlight-JSX PR.

@kagankan
Copy link

@ansh

How did you use Shiki in monaco-react?

Here is my sample.
I use @monaco-editor/react instead of monaco-react.
(I haven't tried it with monaco-react.)

https://github.com/markuplint/markuplint-playground/blob/8782876db22c51cd748f7a08e6aa1859b8e588f4/src/components/CodeEditor.tsx#L60-L81

@QingShan-Xu
Copy link

@ansh

您如何在 monaco-react 中使用 Shiki?

这是我的示例。 我使用@monaco-editor/react而不是monaco-react。 (我还没有尝试过monaco-react。)

https://github.com/markuplint/markuplint-playground/blob/8782876db22c51cd748f7a08e6aa1859b8e588f4/src/components/CodeEditor.tsx#L60-L81

I used it in March, it only supports syntax highlighting but not type hints

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request for new features or functionality help wanted Issues identified as good community contribution opportunities typescript
Projects
None yet
Development

No branches or pull requests