3

I am writing a nodejs script (that will be used in azure pipeline) to check that my Web developer didn't forget to regenerate object contracts used in the web application. So the goal is to read his file and compare objects within with the latest objects version stored somewhere else.

The file appends a subobject in the global object (window in browser) within an anonymous function like https://medium.com/@tkssharma/javascript-module-pattern-b4b5012ada9f

I tried the solution base on the "vm" module found here : Load "Vanilla" Javascript Libraries into Node.js

generatedModels.js

/***************************/
/*  AUTO GENERATED via T4  */
/***************************/
(function(){
    "use strict";

    mynamespace = mynamespace || {};
    mynamespace.factories = mynamespace.factories || {};
    mynamespace.factories.models = mynamespace.factories.models || {};      

    mynamespace.factories.models.AdresseLibreModel_Factory = function() {
        return {"CodePays":null,"ComplementAdresse":null, /*...*/};
    };  
})();

main.js

var vm = require("vm");
var fs = require("fs");
var data = fs.readFileSync("generatedModels.js");
var window = {};
vm.runInNewContext(data, window, "generatedModels.js");

Seems I can't use global object. It always fails during "runInNewContext" --> mynamespace is not defined at generatedModels.js:9:2

How can I use that file like it's used in browser? If needed, I can modify the T4 template to change the structure of the "generatedModels.js" file, but it still needs to be used by the browser.

LHM
  • 721
  • 12
  • 31

3 Answers3

1

Since mynamespace global variable is expected to exist, it should be provided in a sandbox:

var sandbox = { mynamespace: {} };
vm.runInNewContext(data, sandbox, "generatedModels.js");

When the script evaluated in a browser, a global should exist:

<script>
window.mynamespace = {};
</script>
<script src="generatedModels.js"></script>
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
0

Outside your IIFE, determine if you are running in the context of a browser (where the window object exists) or if you are a node module.

Pass either window or module.exports into the IIFE. Then modify that object instead of trying to create an implicit global (which is forbidden in strict mode).

(function(obj){
    "use strict";

    var mynamespace = obj.mynamespace || {};
    mynamespace.factories = mynamespace.factories || {};
    mynamespace.factories.models = mynamespace.factories.models || {};      

    mynamespace.factories.models.AdresseLibreModel_Factory = function() {
        return {"CodePays":null,"ComplementAdresse":null, /*...*/};
    };  

    obj.mynamespace = mynamespace;

})(typeof window !== "undefined" ? window : module.exports);

Then in the browser you can just access window.mynamespace and in node you can just const module = require("./module"); and then use module.mynamespace.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
0

I found that solution: https://code-maven.com/javascript-module-to-run-in-browser-and-in-node

I was forced to use the keyword this in front of each mynamespace (which I don't like very much... and the main.js just became

var lib = require('./generatedModels')
console.log(lib.mynamespace.factories.models.AdresseLibreModel_Factory().CodePays);
Bilaal Rashid
  • 828
  • 2
  • 13
  • 21