How to minify famous.angular without DI errors? - javascript

I'm running into some issues with famous-angular when minified.
A couple of the PRs I submitted yesterday were attempts to fix this, but these don't appear to have resolved the issue.
When built without minfication, everything works as expected.
When built with minification, but removing the dependency on 'famous.angular' from my app module,
the app degrades gracefully to angular only, so the layout is borked, but the underlying angular app works as expected, no errors.
When built with minification, and the app module depends on 'famous.angular',
the app does not load at all, with the following error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:modulerr] Failed to instantiate module famous.angular due to:
Error: [$injector:unpr] Unknown provider: t
http://errors.angularjs.org/1.2.23/$injector/u...<omitted>...2)
By employing this method,
I was able to determine which function was not getting minified correctly,
and tripping up Angular'S dependency injection:
function LocationHashbangInHtml5Url(appBase, hashPrefix) { /* ... */ }
This is in the core angular file - angular.js,
and it does indeed minify correctly in other instances.
So I am not sure why when I include 'famous.angular' in my app module,
this introduces the error.
Anyone know whaty is amiss here?
Demo of problem:
git clone git#github.com:bguiz/browserify-gulp-starter.git
cd browserify-gulp-starter
npm install famous
bower install --save angular angular-route famous-angular
# edit gulpoptions.js
# appName: 'app',
# appFolder: './src-famousangular/app/',
gulp serve-dist

I submitted these two PR's to famous-angular previously, thinking that I had caught all of the $inject scenarios:
https://github.com/Famous/famous-angular/pull/191
https://github.com/Famous/famous-angular/pull/190
Turns out that there was a third one that I had missed, and have now submitted a patch for:
https://github.com/Famous/famous-angular/pull/195
In my question above, I said function LocationHashbangInHtml5Url(appBase, hashPrefix) { /* ... */ } in angular/angular.js was the function that was not minifying correctly.
This was incorrect, and the culprit was in fact a provider in famous-angular/src/scripts/directives/fa-input.js.
For the curious, here is the process that I used to figure the above out.
As an added bonus, I happen to have discovered an additional technique to use when debugging dependency injection errors in minified AngularJs apps.
It turns out that the technique that I linked to above ( https://stackoverflow.com/a/25126490/194982 ) does not always work correctly.
What did work in the end, was to traverse up the execution stack, until we get to the invoke() function, as described in that technique. Then, instead of inspecting only fn, look in the Scope Variables tab in the the developer tools, and inspect every scope member which is a function.
This casts a wider net, and results in more things which need to be inspected;
but was necessary in this case, and I suspect might apply in others.

Related

NullInjectorError: No provider for Overlay! NgxToastr

I have been scratching my head for last one day on this. I am using Ngx-Toastr package in my angular application. Below are the points which I think help you understand the problem.
In dev server (ng serve) I didn't get any error there was no Nullinjector problem, then I make a production build using the following command (ng build). Until this point everything works fine. Now I need to optimize the bundle size so I ran this (ng build --prod). Build was successful no error Now it's time to serve the code (I am using Node server to serve this). Here the problem starts -
First it's asking for
'NullInjectorError: No provider for ToastrService'
which is coming from the Ngx-Toastr Package it self and It makes sense so I add that service to the appmodules and also in other Lazy loaded modules in the providers array. So after this the error has gone . But next is what I want to talk about -
Next it is asking for 'NullInjectorError: No provider for Overlay!' So I though there must be this service from the package which needs to be added in the providers array. So I tried to import it from the package it self and to add it in the providers array like below:
import { Overlay } from 'ngx-toastr/overlay/overlay';;
doing so got the below error
Module not found: Error: Can't resolve 'ngx-toastr/overlay/overlay'
Next I tried searching for this problem and found some stackoverflow solutions which suggest to add the following line:
import {OverlayModule} from '#angular/cdk/overlay';
I added this module in the imports array of every modules. Nothing got changed.
Now I have no clue what to import and where to import. And I am also not sure whether I am going right or not or where should I start looking into it. I also doubt that this error is coming from that package or what!! cause It should work without implicitly importing those services.
I run the following command to get the error ahead of production build:
ng serve --prod --optimization=false
Please also mention how to debug the following error, sometime after production build we get error like this which is undoubtly makes no sense:
ERROR Error: "StaticInjectorError[t -> t]:
StaticInjectorError(Platform: core)[t -> t]:
NullInjectorError: No provider for t!"
I hope my explanation makes some sense to you. Thanks for your time and sorry for this long question.
Lastly FYI : I have already removed node-modules and re-installed it.
Make sure you're using a version of ngx-toastr compatible with your version of angular and typescript. https://github.com/scttcper/ngx-toastr#dependencies
ngx-toastr v13 requires angular >= 10

MathJax with WebPack ReferenceError: require is not defined

I would like to put formulas in my webpage, which uses (dotnet Kestrel). I do not want to load javascript libraries from the net, so I am using webpack and npm for my packages.
My problem is, that I find it impossible to load MathJax. I have tried the following:
import 'mathjax-full';
require('mathjax-full'); // << not the error itself
import MathJax from 'mathjax-full';
The most annoying error that I get is this:
ReferenceError: require is not defined
I must do something obviously wrong. The error message comes from the MathJax internals. I have also tried to import requirejs, as some forums mentioned that as some kind of "workaround". The error I get with it is when I run WebPack:
ERROR in ./node_modules/requirejs/bin/r.js 1:0
Module parse failed: Unexpected character '#' (1:0)
Has anybody succeeded with MathJax on WebPack?
I've encountered the same problems as you plus a million more. MathJax is really not WebPack-friendly.
My solution for Angular:
npm install --save mathjax
Extend the "scripts" array of angular.json with:
"node_modules/mathjax/es5/tex-mml-chtml.js"
And now to call MathJax APIs, DO NOT use import of any kind. The mathjax module sets its main to es5/node-main.js, which uses an ugly hack to call require() at runtime, which is the ultimate source of trouble you saw.
Instead, do this:
declare var MathJax;
Now you may complain that this way you have no type information. Well, the fact is that not even mathjax-full has good type information for methods inside this global object: they inject the methods (such as MathJax.typeset()) at runtime and their types are declared using [name: string]: any;.
If your really want type information, you're probably better off declaring it yourself, e.g.:
declare interface MathJaxGlobal {
typeset(elems: HTMLElement[]);
}
declare var MathJax: MathJaxGlobal;

angular-js uglify downloaded modules

So i have an angular application. With this application i have alot of plugins (modules) that i use in my app.
i am trying to minify them which actually works. However after they have been minified (uglifyed) im getting the following error:
failed to instantiate module app due to:
Due to: And then all the modules. (starting by the first loaded then moving on).
Does this mean that i am unable to minify angular modules. (which would basicly mean im stuck with a 1000 line long HTML file).
Explicit dependency injection
app.controller('myController',function(module1,module2){
//...
});
myController.$inject=['module1','module2'];
Inline annotation
app.controller('myController',['module1','module2',function(module1,module2){
//...
});
You're probably doing it wrong. As the AngularJs documentation specifies, when you are going to minify your files, you must specify the dependencies like this:
app.controller('$ctrl', ['dep1', 'dep2', function(dep1, dep2) {
// your code here
}]);
This way, when the files are minified, the dependencies are not modified. See the angularJs tutorial: https://docs.angularjs.org/tutorial/step_05#a-note-on-minification
No, this does not mean you cannot minnify the module files. You can achieve this.
Check to make sure the order in wich they are concatenated/minnified is correct, if for example module x uses something from module y and x is loaded after y, this will show the error.
If the problem is because of the way the modules are declared, you could install grunt-ng-annotate wich will, when run, change all module declarations to the desired format so that you do not receive the mentioned error.
npm install grunt-ng-annotate --save-dev

AngularJs Uncaught Error when deployed

I am seeing this error in AngularJS
Wierdly, it only occurs when I deploy it in Azure Cloud.
In my local instance - it doesn't occur.
Any ideas?
Update: this is the actual website
login using this sample account
sample#test.com / 1Sample
UPDATE! I suspect that this script causes the error
I dont know why the select.js fails to minify
https://github.com/angular-ui/ui-select
I actually installed the ui-select via bower command line - and then just include it manualy in the bundleconfig. Is this the issue here?
UPDATE - I pinpoint the error and seems like the config of the ui-select is the culprit
Any idea on this?
The issue is because it's getting a 404 error for this resource:
http://tradies-prototype.cloudapp.net/bundles/angular-animate.min.js.map
Make sure to include the .map files in your bundle.
EDIT:
As #CaspNZ pointed out in the comments bellow, if you have a look at this:
http://tradies-prototype.cloudapp.net/bundles/angular
you will see that you are getting this error:
/* Minification failed. Returning unminified contents.
(248,386-393): run-time error JS1019: Can't have 'break' outside of loop: break a
*/
Which means that there is something wrong with your ASP.Net MVC Bundling. It could be many things, but make sure that you are aware of this, so that your angularJs code can be minified properly.
EDIT 2
Also, have a look at this: Mvc4 bundling, minification and AngularJS services and this: http://www.codeproject.com/Tips/786205/ASP-NET-MVC-bundling-minification-with-angularjs-a

Requirejs can't compile my dojo-dependent module

UPDATE: I tried Jeff Barczewski's answer below, and though I no longer get the error below for plugins, I am now getting a different error:
Error: TypeError: Cannot read property 'normalize' of undefined
In module tree:
mymodule/core
at Object.<anonymous> (/usr/local/lib/node_modules/requirejs/bin/r.js:1193:35)
UPDATE 2:
Since Jeff is correct that Dojo's plugins are not compatible with RequireJS, I decided to switch to using grunt-dojo instead for building dojo. I still use RequireJS for my own code and simply override the dojo dependencies to be ignored.
Original Post:
I'm trying to use grunt to compile a single JS file to lower the amount of HTTP requests browsers need to make. Since Dojo 1.9 is AMD-compliant, I figured I'd use Grunt's requirejs plugin to optimize my code. However, I am receiving the following error, both when using the Grunt plugin and when using r.js directly:
>> Tracing dependencies for: mymodule/core
>> TypeError: Cannot call method 'createElement' of undefined
>> In module tree:
>> mymodule/core
>> dojo/behavior
>> dojo/query
>> dojo/selector/_loader
{ [Error: TypeError: Cannot call method 'createElement' of undefined
In module tree:
mymodule/core
dojo/behavior
dojo/query
dojo/selector/_loader
at eval (eval at <anonymous> (/Users/EugeneZ/Workspace/presentment/web/js/node_modules/grunt-contrib-requirejs/node_modules/requirejs/bin/r.js:23690:38), <anonymous>:6:24)
]
originalError:
{ [TypeError: Cannot call method 'createElement' of undefined]
moduleTree:
[ 'dojo/selector/_loader',
'dojo/query',
'dojo/behavior',
'mymodule/core' ],
fileName: '/Users/EugeneZ/Workspace/presentment/web/js/dojo_release/dojo/selector/_loader.js' } }
Looking at the code for the _loader Dojo module, it's assuming it's running in a browser and relying on the document global:
var document;
var testDiv = document.createElement("div");
But why does requirejs not allow this? I've searched their documentation and can't find any way to turn this check off. I'm assuming I'm misunderstanding something or doing something wrong, but can't figure it out.
Here is the requirejs-relevant portion of my Gruntfile.js:
requirejs: {
compile: {
options: {
'baseUrl': './',
'paths': {
'dojo': 'dojo_release/dojo',
'dojox': 'dojo_release/dojox',
'dijit': 'dojo_release/dijit',
'mymodule' : 'core/mymodule',
'osi': 'osi',
'demo': 'demo',
'slick': 'core/slick'
},
'name': 'mymodule/core',
'out': './mymodule.js'
}
}
}
Dojo has several plugins that it uses that are not compatible with the r.js builder/optimizer. The best thing to do is to log an issue on https://bugs.dojotoolkit.org to have someone add the necessary plugin hooks so this can be resolved.
An alternative is to switch over to using the dojo builder, but it doesn't appear to create code that requirejs can use, so you would need to use their loader too, not requirejs. (dojo builder uses some proprietary? {cache:...} option for doing its dependencies rather than just inlining defines, so I could not find a way to build and load with requirejs).
Another work around (until dojo fixes the plugins to be compatible) if you want to stay with requirejs (like I did), you can exclude files that use these dojo plugins from the optimization and just have those files loaded separately unoptimized. So most of your files can be optimized except for ones using these plugins. Its not perfect but it gets you closer. Requirejs will simply load most of the files in optimized fashion and then just fetch those excluded ones individually at runtime.
To do this, add to your r.js build.js exclusions for specific files that use plugins which error out. So after running the build and you get that error, add to your paths the file that is using the plugin, ie. the second to last in the stack trace.
So add to your r.js build options
paths: {
'dojo/query': 'empty:', // this will exclude it from the build
Then run your build again and repeat until you have gotten all the other files that error.
When I was trying to build dojo's dgrid, I ended up with the following exclusions:
paths: {
// r.js having issues building these, the plugins are not
// compatible so let them load normally unoptimized
'dgrid/extensions/ColumnHider': 'empty:',
'put-selector/put': 'empty:'
'dojo/i18n': 'empty:',
'dojo/selector/_loader': 'empty:',
'dojo/query': 'empty:',
'dgrid/extensions/ColumnResizer': 'empty:',
'dgrid/List': 'empty:',
'xstyle/css': 'empty:'
Your list may vary based on what you are using.
Then just have these files (and their dependencies) available when running and requirejs will load them as it does in development. So at least the majority of your files will be loaded optimized from one file, then these will load after.
Note: Asking dojo to make the plugins r.js builder/optimizer compatible is the ultimate solution so we wouldn't need to do this hack. So even if you use this work around, please add an issue for dojo so this can get resolved once and for all. Mention all of the files that you ended up having to exclude to help the developers know what to fix. Then post a comment here for others to +1.

Categories