securingsincity / react-ace

React Ace Component
http://securingsincity.github.io/react-ace/
MIT License
4.06k stars 604 forks source link

Could not load worker #725

Open sergibondarenko opened 5 years ago

sergibondarenko commented 5 years ago

Problem

Couldn't load worker, JSON syntax validation doesn't work. I see Could not load worker warning in the browser console.

Also, I tried to import the json worker

import "ace-builds/src-noconflict/worker-json";

and got the error

TypeError: Cannot read property 'window' of undefined

Sample code to reproduce the issue

import React from "react";
import ReactDOM from "react-dom";
import AceEditor from "react-ace";

import "ace-builds/src-noconflict/ace";
import "ace-builds/src-noconflict/mode-json";
import "ace-builds/src-noconflict/theme-github";

let text =
  '{\n  "id": 0,\n  ' +
  '"script": """\n   function add(x, y) {\n      return x + y;\n   }\n   add(1, 2);\n   """' +
  ',\n   "descr": "add two numbers"\n}';

function App() {
  return (
    <div className="App">
      <h1>Code Editor Demo</h1>
      <AceEditor
        mode="json"
        theme="github"
        onChange={(value, stat) => {
          console.log("onChange", value, stat);
        }}
        value={text}
        name="UNIQUE_ID_OF_DIV"
        editorProps={{ $blockScrolling: true }}
      />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

References

Codesandbox https://codesandbox.io/embed/ace-worker-3-vrr68

ZeD3v commented 5 years ago

I'm experiencing something similar for CSS, getting the following error in browser console:

Uncaught DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://localhost:9000/settings/landing-page/worker-css.js' failed to load.

When attempting to import worker directly

import 'ace-builds/src-noconflict/worker-css';

My build failed with:

ERROR in ../node_modules/ace-builds/src-noconflict/worker-css.js
Module not found: Error: Can't resolve 'ace/lib/es5-shim' in 'path/to/node_modules/ace-builds/src-noconflict'
nightwing commented 5 years ago

You need to either include the webpack-resolver

import "ace-builds/webpack-resolver";

or configure the url for each mode separately

import jsonWorkerUrl from "file-loader!ace-builds/src-noconflict/worker-json";
ace.config.setModuleUrl("ace/mode/json_worker", jsonWorkerUrl)
import cssWorkerUrl from "file-loader!ace-builds/src-noconflict/worker-css";
ace.config.setModuleUrl("ace/mode/css_worker", cssWorkerUrl)

both methods require "file-loader"

also react-ace tries to load brace if ace is not already imported so ace-builds needs to be imported before react-ace.

import "ace-builds";
import AceEditor from "react-ace";
arjunu commented 5 years ago

@nightwing that works but importing ace-builds before react-ace fails in Firefox for me. I got it to work with:

import AceEditor from 'react-ace';
import 'ace-builds/webpack-resolver';
// then the mode, theme & extension
import 'ace-builds/src-noconflict/mode-json';
import 'ace-builds/src-noconflict/theme-tomorrow_night';
import 'ace-builds/src-noconflict/ext-searchbox';

But I couldn't get it to work with my tests. The webpack-resolver import line fails in tests with

TypeError: Cannot read property 'setModuleUrl' of undefined

I'm guessing I need mock ace with something like

global.ace = require('ace-builds/src-min-noconflict/ace');
mattjstar commented 5 years ago

Did anyone get this working with create-react-app? Mine gets stuck compiling forever if I add:

import 'ace-builds/webpack-resolver';
ghost commented 5 years ago

I fixed by adding useWorker: false to setOptions if importing modules directly. If this is a good solution, README.md basic usage should be updated unless I'm missing something.

mattjstar commented 5 years ago

@khoomeister that got rid of all the warnings, but did your performance get noticeably worse (that could just be my implementation)?

(thanks for the tip btw!)

sourovroy commented 4 years ago

setOptions={{ useWorker: false }}

works for me. Thanks @khoomeister

doneumark commented 4 years ago

also still having this issue. does using "useWorker has any downsides? what does those workers do exactly?

caprica commented 4 years ago

I'm using a create-react-app project.

The only thing I needed to do was to add this in my App.tsx:

import 'ace-builds/webpack-resolver'

Setting useWorker to false disables syntax checking at least, maybe other things, so I didn't want to use that.

I don't know yet if this is good enough to make it work with tests as per arjunu's comment above.

bespokebob commented 4 years ago

Adding webpack-resolver to my create-react-app project leads to a huge increase in compile time, and adds hundreds of files to the build directory - I assume one for each module in ace-builds that it configures. Configuring the url for just the modules that I need works fine, though.

This seems like it's an issue with either react-scripts or ace-builds, not react-ace.

jan-osch commented 4 years ago

So far I am happy with react-ace, thanks for all the hard work guys!

I was attempting to upgrade to version 8 but I failed due to issues with worker, so for now I am staying at 7.

I am using "react-scripts": "3.2.0" (Create React App)

I could not get worker to load, and the following errors were displayed in the console:

03226918-0f44-4ac8-b073-1abc2ed64713:1 Refused to execute script from 'http://localhost:8000/worker-javascript.js' because its MIME type ('text/html') is not executable.
(anonymous) @ 03226918-0f44-4ac8-b073-1abc2ed64713:1
9297f3cf-c75b-4245-8c37-3ac2a7fed94d:1 Refused to execute script from 'http://localhost:8000/worker-javascript.js' because its MIME type ('text/html') is not executable.
(anonymous) @ 9297f3cf-c75b-4245-8c37-3ac2a7fed94d:1
03226918-0f44-4ac8-b073-1abc2ed64713:1 Uncaught DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://localhost:8000/worker-javascript.js' failed to load.
    at blob:http://localhost:8000/03226918-0f44-4ac8-b073-1abc2ed64713:1:1
(anonymous) @ 03226918-0f44-4ac8-b073-1abc2ed64713:1
9297f3cf-c75b-4245-8c37-3ac2a7fed94d:1 Uncaught DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://localhost:8000/worker-javascript.js' failed to load.
    at blob:http://localhost:8000/9297f3cf-c75b-4245-8c37-3ac2a7fed94d:1:1
(anonymous) @ 9297f3cf-c75b-4245-8c37-3ac2a7fed94d:1

Disabling the worker is not an option for me. I tried adding the webpack-resolver using import 'ace-builds/webpack-resolver'; but my app would not compile - the compilation was hanging indefinitely.

I also attempted to add it manually using the file-loader and setModuleUrl but then I got the error with missing ace/lib/es5-shim.

It seems that this issue is related to #733 #755 and ajaxorg/ace#4770

bitconym commented 4 years ago

@mattjstar I got it working with:

import 'ace-builds'
import 'ace-builds/webpack-resolver'

So import ace-builds before the resolver (any anything else relater to the AceEditor)

See @arjunu answer above.

Holgrabus commented 4 years ago

I added the last 3 lines to add javascript-worker :

import AceEditor from "react-ace";
import "ace-builds/src-min-noconflict/mode-javascript";
import "ace-builds/src-min-noconflict/theme-tomorrow_night_eighties";
import "ace-builds/src-min-noconflict/ext-language_tools";
import "ace-builds/src-min-noconflict/ext-spellcheck";
import "ace-builds/src-min-noconflict/snippets/javascript";
import 'ace-builds/src-min-noconflict/ext-searchbox';
const ace = require('ace-builds/src-noconflict/ace');
ace.config.set("basePath", "https://cdn.jsdelivr.net/npm/ace-builds@1.4.3/src-noconflict/");
ace.config.setModuleUrl('ace/mode/javascript_worker', "https://cdn.jsdelivr.net/npm/ace-builds@1.4.3/src-noconflict/worker-javascript.js");

You can copy/paste the file worker-javascript.js in your local environment if you don't want to be dependant of cdn.jsdelivr.net.

pranavwani commented 4 years ago

You need to either include the webpack-resolver

import "ace-builds/webpack-resolver";

or configure the url for each mode separately

import jsonWorkerUrl from "file-loader!ace-builds/src-noconflict/worker-json";
ace.config.setModuleUrl("ace/mode/json_worker", jsonWorkerUrl)
import cssWorkerUrl from "file-loader!ace-builds/src-noconflict/worker-css";
ace.config.setModuleUrl("ace/mode/css_worker", cssWorkerUrl)

both methods require "file-loader"

also react-ace tries to load brace if ace is not already imported so ace-builds needs to be imported before react-ace.

import "ace-builds";
import AceEditor from "react-ace";

This works perfectly. Define worker URL before using any mode or theme

import "ace-builds"
import ACE from "react-ace/dist/react-ace.min";

import jsonWorkerUrl from "file-loader!ace-builds/src-noconflict/worker-json";
ace.config.setModuleUrl("ace/mode/json_worker", jsonWorkerUrl);
import xmlWorkerUrl from "file-loader!ace-builds/src-noconflict/worker-xml";
ace.config.setModuleUrl("ace/mode/xml_worker", xmlWorkerUrl);
import jsWorkerUrl from "file-loader!ace-builds/src-noconflict/worker-javascript";
ace.config.setModuleUrl("ace/mode/javascript_worker", jsWorkerUrl);

import "ace-builds/src-min-noconflict/mode-typescript";
import "ace-builds/src-min-noconflict/mode-javascript";
import "ace-builds/src-min-noconflict/mode-graphqlschema";
import "ace-builds/src-min-noconflict/mode-json";
import "ace-builds/src-min-noconflict/mode-xml";
import "ace-builds/src-min-noconflict/mode-markdown";
import "ace-builds/src-min-noconflict/mode-html";
import "ace-builds/src-min-noconflict/theme-github";
import "ace-builds/src-min-noconflict/theme-tomorrow";
import "ace-builds/src-min-noconflict/theme-kuroir";
import "ace-builds/src-min-noconflict/ext-searchbox";

also no need to set: setOptions={{ useWorker: false }} https://github.com/securingsincity/react-ace/issues/725#issuecomment-546711308

MattNot commented 4 years ago

What if i want to have a custom worker that is not in the ace-builds/src-.../ folder? I need to use it with an ANTLR parser done by me.

jchonde commented 4 years ago

I leave the full NextJS@9.3 integration here.

import dynamic from "next/dynamic";

const AceEditor = dynamic(
  async () => {
    const reactAce = await import("react-ace");

    // prevent warning in console about misspelled props name.
    await import("ace-builds/src-min-noconflict/ext-language_tools");

    // import your theme/mode here. <AceEditor mode="javascript" theme="solarized_dark" />
    await import("ace-builds/src-min-noconflict/mode-javascript");
    await import("ace-builds/src-min-noconflict/theme-solarized_dark");

    // as @Holgrabus commented you can paste these file into your /public folder.
    // You will have to set basePath and setModuleUrl accordingly.
    let ace = require("ace-builds/src-min-noconflict/ace");
    ace.config.set(
      "basePath",
      "https://cdn.jsdelivr.net/npm/ace-builds@1.4.8/src-noconflict/"
    );
    ace.config.setModuleUrl(
      "ace/mode/javascript_worker",
      "https://cdn.jsdelivr.net/npm/ace-builds@1.4.8/src-noconflict/worker-javascript.js"
    );

    return reactAce;
  },
  {
    ssr: false // react-ace doesn't support server side rendering as it uses the window object.
  }
);

export default () =>  <AceEditor mode="javascript" theme="solarized_dark" />
MattNot commented 4 years ago

@jan-osch so if I want to use my "customWorker.js" for example, i've to set ace.config.setModuleUrl("ace/mode/myWorker", "/customWorker.js") ? (putting customWorker.js in the /public folder)

jamesej commented 4 years ago

If you want to use the workarounds in Typescript you'll need to do this to set ace config:

import { config } from 'ace-builds';

config.set(
  "basePath",
  "https://cdn.jsdelivr.net/npm/ace-builds@1.4.8/src-noconflict/"
);
config.setModuleUrl(
   "ace/mode/javascript_worker",
   "https://cdn.jsdelivr.net/npm/ace-builds@1.4.8/src-noconflict/worker-javascript.js"
);
aboganas commented 4 years ago

I added the following test to Webpack

  module: {
    rules: [
      {
        test: /ace-builds.*\/worker-.*$/,
        loader: 'file-loader',
        options: {
          esModule: false,
          name: '[name].[hash:8].[ext]',
        },
      },
    ],
  },

then I was able to import as following

import ace from 'ace-builds/src-noconflict/ace';
import cssWorkerUrl from 'ace-builds/src-noconflict/worker-css';

ace.config.setModuleUrl('ace/mode/css_worker', cssWorkerUrl);
johnjackweir commented 4 years ago

I'm importing as suggested by @pranavwani but now am running into the error Cannot read property 'Range' of undefined. "Error loading module." when ace.tsx is attempting to import ace/range.

I believe that the issue is that since window.ace is defined, even though I want to be using ace-builds, ace keeps falling back on the ace.acequire syntax in editorOptions. Has anyone come across a workaround for this issue?

legolasNg commented 3 years ago

I added the following test to Webpack

  module: {
    rules: [
      {
        test: /ace-builds.*\/worker-.*$/,
        loader: 'file-loader',
        options: {
          esModule: false,
          name: '[name].[hash:8].[ext]',
        },
      },
    ],
  },

then I was able to import as following

import ace from 'ace-builds/src-noconflict/ace';
import cssWorkerUrl from 'ace-builds/src-noconflict/worker-css';

ace.config.setModuleUrl('ace/mode/css_worker', cssWorkerUrl);

you can also do that without modify webpack config

import ace from 'ace-builds/src-noconflict/ace';
/* eslint import/no-webpack-loader-syntax: off */
import cssWorkerUrl from 'ace-builds/src-noconflict/worker-css';

ace.config.setModuleUrl('ace/mode/css_worker', cssWorkerUrl);
p3x-robot commented 3 years ago

do you guys how to solve this as file-loader is deprecated, how can we configrue ace now without file-loader?

mgoldenbe commented 3 years ago

What is the status of this issue? Although importing webpack-resolver works, it makes compilation super-slow, so cannot be considered a permanent solution.

mgoldenbe commented 3 years ago

The following seems to have worked for me. The key is the order of imports and the last three lines (including the comment!) I got it from this reply.

import 'ace-builds'
import AceEditor from 'react-ace';
import ace from 'ace-builds/src-noconflict/ace'
// import mode-<language> , this imports the style and colors for the selected language.
import 'ace-builds/src-noconflict/mode-xml';
// there are many themes to import, I liked monokai.
import 'ace-builds/src-noconflict/theme-github';
// this is an optional import just improved the interaction.
import 'ace-builds/src-noconflict/ext-language_tools';
import 'ace-builds/src-noconflict/ext-beautify';
// eslint-disable-next-line import/no-webpack-loader-syntax
import xmlWorkerUrl from "!!file-loader!ace-builds/src-noconflict/worker-xml";
ace.config.setModuleUrl("ace/mode/xml_worker", xmlWorkerUrl);
er-dev commented 3 years ago

None of these suggestions are working for me. I am getting the same Cannot read property 'window' of undefined as the OP.

When I use:

import AceEditor from 'react-ace'
import 'ace-builds/webpack-resolver'
import 'ace-builds/src-noconflict/mode-javascript'

I get the following error: 61b85f295f78e37ba4d607ea64fab1e8.js:1 Uncaught TypeError: Cannot read property 'window' of undefined

After comparing ace-builds/src-noconflict/worker-javascript.js to my generated version, there are some changes:

  1. use strict' is added to the file at the top, right above'no use strict'`
  2. The self-executing function at the start:
!(function (window) {
  if (typeof window.window != 'undefined' && window.document) return
})(this)

Turns into:

!(function (window) {
  if (typeof window.window != "undefined" && window.document) return;
})(void 0);

I believe this is causing me and the OPs issue. Any idea why these files would be transformed like this?

AlmogBaku commented 2 years ago

Adding webpack-resolver creating 100+ js files when building the project https://github.com/securingsincity/react-ace/issues/1168

mattduggan commented 2 years ago

I had trouble getting webpack-resolver to play nicely with Jest and couldn't figure out the magic moduleNameMapper pattern.

I was able to work around this in Webpack v5 by using an Asset Module targeting the worker* files in ace-build:

// webpack.config.js
module: {
  rules: [
    {
      test: /worker-.*\.js/,
      include: [/node_modules\/ace-build/],
      type: 'asset/resource',
    }
  ]
}
// editor.js
import ace from 'ace-builds/src-noconflict/ace';
import 'ace-builds/src-noconflict/mode-json';
import jsonWorker from 'ace-builds/src-noconflict/worker-json';

ace.config.setModuleUrl('ace/mode/json_worker', jsonWorker);
haftav commented 2 years ago

For those of you using Vite, I was able to get it working using Explicit URL Imports (appending ?url to the end of the worker import):

import ace from 'ace-builds/src-noconflict/ace';
import jsonWorkerUrl from 'ace-builds/src-noconflict/worker-json?url';

ace.config.setModuleUrl('ace/mode/json_worker', jsonWorkerUrl);

// ... mode and theme imports here
AmazingYuan commented 2 years ago
import ace from 'ace-builds/src-min-noconflict/ace';
import 'ace-builds/webpack-resolver'; 

This solution works for me, it solves all my import problems, include worker execute problem.

Cactusx09 commented 2 years ago

For those searching how to implement workers now, when file-upload is deprecated with Webpack 5 asset/resource.

webpack config:

rules: [
  {
      test: /ace-builds.*\/worker-.*$/,
      type: "asset/resource"
  },
],

component:

import AceEditor from "react-ace";
import { config } from "ace-builds";
import "ace-builds/src-noconflict/mode-javascript";
import "ace-builds/src-noconflict/theme-github";
import "ace-builds/src-noconflict/ext-language_tools";

import jsWorkerUrl from "ace-builds/src-noconflict/worker-javascript";
config.setModuleUrl("ace/mode/javascript_worker", jsWorkerUrl);

To fix the typescript "no module declaration" error, just add the global.d.ts file to your src folder:

declare module "ace-builds/src-noconflict/worker-javascript";
jumasheff commented 1 year ago

@Cactusx09 thank you!!!

For those who don't know how to add webpack configs to a nextjs project, here's my snippet: next.config.js:

const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  ...
  webpack: (config, options) => {
    config.module.rules.push({
      test: /ace-builds.*\/worker-.*$/,
      type: 'asset/resource',
    });
    return config;
  },
};

module.exports = nextConfig;
miletbaker commented 1 year ago

If you want to use the workarounds in Typescript you'll need to do this to set ace config:

import { config } from 'ace-builds';

config.set(
  "basePath",
  "https://cdn.jsdelivr.net/npm/ace-builds@1.4.8/src-noconflict/"
);
config.setModuleUrl(
   "ace/mode/javascript_worker",
   "https://cdn.jsdelivr.net/npm/ace-builds@1.4.8/src-noconflict/worker-javascript.js"
);

Thanks

This is also the solution if you don't use WebPack or create-react-app

Dragusin-Cristian commented 1 year ago

setOptions={{ useWorker: false }}

works for me. Thanks @khoomeister

Yes, it works also for me.

dolphin0618 commented 1 year ago

if you use vite, you can ...

import { viteStaticCopy } from 'vite-plugin-static-copy'

export default defineConfig(() => {
    plugins: [
      viteStaticCopy({
        targets: [
          {
            src: [
              'node_modules/ace-builds/src-min-noconflict/ace.js',
              'node_modules/ace-builds/src-min-noconflict/mode-json.js',
              'node_modules/ace-builds/src-min-noconflict/worker-json.js'
            ],
            dest: 'node_modules/ace-builds/src-min-noconflict/'
          }
        ]
      })],
    })