Reference Socket.io fron Node server in Offline App with Require.js - node.js

I am trying to use Socket.io hosted by a Node server. I am using Require.js to manage dependencies. My webapp is Offline capable.
When the webapp is offline, and cannot contact the node server, require.js throws an error because it cannot find the socket.io dependency.
GET http://mikemac.local:8000/socket.io/socket.io.js  require.js:33
Uncaught Error: Script error
http://requirejs.org/docs/errors.html#scripterror
In this case I am not using node/io for the majority of the system, just 'bonus' real time notifications. So The app should run without it.
How can I deal with this? I would like a way to detect that it cannot be found and then disable the socket.io functionality until a connection/refresh attempt.

In your configuration setup fallback to other module and in the fallback indicate that it is offline:
requirejs.config({
enforceDefine: true,
paths: {
socketio: [
'http://mikemac.local:8000/socket.io/socket.io',
//If the CDN location fails, load from this location
'lib/socketoffline'
]
}
});
//socketoffline
define({ offline: true});
//Later
require(['socketio'], function (socketio) {
if (socketio.offline){
// your library did not load:
} else {
// socketio loaded
}
});

Related

deploy module to remote server that is running node.js

I'm working on my app.js in node.js
-- trying to deploy server-side script.
Many fine node.js modules need a require('something');
I use NPM locally, which works for require, as modules are nicely visible in the local node_modules folder structure. but now I'm ready to upload or bundle to a host. I can't run npm on this hosted server.
const Hapi = require('hapi');
will result in
Error: Cannot find module 'hapi'
because I don't know how to copy/install/bundle/ftp files to my host.
Hapi is just an example. Most anything that has a require will need something on the host.
I used webpack to create a server side bundle.js but just sticking bundle.js under /node_modules doesn't do anything.
Most modules have a complex folder structure underneath --- I'm trying to avoid copying a ton of folders and files under /node_modules. Ideally, I want to combine the modules into a bundle.js and have those modules visible to app.js
but I am open to other ideas.
I have not yet tried using webpack to bundle app.js TOGETHER with the various modules. Have you had luck with that approach?
thanks.
I've tried to upload hapi files a folder-ful at a time, reaching a new require('something') error at every step.
'use strict';
const Hapi = require('hapi'); // <-- how can I deploy hapi on my node.js server?
// Create a server with a host and port
const server=Hapi.server({
host:'localhost',
port:8000
});
// Add the route
server.route({
method:'GET',
path:'/hello',
handler:function(request,h) {
return'hello world';
}
});
// Start the server
async function start() {
try {
await server.start();
}
catch (err) {
console.log(err);
process.exit(1);
}
console.log('Server running at:', server.info.uri);
};
start();
one approach that worked: using webpack to bundle the back end js.
thanks to
https://medium.com/code-oil/webpack-javascript-bundling-for-both-front-end-and-back-
end-b95f1b429810
the aha moment... run webpack to create bundle-back.js then
tie bundle-back.js to my node server
**You start your backend server with ‘bundle-back.js’ using:
node bundle-back.js
In other words, include app.js in the bundle with the modules.

How to setup a proxy using web sockets and angular CLI

I have a simple web app built using the angular CLI. I want it to communicate with a backend using web sockets. I have the backend already written and have tested with a simple index.html page that the server can send and receive on sockets.
In my angular-cli project I have setup a proxy config file to setup a proxy to the backend.
proxy.conf.json
{
"/sock": {
"target": "http://localhost:3000",
"changeOrigin": true,
"ws": true,
"logLevel": "debug"
}
}
Then start the server with the following.
ng serve --proxy-config proxy.conf.json
For now I have a service that simply attempts to open a socket and send a fixed string which I'm expecting to see logged by the backend.
import { Injectable } from '#angular/core';
import * as io from 'socket.io-client';
#Injectable()
export class ChatService {
private socket: any;
constructor() {
this.socket = io({ 'path': '/sock' });
this.socket.emit('chat message', 'Hello World from browser!');
}
}
Note: I've had several go's at this with and without the /sock part of the url.
I start both servers. Get no console errors in the browser. But in the angular CLI web pack server I get the following messages.
10% building modules 2/2 modules 0 active[HPM] Proxy created: /sock -> http://localhost:3000
[HPM] Subscribed to http-proxy events: [ 'error', 'close' ]
[HPM] GET /sockjs-node/530/z1z3teld/websocket -> http://localhost:3000
[HPM] Upgrading to WebSocket
[HPM] Error occurred while trying to proxy request /sockjs-node/530/z1z3teld/websocket from localhost:4200 to http://localhost:3000 (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)
Are web sockets supported or have I made a silly mistake?
Thanks
I managed to figure it out with a bit of trial and error. I looked at the console for the basic index.html page that works within the backend project. This backend project is basically the chat server demo application on the socket.io website. I noticed that when it opens up the web socket the url looks like the following:
http://localhost:3000/socket.io/EIO=3&transport=websocket&sid=wTvdQTclHXJSUmAmAAAA
So back in the angular CLI project I modified my proxy config to include the /socket.io/ part plus also added a wildcard.
{
"/sock/*": {
"target": "http://localhost:3000/socket.io/",
"ws": true,
"logLevel": "debug"
}
}
Bingo! Now when the service is constructed it opens the socket and emits a message which I can see logged in the backend.

Angular / Express hosting

I want to run angular on a linux box without needing node or express. I've created a website but not sure what tech is what, haha. I'm assuming I have a simple web server using express server, see code below.
var express = require ('express');
var app = express();
var path = require('path');
app.use(express.static(__dirname + '/'));
app.listen(8080);
console.log('Magic happens on port 8080');
I start this using the node server command. And the rest of the code is angular-ui.
Do I need to use express (and host this on a node compatible server), or can I just run this thing on a linux box without express? If so, do i need to replace my server.js file (above) with something else? or... Currently it's not working on the linux box, but works locally just fine.
**Edit: I tested an angular 'hello world' app on my shared server, it worked fine. When I run the full angular app on the shared server I get the following error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module routerApp due to:
Error: [$injector:nomod] Module 'routerApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
** edit: In answer to #RobertMoskal 's question below, the angular hello world test that's working on the shared server is basically this:
<input ng-model="name" type="text" placeholder="Type a name here">
<h1>Hello {{ name }}</h1>
And the real app is basically something like this, using ui-view and ng-repeat in the html:
var routerApp = angular.module('routerApp', ['ui.router']);
routerApp.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/home');
$locationProvider.html5Mode(false).hashPrefix("");
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
templateUrl: 'partial-home.html',
// onEnter: scrollContent
})
// ANIMATION AND NESTED VIEWS ========================================
.state('animation', {
url: '/animation',
templateUrl: 'partial-anim.html',
controller: function($scope) {
$scope.animations = [
{ title:'One', url:'http://yahoo.com', bg:'#f8f8f8', width:'160', height:'600', imageAsset:'assets/imgs/web/MyWebsites_1.jpg', paragraph:'some text of some description'},
{ title:'Two', url:'http://google.com', bg:'#f8f8f8', width:'160', height:'600', imageAsset:'assets/imgs/web/MyWebsites_2.jpg', paragraph:'rabbit rabbit rabbit'},
{ title:'Three', url:'http://bambam.com', bg:'#f8f8f8', width:'160', height:'600', imageAsset:'assets/imgs/web/MyWebsites_3.jpg', paragraph:'blahiblahblah'}];
}
})
// GAME VIEWS ========================================
.state('game', {
url: '/game',
templateUrl: 'partial-game.html'
})
// CONTACT VIEWS ========================================
.state('contact', {
url: '/contact',
templateUrl: 'partial-contact.html'
})
});
You need some web server to server your angular app as a "static" asset. This can be apache or nginx or any number of web servers. Most linux distributions make it easy to install them.
You can also go super lightweight with the built in python web server:
cd /var/www/
$ python -m SimpleHTTPServer
You can even host your application for free on github.
In all cases you you just need to make sure that the web server is serving your assets from the correct path. The above python example example you might have your app entry point in /var/www/index.html and it would be served as http://localhost:8000/index.html.

Difficulty using seperate template files in ember router with browserify

I've followed this tutorial http://kroltech.com/2013/12/boilerplate-web-app-using-backbone-js-expressjs-node-js-mongodb/ to set up my backend node.js server, but instead of using backbone-marionette for the frontend I want to try ember. Therefore, having successfully set up the server, I am now going through this tutorial for ember http://emberjs.com/guides/getting-started/.
The problem I'm running into is including external templates into my ember routes. With this code and the todos template written in the browser the app works fine.
var Ember = require('ember');
window.Todos = Ember.Application.create();
Todos.Router.map(function() {
this.resource('todos', { path: '/' });
});
However, with a template written in ./templates/application.hbs and using browserify to try this,
Todos.Router.map(function() {
this.resource(require('./templates/application.hbs'), { path: '/' });
});
I get the errors shown below.
Uncaught TypeError: undefined is not a function myapp.js:46841
Error: Assertion Failed: The URL '/' did not match any routes in your application
at new Error (native)
at Error.Ember.Error (http://localhost:3300/js/myapp.js:12978:19)
at Object.Ember.assert (http://localhost:3300/js/myapp.js:12141:11)
at http://localhost:3300/js/myapp.js:47347:15
at invokeCallback (http://localhost:3300/js/myapp.js:22081:19)
at publish (http://localhost:3300/js/myapp.js:21751:9)
at publishRejection (http://localhost:3300/js/myapp.js:22179:7)
at http://localhost:3300/js/myapp.js:30448:7
at Object.DeferredActionQueues.flush (http://localhost:3300/js/myapp.js:18195:24)
at Object.Backburner.end (http://localhost:3300/js/myapp.js:18283:27) myapp.js:15589
Uncaught Error: Assertion Failed: Error: Assertion Failed: The URL '/' did not match any routes in your application
I was hoping someone could shed some light on how to include external templates in an ember router. Thanks!
Thanks for looking into it! I think I did a poor job explaining my question - I understood that it was the template name but I didn't understand how to include that in my application. I searched around a bit more and found grunt-ember-templates.
For future reference, they have really good docs to get you set up, this is what my emberTemplates code looked like.
emberTemplates: {
compile: {
options: {
templateBasePath: 'client/src/templates'
},
files: {
'build/templates.js': ['client/src/templates/*.hbs']
}
}
},
And then I just added 'application' as my route template name.
Don't forget to compile all of build/ in your app build.

What's the purpose of gruntjs server task?

I'm learning how to propel use gruntjs. I found the server task but I can't get the point.
Can i use the server task mapping concatenated/minified files to test my application (uses backbone.js) without moving or placing source files in web server root? Without apache for example.
If no, what's the supposed use of server task?
The server task is used to start a static server with the base path set as the web root.
Example: Serve ./web-root as http://localhost:8080/:
grunt.initConfig({
server: {
port: 8080,
base: './web-root'
}
});
It will function similar to an Apache server, serving up static files based on their path, but uses the http module via connect to set it up (source).
If you need it to serve more than just static files, then you'll want to consider defining a custom server task:
grunt.registerTask('server', 'Start a custom web server.', function() {
grunt.log.writeln('Starting web server on port 1234.');
require('./server.js').listen(1234);
});
And custom server instance:
// server.js
var http = require('http');
module.exports = http.createServer(function (req, res) {
// ...
});
Can I use the server task mapping concatenated/minified files to test my application [...]
Concatenation and minification have their own dedicated tasks -- concat and min -- but could be used along with a server task to accomplish all 3.
Edit
If you want it to persist the server for a while (as well as grunt), you could define the task as asynchronous (with the server's 'close' event):
grunt.registerTask('server', 'Start a custom web server.', function() {
var done = this.async();
grunt.log.writeln('Starting web server on port 1234.');
require('./server.js').listen(1234).on('close', done);
});
The server task is now the connect task and it's included in the grunt-contrib-connect package.
The connect task starts a connect web server.
Install this plugin with this command:
npm install grunt-contrib-connect --save-dev
Note: --save-dev includes the package in your devDependencies, see https://npmjs.org/doc/install.html
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
grunt.loadNpmTasks('grunt-contrib-connect');
Run this task with the grunt connect command.
Note that this server only runs as long as grunt is running. Once grunt's tasks have completed, the web server stops. This behavior can be changed with the keepalive option, and can be enabled ad-hoc by running the task like grunt connect:targetname:keepalive. targetname is equal to "server" in the code sample below.
In this example, grunt connect (or more verbosely, grunt connect:server) will start a static web server at http://localhost:9001/, with its base path set to the www-root directory relative to the Gruntfile, and any tasks run afterwards will be able to access it.
// Project configuration.
grunt.initConfig({
connect: {
server: {
options: {
port: 9001,
base: 'www-root'
}
}
}
});
The point of the server task is to have quick and dirty access to static files for testing. grunt server IS NOT a production server environment. It really should only be used during the grunt lifecycle to get static testing assets to the testing environment. Use a full-fledged server, possibly controlled by the NPM lifecycle scripts, for production environments.

Resources