Angular apps break when run in Electron - angularjs

I started building an Electron app and I am encountering some issues when I try to run an angular distribution inside.
For the angular app I'm using yeoman and grunt for building. If I develop the angular app with grunt serve and running it on localhost:9000, the Electron app can pick the application up just fine. However, if I run grunt build and I point the Electron app to the static files I get some angular errors.
[$injector:modulerr] Failed to instantiate module clientApp due to:
Error: [$injector:modulerr] Failed to instantiate module ngResource due to:
Error: [$injector:nomod] Module 'ngResource' 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.
In the electron app Im running a server with express and I also tried to pick run the angular app through express at localhost:8000. That didn't work either. I also tried to run another angular app that it's deployed on my server and working just fin in the browser - didn't work in Electron. Same errors on all the tries.
I also have to mention that in all cases, if I open the angular app in the browser it works fine.
This is the electron code:
app.on('ready', function() {
// Create the browser window.
mainWindow = new BrowserWindow({width: 1024, height: 764, title: "uMaster"});
// and load the index.html of the app.
var url = path.join(__dirname, "dist", "index.html");
url = "file://" + url;
console.log(url);
// mainWindow.loadURL(url); ---- this is not working in Electron
// mainWindow.loadURL("http://localhost:8000"); -- not working when served by express
mainwindow.loadURL("http://localhost:9000"); // working when angular runs with grunt serve
// Emitted when the window is closed.
mainWindow.on('closed', function() {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
/* ----------------------- */
});

Fixed this problem by initialising electron's BrowserWindow with nodeIntegration: false
mainWindow = new BrowserWindow({width: 1024, height: 764, title: "app", webPreferences: {"nodeIntegration":false}});

Your answer is correct. If you want to mantain node integration you can also use this code in your index.html, before loading any other script:
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>

Related

Running two Angular apps simultaneously

I'm working on an application, and want to extend/expand it with another (new) Angular application. The goal is to eventually replace the old one by the new one, but for now, it should just be accessible by going to /v2, and serve as a pilot.
The setup is as follows:
NodeJS backend: port 11020
Angular/AngularJS-hybrid app: port 11000
Angular-app: port 4200 (this is the new application)
I want to be able to access the new application by going to my-app.com/v2.
I have created a proxy.conf.json file for the main application:
{
...
"/v2": {
"target": "http://localhost:4200/",
"secure": false
}
}
I think it works, because when I go to the /v2 route, it indeed forwards me to the new application, and when using 'Inspect Element' I see the new index.html's head, body and page title. Ok, great.
But.. it never loads the application any further, and throws the following error:
app.ts:8 Uncaught ReferenceError: angular is not defined
at app.ts:8
at Object.iN1H (app.ts:39)
at __webpack_require__ (bootstrap:79)
...
The error is thrown both locally using webpack-server, and after building/serving from our server.
The error points to the original (hybrid) application, where angular is used to reference angularjs.
Why is the new application crashing because of references in/to the old application?

Webpack dev server run on different port

So I have IIS serving up my WebApi and AngularJS project on port 80, using a the alias mywebsite.local-dev.com in the hosts file.
I have webpack config setup for bundling, all I want to do now is stick webpack dev server over the top so that when I modify a file it re bundles everything and updates the browser.
I have browser-sync nearly working but require('./somehtmltemplate.html') seems to be causing issues. It's an Angular app so I use require in the ui-router template property. Here is my gulpfile:
var gulp = require('gulp'),
browserSync = require('browser-sync').create(),
watch = require('gulp-watch'),
webpack = require('webpack'),
webpackconfig = require('./webpack.config');
gulp.task("webpack", function(callback) {
// run webpack
webpack(
webpackconfig,
function(err, stats) {
if(err) throw new gutil.PluginError("webpack", err);
callback();
}
);
});
gulp.task('watch', function() {
browserSync.init({
proxy: "mywebsite.local-dev.com"
});
gulp.watch("App/**/*.js", ['webpack']).on('change', browserSync.reload);
gulp.watch("App/**/*.html", ['webpack']).on('change', browserSync.reload);
});
My question is, how do I get either one working.
edit
Because I am using .cshtml I can't use webpack-dev-server. So the question is, how can I get gulp working?
I solved a similar problem by having Browsersync proxy my external server (MAMP in my case, but it shouldn't matter) while using webpack-dev-middleware and webpack-hot-middleware as middleware on the proxy. With that setup, you can have your normal server take care of serving your app, and Browsersync+Webpack will just handle asset bundling & serving, and browser injections & reloads.
Here's a working example if you're interested: github.com/shanecav/webpack-browsersync-proxy

AngularJS better way to read config file?

I built a angularJS app that I wanted dynamically configured, so I created a config.json file with the needed configurations, and decided to load the config file in app.config as such:
angular.module("myapp",[]).config([ my injections] , function(my providers){
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.open("GET","config.json"); //my config file
xhr.send();
xhr.onreadystatechange=function()
{
if (xhr.readyState==4 && xhr.status==200)
{
//config file parsed, set up params
}
}
})
The reason I am doing it this way is because $http is not injected in config state, and I do not want to "configure" the app at a controller level.
The application works fine. it does what I want to do, and everything works great...EXCEPT when it comes to unit testing (with karma + jasmine).
even though in karma.conf i have:
{pattern: 'config.json',served:true,watched:false,included:false}
defined, when I launch karma, I get a cli [WARN] about config.json 404. and my unit tests to see if everything is configured, fails (i.e it didnt read config.json)
Is there a better way to write config files for unit testing?
In our apps we have external file config.js, which contains just ordinary module which provides constants with configuration.
angular.module('myAppPrefixconfig')
.constant('PLAIN_CONSTANT', 'value'),
.constant('APP_CONFIG', {...});
In your app you have dependancy on it, and there is ordinary http request - which can be resolved by your backend with proper configuration.
In Karma tests you can then provide 'testing config' directly in karma.conf.

$httpbackend from ngMockE2E never called

I'm trying to make some backendless e2e tests, so I need to mocks API calls.
Here is what I did:
angular.module('foo.bar.e2eConf', ['foo.bar', 'ngMockE2E']).
run(function($httpBackend) {
$httpBackend.whenGET('/foo/bar').respond({foo:'bar'});
});
Then I configured my conf/karma.e2e.conf like this (pathes are ok):
var basePath = '../';
var files = [
ANGULAR_SCENARIO,
ANGULAR_SCENARIO_ADAPTER,
// bower libs
'components/angular/index.js',
'components/jquery/jquery.js',
'components/angular-resource/index.js',
'components/angular-mocks/index.js',
'components/chai/chai.js',
'test/chai.conf.js',
'src/app/**/*.js',
{pattern:'src/app/**/partials/*.tpl.html', included:false},
'test/e2e/**/*.js'
];
var singleRun = false;
var browsers = ['Chrome'];
var proxies = {'/': 'http://localhost:8000/'};
I can run tests that doesn't involve API calls, but when I run a test that involves it I get a nice Failed to load resource: the server responded with a status of 404 (Not Found) http://localhost:9876/foo/bar
I guess I misconfigured some stuff, but I can't figure out what??
Is there a conflict between the proxy and the mock? i.e. proxying /foo/bar to http://localhost:8000/foo/bar instead of using the mock?
Any idea?
Regards
Xavier
You need to create a version of your app that bootstraps off the foo.bar.e2eConf module, instead of bootstrapping off the foo.bar module.
You'll have to include the javascript files angular-mocks.js and the new module you defined above in your app index page.
You should be able to test this outside Karma by just using this new app and seeing it return data from your mocks.
You probably don't need to add half those files to the Karma configuration. That's just for adding files to the testing scenario.. its going to load your app in an iframe and your app is responsible for loading it's own javascript.
I'm using php to server up either version of the app depending on what URL I use: either the real version that uses the api calls, or the e2e version that uses the mocks.

Using require.js with jasmine to load scripts returning 404

I'm using Backbonejs and am using require.js to load each dependent backbone widget before firing up my app and putting everything in a custom namespace, in this case "Foo". I'd like to have Jasmine load up this loader file and pick up all the dependent javascripts (located in /public/js of my main app), however, I'm getting all 404's as Jasmine doesn't know about the /public/js directory on port 8888. How can I get jasmine to load these javascripts?
Foo = {};
jQuery(function(){
var include = ['/js/widget.js','/js/delta_widget.js','/js/inbox.js','/js/time_widget.js','/js/high_stock_widget.js','/js/daily_summary_widget.js'];
require(include,function(){
$.getScript('/js/app.js');
});
});
For each of the javascripts, I'm getting:
Failed to load resource: the server responded with a status of 404 (Not Found) http://0.0.0.0:8888/js/widget.js
It would seem that your Jasmine loader file / SpecRunner is in a different directory than your require.js loader (main.js by default). You will have to configure require.js to use a different base path by doing the following:
jQuery(function(){
require.config(
{
baseUrl: '/public'
});
var include = ['js/widget.js',
'js/delta_widget.js',
'js/inbox.js',
'js/time_widget.js',
'js/high_stock_widget.js',
'js/daily_summary_widget.js'];
require(include,function()
{
$.getScript('/js/app.js');
});
You have to configure the above "baseUrl" property to point to the proper URL/Path.
For example, if your Jasmine SpecRunner is located in:
base
- main.js
- js
-- widget.js
-- app.js
- Libs
-- Jasmine
--- SpecRunner.html
then you need to configure
baseUrl: "../../"
Hope this helps.

Resources