Use modules on server without install permissions - node.js

Node.js is installed on a server that I have limited access to. I can upload files to the server and execute scripts from the command line, but I cannot run certain commands like install.
I have a Node.js script uploaded to the server that I'd like to use. The script references other files, such as a file.json, that it accesses just fine. There's even some other modules it uses, like const osPath = require( 'path' ) and const crypto = require( "crypto" ), that work just fine.
However, the script references something like const argv = require('commander'), but that gives me an error since the module is not installed.
If I download the commander files, and uploaded them to the server, am I able to modify the require statement to point to where I uploaded the file? Or is all hope lost and I would need to find a server where I can run install commands?

Related

npm package uses fs in wrong dir

I have made a very simple npm package to support my discord bot.
In my bot code, I am trying to use a function from my package. However, when I launch bot code, I receive this error:
Error: ENOENT: no such file or directory, open 'prefixes.json'
I have a prefixes.json file in the main dir of npm package. In the package this code (which returns an error) is executed:
const contents = fs.readFileSync(`prefixes.json`);
const jsonPrefixes = JSON.parse(contents);
This code is executed when I turn on my discord bot that is dependant on this package. prefix.json is in the same dir as index.js of my npm package. I tried ./prefix.json and prefix.json, none of which worked.
Is the error because the package tries to search in my bot dir, instead of his own? How do I overcome this?
Update: When I tried ./node_modules/kifo/prefixes.json it worked, but I don't want it like that - is there a way to provide a path relative to the package?
You need to use require() instead of fs.readFileSync():
const jsonPrefixes = require('./prefixes.json');
const contents = JSON.stringify(jsonPrefixes); // you don't actually need this
Why?
The reason why fs.readFileSync() must behave the way it does is because file API in all programming languages behave that way. Say for example you write a program called dump. The working directory must be the one the user is currently in otherwise if you do:
> cd /my/folder
> ls
test.txt
> dump test.txt
Error: cannot open /path/to/node_modules/dump/test.txt
Of course YOU DO NOT EXPECT THIS. Nor should you. You should not expect fs.readFileSync to use it's own module directory to open files from.
On the other hand, require() was designed to load javascript modules, some of which are form your own project. So require() will open files from the directory the code is in.
The require() function can load either javascript code or a JSON file. So in your case you can use require().
What if it's not JSON?
If you cannot use require() you can use the __dirname variable. It is a special variable that contains the path of the currently executing module:
const contents = fs.readFileSync(`${__dirname}/prefixes.json`);
const jsonPrefixes = JSON.parse(contents);
However for JSON I still prefer to use require().

Loading Nodejs Module at runtime in electron app

Currently I am playing around with electron using vue-cli-plugin-electron-builder along side a simple vue project. This is the project https://github.com/nklayman/vue-cli-plugin-electron-builder .
vue create my-project
cd my-project
vue add electron-builder
npm run electron:serve
My goal is to add a simple plugin-like architecture. The app serves only base functionality but can be extended with "plugins". Those plugins therefore are not included in the built, but will be loaded at runtime by electron. I would prefere when those plugins just behave like node modules ( module.exports = ) with its own dependencies ( probably with a package.json file inside ). I would locate those plugins at app.getPath('userData') + '/Plugins.
I looked at a few approaches on how to tackle this problem :
1. Using Nodejs vm module
First, I tried using Nodejs vm module to read and execute a script from an external file, all at runtime. It works great so far, although I would not be able to use external dependencies inside those loaded scripts. If I want to use external dependencies inside the plugin scripts, those dependencies must have been included in the electron build beforehand. Somehow defeats the whole purpose of having plugins ... only vanilla js + nodejs base modules would be possible .
2. using global.require
I saw this solution in another SO answer.
Using node require with Electron and Webpack
Webpack/electron require dynamic module
They say to use global.require but it throws an error saying global.require is not a function. The solution looked promising first, but somehow I can't get it to work.
3. simply use require
Of course I had to try it. When I try to require an external module from a non-project location it won't find the module, even if the path is correct. Again, the path I am trying to locate the module should be at app.getPath("userData"), not in the projects root directory. When however, I locate the plugins inside the root directory of the project it gets included in the built. This again defeats the purpose of having plugins.
Goal
So far, I haven't found a viable solution to this. I simply want my electron app to be extendible with basic node modules at runtime ( following a pre-defined schema to simplify ) . Of course there is atom, made with electron, using their own apm manager to install and load plugins, but this seems way to overpowered. Its enough for me to only have plugin files located locally, to have a public "marketplace" is no goal. Also, it's ok if the app has to reload / restart to load plugins.
Any ideas ?
After more and more research I stumbled over 2 packages :
https://www.npmjs.com/package/live-plugin-manager
https://github.com/getstation/electron-package-manager
both integrating npm to programmatically handle package installation at runtime. I settled for live-plugin-manager for now since its better documented and even allow package installation from local file system.
Pro
I was able to integrate the system out-of-the-box into a vanilla electron app. Works like a charm.
Cons
.I was not able to use it inside a vue electron boilerplate (like the one I said I was using in OP), since webpack is interferring with the require environment. But there sure is a solution to this.
Update : I was able to get it to work eventually inside a webpack bundled electron vue boilerplate. I accidentally mixed import and require . The following code works for me using live-plugin-manager
// plugin-loader.js
const path = require('path');
const { PluginManager } = require('live-plugin-manager');
const pluginInstallFolder = path.resolve(app.getPath('userData'), '.plugins');
const pluginManager = new PluginManager();
module.exports = async (pkg) => {
// installs pkg from npm
await pluginManager.install(pkg);
const package = pluginManager.require(pkg);
return package
}
// main.js
const pluginLoader = require('./plugin-loader');
pluginLoader("moment").then((moment) => {
console.log(moment().format());
})
This will install "moment" package from npm during runtime into a local directory and load it into the app, without bundling it into the executable files.

How to run node.js file from PHP file

so I've been trying to run an SMS script after the user submits a form.
If I use
node send-sms.js
locally on my machine, it works.
However, if I try to use
$sendSmsPath = "send-sms.js";
exec('/public_html/node_modules/node '.$sendSmsPath);
Nothing happens. No error, nothing. I tried using a relative path, as well as an absolute one. My folder scheme is as follows: public > other_folder > php > php_file.php AND public > node_modules
Any ideas are welcome, thanks
You are using the wrong path to Node.js. Try this:
<?php
$sendSmsPath = "send-sms.js";
exec('/c/Program Files/nodejs/node '.$sendSmsPath);
node_modules is for the dependencies of your script, not the actual Node.js executable.
If you'd like to run your script on another machine make sure it has Node.js installed globally and you know the path of the executable (can be found with which node)

how to require a .js file in node repl

so i usually use ruby irb, and I can pull .rb files I wrote into the console environment by running
load './script.rb'
and then all of the functions I wrote in script.rb will be available.
I cannot figure out for the life of me how to do this in the node "console" environment!
You can load JavaScript files using the require function. The following example assume that the Node.js process was started at the directory where your file is located.
require('./script.js');
This will execute the contents of the file.
If you have exported functions or objects, you can assign them to a variable and use them later.
const myFunction = require('./script.js').myFunction;
myFunction();
Like many other development frameworks/languages, Node has a Modules/Package System which, is a CommonJS variant. To load a Module use require(). The usage of require() is the same when running JavaScript files or running in the REPL.
You can require Node Core Modules, NPM Installed Packages or your own local modules. When loading NPM Packages specified in a package.json or a local module, Node will load them from the Current Working Directory(CWD), you can check this using process.cwd(). The CWD will be set to the absolute path of the directory you launched the REPL from.
You can launch the REPL via running node in your CLI and require your packages like below.
// Core Package
const os = require('os')`
console.log(os)
// NPM Package
const moment = require('moment')
console.log(moment)
// Local Package
const myPackage = require('./myPackage')
console.log(myPackage)
You can also pre-require module(s) using the -r flag when running node. The below will launch the Node REPL with the os package preloaded. You can then access the os package using the variable os
node -r os
console.log(os)
In the future, Node may also support ECMAScript Modules (ie. import). You can read more detailed info about that in the Enhancement Proposal.

Installing a Web Server for Node.js

I'm trying to follow a book I purchased called "Pro Angular JS", and I am having trouble getting a web server pointed to the right port. So I go to the command line, run Node, and the first error I get is this, when trying to install connect:
npm should be run outside of the node repl, in your normal shell.
(Press Control-D to exit.)
Ok, fair enough. So I do as the command specifies, and I get it to install just as the user, and it ends up adding a folder called node_modules in my user root folder. Ok, seems like everything still makes sense.
Now, the book tells me to create a server.js file within the Node.js installation folder. There is no Node.js installation folder actually created on my user. I see the node_modules folder for sure. So I'm guessing the root directory of my user is where node.js was installed but maybe it's hidden or something? I believe when I used the Mac installer for Node, it said it was created at usr/local/bin. But I have no idea if that is my user on my computer, or even more root access to my computer.
Lastly, back to this server.js file...so I created it with a text editor, containing this code:
var connect = require('connect');
connect.createServer(
connect.static(".../angularjs")
).listen(5000);
And of course they want me to add this file to the directory where my Node is installed. Currently, it's sitting where my current user (user is kst001) root directory is. This is also where my node_module folder was created when I installed it using the npm install connect line in the shell. They also wanted me to create a folder called angularjs, where I would store my app, and said to place it in the root directory where node.js was installed. Once again, sitting in the root directory with everything else. Yet, when I try and fire up my test document in port 5000 (localhost:5000/test.html), I get a "could not find page" error.
Already tried using this link to solve my problem, which seems dead on for my issue, but it resolved nothing:
Node / connect issue Object function createServer has no method static
I'm using a Mac, by the way. Any ideas, guys? Any help would be much appreciated.
The reason why connect.static() does not work is that the latest major version of connect (3.x) no longer contains all of the middleware that connect was bundled with in 2.x.
The readme for connect has a list of middleware references that show you the name of the module on npm that gives you the old functionality for each middleware (e.g. static is now broken out into its own module serve-static).
I'm following the same book/example and the following works. I claim no credit, it is from another Stack Overflow answer about setting up a simple server plus the contents of a comment on the same answer (question 24346161 link to it from here: nodejs connect cannot find static)
Because I used it in exactly the same learning context (book I also purchased called "Pro Angular JS") and I have been around the houses for 3 hours trying to sort this out (yes a complete novice), I thought I would post it here.
firstly from your node installation directory
npm install serve-static
secondly, your node server.js code for a simple static server to serve your angularjs directory contents in a localhost:5000 browser window, on a Windows 7 machine should be (as at July 2015) ...
var connect = require('connect'),
serveStatic = require('serve-static');
var app = connect();
app.use(serveStatic("./angularjs"));
app.listen(5000);
I just stuck a simple index.html file in the angularjs directory to begin with containing
connection working
to test it and it worked a treat.

Resources