I keep getting an error "Identifier 'browserSync' has already been declared" but i cant see where the problem is.Here is my code
// Watch files
function watchFiles() {
gulp.watch("*.js", gulp.series(scriptsLint, scripts, browserSyncReload));
gulp.watch(["processHTML"], gulp.series(browserSyncReload));
}
//Task Live Reload
function browserSync(done) {
browserSync.init({
server: './dist',
port: 8080,
ui: {
port: 8081
}
})
done()
};
// BrowserSync Reload
function browserSyncReload(done) {
browserSync.reload();
done();
}
// define complex tasks
const js = gulp.series(scriptsLint, scripts);
const build = gulp.parallel(processHTML,js);
const watch = gulp.parallel(watchFiles, browserSync);
You need to rename your function browserSync to other name, because that's a keyword reserved for the BrowserSync library.
Something like this:
// Watch files
function watchFiles() {
gulp.watch("*.js", gulp.series(scriptsLint, scripts, reload));
gulp.watch(["processHTML"], gulp.series(reload));
}
//Task Live Reload
function localServer(done) {
browserSync.init({
server: './dist',
port: 8080,
ui: {
port: 8081
}
})
done()
};
// BrowserSync Reload
function reload(done) {
browserSync.reload();
done();
}
// define complex tasks
const js = gulp.series(scriptsLint, scripts);
const build = gulp.parallel(processHTML,js);
const watch = gulp.parallel(watchFiles, localServer);
Your browserSync() function, declared in line 9, is named the same as another variable in its scope, browserSync (in line 10), and needs to be renamed.
// Watch files
function watchFiles() {
gulp.watch("*.js", gulp.series(scriptsLint, scripts, browserSyncReload));
gulp.watch(["processHTML"], gulp.series(browserSyncReload));
}
//Task Live Reload
function browserSyncFunc(done) {
browserSync.init({
server: './dist',
port: 8080,
ui: {
port: 8081
}
})
done()
};
// BrowserSync Reload
function browserSyncReload(done) {
browserSync.reload();
done();
}
// define complex tasks
const js = gulp.series(scriptsLint, scripts);
const build = gulp.parallel(processHTML,js);
const watch = gulp.parallel(watchFiles, browserSyncFunc /* I'm guessing you meant to use the browserSync function here, not the object */);
Related
I have my Node.js project having environment file setup like below
let config = {
apiVersion: "/api/v1",
PORT: 3001,
mongodb: {
url: "mongodb://localhost:27017/BTracker",
},
};
module.exports = { config: config };
As i deploy my application , i need to change mongodb url and port fields as per my Prod URL.
How can i change these variables based on the environment?
Here is snippet of my index.js
let { config } = require("./app/config/appConfig");
app.listen(config.PORT, () => {
mongoose.connect(config.mongodb.url, { useMongoClient: true });
console.log("App is listening on " + config.PORT);
});
First of all create 2 .env file where you store all the configurations and keep it at the level of your index.js and make sure its not added in your git repository, one for the development and another for production.
Sample .env file for development:
#ENVIRONMENT
ENV="DEVELOPMENT"
#URI
MONGO_URI="mongodb://localhost:27017/BTracker"
Then in your index.js load this env file. You can use the dotenv package to do that.
Code to load the env file.
The first line of your index.js should be this:
require('dotenv').config();
Then you can read all the keys from the env file using
const enviromentValue = process.env[KEY_VALUE];
For your code, you can use this:
let urlDB = process.env.MONGO_URI;
This will set the value of urlDB="mongodb://localhost:27017/BTracker". You will need change the .env file according to your setup, whether you are in production or development environment.
Set enviroment variables for configuration
process.env.PORT = process.env.PORT || 3001;
process.env.NODE_ENV = process.env.NODE_ENV || 'dev';
let urlDB;
if (process.env.NODE_ENV === 'dev') {
urlDB = 'mongodb://localhost:27017/BTracker'
} else {
urlDB = process.env.MONGO_URI;
}
process.env.URLDB = urlDB;
and for your index
require('./app/config/appConfig')
mongoose.connect(process.env.URLDB, { useNewUrlParser: true, useCreateIndex: true }, (err, res) => {
console.log(process.env.URLDB);
if (err) throw err;
console.log();
});
app.listen(process.env.PORT, () => {
console.log(App is listening on , process.env.PORT));
})
Everything was working fine before adding webpack. Here's my current config (below). Inside login.js, there's a window.onload function, then shortly after there's a socket.on function, which is now breaking the program. It seems as if "socket" is not globally available to the other files after adding webpack.
Here's the error code I receive in console when running my app:
"login.js:1 Uncaught TypeError: socket.on is not a function at window.onload (login.js:1)"
Any help or insight would be appreciated.
webpack.config
const path = require('path')
module.exports = {
entry: {
scripts: './src/scripts.js',
login: './src/login.js'
},
output: {
path: path.resolve(__dirname, 'public/js'),
filename: '[name].js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}]
},
devServer: {
contentBase: path.resolve(__dirname, 'public'),
publicPath: '/js/'
}
}
Script section of index.html
<script src="./socket.io/socket.io.js"></script>
<script src="./js/scripts.js"></script>
<script src="./js/login.js"></script>
</body>
Worked fine before, so I don't believe there's an issue here:
Server
const http = require('http').Server(app);
const io = require('socket.io')(http);
Client
scripts.js (not in a function, globally declared):
const socket = io();
let socketid;
socket.on('connect', () => socketid = socket.io.engine.id);
login.js (inside window.onload function):
socket.on('check email', () => {
setTimeout(() => refreshPage(), 7500);
popupbox({
titletext: 'Verify email', messagetext: 'A verification link has been sent, please verify your email address within 24 hours.',
okaytext: 'Okay', okayfunction: () => refreshPage(),
customcolor: "#007C5B"
});
});
const socket is local to the module defined by scripts.js and is not a global variable. And as of that it does not exists in login.js.
While it would be possible to make it global, the whole idea of modules and bundlers is to encapsulate your code into small logical parts and that you don't need to pollute the global namespace.
So you need to pass your socket in some way to login.js. How you want to do that depends on the overall structure of the project.
One way could be to export it in your module, and import/require it in your login.js or where ever else you need it.
socket.js
const socket = io();
let socketid;
socket.on('connect', () => socketid = socket.io.engine.id);
module.exports.socket = socket; // export the socket
// could also look that way:
// module.exports = socket;
// the require would then look like that:
// const socket = require('./socket.js');
login.js
const socket = require('./socket.js').socket;
socket.on('check email', () => {
setTimeout(() => refreshPage(), 7500);
popupbox({
titletext: 'Verify email', messagetext: 'A verification link has been sent, please verify your email address within 24 hours.',
okaytext: 'Okay', okayfunction: () => refreshPage(),
customcolor: "#007C5B"
});
});
Also you can use global to declare your variables globaly like
global.io = io();
And the use the io variable in other files like
io.on('connect',...)
Might be it would help someone in future
So basically what I'm trying to do is to make the browser refresh whenever there is a change in the files using browserSync, compiles Pug templates, then Parceljs does the bundling. And Gulp is to watch for changes.
The overall objective is a static website/page.
The problem:
If parcel fails building. browserSync exits. Watch stops.
[12:31:41] 'parcel' errored after 3.83 s
[12:31:41] Error in plugin "gulp-parcel"
[12:31:41] The following tasks did not complete: browserSync
[12:31:41] Did you forget to signal async completion?
OS: Windows 10
Thanks!!
Gulpfile.js content:
"use strict";
var gulp = require('gulp');
var parcel = require('gulp-parcel');
var pug = require('gulp-pug');
var browserSync = require('browser-sync').create();
gulp.task('html', function () {
return gulp.src('src/templates/*.pug')
.pipe(pug())
.pipe(gulp.dest('build/html'))
.pipe(browserSync.reload({
stream: true
}));
});
gulp.task('parcel', function () {
return gulp.src('build/html/*.html', {
read: false
})
.pipe(parcel())
.pipe(browserSync.reload({
stream: true
}));
});
gulp.task('browserSync', function () {
browserSync.init({
server: {
baseDir: 'dist'
},
});
});
gulp.task('watch', gulp.parallel('browserSync',gulp.series('html', 'parcel')), function () {
gulp.watch('src/templates/**/*.pug', gulp.series('html', 'parcel'));
});
gulp.task('default', gulp.series('watch'), function(){
console.log('Started default');
});
After investigating a bit, the gulp-parcel plugin had a bug which is still being worked on. Meanwhile, I was able to come up with a workaround.
Upgraded to es6
Implemented 'gulp-run-command' to run Parcel in watch mode
Here is my new solution:
'use strict';
import gulp from 'gulp';
import babel from 'gulp-babel';
import browserSync from 'browser-sync';
import run from 'gulp-run-command';
import log from 'fancy-log';
import errorHandler from 'gulp-error-handle';
const server = browserSync.create();
const paths = {
parcel: {
dist: 'dist/*'
}
};
gulp.task('parcel', run('parcel watch src/templates/index.pug --public-url ./ --no-cache'));
const reload = done => {
server.reload();
done();
};
const serve = done => {
server.init({
server: {
baseDir: 'dist/'
}
});
done();
};
const watch = done => {
gulp.watch(paths.parcel.dist, gulp.series(reload));
done();
};
const dev = gulp.parallel('parcel', serve, watch);
export default dev;
This is similar to Ensuring Express App is running before each Mocha Test , but the specified solution still isnt working + i'm using a websocket server
in short , i'm using a websocket framework called socketcluster and this is my server file
import {SocketCluster} from 'socketcluster';
const socketCluster = new SocketCluster({
workers:1,
brokers:1,
port: 3000,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
})
export default socketCluster
running node server.js starts the worker process specified in worker.js
export const run = (worker) => {
console.log(' >> worker PID: ',process.pid);
const app = express();
const httpServer = worker.httpServer;
const scServer = worker.scServer;
app.use(cookieParser())
httpServer.on('request', app);
app.get('/',(req,res) => {
console.log('recieved')
res.send('Hello world')
})
}
I want to test the server , but the tests are finishing (and failing) way before the server actually starts. is there a way i can force the server to fully load before going ahead with tests? this is what i have so far
describe('Express server',() =>{
beforeEach((done) => {
require('../../server/server')
done()
})
it('should return "Hello World"',(done) => {
http.get('http://127.0.0.1:3000',(res) => {
expect(res).to.contain('wtf world')
done()
})
})
})
the above doesnt seem to work. the server doesnt fully load in the before block despite providing the done() call as well.
edit - i've tried splitting the server.js file to invoke a different server based on how its imported.
const main = () => {
console.log('main server')
new SocketCluster({
workers:1,
brokers:1,
port: 3000,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
})
}
export const test = (port,done) => {
console.log('testing server')
new SocketCluster({
workers:1,
brokers:1,
port: port,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
})
done()
}
if (require.main === module){
main()
}
and in test.js , i do this - still doesnt seem to work though
import {expect} from 'chai';
import {test} from '../../server/server'
describe('Express server',() =>{
before(function(done){
test(3000,done)
})
it('should return "Hello World"',(done) => {
http.get('http://127.0.0.1:3000',(res) => {
expect(res).to.contain('world')
done()
})
})
})
edit:2 - trie another way by returning a promise from the server.js file. still doesnt work
export const test = (port) => {
console.log('testing server')
return Promise.resolve(new SocketCluster({
workers:1,
brokers:1,
port: port,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
}))
}
and in the before hook
before(function(done,port){
test(3000).then(function(){
console.log('arguments: ',arguments)
done()
})
})
Your server module doesn't have a callback, so it could not be ready when you call done() in your beforeEach method.
First, export your app in your server module.
Then, do something like:
const app = require('../../server/server').app;
let server;
before(done => {
server = app.listen(3000, done);
});
/**
...
your tests here
...
**/
/** and, if you need to close the server after the test **/
after(done => {
server.close(done);
});
This way, done() will be called in the listen callback, so in your tests the server will be listening correctly. Then, remember to close it after tests end (useful if server is required in one or more test suites).
The solution explained here worked for me, in particular:
At the end of server.js ( or app.js ):
app.listen( port, ip, function()
{
console.log( 'Server running on http://%s:%s', ip, port )
app.emit( "app_started" )
})
module.exports = app
and in test.js:
var server = require( '../server' )
before( done =>
{
server.on( "app_started", function()
{
done()
})
})
In this case, app sends an "app_started" event when it is listening, and the test code waits for it. The provided URL contains more details.
Hope it helps !
You need to wait until the server actually listens on the given port.
This could be accomplished by exporting some kind of init function in your server.js, which takes the done callback from mocha.
In your server.js
let initCallback;
[..]
app.listen(port, function() {
if (initCallback) {
initCallback();
}
});
exports = {
init: function(cb) {
initCallback = cb;
}
}
In your test
beforeEach((done) => {
require('../../server/server').init(done)
})
Also see: How to know when node.js express server is up and ready to use
I combined the first two posts and it worked for mine.
First, make sure you have init code in your app.js or server.js
// put this in the beginning of your app.js/server.js
let initCallback;
//put this in the end of your app.js/server.js
if (initCallback) {
// if this file was called with init function then initCallback will be used as call back for listen
app.listen(app.get('port'),"0.0.0.0",(initCallback)=>{
console.log("Server started on port "+app.get('port'));
});
}
else{
// if this file was not called with init function then we dont need call back for listen
app.listen(app.get('port'),"0.0.0.0",()=>{
console.log("Server started on port "+app.get('port'));
});
}
//now export the init function so initCallback can be changed to something else when called "init"
module.exports = {
init: function(cb) {
initCallback = cb;
}
}
Next in your test.js you will need this
//beginning of your code
const app = require("../../server/server").app;
before(done => {
require("../app").init();
done();
});
//end of your code
after(done => {
done();
});
I am no expert in javascript but this works for me. Hope it helps!
I have created a gulpfile.js which works fine so far but as soon I try to add browser-sync and I change my .scss-file I get this error ParseError: unexpected token and I have no clue why this happens. Another thing is, that even though in my server.js I have set app.listen(3000) it opens a window with localhost:3001???
Here is my gulpfile.js:
var gulp = require('gulp'),
connect = require('gulp-connect'),
uglify = require('gulp-uglify'),
sass = require('gulp-ruby-sass'),
webserver = require('gulp-webserver'),
browserify = require('gulp-browserify'),
browserSync = require("browser-sync").create();
gulp.task('browser-sync', function(){
browserSync.init({
server: {
baseDir: "./public"
}
});
})
gulp.task('styles', function() {
return sass('public/scss/*.scss')
.pipe(browserify())
.pipe(uglify())
.pipe(gulp.dest('public/css'));
});
gulp.task('watch', function(){
gulp.watch('public/scss/*.scss', ['styles'])
})
gulp.task('webserver', function() {
gulp.src('root')
.pipe(webserver({
livereload: true,
directoryListing: true,
port: 3000
}));
});
gulp.task('default', ['webserver', 'watch', 'browser-sync'])
So, does anyone know what I'm doing wrong??