Is there any way to use "require" directly not only "jsreport.assets.require"



  • Hi Jan,

    I am trying to upgrade our project from V2 -> V3 or V4.
    Although "'trustUserCode': true," and "'allowedFiles': '/.'," were defined in the jsreport config file, I still have to change all the "require" to "jsreport.assets.require". Otherwise, it will throw errors.

    I was blocked here for two days. You know, we have couples of custom scripts, and some of the JS files are compiled result of typescript files. It is impossible to change all the files. And sorry, I could not paste our code here.

    Is there any way to allow directly "require" a javascript file?

    I just noticed that require('lodash') or require('moment') is okay. If they are listed in 'allowModules' array. Does that mean I need to wrap up all my custom code into a module and then require that module instead in my helper js file? Thank you!
    @jan_blaha @bjrmatos



  • I did more test today. I can make part of the old code work.
    First, allow all modules in config.

    'sandbox': {
            'allowModules': "*"
        },
    'trustUserCode': true,
    

    Second, use jsreport.assets.require in beforeRender function. Like this.

    //const test1 = require('./server/test1.js'); //directly use require here does not work.
    
    async function beforeRender(req, res, done) {
        const jsreport = require('jsreport-proxy');
        const test1= await jsreport.assets.require('./server/test1.js');
        if (test1['test1']) {
            test1.test1(req, res, done);
        }
    }
    

    And I have 3 js files like this: ./server/test1.js, ./server/test2.js, ./server/test3.js

    // test1.js
    const handler = module.exports;
    const test2 = require('./server/test2.js');
    handler.test1 = function(req, res, done) {
        test2 .test2 ();   
    }
    
    // test2.js
    const handler = module.exports;
    const test3 = require('./server/test3.js'); **// It will report test2 .test2 is not a function.**
    const test3 = require('./test3.js'); **// It works if I require it like this.**
    const _ = require('lodash');                         
    handler.test2 = function() {
        test3.printTestData('Hello world');
    }
    
    // test3.js
    const handler = module.exports;
    handler.printTestData = function(var) {
        console.log(var);
    }
    

    Why I could not require a file from another folder in test2.js? There is not enough error message, I did a lot of testing. And find out this wired issue. And that blocked me since we have lots of code in different folders.
    Please help! Thank you!



  • The jsreport.assets.require should be used primarily to require asset entities. In your case, you should use the normal require.

    const test3 = require('./test3.js'); **// It works if I require it like this.**
    

    This looks correct, the ./test3.js is a relative path to the /server/test2.js

    Note it seems like we have a bug that is reporting the wrong module name when require fails on nested dependency, I am looking on it so far. I will come back...

    Also, note that the modules are kept in the nodejs require cache. So better to always restart jsreport when troubleshooting this.



  • "The jsreport.assets.require should be used primarily to require asset entities. In your case, you should use the normal require."

    Yep, you are right. I can only make it work by "jsreport.assets.require" at the very beginning of upgrade. And that might because I did not use "'allowModules': "*"" at the very beginning. It complains about "can not find module" or "does not have permission..." every time. Previously, I use relative path for each script in allowModules array. something like: "./server/test1.js" etc.

    Now, I had reverted all the code and just add "'allowModules': "*"" . It will not complain about require issue anymore. Just hung there, I am going to trouble shooting the new issue.

    Useful tips while upgrade:

    1. Do not use "jsreport.assets.require". Otherwise you will encounter lots of wired issue about "require".
    2. Relative path shall be used for all your custom scripts.
    3. If require(./test) does not work. Try require('./test.js'). They should be same thing, but I dont know.
    4. Use "'allowModules': "*"" in your jsreport config file.

    Thank you! @jan_blaha



  • The allowModules config is duplicated when you use trustUserCode.
    https://jsreport.net/learn/configuration#trusting-users-code



  • "The allowModules config is duplicated when you use trustUserCode"
    -- Yep, I saw that mentioned in upgrade documentation. Upgrade job contains too many errors and I have no idea which one take effect. So, I just accept both in my config file.

    I finally locate the error. It is because failed to require a js file. That file is compiled from a typescript file. We had build a demo project to reproduce the issue. https://github.com/Davidliu11/jsreport-test

    data\scripts\test\content.js -> require('./data/scripts/test1.js');
    test1.js -> require('../../dist/application') Then error occurred: "'uncaughtException: Error when evaluating custom script /scripts/test"

    I had required same file in server.js and it works fine.
    You can either clone or download the demo and just npm install and npm start. You will see the error.

    Our Node version v18.16.0.

    Why same js file could be required by normal js file but failed in JSreport helper file? Please do help me. Thank you!

    @jan_blaha



  • Hi Jan,

    I found the root cause. Seems jsreport does not support "require('..');" in new version.
    If I add "console.log('error: ', e);" at node_modules@jsreport\jsreport-core\lib\worker\sandbox\requireSandbox.js ln144.
    It will print the error message clearly. "Error: Cannot find module '..'"
    Loopback use require('..') everywhere.

    And Jsreport eat that error message. So, I can only see error "TypeError: test.printTest is not a function".

    I had a workaround.
    In node_modules@jsreport\jsreport-core\lib\worker\sandbox\isolatedRequire.js ln35. Change the code like this.
    let newModuleId = moduleId === '..' ? '../index' : moduleId;

    const fullModulePath = resolveFilename(ISOLATED_REQUIRE_RESOLVE_CACHE, requireFromRootDirectory.resolve, newModuleId, { parentModulePath: parentModule?.path })

    It is not a solution, but I did not figure out why your isolate require does not support require('..').
    Please do provide us a solution. Thank you!
    @admin @jan_blaha @bjrmatos


  • administrators

    hi @JoeyLi-1

    is the demo supposed to be down? https://github.com/Davidliu11/jsreport-test returns 404 for me



  • https://github.com/77chuachua/jsreport-test Please try this one.
    Sorry! Just realized that repo is private, that might because our company's policy. @bjrmatos


  • administrators

    thanks for the update, we are checking the problem


  • administrators

    i found that this is actually a node.js bug present in require.resolve, which is api we use to implement isolated modules. until they fix it, i have added a workarounds for it to resolve normally. this is fixed and it will be part of next jsreport release.

    for the record, after fixing the bug i noticed that i was not able to finish the render of your template, i was getting browser error Failed to initialize WebGL which is related to the usage of mapbox-gl, what worked for my machine (macos with Apple silicon) was to use chrome arg "--use-angle=gl", maybe it is not needed on your machine but i just wanted to share what worked for me in case you need it.

    this is the final jsreport.config.json that i've used

    {
      "httpPort": 5488,
      "store": {
        "provider": "fs"
      },
      "blobStorage": {
        "provider": "fs"
      },
      "logger": {
        "console": {
          "transport": "console",
          "level": "debug"
        },
        "file": {
          "transport": "file",
          "level": "info",
          "filename": "logs/reporter.log"
        },
        "error": {
          "transport": "file",
          "level": "error",
          "filename": "logs/error.log"
        }
      },
      "trustUserCode": true,
      "reportTimeout": 60000,
      "workers": {
        "numberOfWorkers": 1
      },
      "extensions": {
        "authentication": {
          "cookieSession": {},
          "admin": {
            "username": "admin",
            "password": "password"
          },
          "enabled": false
        },
        "sample-template": {
          "createSamples": true
        },
        "chrome-pdf": {
          "launchOptions": {
              "args": ["--no-sandbox", "--window-size=1800,1350", "--use-angle=gl"]
          },
          "strategy": "chrome-pool",
          "allowLocalFilesAccess": true,
          "numberOfWorkers": 3
        },
        "assets": {
          "allowedFiles": "**/*.*",
          "searchOnDiskIfNotFoundInStore": true,
          "publicAccessEnabled": true,
          "rootUrlForLinks": "file:///Volumes/DATA/workspace/jsreport-bug-with-specific-require-in-isolated-modules/data"
        }
      }
    }
    


  • Yep. That "Failed to initialize WebGL" is known issue for us. We already have solution for that.

    Looking forward to the next release. Thanks a lot! @bjrmatos


Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.