malaporte / nashorn-commonjs-modules

CommonJS modules support for Nashorn
MIT License
108 stars 31 forks source link

webpack es5 commonjs module results in empty exports object #25

Open maybeec opened 7 years ago

maybeec commented 7 years ago

I am trying to call a small library build with webpack2. It is configured to result in a es5, commonjs bundle. I am using nashorn-commonjs-module to import it by evaluating module = require('importModule');. importModule contains a default export to a function served as the API, which I want to call.

However, module is evaluate to an empty object. There are no exports, nothing... any idea? Did I get something wrong?

malaporte commented 7 years ago

Hmm hard to say without seeing any code, but maybe you could step through the loading process in Module and confirm that it's indeed loading the proper file as root, and that this file adds symbols to exports ?

maybeec commented 7 years ago

I could not see any gathering of exports during debugging. However, maybe I missed something. Here is my code: https://github.com/maybeec/ts-merger Here is the built js file with webpack in non-production mode to not have method names uglified for now: tsmerger.zip I wanted to call the default exported merge function utilizing nashorn. However, I am not able to get access. There is nothing in the scope after evaluating merge = require('tsmerger.js'). I have written my own dummy folder to just retrieve the script as a commonjs file: https://github.com/maybeec/nashorn-test-commonjs

maybeec commented 7 years ago

I debuged a little further. The commonjs-module returns an object of type jdk.nashorn.api.scripting.ScriptObjectMirror with property sobj of type jdk.nashorn.internal.scripts.JO containing the property mapwith toString()=

0x71956711 = {
    merge                id=0x457758e8 (0x0   ) SpillProperty {o    } [slot=0]
    default              id=0x4b222f17 (0x0   ) SpillProperty {o    } [slot=1]
}

After that, I cannot see any code from NashornScriptEngine to check further binding resolution. But it seems to be a binding issue. How are the properties returned by commonjs-module injected into the jjs environment?

engine.eval("require('ts-merger.js');");
engine.eval("print(JSON.stringify(merge));");

results in Caused by: <eval>:1 ReferenceError: "merge" is not defined.

engine.eval("merge = require('ts-merger.js');");
engine.eval("print(JSON.stringify(merge));");

results in merge to be an empty object {}.

Can you help me to identify how to access the bindings passed by commonjs-module?

maybeec commented 7 years ago

https://github.com/coveo/nashorn-commonjs-modules/blob/master/src/main/java/com/coveo/nashorn_modules/Module.java#L132

nashorn-commonjs-module

malaporte commented 7 years ago

I've seen cases before where Nashorn seemed unable to resolve a property of an object that really seems to be there. I'll try to have a look when I have a minute but those are usually tricky. What JVM version are you using? I remember that one previous such issue was fixed by upgrading to a more recent one.

maybeec commented 7 years ago

Sounds ugly. My current JVM is

java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

malaporte commented 7 years ago

OK pretty recent then. The one with an issue was much earlier than this (around _3x I think).

Well, I'll try to have a look. Did you try "reducing" the JS file to pinpoint the pattern that is causing an issue? Or maybe creating a dummy library built with webpack that contains almost no code?

maybeec commented 7 years ago

I can try to come up with a minimal example.

maybeec commented 7 years ago

A minimal example of a webpack generated bundle (commonjs, es5):

(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
/******/  // The module cache
/******/  var installedModules = {};
/******/
/******/  // The require function
/******/  function __webpack_require__(moduleId) {
/******/
/******/    // Check if module is in cache
/******/    if(installedModules[moduleId]) {
/******/      return installedModules[moduleId].exports;
/******/    }
/******/    // Create a new module (and put it into the cache)
/******/    var module = installedModules[moduleId] = {
/******/      i: moduleId,
/******/      l: false,
/******/      exports: {}
/******/    };
/******/
/******/    // Execute the module function
/******/    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/    // Flag the module as loaded
/******/    module.l = true;
/******/
/******/    // Return the exports of the module
/******/    return module.exports;
/******/  }
/******/
/******/
/******/  // expose the modules object (__webpack_modules__)
/******/  __webpack_require__.m = modules;
/******/
/******/  // expose the module cache
/******/  __webpack_require__.c = installedModules;
/******/
/******/  // define getter function for harmony exports
/******/  __webpack_require__.d = function(exports, name, getter) {
/******/    if(!__webpack_require__.o(exports, name)) {
/******/      Object.defineProperty(exports, name, {
/******/        configurable: false,
/******/        enumerable: true,
/******/        get: getter
/******/      });
/******/    }
/******/  };
/******/
/******/  // getDefaultExport function for compatibility with non-harmony modules
/******/  __webpack_require__.n = function(module) {
/******/    var getter = module && module.__esModule ?
/******/      function getDefault() { return module['default']; } :
/******/      function getModuleExports() { return module; };
/******/    __webpack_require__.d(getter, 'a', getter);
/******/    return getter;
/******/  };
/******/
/******/  // Object.prototype.hasOwnProperty.call
/******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/  // __webpack_public_path__
/******/  __webpack_require__.p = "";
/******/
/******/  // Load entry module and return exports
/******/  return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });

function merge(patchOverrides, baseContents, patchContents, resultFile, encoding) {
    return "RETURNVAL";
}
exports.merge = merge;
exports.default = merge;

/***/ })
/******/ ])));
maybeec commented 7 years ago

Any news? ;) I could not find any more information about this as I could not dig into nashorn code at all due to missing source code. :(

malaporte commented 7 years ago

To be honest I didn't had time to look deeper into this... I just bought a new house and for a few weeks every shred of spare time my job & kids leave me has been spent ripping out old wallpaper, patching holes, moving furniture, and other such highly entertaining activities.

Believe me when I say I'd rather be coding 😁

maybeec commented 7 years ago

😁 no problem. Have fun! Maybe I will get it to work in some point in time when I have new ideas how to proceed here. If so, I will keep you updated.

maybeec commented 7 years ago

I finally got it to work. Here is the way of how to call functions within a webpack module using nashorn: https://stackoverflow.com/questions/38623186/how-can-i-invoke-a-method-from-nashorn-with-a-webpack-js-file

malaporte commented 7 years ago

Wait, but it worked in Node right? Just tried your minimal sample above and if I require it I can definitively access the merge function defined inside. This lib should have the same behavior as Node on that regard.

I'm curious, what did you change exactly on your side to get it to work (I'm not familiar with Webpack much)?

I'll keep the issue opened to see if I can implement a proper fix in any case - once I'm done with all three bedrooms.

micmicsuarez commented 5 years ago

Hi @maybeec,

I followed the solution on the link provided but it doesn't work on my end.

Regards, Michael

maybeec commented 5 years ago

Hi,

This thread is already quite old. But maybe you can find a helpful tip on my code calling the script here: https://github.com/devonfw/tools-cobigen/blob/cobigen-tsplugin/v2.1.0/cobigen/cobigen-tsplugin/src/main/java/com/devonfw/cobigen/tsplugin/merger/TypeScriptMerger.java#L92

Best Regards Malte