npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

node-direct

v0.5.2

Published

A server which allows to run server-side JavaScript files via NodeJS as easy as PHP via Apache

Downloads

45

Readme

node-direct npm version Build Status

Run server-side JavaScript files directly

If your VPS contains a lot of applications and you don't want to set up NodeJS server for every application, you're in the right place. node-direct allows to run JavaScript on a server just like .php files are run. The tool initializes one NodeJS instance per many websites and executes JavaScript files when URLs like example.com/foo/bar.srv.js are requested. .srv.js extension is configurable.

You know how to set up and run PHP script. You just need to upload it and run like this: example.com/foo.php. But what about NodeJS? You must define routes, run every app on its own port, set up deployment, make sure that all instances work after server reload... It's OK if you do a big application but when you have only small server-side utilities (like ajax proxy) they just wasting your time.

Install:

npm install -g node-direct

Nginx configuration

All the magic mostly happens on Nginx side (the project itself is extremely small). You'll need to configure it to handle requests to .srv.js files.

location ~ \.srv\.js$ {
    root <path_to_website_files>;
    proxy_pass http://localhost:<port>;
    proxy_set_header X-Requested-File-Path $document_root$uri;
}
  • path_to_website_files - where static files are located.
  • port - a port of node-direct server

Example:

server {
    listen 80;

    server_name example.com;

    # Serve static files
    location / {
        root /var/web/example.com/public;
        index index.srv.js index.html index.htm;
    }

    location ~ \.srv\.js$ {
        root /var/web/example.com/public;
        proxy_pass http://localhost:8123;
        proxy_set_header X-Requested-File-Path $document_root$uri;
    }
}

Usage

node-direct --port=8000

node-direct is powered by Express. Every .srv.js file should export a function which accepts request and response objects created by Express.

Hello world:

module.exports = function(req, res) {
    const someModule = require('some-module');
    res.send('Hello world!');
}

JSON API:

module.exports = function(req, res) {
    if(req.method === 'POST') {
        req.json({
            message: 'Everything is awesome'
        });
    } else {
        req.status(400).json({
            message: 'Only POST requests are allowed'
        });
    }
}

HTML rendering:

const fs = require('fs');
const ejs = require('ejs');
const template = ejs.compile(fs.readFileSync('./templates/index.html'));

module.exports = function(req, res) {
    res.type('html').send(template({ foo: 'bar' }));
}

Check out Express documentation for more info.

You can use local package.json and require any modules by .srv.js files placed at node_modules as you usually do. There is an example of potential file structure of an app.

/package.json - a package file with dependencies and devDependencies for this specific application
/index.html - main HTML file
/js/app.js - client-side JavaScript app
/css/style.css - styles
/node_modules/ - things installed by "npm install"
/foo/index.srv.js - some JSON API which allows to make requests to /foo/
/bar/index.srv.js - some dynamic HTML page returned when /bar/ is requested

Flags

Common

  • --port - a port of node-direct server (8123 by default)

Standalone mode

The standalone mode creates static HTTP server which doesn't require Nginx for its work. It should be used for development purposes on your local machine.

  • --standalone - turns on standalone mode
  • --root - a root of static files (process.cwd() by default)
  • --ext - an extension of runnable JS files (.srv.js by default)
node-direct --port=8000 --standalone --root=./foo/bar --ext=.serverside.js

Running node-direct on startup (Linux)

You can add cron job to run the server on startup. To modify crontab run crontab -e. Add the job to the end of the crontab file:

@reboot <path_to_node> <path_to_installed_module> [<flags>]
  • path_to_node - absolute path to NodeJS binary (run which node to get the path)
  • path_to_installed_module - absolute path to installed node-direct (there is no direct way to get it)
  • flags - flags you want to use

Example:

@reboot /usr/local/bin/node /usr/local/lib/node_modules/node-direct/index.js --port=8123

(if you have examples how to set up startup script for another OS, feel free to make PR)

Troubleshooting

Automatic module reload

As you know NodeJS caches values returned by require function. When you call require('foo') twice or more it returns the same object. node-direct updates cache when .srv.js file is replaced (eg. you upload another version of such file) and you don't have to reload node-direct every time when the file is changed. A problem can appear there when you require other modules by .srv.js files.

// foo.srv.js
module.exports = function(req, res) {
    const bar = require('./bar');
    // ...
}

When you change foo.srv.js it is reloaded as expected but when you change ./bar its value returned by require remains the same. The tool could hot-reload all requested modules but this would make side-effects which may cause unpredictable behavior in other modules. To handle this issue and update module cache you need to define watcher and clear cache when the require'd file is changed.

In example below you do want to hot reload ./bar when it's changed but you don't want to update ./baz on its change.

// foo.srv.js

// for more modules you'll need to use a loop
const fs = require('fs');
const barPath = require.resolve('./bar');
const watcher = fs.watch(barPath, (eventType) => {
    if (eventType === 'change') {
        delete require.cache[barPath];
        watcher.close();
    }
});

module.exports = function(req, res) {
    const bar = require('./bar');
    const baz = require('./baz');
    // ...
}

If it looks too tricky check out fresh-up.

// foo.srv.js

// for more modules you'll need to use a loop
const freshUp = require('fresh-up');
freshUp(require.resolve('./bar');

module.exports = function(req, res) {
    const bar = require('./bar');
    const baz = require('./baz');
    // ...
}

Potential vulnerability: X-Requested-File-Path header

As you may notice, Nginx config described above passes requested file path as X-Requested-File-Path HTTP header. A hacker can use this header to run custom JavaScript files on your server. The server needs to contain some dangerous JavaScript file and the hacker needs to know its path relative to root. If you want to fix this potential vulnerability you'll need to deny an access to a port used by node-direct with firewall.

This is how it can be made on Linux:

sudo ufw deny 8123