I am integrating breezeJS into an existing requireJS project which already uses knockoutJS. I ran into a couple of problems.
The first was that breeze is unable to load the Q library unless i include it on my html wrapper as a <script> tag, not as a loaded AMD dependency. In my project i am trying to keep my code down to a single script tag, so this isnt ideal.
The second issue is that breezeJS is unable to load knockout. In my main.js I have defined a path for knockout to be:
knockout: '../libs/knockout/knockout-2.2.0',
(I do this because I like knowing for sure that I am not accessing a global ko)
However when i added breeze to my project, breeze wasn't able to load my knockout library. Looking into the breeze code i can see that it has been hardcoded to load the knockout library as ko.
Not wanting to change all of my code i found that i could add my AMD loaded knockout library to the global window object as window['ko']. But this feels like quite a bodge. Also weirdly adding Q this way and removing the <script> tag didn't work, as i think Q is required too early in the application's lifecycle, even before i get to pollute the global - i did nest my require() calls in main.js but that hid the majority of my application files from the build process so i abandoned that approach.
How can i include Q and knockout and breeze in my project and still use a single line <script> tag, at the moment I am having to include Q as a separate <script> tag and pollute the global to get breeze and knockout to play nicely.
I am using quite a few other libraries in my project and none of them have been this difficult to integrate in.
Any help is much appreciated
Cheers
Gav
EDIT: Here is my full require config:
require.config({
/**
* shims are for 3rd party libraries that have not been written in AMD format.
* shims define AMD modules definitions that get created at runtime.
*/
shim: {
'jqueryUI': { deps: ['jquery'] },
'jqueryAnimateEnhanced': { deps: ['jqueryUI'] },
'jqueryScrollTo': { deps: ['jquery'] },
'touchPunch': { deps: ['jquery'] },
//'Q': { exports: 'Q' },
//'breeze': { deps: ['Q', 'knockout'], exports: 'breeze' },
'path': { exports: 'Path' },
//'signalR': { deps: ['jquery'] },
},
paths: {
//jquery
jquery: '../libs/jquery/jquery-1.7.2.min',
'jquery.adapter': '../libs/jquery/jquery.adapter',
//jquery plugins
horizontalNav: '../libs/jquery/plugins/horizontalNav/jquery.horizontalNav',
jqueryUI: '../libs/jquery/plugins/jquery-ui/jquery-ui-1.9.2.custom',
jqueryAnimateEnhanced: '../libs/jquery/plugins/animate-enhanced/jquery.animate-enhanced',
touchPunch: '../libs/jquery/plugins/touch-punch/jquery.ui.touch-punch.min',
//jqueryScrollTo: '../libs/jquery/plugins/jquery-scrollTo/jquery.scrollTo.min',
//reveal: '../libs/jquery/plugins/reveal/jquery.reveal',
//opentip: '../libs/jquery/plugins/opentip/opentip-jquery',
//RequireJS
domReady: '../libs/require/plugins/domReady',
text: '../libs/require/plugins/text',
async: '../libs/require/plugins/async',
depend: '../libs/require/plugins/depend',
json: '../libs/require/plugins/json',
noext: '../libs/require/plugins/noext',
//coffee-script
'coffee-script': '../libs/coffee/coffee-script',
cs: '../libs/require/plugins/cs',
//Path
path: '../libs/path/path.min',
//Knockout
knockout: '../libs/knockout/knockout-2.2.0',
knockoutTemplateSource: '../libs/knockout/ko.templateSource',
knockoutValidation: '../libs/knockout/ko.validation',
//breeze
Q: '../libs/breeze/q',
breeze: '../libs/breeze/breeze.debug',
//Signals (Observer pattern)
signals: '../libs/signals/signals',
//SignalR - Push notifications
signalR: '../libs/signalR/jquery.signalR-0.5.2.min',
//utils
logger: 'common/logging/logger',
tinycolor: '../libs/tinycolor/tinycolor',
composing: 'common/composition/composing',
//app specific
BaseWidgetViewModel: 'app/view/core/BaseWidgetViewModel',
}
});
Sorry for the (holiday) delay in addressing your question.
I understand and appreciate your goal of eliminating every script tag except the one for RequireJS. This goal is not easily obtained in my experience.
You did uncover a Breeze defect. Breeze internally is referencing a different 'require' function than your application's 'require' function. It doesn't know about the application 'require' function or its configuration. Therefore, when you omit the Q script tag, Breeze cannot find Q ... no matter how well you configure the application 'require'.
We'll have to fix that. I'll add a comment here when we do.
Meanwhile you'll must use a script tag for 'Q' and for 'KO' and you must put those tags above the script tag for RequireJs. Please continue to use require for your application scripts.
Unfortunately, you have other problems that are unrelated to the dual-require-function problem.
First, I think you will always have trouble keeping KO out of the global namespace ... and this has nothing to do with Breeze.
In KO's AMD implementation (at least when I last looked), KO is either in the global namespace or in the require container; never both. Unfortunately, many useful plug-ins (bindingHandlers, debug.helpers) assume it is in the global namespace; you won't be able to use them if you load KO with require.
You can load Knockout in script tags before Require and then shim KO into the Require container during configuration. Your configuration might look like this:
define('knockout', [], function () { return window.ko; });
The jQuery developers realized this would be a problem. Too many good plugins assume jQuery is in the global namespace. Rather than be purists, the jQuery maintainers (correctly in my view) put jQuery in both the Require container and in the global namespace.
Second, many other useful libraries do not support Require. Your code can be written as if these scripts were designed for require. I still think the easiest, clearest way to handle this is specify them in script tags. Then you can add them into the container by defining them with define calls as shown above. With this shimming, your own modules can be consistent in relying on Require for service location and dependency injection of these libraries.
Third, I think you have a bug in your configuration. For reasons that escape me, you decided to refer to the Knockout module as "knockout" in your Require universe.
Fine ... but you shouldn't expect Breeze to anticipate that module name when we fix it to use the application's require container. Breeze will be looking for KnockoutJs under its standard name, "ko". Breeze will not find it under your preferred name, "knockout".
This is not a big deal. If you're wedded to the "knockout" name, you can make the same instance available under both names. I'm pretty sure the following shim line will work when added to your configuration code:
define('ko', ['knockout'], function (ko) { return ko; });
Again ... this will be effective only after we fix our Breeze require bug.
John Papa had to address many similar issues in Code Camper; you might look at what he did there, especially at main.js.
This should be fixed as of Breeze v 1.2.4. We no longer use an internal implementation of "require".
Sounds like your require config is not right. Could you post the code of your require config?
I am curious:
keep my code down to a single script tag
why that?
Edit: Now i get it. Still sounds like the require config is wrong.
Related
I'm trying to use require js and angular js together. Referred to someone guides by googling:
http://marcoslin.github.io/angularAMD/#/home
http://www.sitepoint.com/using-requirejs-angularjs-applications/
Both guides seem to use angular, and angular-route and angular-amd, but I thought they were for other complicated purposes, so I only used "angular js" (so there is no shim in require.config()).
My main.js looks like this;
require.config({
paths: {
jquery : 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min',
'angular' : 'https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min',
'class' : 'class',
'utility' : '../utility/utility',
},
deps: ['main1']
});
where deps: ['main1'] is the file to load right after require is defined as the first guide uses.
But I'm keep getting this error:
Error: $injector:modulerr
('UpdateApp' is the name of the app that I'm using in my project.)
And the webpage says that I get the error when I've forgotten to include the file with the defined module.
Not using deps: ['main1'] but using require(['angular'], function(){} and logging out angular.module('myApp',[]) logs Object nicely though. ... It seems like require(['angular'], function(angular) does not work but require(['angular'], function() works for me, and guides don't seem to tell me whether I should do the latter or the former.
I thought it would be as simple as adding angular js in paths, and loading it with require() or define() will work, but it's not...
How do I use Require JS and Angular JS as simple as just using them together to print "hello world"?
Looking into your code, I can see that you clearly mis-understood about the concept of using requireJS and angular together. Either of the links you found are make by expert JS developers. Where both tried to combine angular and requireJS as simple as it could. So you need to accept the fact that it is complicated.
=> This is why I will not try to help you with some code. Because it will took lots of time and it will related with many topic which will not likely fit into a single question and answer on stackoverflow.
How do I use Require JS and Angular JS as simple as just using them together to print "hello world"?
At first I want to repeat it. This is nothing like simple work. For requireJS you need to at least have advanced knowledge about what called AMD and able to imagine how things happen asynchronusly when requireJS trying to load an JS library.
Secondly, common knowledge about angular module/service injeaction. Since both requireJS and angular can do some sort of module/service injection you need to know about the difference between these two.
Third, the initial stage of your webapp. Since both requireJS and angular need to be initialled to run properly. So this will also the requirement.
Sum up
You will NOT able to understand both in a day or two. It will take time. But fortunately I have a couple of suggestions for you.
Research some about how requireJS and angular load their depenencies.
Go for angularAMD get the project seed. Set it up, run it, play with it.
Improve your knowledge about the initial state of both.
...
Profit!
P.S. just FYI. An year ago, I started with requireJS and angular. And I got hitted up with a big wall of knowleges, just like you. And these are what I have tried to understand them. Take your time, it is not like using jquery which can learn in a day or two. Even for some JS expert it took months just for them to confident about angular (not counting combine it with requireJS). Cheers!
Inside your main1.js you must be use require(['angular'], function(){} to start your application.
Require JS will give you a package dependency manager, concatenator/uglifier, javascript file loader, and an injector. Require JS injectors are used for injecting classes versus Angular, which is used to inject instances.
The big advantage is that RequireJS is going to speed up your application by managing your load and runtime dependencies. It's useful for big SPA's.
You can set up your file structure by defining all of your dependencies using "define". For functions to execute, you will need to use "require".
Here is a helpful video:
https://www.youtube.com/watch?v=4yulGISBF8w&index=1&list=PLgVbnDyASc1qDAam3Fe0f-u6u9MYL6pC8
I’ve been given a design library from a large cooperate client built utilizing Bootstrap 3 and Require.js. It’s very robust and well-built with the various scripts using Require.js to load jQuery. Problem is, Drupal has already loaded jQuery and the double load is causing some items to fail. If I remove all the Require.js calls, Drupal jQuery stuff works great. If I remove the base Drupal jQuery file, all the stuff using the Require.js stuff works great. Here’ are options I have considered:
Stop jQuery from loading with Drupal, use require to load jQuery on every page - I haven’t tried this yet, but it just seems wrong. I think I can remove jQuery with hook_library_alter() in my theme? Wondering if anyone has tried this… My front end and admin screens actually use 2 different themes, so I think I'd have to modify both.
Stop jQuery from loading with Require.js – I tried this and none of the other libraries that are loaded with require.js can find query if it’s not loaded with Require.js, so I don’t think this option works. This is my first time using require.js so maybe there is some fun fix for this I haven't figured out?
Add all libraries to the site with Drupal – This seems like a lot of messy work as I would have to remove all the require.js dependencies in the library, and there is an expectation that we not modify the library/framework so implementing new releases is easy.
Any other recommendations?
UPDATE per Nikos Paraskevopoulos’ answer:
I have configured Drupal to load the jQuery version that came with the require.js package, and Drupal is happy with that. So now on each page I am loading in the following order:
/components/jquery/jquery.js
/misc/jquery.once.js
/misc/drupal.js
/components/requirejs/require.js
/js/require.config.js
My requires.config looks like this:
requirejs.config({
baseUrl: "./",
paths: {
.....
jquery:
"components/jquery/jquery", "jquery-csv": "components/jquery-csv/src/jquery.csv",
"jqueryui-sortable-amd": "components/jqueryui-sortable-amd/js/jquery-ui-1.10.2.custom",
.....
},
shim: {
"jquery-backstretch": [
"jquery"
],
masonry: [
"jquery"
],
OpenLayers: {
exports: "OpenLayers"
},
"jquery-csv": [
"jquery"
]
}
});
If I remove the jquery entry from paths, and add:
jquery: {
exports: 'jQuery' // NOTE THE CASE OF 'Q', THIS IS THE GLOBAL NAME
}
I immediately get errors like:
Uncaught Error: Script error for: jqueryui-sortable-amd
Which makes sense as they have all be declared together. uggg.
Regarding option 2:
I do not know how exactly things load, but I guess Drupal loads jQuery + other stuff it needs, then RequireJS is loaded, which in turn loads its own version of jQuery + other stuff it needs.
First of all you should ensure that the both Drupal and your RequireJS app can play with the same version of jQuery. Then in your RequireJS configuration shim jQuery, instead of loading it normally, e.g. instead of:
require.config({
...
paths: {
// REMOVE THIS IF USED (PROBABLY IS)
jquery: 'lib/jquery-x.y.z'
...
Do:
require.config({
...
shim: {
jquery: {
exports: 'jQuery' // NOTE THE CASE OF 'Q', THIS IS THE GLOBAL NAME
}
...
Explanation: If jQuery is loaded after RequireJS, it defines itself as jquery (lower-case Q). This is the name used by other modules to depend on jQuery. On the other hand, if it is loaded before RequireJS, it does not define itdelf and you are left with the jQuery (and possibly $) globals. The shim above instructs RequireJS to use the global jQuery variable whenever a module depends on the jquery module, which hopefully achieves what you want, i.e. loading jQuery only through Drupal.
Good morrow!
I've spent many days searching for a similar question and answer, but can't find (or maybe understand) any similar ones.
The Summary
I am adding onto a series of pages for a client that currently use jQuery 1.4.2. I am limited in that existing code must stay as is, and cannot be leveraged that much.
Yadda, yadda, yadda. All I've built thus far uses RequireJS 2.1.9, jQuery 1.10.2, and my own modules. I've made a jQuery loader module that calls $.noConflict(true) and all that good stuff to ensure my modules get 1.10.2 and I don't intrude on the globally necessary 1.4.2.
Below is an similar example of my current RequireJS configuration:
{
baseUrl: '/some/path',
paths: {
'jquery': 'lib/path/jquery',
'jquery-loader': 'lib/path/jquery-loader',
'jquery-validator': 'lib/path/jquery-validator'
},
map: {
'*': {
'jquery': 'jquery-loader'
},
'jquery-loader': {
'jquery': 'jquery'
}
},
shim: {
'jquery-validator': ['jquery']
}
}
The Problem
Some coworkers need to use some plugins inside my new code, namely jquery-validator.
My problem is that with the current configuration above, jquery-validator, which is a non-AMD plugin gets set to the globally available jQuery (1.4.2) instead of my jQuery (1.10.2) despite the entire setup.
I'd rather all the new code not have to use the globally available jQuery just to get to the validator plugin.
The Question
I'm not sure how I can get this to go as I want it, but my question is: is there actually any way to get this to work without me having to go into jquery-validator and wrap it in a define call?
I'm an experienced javascript programmer, and I'm trying to write my own modular game engine from scratch. I haven't used requirejs before, but after reading a bit about it, it sounds like it's probably the best way to manage all the components of the engine and load them into one coherent structure.
My main problem is that I'm not really sure how to really use requirejs. I've been looking over their API documentation, but I'm not sure how to integrate it with the way I've laid out my project.
Currently, my project uses the following structure:
src
engine.js //This contains the common engine stuff, most notably the engine namespace
resource
resource-module.js //This is the module constructor, which handles all the common stuff between the different
substructures
sprites.js //This is a substructure that contains sprite loading code
render
etc...
third-party
jquery
requirejs
I want to be able to load the modules independently of each other. It should be possible for instance to remove the audio module from the engine, and it still work. It should also be easy to substitute modules, or add new modules.
Also, I'm using jQuery for event handling, so it needs to be loaded before the engine is initiated.
You can find my current source here: https://github.com/superlinkx/lithium-engine
I know the current code is messy, and there isn't a whole lot built yet, but I'm mostly still figuring out how to best structure it. Any help/advice would be appreciated, but my main concern is how to structure it with requirejs so that it will be easier to compile into a single file for production use.
Require.js does not enforce any specific structure of your files. You can either specify the full paths in the require configuration, or just use the full path in the require() or define() calls. Both will work, however the latter will save you some typing and makes it easier to move stuff around when you include something from a lot of different places:
var $ = require("third-party/jquery");
require.config({
paths: {
"jquery": "third-party/jquery"
}
});
var $ = require("jquery");
I want to be able to load the modules independently of each other. It should be possible for instance to remove the audio module from the engine, and it still work. It should also be easy to substitute modules, or add new modules.
This is not something require.js does four you. You can decide when and when not to load it, but you would have to make sure that it won't break the rest of your code.
Also, I'm using jQuery for event handling, so it needs to be loaded before the engine is initiated.
You can do this in several different ways.
require() it in your main.js so that it is always loaded (you can also use the require-jquery.js, which has jQuery included).
Specify jQuery as a dependency of your engine
require.config({
paths: {
"jquery": "path.to.jquery",
"engine": "path.to.engine"
},
shim: {
"engine": {
"deps": ["jquery"]
}
}
});
Pass jQuery to the define() call in your module (probably the best choice)
define(["jquery"], function ($) {
// your engine code
}
I'm working with a very large project that uses:
Legacy JSP pages that includes javascript files with script tags
Backbone models and views that uses other javascript modules without RequireJS
We now want to start using RequireJS with jQuery, BackboneJS and UnderscoreJS for everything we develop from now on, but we don't have the resources to rewrite all the legacy JSP pages. We may have time to rewrite the Backbone models and views we have already developed.
The problem is that for our legacy code (both 1 and 2 above) we include all our javascript files in a huge file and ship to the browsers. This huge file must be able to co-exist with our new RequireJS templates, but how can I e.g. separate certain parts of the huge file, so I can use them with the templates using RequireJS? Without having to rewrite all pages that uses this part of the file, or having duplicate code.
Thanks!
I don't know if I fully grasp the problem at hand, but I think a the shim or map functions of RequireJS will help you out.
Extract the parts you want in a new module from your huge javascript file. Then tell RequireJS that your huge javascript file is a dependecy for this new module using shim. Something like:
requirejs.config({
shim: {
'new-module': {
deps: ['huge-javascript-file'],
exports: 'NewModule'
}
});
Shim documentation: http://requirejs.org/docs/api.html#config-shim
The map function might be useful when only portions of your new code have to use your old huge file. Check out this documentation: http://requirejs.org/docs/api.html#config-map
I don't think there is One True Way to achieve this, but I've approached a similar problem by defining module "facades" around the globally scoped code. Let's say your legacy scripts define a global variable called foo. You can define a AMD module and export that variable from it:
//foo.js
define(function() {
return window.foo;
});
//bar.js
define(['foo'], function(foo) {
//do something with foo
});
This way you only need to write a single-line facade every time you need to use a new piece of the existing, globally defined code, without breaking existing code which expects the same code to be globally defined. Over time you can move and refactor the actual implementation into the module without breaking consumer code.