Browser reloaded before server with grunt-express-server and grunt-contrib-watch - express

I am trying to use grunt-contrib-watch together with grunt-express-server to reload my express server and the browser page whenever I made changes to the javascript files. The problem I am having is that the page reloads before the server is ready, so I get a "can't establish a connection to the server at localhost:3000."
Here is my Gruntfile.js:
module.exports = function(grunt) {
'use strict';
grunt.initConfig({
express: {
dev: {
options: {
script: 'gui-resources/scripts/js/server.js'
}
}
},
watch: {
express: {
files: ['gui-resources/scripts/js/**/*.js'],
tasks: ['express:dev'],
options: {
livereload: true,
spawn: false
}
}
}
});
// Load all grunt tasks declared in package.json
require('load-grunt-tasks')(grunt);
grunt.registerTask('default', ['express:dev', 'watch'])
};
In my server.js file I start the server with:
var port = 3000;
app.listen(port, function() {
console.log('Listening on port %d', port);
});
I found this similar question, but the solution proposed there doesn't apply on my case, since I am logging some output when the server is started, but the race condition appears anyway.
Update:
If I remove 'spawn: false' from watch:express config, everything works but express logs an error when started:
Error: listen EADDRINUSE
at errnoException (net.js:878:11)
at Server._listen2 (net.js:1016:14)
at listen (net.js:1038:10)
at Server.listen (net.js:1104:5)
at Function.app.listen (/Users/pat/projects/sourcefabric/plugin-liveblog-embed-server/node_modules/express/lib/application.js:533:24)
at /Users/pat/projects/sourcefabric/plugin-liveblog-embed-server/gui-resources/scripts/js/server.js:86:13
at Object.context.execCb (/Users/pat/projects/sourcefabric/plugin-liveblog-embed-server/node_modules/requirejs/bin/r.js:1890:33)
at Object.Module.check (/Users/pat/projects/sourcefabric/plugin-liveblog-embed-server/node_modules/requirejs/bin/r.js:1106:51)
at Object.<anonymous> (/Users/pat/projects/sourcefabric/plugin-liveblog-embed-server/node_modules/requirejs/bin/r.js:1353:34)
at /Users/pat/projects/sourcefabric/plugin-liveblog-embed-server/node_modules/requirejs/bin/r.js:372:23
Strange enough, in spite of the error the server and the page reload correctly.
Here is my code (the real Gruntfile is bigger, but I removed the parts not related to watch or express to make the question more readable).

I think you should be able to use the debounceDelay option with livereload to wait a bit longer until your server is ready:
watch: {
express: {
files: ['gui-resources/scripts/js/**/*.js'],
tasks: ['express:dev'],
options: {
livereload: true,
spawn: false,
debounceDelay: 1000 // in milliseconds
}
}
}

Related

vuejs cross origin blocked

I opened the console on my browser, and I found an error message how to resolve cross on vue js?
I created a file called vue.config.js
and this , but not work
module.exports = {
devServer: {
proxy: 'http://localhost:8080/',
}
}
I run my web on localhost
'http://localhost:8080/'
How to deal with this?
It looks like it has something to do with WebSockets.
Can you try this syntax?
proxy: { '/': { target: 'http://localhost:8080', ws: true }, }
More info here.
Maybe check out this question tho (WebSockets!).

Nuxt static generated page and axios post

I have a Nuxt project. Everything is OK when I generate a static page.
However, I need to send a POST request to the other server.
I tried to use both a proxy in nuxt.config.js and just direct query, but after deploy to the ngnix eventually, nothing works.
Please help.
UPDATE. Steps to reproduce.
Create Nuxt App including axios and proxy
Configure your proxy for other webservice:
proxy: {
'/api': {
target: 'http://example.com:9000',
pathRewrite: {
'^/api': '/',
},
},
changeOrigin: true,
},
call this service somewhere in the code:
const result = await this.$axios.post('/api/email/subscribe', {email: email})
run "yarn dev" and test the service. It works locally properly.
run 'nuxt generate' and deploy the static code hosting service, for example, hosting.com
run your page which calls the above-mentioned service.
As a result, instead of making POST call to the hosting.com/api/email/subscribe, it calls localhost:3000/api/email/subscribe.
Be sure to install the nuxt versions of axios and proxy in your project #nuxt/axios and #nuxtjs/proxy
after that in your nuxt.config.js add axios as module plus this options for axios and proxy:
modules: [
// Doc: https://axios.nuxtjs.org/usage
'#nuxtjs/axios',
//more modules if you need
],
/*
** Axios module configuration
*/
axios: {
proxy: true,
// See https://github.com/nuxt-community/axios-module#options
},
proxy: {
'/api/': {
target: process.env.AXIOS_SERVER, // I use .env files for the variables
pathRewrite: { '^/api/': '' }, //this should be your bug
},
},
now you can use axios in any part of the code like this
const result = await this.$axios.post('/api/email/subscribe', {email: email})
it will internally resolve to AXIOS_SERVER/email/subscribe without cause cors issues.
EXTRA: test enviroments in local using multiples .env files
you can configure .env for dev and .env.prod for production, after that in local you can use yarn build && yarn start for test your app with your production enviroment. You only need add this at the top of your nuxt.config.js file
const fs = require('fs')
const path = require('path')
if (process.env.NODE_ENV === 'production' && fs.existsSync('.env.prod')) {
require('dotenv').config({ path: path.join(__dirname, `.env.prod`) })
} else {
require('dotenv').config()
}
By definition on the Nuxt docs page what nuxt generate does is: Build the application and generate every route as a HTML file (used for static hosting).
Therefore, using proxy is out of question here. Take note that you path is not even being rewritten.
And probably the result you're looking for is not hosting.com/api/email/subscribe (wit /api), but hosting.com/email/subscribe.
Nevertheless, if you use nginx then I don't think you should use Nuxt's proxy option. Nginx is built just for that so point your API calls there and in nginx config file just declare where it should point further.

Vue Cli 3 vue.config.js no autoOpenBrowser option

I created a project using #vue/cli 3 and attempted to add the autoOpenBrowser option and received the following error. So, I gather that this option is no longer available?
ERROR WebpackDevServerOptionsValidationError: Invalid configuration object. webpack-dev-server has been initialised using a configuration object that does not match the API schema.
- configuration has an unknown property 'autoOpenBrowser'. These properties are valid:
object { hot?, hotOnly?, lazy?, bonjour?, host?, allowedHosts?, filename?, publicPath?, port?, socket?, watchOptions?, headers?, logLevel?, clientLogLevel?, overlay?, progress?, key?, cert?, ca?, pfx?, pfxPassphrase?, requestCert?, inline?, disableHostCheck?, public?, https?, contentBase?, watchContentBase?, open?, useLocalIp?, openPage?, features?, compress?, proxy?, historyApiFallback?, staticOptions?, setup?, before?, after?, stats?, reporter?, logTime?, noInfo?, quiet?, serverSideRender?, index?, log?, warn? }
module.exports = {
devServer: {
port: 4020,
autoOpenBrowser: true
}
}
Create vue.config.js file at root level and add your code in this file. Running the command npm run serve will automatically open your application in browser.
module.exports = {
devServer: {
port: 8080,
open: true
}
}
Duh, it was the open option... I was confusing the config/index.js file with webpack.config.js.
module.exports = {
devServer: {
port: 4020,
open: true
}
}

How can I use the grunt-express for express 4.12?

I use the Express 4.12 to build my project and I want to use grunt-express to start my application. I have known that Express 4.12 start the application via node ./bin/www, so I write the Gruntfile.js like this:
express: {
dev: {
options: {
port: 3000,
bases: path.resolve('bin/'),
server: path.resolve('bin/www')
}
}
}
grunt.loadNpmTasks('grunt-express')
grunt.registerTask('default', ['express', 'express-keepalive']);
Unfortunately, when I run grunt, it reports an error:
Fatal error: Server should provide a function called "listen" that acts as http.Server.listen
But I found that in the www file, there is a function "listen":
var server = http.createServer(app)
server.listen(port);
I am confused about this. Could you please teach me write the Gruntfile.js
for the www file?
The grunt-express server option expects to see an express app, which is not what bin/www is. If you look at bin/www, what is it requiring for an express app? Eg, it should be an app.js in your project root, or maybe it would be server/index.js.
Also, your bases probably shouldn't be bin, rather it should be pointing to a public static resources dir, eg /public or if you have a build step that generates minified stuff it might be /dist.
Try this (editing server and bases to match your project):
grunt.initConfig({
express: {
options: {
port: 3000,
hostname: 'localhost'
},
dev: {
options: {
server: path.resolve('./app.js'),
bases: [path.resolve('./public')]
}
}
}
});

Grunt watch: only upload files that have changed

related
I was able to set up a Grunt task to SFTP files up to my dev server using grunt-ssh:
sftp: {
dev: {
files: {
'./': ['**','!{node_modules,artifacts,sql,logs}/**'],
},
options: {
path: '/path/to/project',
privateKey: grunt.file.read(process.env.HOME+'/.ssh/id_rsa'),
host: '111.111.111.111',
port: 22,
username: 'marksthebest',
}
}
},
But this uploads everything when I run it. There are thousands of files. I don't have time to wait for them to upload one-by-one every time I modify a file.
How can I set up a watch to upload only the files I've changed, as soon as I've changed them?
(For the curious, the server is a VM on the local network. It runs on a different OS and the setup is more similar to production than my local machine. Uploads should be lightning quick if I can get this working correctly)
What you need is grunt-newer, a task designed especially to update the configuration of any task depending on what file just changed, then run it. An example configuration could look like the following:
watch: {
all: {
files: ['**','!{node_modules,artifacts,sql,logs}/**'],
tasks: ['newer:sftp:dev']
}
}
You can do that using the watch event of grunt-contrib-watch.
You basically need to handle the watch event, modify the sftp files config to only include the changed files, and then let grunt run the sftp task.
Something like this:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
secret: grunt.file.readJSON('secret.json'),
watch: {
test: {
files: 'files/**/*',
tasks: 'sftp',
options: {
spawn: false
}
}
},
sftp: {
test: {
files: {
"./": "files/**/*"
},
options: {
path: '/path/on/the/server/',
srcBasePath: 'files/',
host: 'hostname.com',
username: '<%= secret.username %>',
password: '<%= secret.password %>',
showProgress: true
}
}
}
}); // end grunt.initConfig
// on watch events configure sftp.test.files to only run on changed file
grunt.event.on('watch', function(action, filepath) {
grunt.config('sftp.test.files', {"./": filepath});
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-ssh');
};
Note the "spawn: false" option, and the way you need to set the config inside the event handler.
Note2: this code will upload one file at a time, there's a more robust method in the same link.
You can achieve that with Grunt:
grunt-contrib-watch
grunt-rsync
First things first: I am using a Docker Container. I also added a public SSH key into my Docker Container. So I am uploading into my "remote" container only the files that have changed in my local environment with this Grunt Task:
'use strict';
module.exports = function(grunt) {
grunt.initConfig({
rsync: {
options: {
args: ['-avz', '--verbose', '--delete'],
exclude: ['.git*', 'cache', 'log'],
recursive: true
},
development: {
options: {
src: './',
dest: '/var/www/development',
host: 'root#www.localhost.com',
port: 2222
}
}
},
sshexec: {
development: {
command: 'chown -R www-data:www-data /var/www/development',
options: {
host: 'www.localhost.com',
username: 'root',
port: 2222,
privateKey: grunt.file.read("/Users/YOUR_USER/.ssh/id_containers_rsa")
}
}
},
watch: {
development: {
files: [
'node_modules',
'package.json',
'Gruntfile.js',
'.gitignore',
'.htaccess',
'README.md',
'config/*',
'modules/*',
'themes/*',
'!cache/*',
'!log/*'
],
tasks: ['rsync:development', 'sshexec:development']
}
},
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-rsync');
grunt.loadNpmTasks('grunt-ssh');
grunt.registerTask('default', ['watch:development']);
};
Good Luck and Happy Hacking!
I have recently ran into a similar issue where I wanted to only upload files that have changed. I'm only using grunt-exec. Providing you have ssh access to your server, you can do this task with much greater efficiency. I also created an rsync.json that is ignored by git, so collaborators can have their own rsync data.
The benefit is that if anyone makes a change it automatically uploads to their stage.
// Watch - runs tasks when any changes are detected.
watch: {
scripts: {
files: '**/*',
tasks: ['deploy'],
options: {
spawn: false
}
}
}
My deploy task is a registered task that compiles scripts then runs exec:deploy
// Showing exec:deploy task
// Using rsync with ssh keys instead of login/pass
exec: {
deploy: {
cmd: 'rsync public_html/* <%= rsync.options %> <%= rsync.user %>#<%= rsync.host %>:<%=rsync.path %>'
}
You see a lot of the <%= rsync %> stuff? I use that to grab info from rysnc.json which is ingored by git. I only have this because this is a team workflow.
// rsync.json
{
"options": "-rvp --progress -a --delete -e 'ssh -q'",
"user": "mmcfarland",
"host": "example.com",
"path": "~/stage/public_html"
}
Make sure you rsync.json is defined in grunt:
module.exports = function(grunt) {
var rsync = grunt.file.readJSON('path/to/rsync.json');
var pkg = grunt.file.readJSON('path/to/package.json');
grunt.initConfig({
pkg: pkg,
rsync: rsync,
I think it's not good idea to upload everything that changed at once to staging server. And working on the staging server is not a good idea too. You have to configure your local machine server, to be the same as staging/production
It's better to upload 1 time, when you do deployment.
You can archive all the files using grunt-contrib-compress. And push them using grunt-ssh as 1 file, then extract it on the server, that will be much faster.
that's example of compress task:
compress: {
main: {
options:{
archive:'build/build.tar.gz',
mode: 'tgz'
},
files: [
{cwd: 'build/', src: ['sites/all/modules/**'], dest:'./'},
{cwd: 'build/', src: ['sites/all/themes/**'], dest:'./'},
{cwd: 'build/', src: ['sites/default/files/**'], dest:'./'}
]
}
}
PS: Didn't ever look to rsync grunt modules.
I understand that it's might not what you are looking for. But i decided to create my answer as standalone answer.