gulp-livereload with vagrant environment : livereload.js not accessible - javascript

I have a problem using gulp-livereload in my vagrant environment (generated with puphpet).
My computer is a Windows Host, and the VM a Debian.
I use this gulpfile :
var gulp = require('gulp'),
less = require('gulp-less')
lr = require('tiny-lr'),
livereload = require('gulp-livereload'),
server = lr()
;
gulp.task('less', function () {
gulp.src('assets/less/*.less')
.pipe(less())
.pipe(gulp.dest('build/css'))
.pipe(livereload(server))
;
});
gulp.task('watch', function() {
gulp.watch('assets/less/*.less', ['less']);
livereload.listen(35729, function(err){
if(err) return console.log(err);
});
});
gulp.task('default', ['watch', 'less']);
And when Chrome Extension add the magic JS file I obtain this message :
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT http://markup.dev:35729/livereload.js?ext=Chrome&extver=0.0.5
But in my VM, if I run the following command line, I get it
wget http://localhost:35729/livereload.js?ext=Chrome&extver=0.0.5

I don't have enough information to be certain, but I would guess that your problem is you are trying to access the page from the host, but the livereload port isn't forwarded (the VM has it's own IP address and vagrant can be configured to forward certain ports to the host so that they "appear" to be local on the host).
Try adding the following line to your Vagrantfile:
config.vm.network "forwarded_port", guest: 35729, host: 35729
(For documentation see: https://docs.vagrantup.com/v2/networking/forwarded_ports.html)
Alternatively if you are directly hitting the VM (that is you have markup.dev mapped to the guest's IP) it may be worth verifying that there is not a firewall configured on your VM which might block the livereload port from external access.

In my case, the port forwarding worked automagically. However, I had to specify the VM's IP as host:
livereload.listen({
host: '192.168.33.10'
});
Update: Passing null works, too:
livereload.listen({
host: null
});
I guess that the underlying http server behaves differently when passing 'localhost' explicitly.

Related

NodeJS HTTPS server serving over HTTP instead of HTTPS when running inside Docker container

I'm creating a website using NextJS and Docker so that I can easily deploy it. I used npx-create-next-app to initialize it and used this Dockerfile (slightly modified) to containerize it. Since I wanted to use SSL with my server without going through the hassle of setting up a proxy, I followed this article, and setup the custom server.
This worked fine when I ran it outside of a docker container, and performed as expected, serving over HTTPS. However when I containerized it, and tried to open the webpage over HTTPS, I came up with SSL_ERROR_RX_RECORD_TOO_LONG, but I could open the page using just HTTP (which I could not do when running outside of a container). Some googling led me to this question, from which I concluded that when running outside of a docker container, the custom server runs the server over HTTPS, as expected, however when I containerize it, it starts running HTTP, even though no code has been changed.
I'd expect the behavior to be the same when running locally or containerized.
At first I assumed this was due to invalid key and cert values in httpsOptions however I wasn't able to find anything that would make them invalid, and I don't see how that would cause this strange behavior. I tried changing the Docker run environment from node:alpine-16 to just node:latest to see if it had something to do with the parent image, but that was fruitless.
One other minor issue I had is that console.log does not seem to output to the container's log for some reason, I tried googling this but didn't find much of anything pertaining to it. This has made debugging much harder as I can't really output any debug data. The only log I get when running inside of a container is Listening on port 3000 url: http://localhost:3000, which I assume is output by some library/package as it isn't anywhere in my code.
Here is my custom server code in case it would be helpful:
const https = require('https');
const fs = require('fs');
const { parse } = require('url');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const hostname = "127.0.0.1";
const port = process.env.PORT || 3000
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()
const httpsOptions = {
key: fs.readFileSync('./cert/privkey.pem'),
cert: fs.readFileSync('./cert/fullchain.pem')
};
app.prepare().then(() => {
https.createServer(httpsOptions, async (req, res) => { // When running on docker this creates an HTTP server instead of HTTPS
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
await handle(req, res, parsedUrl)
}).listen(port, (err) => {
if(err) throw err
console.log(`Ready on https://localhost:${port}`)
})
})
Link to a reproducible example here.
The thing is, based on your sample repo, that your server.js file that is in the root of your repo gets overwritten in the image because of this line in the Dockerfile:
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
So the actual server.js that is running in the container is the server.js that is created by the yarn build command and it looks like this (you can exec into the container and see it for yourself):
const NextServer = require('next/dist/server/next-server').default
const http = require('http')
const path = require('path')
process.env.NODE_ENV = 'production'
process.chdir(__dirname)
// Make sure commands gracefully respect termination signals (e.g. from Docker)
// Allow the graceful termination to be manually configurable
if (!process.env.NEXT_MANUAL_SIG_HANDLE) {
process.on('SIGTERM', () => process.exit(0))
process.on('SIGINT', () => process.exit(0))
}
let handler
const server = http.createServer(async (req, res) => {
try {
await handler(req, res)
} catch (err) {
console.error(err);
res.statusCode = 500
res.end('internal server error')
}
})
const currentPort = parseInt(process.env.PORT, 10) || 3000
server.listen(currentPort, (err) => {
if (err) {
console.error("Failed to start server", err)
process.exit(1)
}
const nextServer = new NextServer({
hostname: 'localhost',
port: currentPort,
dir: path.join(__dirname),
dev: false,
customServer: false,
conf: {"env":{},"webpack":null,"webpackDevMiddleware":null,"eslint":{"ignoreDuringBuilds":false},"typescript":{"ignoreBuildErrors":false,"tsconfigPath":"tsconfig.json"},"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","configOrigin":"next.config.js","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"target":"server","poweredByHeader":true,"compress":true,"analyticsId":"","images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[16,32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":60,"formats":["image/webp"],"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","remotePatterns":[],"unoptimized":false},"devIndicators":{"buildActivity":true,"buildActivityPosition":"bottom-right"},"onDemandEntries":{"maxInactiveAge":15000,"pagesBufferLength":2},"amp":{"canonicalBase":""},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":{"locales":["en"],"defaultLocale":"en"},"productionBrowserSourceMaps":false,"optimizeFonts":true,"excludeDefaultMomentLocales":true,"serverRuntimeConfig":{},"publicRuntimeConfig":{},"reactStrictMode":true,"httpAgentOptions":{"keepAlive":true},"outputFileTracing":true,"staticPageGenerationTimeout":60,"swcMinify":true,"output":"standalone","experimental":{"middlewarePrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"legacyBrowsers":false,"newNextLinkBehavior":true,"cpus":7,"sharedPool":true,"profiling":false,"isrFlushToDisk":true,"workerThreads":false,"pageEnv":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"swcFileReading":true,"craCompat":false,"esmExternals":true,"appDir":false,"isrMemoryCacheSize":52428800,"fullySpecified":false,"outputFileTracingRoot":"","swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"enableUndici":false,"adjustFontFallbacks":false,"adjustFontFallbacksWithSizeAdjust":false,"trustHostHeader":false},"configFileName":"next.config.js"},
})
handler = nextServer.getRequestHandler()
console.log(
'Listening on port',
currentPort,
'url: http://localhost:' + currentPort
)
})
And as you see it starts a http server not a https. Also this is why the console.log("lksdfjls"); in your own server.js will not get executed.
What I would suggest is to leave node as it is, running on http://localhost:3000 and set up a reverse proxy that would forward incoming requests to this node backend that is accessible only from the reverse proxy. And of course reverse proxy would handle TLS termination. A docker compose setup would be more convenient for this so you could put the reverse proxy container (nginx for example) in the compose project too and map a directory from the docker host where your cert files are stored into the reverse proxy container at runtime - DO NOT BAKE CERTS OR ANY OTHER SECRETS INTO ANY IMAGE, not even if it is an internally used image only because it could leak out accidentally any time.
Also you could just manually run the two container with docker run but compose would make life easier it has a lot of capabilities for example you could scale compose services up and down so your backend service would run not in one but many containers. But if this would be a high load and/or business critical production stuff then you are better off with a better (real) container orchestrator like kubernetes, docker swarm, nomad etc but today as I see it the de facto container orchestrator is kubernetes.

NodeJS , gulp , Error: listen EADDRINUSE :::3000

i am working with NodeJS and i am using gulp.
My foler look like that :
Root
dist
node_modules
src
index.html
gulpfile.js
package.json
My gulpfile is :
"use strict";
var gulp = require('gulp');
var connect = require('gulp-connect'); // runs a local dev server
var open = require('gulp-open'); // open a URL in a web browser
var config ={
port : 3000,
devBaseUrl : 'http://localhost',
paths:{
html:'./src/*.html',
dist:'./dist'
}
}
//Start a local development server
gulp.task = ('connect' , function(){
connect.server({
root:['dist'],
port: config.port,
base: config.devBaseUrl,
});
});
gulp.task('open', ['connect'], function(){
gulp.src('dist/index.html').pipe(open({uri: config.devBaseUrl + ":" + config.port + '/'}))
});
gulp.task('html',function(){
gulp.src(config.paths.html)
.pipe(gulp.dest(config.paths.dist))
.pipe(connect.reload());
});
gulp.task('default', ['html', 'open']);
When i am type 'gulp' in the cmd i get this error :
C:\Users\maor\Documents\NodeProject\2>gulp
[13:18:28] Using gulpfile ~\Documents\NodeProject\2\gulpfile.js
[13:18:28] Server started http://localhost:3000
events.js:160
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE :::3000
at Object.exports._errnoException (util.js:1018:11)
at exports._exceptionWithHostPort (util.js:1041:20)
at Server._listen2 (net.js:1262:14)
at listen (net.js:1298:10)
at Server.listen (net.js:1394:5)
at ConnectApp.server (C:\Users\maor\Documents\NodeProject\2\node_modules\gulp-connect\index.js:57:19)
at new ConnectApp (C:\Users\maor\Documents\NodeProject\2\node_modules\gulp-connect\index.js:37:10)
at Object.server (C:\Users\maor\Documents\NodeProject\2\node_modules\gulp-connect\index.js:170:12)
at Gulp.gulp.task (C:\Users\maor\Documents\NodeProject\2\gulpfile.js:18:10)
at Object.<anonymous> (C:\Users\maor\Documents\NodeProject\2\gulpfile.js:29:6)
I really dont know what the problem is , i already checked and the port : 3000 is free. can you guys help me figure what the problem is ?
Are you running any other applications that might be using port 3000?
It's possible that a previous instance of node may still be running, even if you intended to kill it. Check your processes, I sometimes get this issue and generally use
killall node
to resolve it.
This problem arise, when node process already running on the port.
You can fix it by
pkill node
OR you can use this
killall node
you still see node process with this command: ps aux | grep node.
If you are using windows, then open task manager & in process tab, search node & right click on that process & end process.
Surely it will work.
Or better still you can change the port number to something else like 8000.

http-proxy-middleware does not forward the full path

I am trying to configure BrowserSync to work in server mode and to proxy my API requests to the backend that runs on the same machine on a different port, using http-proxy-middleware. I use Gulp to launch BrowserSync.
BrowserSync runs on port 8081. My backend runs on 8080.
Here is how I create the proxy middleware :
var proxyApi = proxy('/api', {target : 'http://localhost:8080/api', logLevel : 'debug'});
And here is how I run BrowserSync from my Gulp task :
// Init BrowserSync with proxies as middleware and based on the dest dir
browserSync.init({
open: true,
port: config.proxyPort,
server: {
baseDir: config.destDir,
middleware: [proxyApi]
},
browser: "google chrome"
});
The output :
[HPM] Proxy created: /api -> http://localhost:8080/api
Everything looks good.
But When I hit e.g. http://localhost:8081/api/users, the output is :
[HPM] GET /api/users/123 -> http://localhost:8080/api
...And my client gets a 404 error because /api on its own does not match anything on the backend.
From what I understood from the doc and examples, the target should actually be http://localhost:8080/api/users/123
Why is the rest of the path (in this case /users/123) being left out ?
Using the following versions :
"gulp": "3.9.1",
"browser-sync": "2.16.0",
"http-proxy-middleware": "0.17.1",
The prependPath option is true by default. This option is provided by the underlying lib: http-proxy.
prependPath: true/false, Default: true - specify whether you want to
prepend the target's path to the proxy path
There are two ways to fix the issue:
1.) Change your target from 'http://localhost:8080/api' to 'http://localhost:8080'
var proxyApi = proxy('/api', {target: 'http://localhost:8080', logLevel: 'debug'});
2.) Alternatively you can set the option prependPath to false.
var proxyApi = proxy('/api', {target: 'http://localhost:8080/api', prependPath: false, logLevel: 'debug'});

Multiple server instances by using Hapi.js framework

I'm approaching to this framework for node.js for several reasons. Simplicity, great modularity and a fast configuration out of the box. I have soon encountered the concept of Pack which I have never seen during my experience in the learning of express.js framework. From the official guide the following example:
var Good = require('good');
server.pack.register(Good, function (err) {
if (err) {
throw err; // something bad happened loading the plugin
}
server.start(function () {
server.log('info', 'Server running at: ' + server.info.uri);
});
});
They says about Pack:
Packs are a way for hapi to combine multiple servers into a single
unit, and are designed to give a unified interface when working with
plugins.
This concept is weird for me. How many times do we work with different servers in a project? In addition is not clear for me whether I should call pack every time to register a plugins in hapi.
Update: This is pre v8 api code, the way to register a plugin has been changed. (call register directly on the server)
This concept is weird for me. How many times do we work with different servers in a project?
One example is when you have an api and a web server. These are usually developed separately, often in separate repositories. You could then create a third project which combines these plugins:
var Hapi = require('hapi');
var manifest = {
servers: [
{
host: 'localhost',
port: 8000,
options: {
labels: 'api',
cors: true
}
},
{
host: 'localhost',
port: 8001,
options: {
labels: 'web'
}
}
],
plugins: {
'./example-api': [{select: 'api'}],
'./example-web': [{select: 'web'}]
}
};
Hapi.Pack.compose(manifest, function(err, pack) {
pack.start();
});
In addition is not clear for me whether I should call ever time pack to register a plugins in hapi.
Yes, you need to call pack.register() when you want to register a plugin. However you can register more plugins at once:
plugin.register([
require('crumb'),
require('hapi-auth-cookie')
], function (err) {
// Error handling
}
Visit Link: http://cronj.com/blog/hapi-mongoose
Sample Project which can help you Repo Link: https://github.com/gauravgupta90/Hapi-Mongoose-Angular
For hapi version earlier than 8.x
var server = Hapi.createServer(host, port, {
cors: true
});
server.start(function() {
console.log('Server started ', server.info.uri);
});
For hapi new version
var Hapi = require('hapi');
var server = new Hapi.Server();
server.connection({ port: app.config.server.port });
Hapi.Pack() is no longer available in the newest versions of Hapi (8.x). They have pulled the functionality out into a small library called Glue. You can find it here: https://github.com/hapijs/glue. It works exactly how Hapi.Pack() used to.
By default, hapi supports multiple connections and you can customize them individually, like installing plugins only for a selected server (like API only).
You can instantiate and kick off multiple connection like this:
const hapi = require('hapi');
const port = 3000;
const _ = require('lodash');
// Create hapi server instance
const server = new hapi.Server();
// add connection parameters
server.connection({
host: 'localhost',
port: process.env.PORT || port
});
server.connection({
host: 'localhost',
port: process.env.PORT + 1 || port + 1
});
// Start the server
server.start(function () {
// Log to the console the host and port info
_.forEach(server.connections, function(connection) {
console.log('Server started at: ' + connection.info.uri);
});
});
Hope that helps.
If you need more details about that topic, you can find them within this tutorial on how to run separate frontend and backend servers within a single project

Yeoman to use google app engine server

I setup Yeoman 1.0 beta to handle my js/css tasks. Everything works fine that, if I run grunt server, it starts up a static server and connects a browser session to port 9000 (livereload). js/css concat, minification are also working.
Now, is there a way I can make it to connect to a google app engine development server (instead of starting a static server). The server is running at port 8080 on localhost, and I want grunt to reload the webpage upon css/js files under watch. These files would be served by GAE server.
I see a section rolling your own at grunt-contrib-connect documentation, but not sure it means an external server. As far as I see, these are the relavent configuration from Gruntfile.js
connect: {
livereload: {
options: {
port: 8080, //*** was 9001 originally **
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app)
];
}
}
},
When I change the port number to 8080, and try to start, obviously it gives error.
Fatal error: Port 8080 is already in use by another process.
so, I don't want to start a new server, but connect through GAE server already running.
Thanks.
In order to use GAE server instead of nodejs server, we need to do the following.
* Compile your less/coffeescript, concat[, minify], copy your code to the location where the app engine code resides.
* Create a task in grunt.js to spawn a shell command to run app engine.
This is the example, that I used as reference. https://github.com/cowboy/grunt/tree/master/tasks
Following grunt.js file may help!
module.exports = function(grunt) {
grunt.initConfig({
....
});
grunt.registerTask('appengine-update', 'Upload to App Engine.', function() {
var spawn = require('child_process').spawn;
var PIPE = {stdio: 'inherit'};
var done = this.async();
spawn('appcfg.py', ['update', 'build/task-manager-angular'], PIPE).on('exit', function(status) {
done(status === 0);
});
});
grunt.registerTask('clean', 'Clean the whole build directory.', function() {
require('child_process').exec('rm -rdf build', this.async());
});
grunt.registerTask('run', 'Run app server.', function() {
var spawn = require('child_process').spawn;
var PIPE = {stdio: 'inherit'};
var done = this.async();
spawn('dev_appserver.py', ['.'], PIPE).on('exit', function(status) {
done(status === 0);
});
});
});
//....
//Other settings
//....
grunt.loadTasks('tasks');
grunt.loadNpmTasks('grunt-coffeelint');
grunt.registerTask('build', 'coffee less concat');
grunt.registerTask('deploy', 'coffee less concat build appengine-update');
grunt.registerTask('default', 'coffee less');
};
Found this Google App Engine management plugin for Grunt

Categories

Resources