Adding Webpack to an existing Angular app - javascript

I'm working on an existing (and working) Angular 1.5.5 app. It's very small and has a controller, a directive and a couple of services, all split into individual files.
I'd now like to move to Webpack and make the minimum number of changes to the app to support that. A lot of the Webpack/Angular demos I've found have been about creating a new Angular app with web pack built in from the start, but I don't want to rebuild the existing app, just make whatever changes are necessary to use a webpack-produced bundle. It's also using regular JS, whereas most of the tutorials I've seen are for ES6.
I've got grunt-webpack installed and working, it's creating the bundle.js file and I can see inside the bundle that it's pulling in Angular, Angular-aria and Angular-animate (my module dependencies)
However, when I run the site I see an error:
Uncaught TypeError: angular.module is not a function
My webpack task is as follows:
module.exports = {
dist: {
entry: './Static/js/Ng/app.js',
output: {
path: './Static/dist/js',
filename: 'bundle.js'
}
}
};
As I say, the actual Webpack bundling seems to be working as expected and creates the bundle.js file.
The main entry file (app.js) is as follows:
(function () {
'use strict';
var angular = require('../vendor/angular.js');
var ngAria = require('../vendor/angular-aria.js');
var ngAnimate = require('../vendor/angular-animate.js');
angular.module('app', [ngAria, ngAnimate]);
}());
If I log out the angular variable in this file, it's just an empty object, even though I can see the Angular source in the bundle.
What am I missing?

You probably shadow the global angular property by your local var angular variable. Try this:
(function () {
'use strict';
require('../vendor/angular.js');
require('../vendor/angular-aria.js');
require('../vendor/angular-animate.js');
angular.module('app', [ngAria, ngAnimate]);
}());

Related

Angular 6 Module - angular not defined

im very new to Angular and i started a test Project with Angular Cli.
All works fine but i have installed a 3.rd Party Module (angular-ui-carousel).
Now i get following error:
Uncaught ReferenceError: angular is not defined
at Module../node_modules/angular-ui-carousel/dist/ui-carousel.js (ui-carousel.js:21)
ui.carousel.js (only the first rows..)
'use strict';
(function (angular) {
// Create all modules and define dependencies to make sure they exist
// and are loaded in the correct order to satisfy dependency injection
// before all nested files are concatenated by Gulp
// Config
angular.module('ui.carousel.config', []).value('ui.carousel.config', {
debug: true
});
// Modules
angular.module('ui.carousel.providers', []);
angular.module('ui.carousel.controllers', []);
angular.module('ui.carousel.directives', []);
angular.module('ui.carousel', ['ui.carousel.config', 'ui.carousel.directives', 'ui.carousel.controllers', 'ui.carousel.providers']);
})(angular); //error points here
'use strict';
is there any workaround to run this module in Angular 6?
You're confusing Angular and AngularJS.
angular. references are applicable to AngularJS(AngularJS 1.x)
And Angular(Angular 2+) don't have angular. references.
angular-ui-carousel is a library for AngularJS and NOT Angular
Please consider using some other library that is meant for Angular, like ng-simple-slideshow

Error while requiring external library with browserify (this = undefined)

I'm trying to require the library Chart.js with Browserify (tbh it's development environment with gulp, browserify and some other stuff that I barely know how it works togheter):
'use strict';
var angular = require('angular');
require('angular-ui-router');
require('./templates');
require('./controllers/_index');
require('./services/_index');
require('./directives/_index');
window.gauge = require('./vendors/gauge');
//this is what i'm trying to require
window.chartjs = require('./vendors/chart');
angular.element(document).ready(function() {
var requires = [
'ui.router',
'templates',
'app.controllers',
'app.services',
'app.directives'
];
window.app = angular.module('app', requires);
angular.module('app').constant('AppSettings', require('./constants'));
angular.module('app').config(require('./routes'));
angular.module('app').config(require('./PostFix'));
angular.module('app').run(require('./on_run'));
angular.bootstrap(document, ['app']);
});
Tbh it did work well with window.gauge = require('./vendors/gauge'); but when I require vendors/chart.js it throws this error:
undefined // chart.js:4
Uncaught TypeError: Cannot read property 'Chart' of undefined // chart.js:4
And here is those lines in the chart.js file:
(function(){
"use strict";
console.log(this); <------ outputs the "undefined"
var root = this,
previous = root.Chart; <----- fails, as "root" doesn't exist
It's weird, because when I add chart.js using <script></script> that console.log(this) outputs the window object/scope, but when executed from browserify, it's undefined, that's why the chart.js fails.
I'm a total newb with browserify/node/gulp, but I tried different stuff such as:
Browserify-shim -> same error
Requiring the script in different ways, like trying to require it inside an object { }, trying to do a var whatever = new require('./vendors/chart') but failed miserably like a beheaded chicken trying to go to the bathroom.
I'm guessing that somehow I have to attach that script to an object or something so this would not be undefined when executed, but I'm failing to find the way.
I already solved it. The problem was a browserify transform called Babelify. I still don't know why Babel was doing that, but I didn't need it anyway so I just disabled it and that was it. Just posting it here in case it happens to someone else.

Loading templates

Good day,
I've tried using both ng-html2js and grunt-html2js to try to load my directive templates as modules when testing but have hit a-bit of a road block on both cases. My questions will revolve around the former as this is what I've attempting to use most.
Correct me if I'm wrong; In order to use ng-html2js you must first register the module from node like so:
npm install karma-ng-html2js-preprocessor -g
This installs it globally which is what I want as I run my karma
tests using the following command which hands over to the global instance of karma installed.:
karma start
Next in the karma.conf.js file you must then specify which templates you
want to use and what dependency it is to be used with:
preprocessors: {
'webapp/scripts/*.js': 'coverage',
'webapp/modules/**/*.js': 'coverage',
'webapp/modules/groupbydrug.html': 'ng-html2js'
},
When it comes to the test, we can load the module doing this:
beforeEach(module('webapp/modules/groupbydrug.html'));
Finally we compile as usual, add the directive to a piece of html and test:
beforeEach(function () {
ele = angular.element('<div group-by-drug=""></div>');
compile(ele)(scope);
scope.$digest();
});
it('should have a table with a class of "drugs-by-mail"', function () {
var div = ele.find('div.outrepeat');
console.log(div);
});
BTW - The template looks like this:
<div ng-repeat="(orderNumber,orderData) in orders" class="drugs-by-mail">
<table class="recent-order-mail">
...
</table>
</div>
Based on what I've read I should beable to retrieve the div from the template but when I try and print it to the console I get an empty object (Object{}) when I'd actually expect to see all the content within that div - is that not correct?
So where along here am I going wrong? Or is this an issue with installation (global karma vs local)
Thanks

How to properly require modules from mocha.opts file

I'm using the expect.js library with my mocha unit tests. Currently, I'm requiring the library on the first line of each file, like this:
var expect = require('expect.js');
describe('something', function () {
it('should pass', function () {
expect(true).to.be(true); // works
});
});
If possible, I'd like to remove the boilerplate require code from the first line of each file, and have my unit tests magically know about expect. I thought I might be able to do this using the mocha.opts file:
--require ./node_modules/expect.js/index.js
But now I get the following error when running my test:
ReferenceError: expect is not defined
This seems to make sense - how can it know that the reference to expect in my tests refers to what is exported by the expect.js library?
The expect library is definitely getting loaded, as if I change the path to something non-existent then mocha says:
"Error: Cannot find module './does-not-exist.js'"
Is there any way to accomplish what I want? I'm running my tests from a gulp task if perhaps that could help.
You are requiring the module properly but as you figured out, the symbols that the module export won't automatically find themselves into the global space. You can remedy this with your own helper module.
Create test/helper.js:
var expect = require("expect.js")
global.expect = expect;
and set your test/mocha.opts to:
--require test/helper
While Louis's answer is spot on, in the end I solved this with a different approach by using karma and the karma-chai plugin:
Install:
npm install karma-chai --save-dev
Configure:
karma.set({
frameworks: ['mocha', 'chai']
// ...
});
Use:
describe('something', function () {
it('should pass', function () {
expect(true).to.be(true); // works
});
});
Thanks to Louis answer and a bit of fiddling around I sorted out my test environment references using mocha.opts. Here is the complete setup.
My project is a legacy JavaScript application with a lot of "plain" js files which I wish to reference both in an html file using script tags and using require for unit testing with mocha.
I am not certain that this is good practice but I am used to Mocha for unit testing in node project and was eager to use the same tool with minimal adaptation.
I found that exporting is easy:
class Foo{...}
class Bar{...}
if (typeof module !== 'undefined') module.exports = { Foo, Bar };
or
class Buzz{...}
if (typeof module !== 'undefined') module.exports = Buzz;
However, trying to use require in all the files was an issue as the browser would complain about variables being already declared even when enclosed in an if block such as:
if (typeof require !== 'undefined') {
var {Foo,Bar} = require('./foobar.js');
}
So I got rid of the require part in the files and set up a mocha.opts file in my test folder with this content. The paths are relative to the root folder:
--require test/mocha.opts.js
mocha.opts.js content. The paths are relative to the location of the file:
global.assert = require('assert');
global.Foo = require("../foobar.js").Foo;
global.Bar = require("../foobar.js").Bar;
global.Buzz = require("../buzz.js");

RequireJS plugin: load timeouts experienced when using plugin

Using RequireJS I'm building an app which make extensive use of widgets. For each widget I have at least 3 separate files:
request.js containing code for setting up request/response handlers to request a widget in another part of my application
controller.js containing handling between model and view
view.js containing handling between user and controller
Module definition in request.js:
define(['common/view/widget/entity/term/list/table/controller'],
function(WidgetController) { ... });
Module definition in controller.js:
define(['common/view/widget/entity/term/list/table/view'],
function(WidgetView) { ... });
Module definition of view.js is:
define(['module','require'],function(module,require) {
'use strict';
var WidgetView = <constructor definition>;
return WidgetView;
});
I have lots of these little situations as above in the case of widgets I have developed. What I dislike is using the full path every time when a module is requiring another module and both are located in the same folder. I'd like to simply specify as follows (assuming we have a RequireJS plugin which solves this for us):
define(['currentfolder!controller'],
function(WidgetController) { ... });
For this, I have written a small plugin, as I couldn't find it on the web:
define({
load: function (name, parentRequire, onload, config) {
var path = parentRequire.toUrl('.').substring(config.baseUrl.length) + '/' + name;
parentRequire([path], function (value) {
onload(value);
});
}
});
As you might notice, in its basic form it looks like the example of the RequireJS plugins documentation.
Now in some cases, the above works fine (e.g. from the request.js to the controller.js), but in other cases a load timeout occurs (from controller.js to view.js). When I look at the paths which are generated, all are proper RequireJS paths. Looking at the load timeouts, the following is logged:
Timestamp: 13-09-13 17:27:10
Error: Error: Load timeout for modules: currentfolder!view_unnormalized2,currentfolder!view
http://requirejs.org/docs/errors.html#timeout
Source File: http://localhost/app/vendor/requirejs/require.js?msv15z
Line: 159
The above log was from a test I did with only loading the view.js from controller.js using currentfolder!view in the list of modules in the define statement. Since I only requested currentfolder!view once, I'm confused as to why I both see currentfolder!view_unnormalized2 and currentfolder!view in the message.
Any idea as to why this might be happening?
My answer may not answer your primary questions, but it will help you achieve what you're trying to do with your plugin.
In fact, Require.js support relative paths for requiring modules when using CommonJS style. Like so:
define(function( require, exports, module ) {
var relativeModule = require("./subfolder/module");
module.exports = function() {
console.log( relativeModule );
};
});

Categories