Can I provide different baseref for Angular Universal SSR and clientside rendering? - node.js

I have an angular universal app. All works perfectly when run directly from node (localhost:4000) with the following commands:
npm run build:ssr
npm run serve:ssr
For production, I need to serve the app at a subpath (servername/appname) instead of root. The webserver is apache and I use proxypass as follows:
ProxyPass "/appname/" "http://localhost:4000/"
Now to the problem:
For SSR, the baseref is “/”, but for clientside-rendering, the baseref is “/appname”. This means, either SSR using node/express on root or the client running the app on servername/appname cannot find the files linked in index.html (main.js etc)
Is it possible to provide a different baseref for SSR and CSR?
A hack I can think of would be to host the SSR-app at “localhost:4000/appname”… but I couldn’t figure out how to configure this in my server.ts …
Any help much appreciated!

At least I've now got node running the SSR-app under the same href
const allowed = [
'.js',
'.css',
'.png',
'.jpg',
'.svg',
'.woff',
'.ttf'
];
const disallowed = [
'.map'
]
app.get('/appname/*', (req, res) => {
if (allowed.filter(ext => req.url.indexOf(ext) > 0).length > 0 && disallowed.filter(ext => req.url.indexOf(ext) > 0).length == 0) {
res.sendFile(resolve(DIST_FOLDER + req.url.replace("appname/", "")));
} else {
res.render('index', {req})
//res.sendFile(path.join(__dirname, 'client/dist/client/index.html'));
}
});

Related

react express Uncaught SyntaxError: Unexpected token <

I understand this error is not the reason for the failing. It is failing because in my index.html file i have:
<body><noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript" src="/static/js/main.f4a49fba.js"></script>
</body>
That script tag src is failing and returning the same file contents as the index.html itself. This causes it to render HTML (hence < unexcpected from <!DOCTYPE html>).
I am trying to have both express server with /graphql and react together. The working solution is using express.static middlewear shown below. Problem is the working solution breaks the /graphql endpoint so I cannot return any data.
app.use(express.static(path.join(__dirname, 'client/build')));
I need to get this working so it first allows the previous enpoints (/graphql) before checking static pages so I am trying to use this:
app.get('*', (req, res) => {
res.sendFile('index.html', { root: path.join(__dirname, 'client/build/') });
});
This is successfully getting pulled back but failing to work because main.f4a49fba.js in the script tag does not want to load. I tried changing it to /client/build/static/js/main.f4a49fba.js but still wont load. This is using a build file for production.
UPDATE:
I replaced my code with below which helped but for some reason even though I have /graphql above this it is still being run when a full address is being run.
app.get('*', (req, res) => {
const link = (req.path == '/' ? 'index.html' : req.path);
const root = path.join(__dirname, 'client/build');
res.sendFile(link, { root: root }, (error) => {
if (error) {
res.sendFile('/', { root: root });
}
});
});
I am getting this now when a graphql request comes in which seems like it is missing the first /graphql and going to my updated function above. It is very strange and sticking the graphql full address at the end of whatever current page I am in.
http://localhost:3000/dashboard/accounts/my.herokuapp.com/graphql 404 (Not Found)

Issues Getting Highcharts Export Server Running Under iisnode

I am working on trying to set up the Highcharts export server under node.js using iisnode (https://github.com/tjanczuk/iisnode). It basically acts as a pipe between requests to IIS through to node. Great! Only, how do I "install" the highcharts export server so it is using iisnode? I did the instructions on how to install the highcharts-export node module but it is installed under (Windows) AppData\Roaming\npm. How to move or point iisnode to the export server?
This export server is run via the following once installed from npm:
highcharts-export-server --enableServer 1
So, to get this installed and used in IIS8 + iisnode
1) What is the right directory to install export server locally (on Windows the modules pulled in via npm go to C:\Users\\AppData\Roaming\nmp\ where is the logged in user using npm to install the package)?
2) What is the iisnode configuration necessary for this?
I have the iisnode setup and running on our development box and all the examples work. My confusion lies partly with the utter lack of documentation for issnode. All the links I have found just repeat the items listed in the links from the issnode developer with no actual "here is how you take a node app that exists in npm and have it work in issnode." I don't necessarily need my hand held every step of the way. I am just seeing no list of steps to even follow.
install node (if not already installed)
install iisnode (if not already installed => https://github.com/tjanczuk/iisnode)
verify IIS has iisnode registered as a module
create a new Application Pool, set to "No Managed Code"
create a new empty web site
load the iisnode sample content into it, update the web.config
verify you can hit it and it runs and can write it's logs
go to the IIS web site folder and run these npm commands
npm init /empty
npm install --save highcharts-export-server
npm install --save tmp
add file hcexport.js and reconfigure web.config
var fs = require('fs');
var http = require('http');
var path = require("path");
var tmp = require('tmp');
const exporter = require('highcharts-export-server');
http.createServer(function (req, res) {
try {
if (req.method !== 'POST') { throw "POST Only"; }
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
if (body === '') { throw "Empty body"; }
var tempFile = tmp.fileSync({discardDescriptor: true, postfix: ".svg", dir: process.cwd()});
var input = JSON.parse(body);
input.outfile = path.basename(tempFile.name);
exporter.initPool();
exporter.export(input, function (err, exres) {
if (err) { throw "Export failed"; }
var filename = path.join(process.cwd(), exres.filename);
exporter.killPool();
fs.readFile(filename, function(err, file) {
res.writeHead(200, { 'Content-Type': 'image/svg+xml', 'Content-disposition': 'attachment; filename=' + exres.filename });
res.write(file.toString());
res.end();
tempFile.removeCallback();
});
});
});
} catch (err) {
console.log({port: process.env.PORT, error: err});
res.writeHead(409, { 'Content-Type': 'text/html' });
res.end(err.message);
}
}).listen(process.env.PORT);
Extend as needed to support the export types you plan to use.
The highcharts-export-server uses phantomjs internally and this can run away under some error conditions using up 100% of available CPU, if you see this you can kill it using:
Taskkill /IM phantomjs.exe /F
The solution from saukender seems to work, however it seems that it always initializes a new pool of phantom workers every time.
If you already have node and issnode setup, another solution is to directly start the highcharts export server and not call the export function manually. This seems to provide a better performance, since it doesn't initialze the worker pool on every request.
// app.js
const highcharts = require("highcharts-export-server");
highcharts.initPool();
highcharts.startServer(process.env.PORT || 8012);
Don't forget to point your web.config to app.js.
I found these two resource quite useful during setup:
https://www.galaco.me/node-js-on-windows-server-2012/
https://tomasz.janczuk.org/2011/08/hosting-nodejs-applications-in-iis-on.html

How do I serve static files using Sails.js only in development environment?

On production servers, we use nginx to serve static files for our Sails.js application, however in development environment we want Sails to serve static files for us. This will allow us to skip nginx installation and configuration on dev's machines.
How do I do this?
I'm going to show you how you could solve this using serve-static module for Node.js/Express.
1). First of all install the module for development environment: npm i -D serve-static.
2). Create serve-static directory inside of api/hooks directory.
3). Create the index.js file in the serve-static directory, created earlier.
4). Add the following content to it:
module.exports = function serveStatic (sails) {
let serveStaticHandler;
if ('production' !== sails.config.environment) {
// Only initializing the module in non-production environment.
const serveStatic = require('serve-static');
var staticFilePath = sails.config.appPath + '/.tmp/public';
serveStaticHandler = serveStatic(staticFilePath);
sails.log.info('Serving static files from: «%s»', staticFilePath);
}
// Adding middleware, make sure to enable it in your config.
sails.config.http.middleware.serveStatic = function (req, res, next) {
if (serveStaticHandler) {
serveStaticHandler.apply(serveStaticHandler, arguments);
} else {
next();
}
};
return {};
};
5). Edit config/http.js file and add the previously defined middleware:
module.exports.http = {
middleware: {
order: [
'serveStatic',
// ...
]
}
};
6). Restart/run your application, e.g. node ./app.js and try to fetch one of static files. It should work.

Using grunt server, how can I redirect all requests to root url?

I am building my first Angular.js application and I'm using Yeoman.
Yeoman uses Grunt to allow you to run a node.js connect server with the command 'grunt server'.
I'm running my angular application in html5 mode. According to the angular docs, this requires a modification of the server to redirect all requests to the root of the application (index.html), since angular apps are single page ajax applications.
"Using [html5] mode requires URL rewriting on server side, basically you have to rewrite all your links to entry point of your application (e.g. index.html)"
The problem that I'm trying to solve is detailed in this question.
How can I modify my grunt server to redirect all page requests to the index.html page?
First, using your command line, navigate to your directory with your gruntfile.
Type this in the CLI:
npm install --save-dev connect-modrewrite
At the top of your grunt file put this:
var modRewrite = require('connect-modrewrite');
Now the next part, you only want to add modRewrite into your connect:
modRewrite(['!\\.html|\\.js|\\.svg|\\.css|\\.png$ /index.html [L]']),
Here is a example of what my "connect" looks like inside my Gruntfile.js. You don't need to worry about my lrSnippet and my ssIncludes. The main thing you need is to just get the modRewrite in.
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: '0.0.0.0',
},
livereload: {
options: {
middleware: function (connect) {
return [
modRewrite(['!\\.html|\\.js|\\.svg|\\.css|\\.png$ /index.html [L]']),
lrSnippet,
ssInclude(yeomanConfig.app),
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app)
];
}
}
},
test: {
options: {
middleware: function (connect) {
return [
mountFolder(connect, '.tmp'),
mountFolder(connect, 'test')
];
}
}
},
dist: {
options: {
middleware: function (connect) {
return [
mountFolder(connect, yeomanConfig.dist)
];
}
}
}
},
FYI Yeoman/Grunt recently changed the default template for new Gruntfiles.
Copying the default middlewares logic worked for me:
middleware: function (connect, options) {
var middlewares = [];
var directory = options.directory || options.base[options.base.length - 1];
// enable Angular's HTML5 mode
middlewares.push(modRewrite(['!\\.html|\\.js|\\.svg|\\.css|\\.png$ /index.html [L]']));
if (!Array.isArray(options.base)) {
options.base = [options.base];
}
options.base.forEach(function(base) {
// Serve static files.
middlewares.push(connect.static(base));
});
// Make directory browse-able.
middlewares.push(connect.directory(directory));
return middlewares;
}
UPDATE: As of grunt-contrib-connect 0.9.0, injecting middlewares into the connect server is much easier:
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
grunt.initConfig({
// The actual grunt server settings
connect: {
livereload: {
options: {
/* Support `$locationProvider.html5Mode(true);`
* Requires grunt 0.9.0 or higher
* Otherwise you will see this error:
* Running "connect:livereload" (connect) task
* Warning: Cannot call method 'push' of undefined Use --force to continue.
*/
middleware: function(connect, options, middlewares) {
var modRewrite = require('connect-modrewrite');
// enable Angular's HTML5 mode
middlewares.unshift(modRewrite(['!\\.html|\\.js|\\.svg|\\.css|\\.png$ /index.html [L]']));
return middlewares;
}
}
}
}
});
}
There is a pull request I sent for this problem: https://github.com/yeoman/generator-angular/pull/132, but you need to apply it manually.
To deeply simplify #Zuriel's answer, here's what I found to work on my behalf.
Install connect-modrewrite: npm install connect-modrewrite --save
Include it in your grunt file: var rewrite = require( "connect-modrewrite" );
Modify your connect options to use the rewrite:
connect: {
options: {
middleware: function ( connect, options, middlewares ) {
var rules = [
"!\\.html|\\.js|\\.css|\\.svg|\\.jp(e?)g|\\.png|\\.gif$ /index.html"
];
middlewares.unshift( rewrite( rules ) );
return middlewares;
}
},
server: {
options: {
port: 9000,
base: "path/to/base"
}
}
}
Simplified this as much as possible. Because you have access to the middlewares provided by connect, it's easy to set the rewrite to the first priority response. I know it's been a while since the question has been asked, but this is one of the top results of google searching regarding the problem.
Idea came from source code: https://github.com/gruntjs/grunt-contrib-connect/blob/master/Gruntfile.js#L126-L139
Rules string from: http://danburzo.ro/grunt/chapters/server/
I tried all of these, but had no luck. I am writing an angular2 app, and the solution came from grunt-connect pushstate.
All I did was:
npm install grunt-connect-pushstate --save
and in the grunt file:
var pushState = require('grunt-connect-pushstate/lib/utils').pushState;
middleware: function (connect, options) {
return [
// Rewrite requests to root so they may be handled by router
pushState(),
// Serve static files
connect.static(options.base)
];
}
and it all worked like magic.
https://www.npmjs.com/package/grunt-connect-pushstate

Node.js quick file server (static files over HTTP)

Is there Node.js ready-to-use tool (installed with npm), that would help me expose folder content as file server over HTTP.
Example, if I have
D:\Folder\file.zip
D:\Folder\file2.html
D:\Folder\folder\file-in-folder.jpg
Then starting in D:\Folder\ node node-file-server.js
I could access file via
http://hostname/file.zip
http://hostname/file2.html
http://hostname/folder/file-in-folder.jpg
Why is my node static file server dropping requests?
reference some mystical
standard node.js static file server
If there's no such tool, what framework should I use?
Related:
Basic static file server in NodeJS
A good "ready-to-use tool" option could be http-server:
npm install http-server -g
To use it:
cd D:\Folder
http-server
Or, like this:
http-server D:\Folder
Check it out: https://github.com/nodeapps/http-server
If you do not want to use ready tool, you can use the code below, as demonstrated by me at https://developer.mozilla.org/en-US/docs/Node_server_without_framework:
var http = require('http');
var fs = require('fs');
var path = require('path');
http.createServer(function (request, response) {
console.log('request starting...');
var filePath = '.' + request.url;
if (filePath == './')
filePath = './index.html';
var extname = path.extname(filePath);
var contentType = 'text/html';
switch (extname) {
case '.js':
contentType = 'text/javascript';
break;
case '.css':
contentType = 'text/css';
break;
case '.json':
contentType = 'application/json';
break;
case '.png':
contentType = 'image/png';
break;
case '.jpg':
contentType = 'image/jpg';
break;
case '.wav':
contentType = 'audio/wav';
break;
}
fs.readFile(filePath, function(error, content) {
if (error) {
if(error.code == 'ENOENT'){
fs.readFile('./404.html', function(error, content) {
response.writeHead(200, { 'Content-Type': contentType });
response.end(content, 'utf-8');
});
}
else {
response.writeHead(500);
response.end('Sorry, check with the site admin for error: '+error.code+' ..\n');
response.end();
}
}
else {
response.writeHead(200, { 'Content-Type': contentType });
response.end(content, 'utf-8');
}
});
}).listen(8125);
console.log('Server running at http://127.0.0.1:8125/');
UPDATE
If you need to access your server from external demand/file, you need to overcome the CORS, in your node.js file by writing the below, as I mentioned in a previous answer here
// Website you wish to allow to connect
response.setHeader('Access-Control-Allow-Origin', '*');
// Request methods you wish to allow
response.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
response.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
response.setHeader('Access-Control-Allow-Credentials', true);
UPDATE
As Adrian mentioned, in the comments, he wrote an ES6 code with full explanation here, I just re-posting his code below, in case the code gone from the original site for any reason:
const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
const port = process.argv[2] || 9000;
http.createServer(function (req, res) {
console.log(`${req.method} ${req.url}`);
// parse URL
const parsedUrl = url.parse(req.url);
// extract URL path
let pathname = `.${parsedUrl.pathname}`;
// based on the URL path, extract the file extension. e.g. .js, .doc, ...
const ext = path.parse(pathname).ext;
// maps file extension to MIME typere
const map = {
'.ico': 'image/x-icon',
'.html': 'text/html',
'.js': 'text/javascript',
'.json': 'application/json',
'.css': 'text/css',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.wav': 'audio/wav',
'.mp3': 'audio/mpeg',
'.svg': 'image/svg+xml',
'.pdf': 'application/pdf',
'.doc': 'application/msword'
};
fs.exists(pathname, function (exist) {
if(!exist) {
// if the file is not found, return 404
res.statusCode = 404;
res.end(`File ${pathname} not found!`);
return;
}
// if is a directory search for index file matching the extension
if (fs.statSync(pathname).isDirectory()) pathname += '/index' + ext;
// read file from file system
fs.readFile(pathname, function(err, data){
if(err){
res.statusCode = 500;
res.end(`Error getting the file: ${err}.`);
} else {
// if the file is found, set Content-type and send data
res.setHeader('Content-type', map[ext] || 'text/plain' );
res.end(data);
}
});
});
}).listen(parseInt(port));
console.log(`Server listening on port ${port}`);
For people wanting a server runnable from within NodeJS script:
You can use expressjs/serve-static which replaces connect.static (which is no longer available as of connect 3):
myapp.js:
var http = require('http');
var finalhandler = require('finalhandler');
var serveStatic = require('serve-static');
var serve = serveStatic("./");
var server = http.createServer(function(req, res) {
var done = finalhandler(req, res);
serve(req, res, done);
});
server.listen(8000);
and then from command line:
$ npm install finalhandler serve-static
$ node myapp.js
I know it's not Node, but I've used Python's SimpleHTTPServer:
python -m SimpleHTTPServer [port]
It works well and comes with Python.
From npm#5.2.0, npm started installing a new binary alongside the usual npm called npx. So now, one liners to create static http server from current directory:
npx serve
or
npx http-server
connect could be what you're looking for.
Installed easily with:
npm install connect
Then the most basic static file server could be written as:
var connect = require('connect'),
directory = '/path/to/Folder';
connect()
.use(connect.static(directory))
.listen(80);
console.log('Listening on port 80.');
One-line™ Proofs instead of promises
The first is http-server, hs - link
npm i -g http-server // install
hs C:\repos // run with one line?? FTW!!
The second is serve by ZEIT.co - link
npm i -g serve // install
serve C:\repos // run with one line?? FTW!!
Following are available options, if this is what helps you decide.
C:\Users\Qwerty>http-server --help
usage: http-server [path] [options]
options:
-p Port to use [8080]
-a Address to use [0.0.0.0]
-d Show directory listings [true]
-i Display autoIndex [true]
-g --gzip Serve gzip files when possible [false]
-e --ext Default file extension if none supplied [none]
-s --silent Suppress log messages from output
--cors[=headers] Enable CORS via the "Access-Control-Allow-Origin" header
Optionally provide CORS headers list separated by commas
-o [path] Open browser window after starting the server
-c Cache time (max-age) in seconds [3600], e.g. -c10 for 10 seconds.
To disable caching, use -c-1.
-U --utc Use UTC time format in log messages.
-P --proxy Fallback proxy if the request cannot be resolved. e.g.: http://someurl.com
-S --ssl Enable https.
-C --cert Path to ssl cert file (default: cert.pem).
-K --key Path to ssl key file (default: key.pem).
-r --robots Respond to /robots.txt [User-agent: *\nDisallow: /]
-h --help Print this list and exit.
C:\Users\Qwerty>serve --help
Usage: serve.js [options] [command]
Commands:
help Display help
Options:
-a, --auth Serve behind basic auth
-c, --cache Time in milliseconds for caching files in the browser
-n, --clipless Don't copy address to clipboard (disabled by default)
-C, --cors Setup * CORS headers to allow requests from any origin (disabled by default)
-h, --help Output usage information
-i, --ignore Files and directories to ignore
-o, --open Open local address in browser (disabled by default)
-p, --port Port to listen on (defaults to 5000)
-S, --silent Don't log anything to the console
-s, --single Serve single page applications (sets `-c` to 1 day)
-t, --treeless Don't display statics tree (disabled by default)
-u, --unzipped Disable GZIP compression
-v, --version Output the version number
If you need to watch for changes, see hostr, credit Henry Tseng's answer
Install express using npm: https://expressjs.com/en/starter/installing.html
Create a file named server.js at the same level of your index.html with this content:
var express = require('express');
var server = express();
server.use(express.static(__dirname));
server.listen(8080);
This will load your index.html file. If you wish to specify the html file to load, use this syntax:
server.use('/', express.static(__dirname + '/myfile.html'));
If you wish to put it in a different location, set the path on the third line:
server.use('/', express.static(__dirname + '/public'));
CD to the folder containing your file and run node from the console with this command:
node server.js
Browse to localhost:8080
#DEMO/PROTO SERVER ONLY
If that's all you need, try this:
const fs = require('fs'),
http = require('http'),
arg = process.argv.slice(2),
rootdir = arg[0] || process.cwd(),
port = process.env.PORT || 9000,
hostname = process.env.HOST || '127.0.0.1';
//tested on node=v10.19.0
http.createServer(function (req, res) {
try {
// change 'path///to/////dir' -> 'path/to/dir'
req_url = decodeURIComponent(req.url).replace(/\/+/g, '/');
stats = fs.statSync(rootdir + req_url);
if (stats.isFile()) {
buffer = fs.createReadStream(rootdir + req_url);
buffer.on('open', () => buffer.pipe(res));
return;
}
if (stats.isDirectory()) {
//Get list of files and folder in requested directory
lsof = fs.readdirSync(rootdir + req_url, {encoding:'utf8', withFileTypes:false});
// make an html page with the list of files and send to browser
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
res.end(html_page(`http://${hostname}:${port}`, req_url, lsof));
return;
}
} catch (err) {
res.writeHead(404);
res.end(err);
return;
}
}).listen(port, hostname, () => console.log(`Server running at http://${hostname}:${port}`));
function html_page(host, req_url, lsof) {//this is a Function declarations can be called before it is defined
// Add link to root directory and parent directory if not already in root directory
list = req_url == '/' ? [] : [`/`,
`..`];
templete = (host, req_url, file) => {// the above is a Function expressions cannot be called before it is defined
return `${file}`; }
// Add all the links to the files and folder in requested directory
lsof.forEach(file => {
list.push(templete(host, req_url, file));
});
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html" charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Directory of ${req_url}</title>
</head>
<body>
<h2>Directory of ${req_url}</h2>
${list.join('<br/>\n')}
</body>
</html>`
}
In plain node.js:
const http = require('http')
const fs = require('fs')
const path = require('path')
process.on('uncaughtException', err => console.error('uncaughtException', err))
process.on('unhandledRejection', err => console.error('unhandledRejection', err))
const publicFolder = process.argv.length > 2 ? process.argv[2] : '.'
const port = process.argv.length > 3 ? process.argv[3] : 8080
const mediaTypes = {
zip: 'application/zip',
jpg: 'image/jpeg',
html: 'text/html',
/* add more media types */
}
const server = http.createServer(function(request, response) {
console.log(request.method + ' ' + request.url)
const filepath = path.join(publicFolder, request.url)
fs.readFile(filepath, function(err, data) {
if (err) {
response.statusCode = 404
return response.end('File not found or you made an invalid request.')
}
let mediaType = 'text/html'
const ext = path.extname(filepath)
if (ext.length > 0 && mediaTypes.hasOwnProperty(ext.slice(1))) {
mediaType = mediaTypes[ext.slice(1)]
}
response.setHeader('Content-Type', mediaType)
response.end(data)
})
})
server.on('clientError', function onClientError(err, socket) {
console.log('clientError', err)
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
})
server.listen(port, '127.0.0.1', function() {
console.log('👨‍🔧 Development server is online.')
})
This is a simple node.js server that only serves requested files in a certain directory.
Usage:
node server.js folder port
folder may be absolute or relative depending on the server.js location. The default value is . which is the directory you execute node server.js command.
port is 8080 by default but you can specify any port available in your OS.
In your case, I would do:
cd D:\Folder
node server.js
You can browse the files under D:\Folder from a browser by typing http://127.0.0.1:8080/somefolder/somefile.html
There is another static web server that is quite nice: browser-sync.
It can be downloaded using node package manager:
npm install -g browser-sync
After installation, navigate to the project folder in the cmd prompt and just run the following:
browser-sync start --server --port 3001 --files="./*"
It will start catering all the files in the current folder in the browser.
More can be found out from BrowserSync
Thanks.
Here is my one-file/lightweight node.js static file web-server pet project with no-dependency that I believe is a quick and rich tool which its use is as easy as issuing this command on your Linux/Unix/macOS terminal (or termux on Android) when node.js (or nodejs-legacy on Debian/Ubuntu) is installed:
curl pad.js.org | node
(different commands exist for Windows users on the documentation)
It supports different things that I believe can be found useful,
Hierarchical directory index creation/serving
With sort capability on the different criteria
Upload from browser by [multi-file] drag-and-drop and file/text-only copy-paste and system clipboard screen-shot paste on Chrome, Firefox and other browsers may with some limitations (which can be turned off by command line options it provides)
Folder/note-creation/upload button
Serving correct MIMEs for well known file types (with possibility for disabling that)
Possibility of installation as a npm package and local tool or, one-linear installation as a permanent service with Docker
HTTP 206 file serving (multipart file transfer) for faster transfers
Uploads from terminal and browser console (in fact it was originally intended to be a file-system proxy for JS console of browsers on other pages/domains)
CORS download/uploads (which also can be turned off)
Easy HTTPS integration
Lightweight command line options for achieving better secure serving with it:
With my patch on node.js 8, you can have access to the options without first installation: curl pad.js.org | node - -h
Or first install it as a system-global npm package by [sudo] npm install -g pad.js and then use its installed version to have access to its options: pad -h
Or use the provided Docker image which uses relatively secure options by default. [sudo] docker run --restart=always -v /files:/files --name pad.js -d -p 9090:9090 quay.io/ebraminio/pad.js
The features described above are mostly documented on the main page of the tool http://pad.js.org which by some nice trick I used is also the place the tool source itself is also served from!
The tool source is on GitHub which welcomes your feedback, feature requests and ⭐s!
You can use the NPM serve package for this, if you don't need the NodeJS stuff it is a quick and easy to use tool:
1 - Install the package on your PC:
npm install -g serve
2 - Serve your static folder with serve <path> :
d:> serve d:\StaticSite
It will show you which port your static folder is being served, just navigate to the host like:
http://localhost:3000
I haven't had much luck with any of the answers on this page, however, below seemed to do the trick.
Add a server.js file with the following content:
const express = require('express')
const path = require('path')
const port = process.env.PORT || 3000
const app = express()
// serve static assets normally
app.use(express.static(__dirname + '/dist'))
// handle every other route with index.html, which will contain
// a script tag to your application's JavaScript file(s).
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'dist', 'index.html'))
})
app.listen(port)
console.log("server started on port " + port)
Also make sure that you require express. Run yarn add express --save or npm install express --save depending on your setup (I can recommend yarn it's pretty fast).
You may change dist to whatever folder you are serving your content is. For my simple project, I wasn't serving from any folder, so I simply removed the dist filename.
Then you may run node server.js. As I had to upload my project to a Heroku server, I needed to add the following to my package.json file:
"scripts": {
"start": "node server.js"
}
Below worked for me:
Create a file app.js with below contents:
// app.js
var fs = require('fs'),
http = require('http');
http.createServer(function (req, res) {
fs.readFile(__dirname + req.url, function (err,data) {
if (err) {
res.writeHead(404);
res.end(JSON.stringify(err));
return;
}
res.writeHead(200);
res.end(data);
});
}).listen(8080);
Create a file index.html with below contents:
Hi
Start a command line:
cmd
Run below in cmd:
node app.js
Goto below URL, in chrome:
http://localhost:8080/index.html
That's all. Hope that helps.
Source: https://nodejs.org/en/knowledge/HTTP/servers/how-to-serve-static-files/
If you use the Express framework, this functionality comes ready to go.
To setup a simple file serving app just do this:
mkdir yourapp
cd yourapp
npm install express
node_modules/express/bin/express
Searching in NPM registry https://npmjs.org/search?q=server, I have found static-server https://github.com/maelstrom/static-server
Ever needed to send a colleague a file, but can't be bothered emailing
the 100MB beast? Wanted to run a simple example JavaScript
application, but had problems with running it through the file:///
protocol? Wanted to share your media directory at a LAN without
setting up Samba, or FTP, or anything else requiring you to edit
configuration files? Then this file server will make your life that
little bit easier.
To install the simple static stuff server, use npm:
npm install -g static-server
Then to serve a file or a directory, simply run
$ serve path/to/stuff
Serving path/to/stuff on port 8001
That could even list folder content.
Unfortunately, it couldn't serve files :)
You can try serve-me
Using it is so easy:
ServeMe = require('serve-me')();
ServeMe.start(3000);
Thats all.
PD: The folder served by default is "public".
Here's another simple web server.
https://www.npmjs.com/package/hostr
Install
npm install -g hostr
Change working director
cd myprojectfolder/
And start
hostr
For a healthy increase of performance using node to serve static resources, I recommend using Buffet. It works similar to as a web application accelerator also known as a caching HTTP reverse proxy but it just loads the chosen directory into memory.
Buffet takes a fully-bufferred approach -- all files are fully loaded into memory when your app boots, so you will never feel the burn of the filesystem. In practice, this is immensely efficient. So much so that putting Varnish in front of your app might even make it slower! 
We use it on the codePile site and found an increase of ~700requests/sec to >4k requests/sec on a page that downloads 25 resources under a 1k concurrent user connection load.
Example:
var server = require('http').createServer();
var buffet = require('buffet')(root: './file'); 
 
server.on('request', function (req, res) {
  buffet(req, res, function () {
    buffet.notFound(req, res);
  });
});
 
server.listen(3000, function () {
  console.log('test server running on port 3000');
});
Take a look on that link.
You need only to install express module of node js.
var express = require('express');
var app = express();
app.use('/Folder', express.static(__dirname + '/Folder'));
You can access your file like http://hostname/Folder/file.zip
First install node-static server via npm install node-static -g -g is to install it global on your system, then navigate to the directory where your files are located, start the server with static it listens on port 8080, naviaget to the browser and type localhost:8080/yourhtmlfilename.
A simple Static-Server using connect
var connect = require('connect'),
directory = __dirname,
port = 3000;
connect()
.use(connect.logger('dev'))
.use(connect.static(directory))
.listen(port);
console.log('Listening on port ' + port);
See also Using node.js as a simple web server
It isn't on NPM, yet, but I built a simple static server on Express that also allows you to accept form submissions and email them through a transactional email service (Sendgrid for now, Mandrill coming).
https://github.com/jdr0dn3y/nodejs-StatServe
For the benefit of searchers, I liked Jakub g's answer, but wanted a little error handling. Obviously it's best to handle errors properly, but this should help prevent a site stopping if an error occurs. Code below:
var http = require('http');
var express = require('express');
process.on('uncaughtException', function(err) {
console.log(err);
});
var server = express();
server.use(express.static(__dirname));
var port = 10001;
server.listen(port, function() {
console.log('listening on port ' + port);
//var err = new Error('This error won't break the application...')
//throw err
});
For dev work you can use (express 4)
https://github.com/appsmatics/simple-httpserver.git
I use Houston at work and for personal projects, it works well for me.
https://github.com/alejandro/Houston
const http = require('http');
const fs = require('fs');
const url = require('url');
const path = require('path');
let mimeTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript',
'.jpg': 'image/jpeg',
'.png': 'image/png',
'.ico': 'image/x-icon',
'.svg': 'image/svg+xml',
'.eot': 'appliaction/vnd.ms-fontobject',
'.ttf': 'aplication/font-sfnt'
};
http.createServer(function (request, response) {
let pathName = url.parse(request.url).path;
if(pathName === '/'){
pathName = '/index.html';
}
pathName = pathName.substring(1, pathName.length);
let extName = path.extName(pathName);
let staticFiles = `${__dirname}/template/${pathName}`;
if(extName =='.jpg' || extName == '.png' || extName == '.ico' || extName == '.eot' || extName == '.ttf' || extName == '.svg')
{
let file = fr.readFileSync(staticFiles);
res.writeHead(200, {'Content-Type': mimeTypes[extname]});
res.write(file, 'binary');
res.end();
}else {
fs.readFile(staticFiles, 'utf8', function (err, data) {
if(!err){
res.writeHead(200, {'Content-Type': mimeTypes[extname]});
res.end(data);
}else {
res.writeHead(404, {'Content-Type': 'text/html;charset=utf8'});
res.write(`<strong>${staticFiles}</strong>File is not found.`);
}
res.end();
});
}
}).listen(8081);
If you are intrested in ultra-light http server without any prerequisites
you should have a look at: mongoose
You also asked why requests are dropping - not sure what's the specific reason on your case, but in overall you better server static content using dedicated middleware (nginx, S3, CDN) because Node is really not optimized for this networking pattern. See further explanation here (bullet 13):
http://goldbergyoni.com/checklist-best-practice-of-node-js-in-production/

Resources