ggrossetie / opal-node-runtime

Opal Runtime for Node.js
https://opalrb.com/
MIT License
4 stars 2 forks source link

method 'new' not defined in Object.Opal.udef #6

Open robogeek opened 5 years ago

robogeek commented 5 years ago

This issue is pretty arcane - so please bear with me. Any ideas you have will be appreciated.

I'm building an Electron app that is using Vue.js and therefore behind the scenes Webpack is used.

Included in the code is a toolset that uses Asciidoctor.js, which in turn uses Opal-Runtime.

Outside the Electron app it (the toolset that eventually uses Opal Runtime) works fine -- and if I don't try to configure Webpack, then the app builds and runs fine. However, I am trying to solve some other issues and it was recommended to use this Webpack config (in vue.config.js). The idea is that any Node module listed in the externals array is not handled by Webpack.

module.exports = {
    pluginOptions: {
      electronBuilder: {
        // List native deps here if they don't work
        externals: ['@akashacms/plugins-epub', 'akasharender', 'mahabhuta', 
            'cheerio', 'opal-runtime', 'asciidoctor.js', 'cachd', 'cmnd',
            'debug', 'ejs', 'fast-memoize', 'flat-cache', 'fs-extra', 'glob-fs',
            'gray-matter', 'less', 'markdown-it', 'oembetter', 'rss', 'run-parallel-limit'],
        // If you are using Yarn Workspaces, you may have multiple node_modules folders
        // List them all here so that VCP Electron Builder can find them
        nodeModulesPath: ['../../node_modules', './node_modules']
      }
    }
  }

As per instructions here: https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/guide.html#native-modules

But when I have this config in place, this error arises:

App threw an error during load
method 'new' not defined in 
    at Object.Opal.udef (webpack:///./node_modules/opal-runtime/src/opal.js?:1784:28)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6225:12)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6227:7)
    at Opal.modules.corelib/boolean (webpack:///./node_modules/opal-runtime/src/opal.js?:6302:5)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2300:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2328:17)
    at Opal.modules.opal/mini (webpack:///./node_modules/opal-runtime/src/opal.js?:18607:8)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2300:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2328:17)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:23338:8)

If I rename the webpack config to e.g. vue.config.non-js (so it's not recognized) then the app loads without problem.

ggrossetie commented 5 years ago

Hello @robogeek What version of Opal runtime are you using ?

The error is thrown by Opal.udef(self, '$' + "new"). In this context self is an Opal class that "extends" Boolean: https://github.com/opal/opal/blob/master/opal/corelib/boolean.rb

https://github.com/Mogztter/opal-node-runtime/blob/3489d53241b1e157ad87264dc3782c697597ed6f/src/opal.js#L1785-L1788

Every should have a $new function so my guess is that Opal is not loaded properly. Could you add a console.log to print the self class ? Also you need to make sure that corelib/class is called (and especially the function that define the $new function):

https://github.com/Mogztter/opal-node-runtime/blob/3489d53241b1e157ad87264dc3782c697597ed6f/src/opal.js#L3535

Did you try to change the order ? Put 'opal-runtime' first or last (just before asciidoctor.js) to see if you get a different error ?

robogeek commented 5 years ago

Opal Runtime version is "version": "1.0.11". I see that's one minor version back from the latest. My code is referencing AsciiDoctor 1.5.9 which is the latest, and at the time of its latest publishing 1.0.11 was the latest Opal Runtime release.

My code is not directly referencing Opal. Instead AsciiDoctor.js is doing it.

At that point printing "this" gives this:

Opal.udef this: 2
Opal.udef this: 2
App threw an error during load
RangeError: Maximum call stack size exceeded
    at Function.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:3453:15)
    at Opal.send (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:1660:19)
    at Function.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:3633:14)
    at Function.<anonymous> (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:2367:21)
    at Number.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:5393:24)
    at Number.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:5393:68)
    at Number.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:5393:68)
    at Number.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:5393:68)
    at Number.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:5393:68)
    at Number.$$to_s (/Volumes/Extra/akasharender/epubuilder-electron/node_modules/opal-runtime/src/opal.js:5393:68)

In other words, two instances that simply print "2" and another that blows up the stack. If instead I try to print 'self' I get a message that self is not defined at that point.

ReferenceError: self is not defined
    at Object.Opal.udef (webpack:///./node_modules/opal-runtime/src/opal.js?:1783:80)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6065:12)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6067:7)
    at Opal.modules.corelib/nil (webpack:///./node_modules/opal-runtime/src/opal.js?:6195:5)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2301:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2329:17)
    at Opal.modules.opal/mini (webpack:///./node_modules/opal-runtime/src/opal.js?:18607:8)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2301:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2329:17)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:23339:8)

The code inserted to do the printing is:

  Opal.udef = function(obj, jsid) {
console.log(`Opal.udef this: ${require('util').inspect(this)}`);
    if (!obj.prototype[jsid] || obj.prototype[jsid].$$stub) {
      throw Opal.NameError.$new("method '" + jsid.substr(1) + "' not defined in " + obj.$name());
    }

    Opal.add_stub_for(obj.prototype, jsid);

    if (obj.$$is_singleton) {
      if (obj.prototype.$singleton_method_undefined && !obj.prototype.$singleton_method_undefined.$$stub) {
        obj.prototype.$singleton_method_undefined(jsid.substr(1));
      }
    }
    else {
      if (obj.$method_undefined && !obj.$method_undefined.$$stub) {
        obj.$method_undefined(jsid.substr(1));
      }
    }
  };

And if I comment out the console.log it reverts to the original error.

ggrossetie commented 5 years ago

Could you please move the console.log just before the throw and print obj ?

Any chance with the order in the vue.config.js with the externals list ?

robogeek commented 5 years ago

The ordering of entries in vue.config.js did not make a difference.

I changed the console.log and got different output:

Opal.udef obj: [$Class] name: '' prototype: $Class {}
App threw an error during load
method 'new' not defined in 
    at Object.Opal.udef (webpack:///./node_modules/opal-runtime/src/opal.js?:1785:28)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6226:12)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6228:7)
    at Opal.modules.corelib/boolean (webpack:///./node_modules/opal-runtime/src/opal.js?:6303:5)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2301:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2329:17)
    at Opal.modules.opal/mini (webpack:///./node_modules/opal-runtime/src/opal.js?:18608:8)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2301:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2329:17)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:23339:8)

With this code change:

 Opal.udef = function(obj, jsid) {
    if (!obj.prototype[jsid] || obj.prototype[jsid].$$stub) {
 console.log(`Opal.udef obj: ${require('util').inspect(obj)} name: '${obj.$name()}' prototype: ${require('util').inspect(obj.prototype)}`);
      throw Opal.NameError.$new("method '" + jsid.substr(1) + "' not defined in " + obj.$name());
    }

Ergo... the obj.prototype is empty, which I suspect means an incompletely initialized obj.

ggrossetie commented 5 years ago

Yes that's what I suspected. It's weird because corelib/class is required/loaded before opal/mini. Could you also add a log in the function that define the $new function on $Class:

https://github.com/Mogztter/opal-node-runtime/blob/3489d53241b1e157ad87264dc3782c697597ed6f/src/opal.js#L3535

Do you have a sample project where I can reproduce this issue so I can debug it further ?

robogeek commented 5 years ago

I apologize for the delay in responding, some other things came up.

I don't know if this is the sort of logging statement you had in mind. I tried several options -- BTW, the self variable is undefined at that point -- and came up with this:

    Opal.defs(self, '$new', TMP_Class_new_1 = function(superclass) {
console.log(`Opal.udef self: ${require('util').inspect(superclass)}  prototype: ${require('util').inspect(superclass.prototype)}`);

      var $iter = TMP_Class_new_1.$$p, block = $iter || nil, self = this;

      if ($iter) TMP_Class_new_1.$$p = null;

With that, I got printouts of various class objects. What's shown below is the final one before the crash described above.

Opal.udef self: { [$Class: $SystemCallError]
  '$$base_module':
   { [$Class: $Object]
     '$$':
      { BasicObject: [$Class],
        Object: [Circular],
        Module: [$Class],
        Class: [$Class],
        NilClass: [$Class],
        Opal: [$Module],
        Kernel: [$Module],
        Exception: [$Class],
        ScriptError: [$Class],
        SyntaxError: [$Class],
        LoadError: [$Class],
        NotImplementedError: [$Class],
        SystemExit: [$Class],
        NoMemoryError: [$Class],
        SignalException: [$Class],
        Interrupt: [$Class],
        SecurityError: [$Class],
        StandardError: [$Class],
        EncodingError: [$Class],
        ZeroDivisionError: [$Class],
        NameError: [$Class],
        NoMethodError: [$Class],
        RuntimeError: [$Class],
        FrozenError: [$Class],
        LocalJumpError: [$Class],
        TypeError: [$Class],
        ArgumentError: [$Class],
        IndexError: [$Class],
        StopIteration: [$Class],
        KeyError: [$Class],
        RangeError: [$Class],
        FloatDomainError: [$Class],
        IOError: [$Class],
        SystemCallError: [Circular],
        Errno: [$Module],
        UncaughtThrowError: [$Class],
        JS: [$Module],
        RUBY_PLATFORM: 'opal',
        RUBY_ENGINE: 'opal',
        RUBY_VERSION: '2.5.1',
        RUBY_ENGINE_VERSION: '0.11.99.dev',
        RUBY_RELEASE_DATE: '2018-12-25',
        RUBY_PATCHLEVEL: 0,
        RUBY_REVISION: 0,
        RUBY_COPYRIGHT:
         'opal - Copyright (C) 2013-2018 Adam Beynon and the Opal contributors',
        RUBY_DESCRIPTION: 'opal 0.11.99.dev (2018-12-25 revision 0)',
        NIL: [$NilClass],
        Boolean: [$Class],
        TrueClass: [$Class],
        FalseClass: [$Class],
        TRUE: true,
        FALSE: false,
        Comparable: [$Module],
        RegexpError: [$Class],
        Regexp: [$Class],
        MatchData: [$Class],
        String: [$Class],
        Symbol: [$Class],
        Enumerable: [$Module],
        Enumerator: [$Class],
        Numeric: [$Class],
        Array: [$Class],
        Hash: [$Class],
        Number: [$Class],
        Fixnum: [$Class],
        Integer: [$Class],
        Float: [$Class],
        Range: [$Class],
        Proc: [$Class],
        Method: [$Class],
        UnboundMethod: [$Class],
        ARGV: [],
        ARGF: [$Object],
        ENV: [$Object],
        Encoding: [$Class],
        Math: [$Module],
        Complex: [$Class],
        Rational: [$Class],
        Time: [$Class],
        Struct: [$Class],
        IO: [$Class],
        STDERR: [$Writable],
        STDIN: [$IO],
        STDOUT: [$Writable],
        Dir: [$Class],
        File: [$Class],
        Process: [$Class],
        Signal: [$Class],
        GC: [$Class],
        Random: [$Class],
        RUBY_ENGINE_OPAL: true,
        RUBY_ENGINE_JRUBY: false,
        RUBY_MIN_VERSION_1_9: true,
        RUBY_MIN_VERSION_2: true,
        Set: [$Class],
        ThreadSafe: [$Module],
        URI: [$Module],
        JAVASCRIPT_IO_MODULE: 'node',
        JAVASCRIPT_PLATFORM: 'node',
        JAVASCRIPT_ENGINE: 'v8',
        JAVASCRIPT_FRAMEWORK: '',
        Pathname: [$Class],
        Base64: [$Module],
        StringIO: [$Class],
        OpenURI: [$Module],
        NodeJS: [$Module] },
     '$$base_module': [Circular] } }  prototype: [Error]
App threw an error during load
method 'new' not defined in 
    at Object.Opal.udef (webpack:///./node_modules/opal-runtime/src/opal.js?:1786:28)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6229:12)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6231:7)
    at Opal.modules.corelib/boolean (webpack:///./node_modules/opal-runtime/src/opal.js?:6306:5)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2302:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2330:17)
    at Opal.modules.opal/mini (webpack:///./node_modules/opal-runtime/src/opal.js?:18611:8)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2302:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2330:17)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:23342:8)
robogeek commented 5 years ago

Then, I noticed that line reading self = this and yeah, self is simply an alias for this. So switching the console.log to use this I get the following as the final printout:

Opal.udef self: { [$Class: $Class]
  '$$base_module':
   { [$Class: $Object]
     '$$':
      { BasicObject: [$Class],
        Object: [Circular],
        Module: [$Class],
        Class: [Circular],
        NilClass: [$Class],
        Opal: [$Module],
        Kernel: [$Module],
        Exception: [$Class],
        ScriptError: [$Class],
        SyntaxError: [$Class],
        LoadError: [$Class],
        NotImplementedError: [$Class],
        SystemExit: [$Class],
        NoMemoryError: [$Class],
        SignalException: [$Class],
        Interrupt: [$Class],
        SecurityError: [$Class],
        StandardError: [$Class],
        EncodingError: [$Class],
        ZeroDivisionError: [$Class],
        NameError: [$Class],
        NoMethodError: [$Class],
        RuntimeError: [$Class],
        FrozenError: [$Class],
        LocalJumpError: [$Class],
        TypeError: [$Class],
        ArgumentError: [$Class],
        IndexError: [$Class],
        StopIteration: [$Class],
        KeyError: [$Class],
        RangeError: [$Class],
        FloatDomainError: [$Class],
        IOError: [$Class],
        SystemCallError: [$Class],
        Errno: [$Module],
        UncaughtThrowError: [$Class],
        JS: [$Module],
        RUBY_PLATFORM: 'opal',
        RUBY_ENGINE: 'opal',
        RUBY_VERSION: '2.5.1',
        RUBY_ENGINE_VERSION: '0.11.99.dev',
        RUBY_RELEASE_DATE: '2018-12-25',
        RUBY_PATCHLEVEL: 0,
        RUBY_REVISION: 0,
        RUBY_COPYRIGHT:
         'opal - Copyright (C) 2013-2018 Adam Beynon and the Opal contributors',
        RUBY_DESCRIPTION: 'opal 0.11.99.dev (2018-12-25 revision 0)',
        NIL: [$NilClass],
        Boolean: [$Class],
        TrueClass: [$Class],
        FalseClass: [$Class],
        TRUE: true,
        FALSE: false,
        Comparable: [$Module],
        RegexpError: [$Class],
        Regexp: [$Class],
        MatchData: [$Class],
        String: [$Class],
        Symbol: [$Class],
        Enumerable: [$Module],
        Enumerator: [$Class],
        Numeric: [$Class],
        Array: [$Class],
        Hash: [$Class],
        Number: [$Class],
        Fixnum: [$Class],
        Integer: [$Class],
        Float: [$Class],
        Range: [$Class],
        Proc: [$Class],
        Method: [$Class],
        UnboundMethod: [$Class],
        ARGV: [],
        ARGF: [$Object],
        ENV: [$Hash],
        Encoding: [$Class] },
     '$$base_module': [Circular] } }  prototype: $Class {}
App threw an error during load
method 'new' not defined in 
    at Object.Opal.udef (webpack:///./node_modules/opal-runtime/src/opal.js?:1786:28)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6229:12)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:6231:7)
    at Opal.modules.corelib/boolean (webpack:///./node_modules/opal-runtime/src/opal.js?:6306:5)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2302:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2330:17)
    at Opal.modules.opal/mini (webpack:///./node_modules/opal-runtime/src/opal.js?:18611:8)
    at Object.Opal.load (webpack:///./node_modules/opal-runtime/src/opal.js?:2302:7)
    at $Object.Opal.require (webpack:///./node_modules/opal-runtime/src/opal.js?:2330:17)
    at eval (webpack:///./node_modules/opal-runtime/src/opal.js?:23342:8)
robogeek commented 5 years ago

And - since you asked for a demo app ...

See: https://git.7gen.com/david/electron-vuejs-asciidoctor-opal-demo

If you get an out-of-date certificate error while visiting this, proceed anyway.

As the README says, do npm install then npm run electron:serve and of course you should have a recent (v10.x or later) version of Node.js.

Running it with vue.config.js in place gives the error. Renaming that file to something else, and you won't see the error.

AsciiDoctor (and hence Opal) is referenced from the code, but is not executed. Even so the error occurs.

Since you may not be familiar with Electron applications. In this case src/background.js is where the application launches, and this file runs the main application process. In akashaepub-config.js is some code meant to run in this process, to handle watching and rendering files that get changed.

In src/main.js is code to run the Renderer process and in this case I'm using Vue.js for this.

The Renderer process code is simply the default Vue.js demo app with no changes. There is one line of code to send a message from the Renderer to the Main process to launch the AkashaRender/AkashaEPUB code, but it's not necessary to do this, and the line of code is commented out.

To generate the demo app I ran these commands:

803  vue create demo1
  804  cd demo1
  805  vue add electron-builder
  806  npm install @akashacms/plugins-epub akashacms/akasharender "git+https://github.com/akashacms/epubtools.git#epubuilder" fs-extra cheerio --save
  807  npm install 

 811  npm install aws-sdk --save
  812  npm install chokidar --save
  813  npm install 
  814  npm run electron:serve
   817  cp ../epubuilder-electron/vue.config.js .
  818  npm run electron:serve

There was a small amount of customization to copy some code from my application (the akashaepub-config.js module) that isn't shown in that transcript.

ggrossetie commented 5 years ago

Thanks for all the details, I will give it a try :+1:

ggrossetie commented 5 years ago

Webpack is doing a lot of things and is probably changing the initialization order. I think that's the reason why Opal is not loaded properly.

You should try to compare:

You might find what you need to change in the Webpack config to preserve initialization order. Sorry I can't really help you more than that as I know very little about Webpack :neutral_face:

SebastienPede commented 4 years ago

I am having this exact same problem using Scully Static Site Generation With an Angular App:

⠹ method 'new' not defined in
    at Object.Opal.udef (C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:1784:28)
    at C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:6225:12
    at C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:6227:7
    at Opal.modules.corelib/boolean (C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:6302:5)
    at Object.Opal.load (C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:2300:7)
    at $Object.Opal.require (C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:2328:17)
    at Opal.modules.opal/mini (C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:18607:8)
    at Object.Opal.load (C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:2300:7)
    at $Object.Opal.require (C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:2328:17)
    at C:\Users\Sebo\desktop\fireship\scullytest\node_modules\opal-runtime\src\opal.js:23338:8

any updates on this issue?

ggrossetie commented 3 years ago

@SebastienPede could you please share the code initializing Asciidoctor.js and/or Opal? As mentioned above, the initialization order is most likely wrong. Thanks!

robogeek commented 3 years ago

I made the original report on this issue. At some time in the past it was resolved and normally I do not see this behavior in my application any longer. There was no change in my code, so presumably something was updated either Opal or Asciidoctor.js.

However, occasionally I see it happen. What I've learned is that by deleting the node_modules directory, then rerunning npm install, the issue will clear and I can move on. Hence, I'm assuming there's some issue with initialization if my node_modules directory gets into a certain mode because of updates I've made.