Gulp Browsersync + Babel Express server waiting for localhost indefinitely - javascript

I'm running a basic static server with Express in a separate server file.
In my Gulpfile, I use nodemon to run the server file and then pass its address to browsersync to proxy through.
When the browser navigates to the webpage, I am presented with an infinitely loading page which is "Waiting for localhost:3000". The website loads instantly after refreshing the page.
Below are my express server and gulpfile:
// server.js
import express from 'express';
const app = express();
app.use(express.static('build'));
app.listen(4000);
// gulpfile.babel.js
import browser from 'browser-sync';
import gulp from 'gulp';
import plugins from 'gulp-load-plugins';
const $ = plugins();
gulp.task('default',
gulp.series(server, browsersync, watch));
// Start the server with nodemon
function server(done) {
return $.nodemon({
script: 'server.js',
exec: 'babel-node',
})
.on('start', () => {
done();
});
}
// Proxy the server with browsersync
function browsersync(done) {
browser.init({
proxy: 'http://localhost:4000',
});
done();
}
// Watch for file changes
function watch() {
gulp.watch('scripts/**/*.js').on('change', gulp.series(browser.reload));
}

This issue was unfortunately caused by babel-node.

Related

I can’t serve subroutes when I reload the page

It’s the first time I deployed a full-stack app I created on Render and all seems to be working fine except for the fact that my routes are not found when I reload the component. I’ve got a general idea why as I did a research online but I haven’t managed to solve the problem yet.
Here’s my server file
const express = require("express");
const dotenv = require("dotenv");
const connectDB = require("./config/db");
const path = require("path");
const cors = require("cors");
const corsOptions = {
origin: "*",
credentials: true,
optionSuccessStatus: 200,
};
const app = express();
app.use(cors(corsOptions));
// read variables and save them as environment variables
dotenv.config({path: "./.env"});
// Init Middleware
app.use(express.json({extended: false}));
// data from req object is added to it(middleware)
app.use(express.json());
// Define Routes
app.use("/api/data", require("./routes/data"));
app.use("/api", require("./routes/collection"));
app.use(`/api/item`, require("./routes/item"));
app.use(`/api`, require("./routes/under"));
app.use("/api/users", require("./routes/users"));
app.use("/api/auth", require("./routes/auth"));
app.use("/api/email", require("./routes/email"));
app.use("/api/basket", require("./routes/basket"));
app.use("/api/size", require("./routes/size"));
app.use("/api/wishlist", require("./routes/wishlist"));
app.use("/api/checkout", require("./routes/checkout"));
app.use("/api/payment_confirmation", require("./routes/confirmation"));
const PORT = process.env.PORT || 5000;
// Connect to Database
connectDB();
// Load React App in production
if (process.env.MODE === "production") {
app.use(express.static(path.join(__dirname, "build")));
app.get("*", (req, res) => res.sendFile(path.resolve(__dirname, "build", "index.html")));
} else {
app.get("/", (req, res) => {
res.send("Welcome to the home page");
});
}
app.listen(PORT, () => {
console.log(`App running on port ${PORT}`);
});
That's my package.json and my scripts
“scripts”: {
“start”: “node app.js”,
“server”: “nodemon app.js”,
“client”: “npm start --prefix …/client”,
“client:install”: “npm install --prefix client”,
“build”: “npm install --prefix client && npm run build --prefix client”,
"dev": "concurrently \"npm run server\" \"npm run client\""
}
That's my repo if you want to have a look at the file structure.
enter link description here
enter link description here
I get this error on the console
Error: ENOENT: no such file or directory, stat '/opt/render/project/client/build/index.html'
Although on the events log it says that build is successful so I'm not sure what the correct folder would be.
Thanks in advance
When I downloaded the app and ran it on my system reloading the page, it seems like the server cannot find the routes defined in your server file. This is because your server is configured to handle all routes in your React app's index.html file.
your client-side routes will match the routes defined in your React app, and the server will only serve the index.html file for the initial request.
In your server file, modify your app.get("*")method to serve the index.html file only for the initial request:
if (process.env.MODE === "production") {
app.use(express.static(path.join(__dirname, "build")));
app.get("*", (req, res) => {
// Serve index.html for the initial request
if (req.originalUrl === '/') {
res.sendFile(path.resolve(__dirname, "build", "index.html"));
} else {
// Serve static files for all other requests
res.sendFile(path.join(__dirname, "build", req.originalUrl));
}
});
}

Vue Production issue with Express

I'm trying to install SSR on my current Vue app, and for this I'm using the vue-plugin-ssr extension. I want to run it with express, so I created a new file called server.mjs and have this:
import express from "express";
import { createServer as createViteServer } from "vite";
import { renderPage } from "vite-plugin-ssr";
async function createServer() {
const app = express();
// Create Vite server in middleware mode and configure the app type as
// 'custom', disabling Vite's own HTML serving logic so parent server
// can take control
const vite = await createViteServer({
server: { middlewareMode: true },
appType: "custom",
});
// use vite's connect instance as middleware
// if you use your own express router (express.Router()), you should use router.use
app.use(vite.middlewares);
app.get("*", async (req, res) => {
// `renderPage()` can also be used in serverless environments such as
// Cloudflare Workers and Vercel
const { httpResponse } = await renderPage({ url: req.url });
res.send(httpResponse.body);
});
app.listen(3000);
}
createServer();
So this actually works for dev, when I run node server.mjs, but neither client or server folder has an index.html file, so how can I run this on production actually?
Only what I'm doing is to set the folder on nginx to path/dist/client, do I need to do something else?
btw as a response on production I have only 403 forbbiden.
You need to run the client and ssr build process as demonstrated in Vite's documentation and then:
Move the creation and all usage of the vite dev server behind dev-only
conditional branches, then add static file serving middlewares to
serve files from dist/client

How to call function from Nodejs running as windows service

I have created windows service from nodeJs application using node-windows package. Below is my code.
Main.js
var Service = require('node-windows').Service;
// Create a new service object
var svc = new Service({
name:'SNMPCollector',
description: 'SNMP collector',
script: './app.js',
nodeOptions: [
'--harmony',
'--max_old_space_size=4096'
]
//, workingDirectory: '...'
});
// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install',function(){
svc.start();
});
svc.install();
/* svc.uninstall(); */
App.js
const { workerData, parentPort, isMainThread, Worker } = require('worker_threads')
var NodesList = ["xxxxxxx", "xxxxxxx"]
module.exports.run = function (Nodes) {
if (isMainThread) {
while (Nodes.length > 0) {
// my logic
})
}
}
}
Now when I run main.js, it creates a windows service and I can see the service running in services.msc
But, how can I call this run() method which is inside the running service, from any outside application? I couldn't find any solution for this, any help would be great.
You might consider simply importing your run function where you need it and run it there, then there is no need for a windows service or main.js - this assumes that "any outside application" is a Node application.
In your other application you you do the folowing:
const app = require('<path to App.js>');
app.run(someNodes)
For broader usage or if you do need to run it as a service, you could be starting an express (or another webserver) in your App.js with an endpoint that invokes your run function. Then from anywhere else you'll need to make an http call to that endpoint.
App.js
const express = require('express')
const bodyParser = require('body-parser')
const { workerData, parentPort, isMainThread, Worker } = require('worker_threads')
const app = express()
const port = 3000
var NodesList = ["xxxxxxx", "xxxxxxx"]
const run = function (Nodes) {
if (isMainThread) {
while (Nodes.length > 0) {
// my logic
})
}
}
}
app.use(bodyParser.json())
app.post('/', (req, res) => res.send(run(req.body)))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
(Based off of example for express - https://expressjs.com/en/starter/hello-world.html)
You'll need to install both express and body-parser: $ npm install --save express body-parser from the directory of App.js.
From your other applications you will need to call the endpoint http://localhost:3000 with a POST request and the Nodes as a JSON array.
You can expose it on a port like the other answer mentions, though you'll want to make sure you don't expose it more broadly depending on the environment you're running in. There's a good answer here on ensuring the port is locked down.
As an alternative to exposing it on a port you can simply call the function by running the command in any other application:
node -e 'require("/somePathToYourJS/app").run()'
One concern is that app.js will now run at whatever permissions the calling application has. Although that can be resolved by running runas prior. More details here. But an example is:
runas /user:domainname\username "node -e 'require(^"/somePathToYourJS/app^").run()'"

Node.js - Auto Refresh In Dev

I am trying to improve the DEV experience in my Node. To do that, I want to:
a) restart my server when server-side code is changed
b) refresh the browser when client-side code is changes. In an effort to accomplish this, I began integrating nodemon and browserSync into my gulp script.
In my gulp script, I have the following task:
gulp.task('startDevEnv', function(done) {
// Begin watching for server-side file changes
nodemon(
{ script: input.server, ignore:[input.views] })
.on('start', function () {
browserSync.init({
proxy: "http://localhost:3002"
});
})
;
// Begin watching client-side file changes
gulp.watch([ input.css, input.js, input.html ], function() { browserSync.reload(); });
done();
});
When the above task runs, my browser opens to http://localhost:3000/. My app is visible as expected. However, in the console window, I notice:
Error: listen EADDRINUSE :::3002
I understand to some extend. I have app.set('port', process.env.PORT || 3002); in my server.js file. Yet, I thought that was purpose of setting the proxy value. Still, whenever I make a code change, I see the following related error in my console window:
[07:08:19] [nodemon] restarting due to changes...
[07:08:19] [nodemon] starting `node ./dist/server.js`
events.js:142
throw er; // Unhandled 'error' event
^
TypeError: args.cb is not a function
at Object.init (/Users/me/Website/Develop/node_modules/browser-sync/lib/public/init.js:25:25)
at null.<anonymous> (/Users/me/Website/Develop/gulpfile.js:142:25)
at emitNone (events.js:73:20)
at emit (events.js:167:7)
at Object.run (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:97:7)
at Function.run.kill (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:221:7)
at null.<anonymous> (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:333:7)
at emitOne (events.js:83:20)
at emit (events.js:170:7)
at restartBus (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/watch.js:162:7)
Me-MBP:Develop me$ events.js:142
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE :::3002
at Object.exports._errnoException (util.js:856:11)
at exports._exceptionWithHostPort (util.js:879:20)
at Server._listen2 (net.js:1238:14)
at listen (net.js:1274:10)
at Server.listen (net.js:1370:5)
at Object.<anonymous> (/Users/me/Website/Develop/dist/server.js:70:8)
at Module._compile (module.js:399:26)
at Object.Module._extensions..js (module.js:406:10)
at Module.load (module.js:345:32)
at Function.Module._load (module.js:302:12)
At this point, my code changes do not appear in my browser. I do not understand what I'm doing wrong. I suspect I have my ports misconfigured. But, I'm not really sure how they should be setup.
By default BrowserSync uses port 3000. BrowserSync also uses port 3001 for the BrowserSync UI. For these two reasons, I thought I would set the port to 3002 in my server.js file and create the proxy shown above. What am I doing wrong?
You actually don't need to use gulp for this to work.
a) restart my server when server-side code is changed
Install nodemon globally using npm i -g nodemon then on your app folder do nodemon or nodemon ${index-file-of-your-app}.
b) refresh the browser when client-side code is changes.
Use browserify or webpack. I prefer using webpack; you may need to learn about the configuration a little bit but the good thing with webpack is that you don't need to refresh it. Once changes are found the changes will be reflected on the browser automatically. https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack
You can livereload both front and backend changes to the browser by using the 'livereload', 'connect-livereload', and 'nodemon' packages together. Also, this way you don't need Gulp or Grunt. Here's how the packages play together:
livereload opens a high port and notifies the browser of changed public files
connect-livereload monkey patches every served HTML page with a snippet that connects to this high port
nodemon is then used to restart the server on changed backend files
Set up livereload in Express
Set up the Express to both start livereload server watching the public directory and ping the browser during nodemon-induced restart:
const livereload = require("livereload");
const connectLivereload = require("connect-livereload");
// open livereload high port and start to watch public directory for changes
const liveReloadServer = livereload.createServer();
liveReloadServer.watch(path.join(__dirname, 'public'));
// ping browser on Express boot, once browser has reconnected and handshaken
liveReloadServer.server.once("connection", () => {
setTimeout(() => {
liveReloadServer.refresh("/");
}, 100);
});
const app = express();
// monkey patch every served HTML so they know of changes
app.use(connectLivereload());
Start Express with nodemon
Then you'd start the server with nodemon, for example, with a dedicated watch script by running npm run watch.
The key point here is to ignore the public directory that's already being watched by livereload. You can also configure files with non-default extensions, like pug and mustache, to be watched.
"scripts": {
"start": "node ./bin/www",
"watch": "nodemon --ext js,pug --ignore public"
},
You can read a longer explanation in "Refresh front and backend changes to browser with Express, LiveReload and Nodemon."
#mateeyow is right.
But if you want the browser to reload automaticaly, you also need livereload-plugin.
Enable webpack-hot-replacement only replace code in browser's memory, livereload-plugin do reload it.
See rock for example: https://github.com/orange727/rock/blob/master/app/templates/webpack/webpack.make.js#L255
Just as:
webpackConfig.plugins: [
new webpack.HotModuleReplacementPlugin(),
new LiveReloadPlugin({
appendScriptTag: true,
port: config.ports.livereload,
})];
I might be missing some context (e.g. I'm not sure what input represents), however, I think the npm module reload might solve your problem. Here's an example from the npm package page:
var express = require('express')
, http = require('http')
, path = require('path')
, reload = require('reload')
, bodyParser = require('body-parser')
, logger = require('morgan')
var app = express()
var publicDir = path.join(__dirname, '')
app.set('port', process.env.PORT || 3000)
app.use(logger('dev'))
app.use(bodyParser.json()) //parses json, multi-part (file), url-encoded
app.get('/', function(req, res) {
res.sendFile(path.join(publicDir, 'index.html'))
})
var server = http.createServer(app)
//reload code here
//optional reload delay and wait argument can be given to reload, refer to [API](https://github.com/jprichardson/reload#api) below
reload(server, app, [reloadDelay], [wait])
server.listen(app.get('port'), function(){
console.log("Web server listening on port " + app.get('port'));
});
The EADDRINUSE error is normally due to a connection already open on the specified port. This is probably due to a previous instance of the connection not being correctly closed when restarting the app.
Take a look at this gist and in particular try something like this in your gulp file:
'use strict';
var gulp = require('gulp');
var browserSync = require('browser-sync');
var nodemon = require('gulp-nodemon');
gulp.task('default', ['browser-sync'], function () {});
gulp.task('browser-sync', ['nodemon'], function() {
browserSync.init(null, {
proxy: "http://localhost:3002"
});
});
gulp.task('nodemon', function (cb) {
var started = false;
return nodemon({
script: 'app.js'
}).on('start', function () {
// to avoid nodemon being started multiple times
if (!started) {
cb();
started = true;
}
});
});

NodeJS: My node files have dependencies on variables in an other file

I am creating an app with nodejs. In the app, I have a app.js script that is the entrypoint that initializes both the app, as an expressjs app, and the http server that I use.
Just to clarify: modules here are not npm modules, they are my own files. I've written the app in modules. They are just seperate script files used by require()-ing them.
This app has several modules that a main module handler initializes. It reads the contents of a folder, which contains my own modules, and then by convention call the .initialize on each module after running a require() call on the filenames without the .js extension.
However, I have 1 module that needs the app variable to create an endpoint, and 1 module that needs the httpServer variable to create a web socket. Both of these are instansiated in app.js.
Seeing as I don't know what kind of modules will be in the folder, I don't really want to send app and httpServer to every module if they are just needed by 1 module each. Something like dependency injection would fit nice, but is that possible without to much overhead?
Right now I just temporarily added app and httpServer to the GLOBAL object.
What I usually do is have app.js export app so that modules elsewhere in my app can require it directly rather than having to deal with passing it around everywhere. I also slightly modify app.js so that it won't "listen" if it is required as a module that way later on if i decide to wrap it with another app, I can with minimal changes. This is not important to your question, I just find it give me more control when unit testing. All you really need from the code below is module.exports = app
'use strict';
var express = require('express'),
app = express(),
config = require('config'),
pkg = require('./package.json');
// trust reverse proxies
app.enable('trust proxy');
app.set('version', pkg.version);
module.exports = app; // <--- *** important ***
if (app.get('env') !== 'production') {
app.set('debug', true);
}
// calling app.boot bootstraps the app
app.boot = function (skipStart) { // skipStart var makes it easy to unit test without actually starting the server
// add middleware
require('./middleware/');
// setup models
app.set('models', require('./models'));
// setup routes
require('./routes/');
// wait for a dbconnection to start listening
app.on('dbopen', function () {
// setup hosting params
if (!skipStart) {
let server = app.listen(config.port, function () {
app.emit('started');
console.log('Web Server listening at: http://%s:%s', server.address().address, server.address().port);
// mail server interceptor for dev
if (app.get('env') !== 'production') {
// Config smtp server for dev
let SMTPServer = require('smtp-server').SMTPServer,
mailServer = new SMTPServer({
secure: false,
disabledCommands: ['STARTTLS'],
onData: function(stream, session, callback){
stream.pipe(process.stdout); // print message to console
stream.on('end', callback);
},
onAuth: function (auth, session, callback) {
callback(null, {user: 1, data: {}});
}
});
// Start smtp server
mailServer.listen(1025, '0.0.0.0');
} else {
// start agenda jobs only on production
require('./jobs.js');
console.log('Agenda Jobs Running.');
}
});
} else {
app.emit('booted');
}
});
};
// If this is the main module, run boot.
if (require.main === module) {
// move all of this to next tick so we can require app.js in other modules safely.
process.nextTick(app.boot);
}
Suppose you want to initialize 2 file from main app.js
app.js
var socketIni = require('./socketini.js');//You have to pass server
var xyz = require('./xyz.js')//you have to pass app
var app = express();
var server=http.createServer(app);
socketIni(server);
xyz(app);
socketini.js
module.exports = function(server){
//your socket initilize goes here
var io = require('socket.io').listen(server);
}
xyz.js
module.exports = function(app){
//you can access app here
}

Categories