Best way to evaluate javascript source code module with node.js - javascript

With node, I transpile a typescript tsx file int javascript. Then I need to call a function that is described in that javascript code. ES6 modules are used.
I use
writeFileSync('./temp/page1.js', js) // js is the module source code
import page from '../temp/page1.js'
page is here the default export which is a function that I want to call.
That works fine but I wonder if there is a better way to call the function inside the module source code? A way that avoids saving the source code into a temporary file.
eval would not be a security concern, but I think it would not give me the default export, modules are not considered in this old function.
Maybe something node related?
I found https://www.npmjs.com/package/node-eval which would avoid the file saving, although it still requires a filename, which causes some brittleness in my code.
node:module
node:vm
are maybe promising, looking at https://github.com/node-eval/node-eval/blob/master/index.js but I have not yet figured out if and how.
Similar, but more related to require: Load node.js module from string in memory
https://github.com/floatdrop/require-from-string
did not work either
all the variants with node:vm like
import vm from 'node:vm'
let context = vm.createContext({}, {name:"temp1.mjs"})
vm.runInContext(js, context, {filename: "temp2.mjs"})
result in "Cannot use import statement outside a module"

The best way would be nodes vm.Module class
https://nodejs.org/api/vm.html#vm_module_evaluate_options
but that is in draft stage and behind feature flags.

Related

NodeJS - Dynamically import built in modules

I'd like to get a built in module (for example Math or path or fs), whether from the global object or require, I thought about doing something like this:
function getModuleByName(name) {
return global[name] || require(name);
}
Is there a way to check that it is indeed a module and not something else? Would this make a security problem?
Is there a way to check that it is indeed a module and not something else?
Other methods but here's an example:
function getModuleByName(name)
{
let module = null;
try {
module = require(name);
} catch (e) {
// Recommend Logging e Somewhere
}
return module;
}
This will graciously fail as null where the module does not exist, or return it.
Would this make a security problem?
Quite possibly, it depends on how it's used. I'd argue it is more of a general design issue however and would blanket say avoid doing it (without any context, you may have a very good reason).
You, like anyone, obviously have a finite amount of modules you could be loading. These modules have all been selected by yourself for your application for specific reasons, or are bundled into your node version natively and are expected parts of your environment.
What you are doing by introducing this functionality is adding the addition of unexpected elements in your environment. If you are using getModuleByName to access a third party library- you should know outright that library is available and as such there's no reason why you can't just require it directly.
--
If you do think your use case warrants this, please let me know what it is as I may never have encountered it before. I have used dynamic imports like the following:
https://javascript.info/modules-dynamic-imports
But that hasn't been for global packages/libraries, but for dynamic reference to modules built internally to the application (i.e. routing to different views, invokation of internal scripts).
These I have protected by ensuring filepaths can't be altered by whitelisting the target directories, making sure each script follows a strict interface per use case and graciously failing where a module doesn't exist (error output "this script does not exist" for the script usage and a 404 view for the routing example).

What to do when no export is needed in TypeScript file

I had a problem while making some demo files using TypeScript, each file is considered to run alone (no import or export needed).
The problem is that the files leaked to each other as they all went global (I'll appreciate if someone explains why this happened). I found a few ways to get rid of this as wrapping them in a module or a namespace, or even exporting an empty object.
What I need to know is the best practice that should be done in this situation? which solutions is considered the best? especially that I thought I can face the same situation if I have multiple files that are required for their side-effects only or something.
I had a problem while making some demo files using TypeScript
What I need to know is the best practice that should be done in this situation? which solutions is considered the best? especially that I thought I can face the same situation if I have multiple files that are required for their side-effects only or something.
The only time I've experienced it in my long career as well is with demo files. I had this when creating TypeScript deep dive so I would put in some junk at the top of the file e.g. see const
export var asdfasdfasfadf = 123;
Why its not a concern
You do not see it happening in real world code because you start you brain with module mind set. E.g.
In a file with zero dependencies you are normally thinking : What am I going to export
In a file where you are going to action something you are normally thinking: What will I need to import. As simple as import fs from 'fs' makes it a module ๐ŸŒน

Ignore not declared variables (TypeScript)

I am creating a WebExtension using TypeScript which is later compiled to JavaScript.
My extension depends on one of the APIs the browser (Firefox) offers, specifically the extension API. As an example, I use the getURL() method, which is called like this:
browser.extension.getURL("foo/bar.js");
Of course, TypeScript gives an error "Cannot find name 'browser'". This prevents me from fully compiling the code. I would like to know if there is any way to bypass this. Preferably not only at compile level, but also at the linting level.
I have tried:
Defining browser at the beginning as var browser: any;: breaks the API.
Compiling with --noEmit, --noEmitOnErrors: irrelevant, still complains.
Any suggestions?
If you want to let Typescript know that the variable exists but not actually emit any code for it you can use declare
declare var browser: any;

When using ES6 import statement, is there a way to protect against items being undefined?

import {
foobar1,
foobar2,
foobor3, //typo! this key doesn't exist in the module.
} from './module_file.js'
console.log(foobar1, foobar2, foobar3) //EXPLODES
One of the most frequent silly mistakes I make when using the new ES6 style import statement is that I'll have a typo in one of the keys in object destructuring. I can't think of a single instance where I'd ever want a value in a destructuring assignment to be undefined. Is there any way to force the import statement to fail-fast if one of the items I'm trying to import is undefined?
ie:
import {
doesntExistInModule //EXPLODE NOW! ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ
} from './module_file.js'
There is no hook allowing a module to run some code before its dependencies load. This means that modules have no control over how
their dependencies are loaded.
There is no error recovery for import errors. An app may have hundreds of modules in it, and if anything fails to load or link,
nothing runs. You canโ€™t import in a try/catch block. (The upside here
is that because the system is so static, webpack can detect those
errors for you at compile time.)
For more details, read it out
The module stuff in the spec is pretty gnarly, but I believe a real implementation will throw a SyntaxError at 15.2.1.16.4 ModuleDeclarationInstantiation( ) Concrete Method step 12.d.iii in that case. Since there are no legit implementations I don't know if you're talking about a way to do it in transpiled code in the meantime, or if you don't realize that's the case and will be satisfied to know it'll work that way eventually. There's been talk before of trying to implement that kind of check in Babel, but as far as I know nothing's actually been done to that effect. Babel compiles each module in isolation.
Also, this is not object destructuring, it just has similar syntax.

Import existing library with JavaScript ES6 Modules

How can an existing library be loaded and run using JavaScript's ES6 Modules?
For example, suppose I need to load an existing polyfill:
import {poly} from "thirdParty/poly";
How can I run the imported poly script and load its properties into the current namespace without changing the source?
Here are two practical problems to help clarify the problem I'm trying to solve:
I have a script called rafPolyfill.js which is a polyfill for window.requestAnimationFrame. I need to import it into the global scope and run it immediately as soon as it loads. This is easy to do with a <script> tag:
It runs and loads itself into the global scope. How is can this be done using ES6 modules?
I have another script called Font.js which is a pre-loader for fonts. It let's you create new font object like this:
var font = new Font();
I used Font.js by loading it with a script tag, like this:
<script src="Font.js"><script>
Without accessing, changing, or understanding the source code of this script, how is it possible to use ES6 modules to load and use the in the same way that I would with a <script> tag? I just need these scripts to run when they're loaded and take care of themselves.
A possible solution might be using the module Loader API:
http://wiki.ecmascript.org/doku.php?id=harmony:module_loaders
This document describes global binding of the System loader, but I'm afraid I don't have the vocabulary to fully understand what it's trying to explain. Any help in decoding this document would be greatly appreciated!
This answer is: "No, based on the ES6 spec it's not possible to load and run a global script the same way you can with a script tag."
But there is a solution: SystemJS
https://github.com/systemjs/systemjs
It's a universal module loader for ES6 modules, AMD modules, and global scripts (anything you load with the <script> tag)
Does this or something close to this work for you?
var stuffFromPoly = import "thirdParty/poly"
Then you would call methods off of the object stored in stuffFromPoly.
If that's not quite it, could you expand your question a bit, I'm trying to guess at exactly what you mean and I may be a bit off.
Quick note post-'your update':
Are you opposed to using https://www.npmjs.org/package/es6-module-loader ? Or does that not quite solve the problem?
From the readme:
The new ES6 module specification defines a module system in JavaScript using import and export syntax. For dynamically loading modules, a dynamic module loader factory is also included in the specification (new Loader).
A separate browser specification defines a dynamic ES6 module loader loader for the browser, window.System, as well as a tag for using modules.
This polyfill implements the Loader and Module globals, exactly as specified in the 2013-12-02 ES6 Module Specification Draft and the System browser loader exactly as suggested in the sample implementation.

Categories

Resources