I'm trying to add vis.js to a 4-year-old web application.
When I run the application without packaging everything, it works. However, when I package everything with grunt, I get the following error in the browser's console:
Mismatched anonymous define() module
When I comment out the code
require(['vis'], function(vis)) { ... }
The error disappears, but obviously I don't have any access to vis any more.
I seem to be doing everything that is shown in the example , with the exception of using data-main when loading require.js. That's because it is no longer supported by use-min.
I had the same issue with other library (NanoModal). The only solution which worked for me was to exclude that library from packaging using the paths configuration of the r.js optimizer:
paths: {
"nanomodal": "empty:"
}
Related
In my project I have long used require.js together with the pdf.js library. Pdf.js have until recently been putting itself on the global object. I could still use it in my requirejs config by using a shim. The pdfjs library will in turn load another library called pdf.worker. In order to find this module the solution was to add a property to the global PDFJS object called workerSrc and point to the file on disk. This could be done before or after loading the pdfjs library.
The pdfjs library uses the pdf.worker to start a WebWorker and to do so it needs the path to a source file.
When I tried to update the pdfjs library in my project to a new version (1.5.314) the way to load and include the library have changed to use UMD modules and now everything get's a bit tricky.
The pdfjs library checks if the environment is using requirejs and so it defines itself as a module named "pdfjs-dist/build/pdf". When this module loads it checks for a module named "pdfjs-dist/build/pdf.worker". Since I have another folder structure I have added them to my requirejs config object with a new path:
paths: {
"pdfjs-dist/build/pdf": "vendor/pdfjs/build/pdf",
"pdfjs-dist/build/pdf.worker": "vendor/pdfjs/build/pdf.worker"
}
This is to make the module loader to find the modules at all. In development this works great. When I try to use the requirejs optimizer in my grunt build step however, it will put all of my project files into one single file. This step will try to include the pdf.worker module as well and this generates an error:
Error: Cannot uglify2 file: vendor/pdfjs/build/pdf.worker.js. Skipping
it. Error is: RangeError: Maximum call stack size exceeded
Since the worker source needs to be in a single file on disk I don't want this module to be included.
So I've tried two different config-settings in the requirejs config.
The first attempt was to override the paths property in my grunt build options:
paths: {
"pdfjs-dist/build/pdf.worker": "empty:"
}
The second thing to test is to exclude it from my module:
modules: [{
name: "core/app",
exclude: [
"pdfjs-dist/build/pdf.worker"
]
}]
Both techniques should tell the optimizer not to include the module but both attempts ended up with the same error as before. The requirejs optimizer still tries to include the module into the build and the attempt to uglify it ends up with a RangeError.
One could argue that since the uglify step fails it will not be included and I can go about my bussiness, but if the uglify step should happen to start working at a new update of pdfjs - what then?
Can anyone help me figure out why the requirejs config won't just exclude it in the build step and how to make it do so.
I found out what the core of my problem was and now I have a way to solve the problem and make my build process to work. My build step in grunt is using grunt-contrib-requirejs and I needed to override some options in the config for this job.
I didn't want the pdf.worker module to be included in my concatenated and minified production code.
I didn't want r.js to minify it only to later exclude it from the concatenated file.
I tried to solve the first problem thinking that it would mean that the second problem also should be solved. When I figured out the two were separate I finally found a solution.
In the r.js example on github there is a property named fileExclusionRegExp. This is what I now use to tell r.js not to copy the file over to the build folder.
fileExclusionRegExp: /pdf.worker.js/
Second, I need to tell the optimizer to not include this module in the concatenated file. This is done by overriding the paths property for this module to the value of "empty:".
paths: {
"pdfjs-dist/build/pdf.worker": "empty:"
}
Now my grunt build step will work without errors and all is well.
Thanks to async5 for informing me about the bug with uglify and the pdf.worker. The workaround is applied in another grunt task that uglify the worker and copies it into the build-folder separately. The options object for the grunt-contrib-uglify task will need this property in order to not break the pdf.worker file:
compress: {
sequences: false
}
Now my project works great when built for production.
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
In my Angular JS app, I'm using a lot of third party packages, mainly maintained via Bower.
When I use Grunt to concatenate all of them into one mega file, I'm getting errors when I load my page, for example that
Uncaught ReferenceError: angular is not defined and
GET http://localhost:8080/theproj/v4/dist/app/bootstrap.css.map 404 (Not Found)
What is the best way to properly concatenate all these files to ensure that everything loads in the right order and doesn't cause problems?
First issue: A lot of times third party libraries must be loaded in a particular order. That looks like like it's the source of your first issue. Something is trying to use angular and it's getting loaded before the angular code. You should refactor your grunt task to use a pre-defined order for third party libraries.
Second issue: You probably are missing the .map file. This is a file used by Chrome dev tools to show you the original source for the css (sass or less). Either provide the map file, or delete the reference to it from bootstrap.css. Or just ignore the error, it's only an error when you have chrome dev tools open, and doesn't actually affect your application.
For the issue of the correct order for your javascript files, i had that problem in a larger project where noone really had a clue which was the correct order.
Luckily we found that the Google Closure Compiler does exactly this: https://github.com/google/closure-compiler
You give it all your js files and it analyzes them all and concatenates them in order
$ java -jar compiler.jar --js_output_file=out.js in1.js in2.js in3.js ...
There is even a grunt plugin for the connection: https://github.com/gmarty/grunt-closure-compiler
'closure-compiler': {
frontend: {
closurePath: '/src/to/closure-compiler',
js: 'static/src/frontend.js',
jsOutputFile: 'static/js/frontend.min.js',
maxBuffer: 500,
options: {
compilation_level: 'ADVANCED_OPTIMIZATIONS',
language_in: 'ECMASCRIPT5_STRICT'
}
}
},
Another way would be to change your javascripts into AMD or CommonJS modules, this way you don't have to worry about the correct order. RequireJS (http://requirejs.org/docs/start.html) is a possibility for AMD for example or Webpack (http://webpack.github.io/) ...or many many others.
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.
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.