Using RequireJS with legacy code - javascript

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.

Related

How do I instantiate require.js modules on different pages, partials with codeigniter?

I'm trying to update the javascript on a large scale, php/codeigniter based website. It has many, many php partials for code being loaded onto certain pages, but only one footer, header. Most of the partials have inline script tags in them for loading javascript. This needs to be fixed and because the site is very modular with components being used multiple times across pages, require.js seems like a pretty good solution.
So, it's instantiate javascript, we typically do this.
<script type="javascript" src="../js/scriptname.js">
<script type="javascript">
DP.scriptname.init(parameters)
</script>
I'd like to get away from this and just have a have a single entry point for the js using require.
My question is this: what's the best way to instantiate javascript for certain pages using require? Do I need I need to continue including my scripts in the partial and then do something like writing a require module for that specific page and then wrap it all in my data-main script like this? We're planning on using Backbone and Marionette as well, but I won't be able to use the Backbone router to do anything like setting hash URLs. Should I use the URLs to instantiate my require modules perhaps?
Ok, hope someone can help. My experience has typically been in building single page websites. This is different. Thanks
Cam
Well, if I understand your question correctly, you can use Require JS in such way.
First of all, write a config in which you can describe mapping between module names and concrete files. For example:
requirejs.config({
baseUrl: 'js/modules' // by default load any module using this path
});
After that you should refactor your existing module and adjust it to the AMD format (see http://requirejs.org/docs/whyamd.html)
As a result of this step you will have something like this (let's say in file 'js/modules/scriptname.js'):
// module has the same name as the file, which contains it - "scriptname"
define(function () {
// define the module value by returning a value
return function () {};
});
And as a final step you can refactor your inline script and use this module in such way:
<script type="javascript">
// when we place name of the module as a first argument of the "define"
// function, Require JS find file that contains it and load it asynchronously
define(["scriptname"], function (scriptname) {
// "scriptname" now contains value that we recieve from the module definition
scriptname.init(parameters);
});
</script>
Hope this helps.
Note. My solution based on this section of official Require JS documentation: http://requirejs.org/docs/api.html#jsfiles
This question seems to come up a lot, so I'll point you to some resources that may help:
How does RequireJS work with multiple pages and partial views? - https://stackoverflow.com/a/10816983/617615
Modular HTML components with RequireJS - http://simonsmith.io/modular-html-components-with-requirejs/
Example RequireJS-based project that has multiple pages that share a common set of modules - https://github.com/requirejs/example-multipage

Using requirejs for a modular game engine

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
}

BreezeJS and RequireJS not working as expected

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.

What is a typescript AMD module and do I need it for an ASP MVC4 web application?

I started to use Web Essentials and I see there's an option "Use the AMD module". I am using typescript for an ASP MVC4 application. Can someone explain what the AMD module is all
about. Is this something that I should know about?
AMD is one way to format and load modular JavaScript. See here: http://addyosmani.com/writing-modular-js/ and especially here: http://requirejs.org/docs/whyamd.html
To quote from that latter source:
The AMD format comes from wanting a module format that was better than
today's "write a bunch of script tags with implicit dependencies that
you have to manually order" and something that was easy to use
directly in the browser.
Essentially AMD allows you to load JavaScript modules on demand, and provides a format for encapsulating their content so the Global namespace isn't polluted.
In TypeScript, with the AMD compiler switch that you've discovered set to 'on', you export a module like this:
export module pe.components {
export class Component { // 'export' makes this visible outside the module
}
class FriendComponent { // no 'export' so this is only visible inside the module.
}
}
And in another file you import this module like this:
import c = module('relative-path-to-file/pe.components');
And then use it like this:
var component:Component = new c.pe.components.Component(); // Works, because Component is exported
... but not this:
var friend:FriendComponent = new c.pe.components.FriendComponent(); // Shouldn't work* because FriendComponent is not exported.
(* there was a bug that made non-exported interfaces visible outside their declaring modules. I think this has been fixed in TS 0.8.1).
As to the second part of your question - this is really too broad. If your architecture requires you to load new functionality (plug-ins or applets within a single page application, for example), then yes, AMD modules and a loading framework such as RequireJS may be the way to go. If, on the other hand, you know in advance all the functionality your users are going to require, you might be better off just minifying your scripts thoroughly and loading them in advance as a single file.
I don't think the fact that you are working with MVC is relevant here: the question is whether your client-side architecture warrants an asynchronous, modular approach.

Questions about Dojo modules from Dojo newb?

I'm new to Dojo so I don't quite understand all of Dojo's features. Here are some questions, but I'm sure some of them seem really stupid since I don't quite get how Dojo is structured yet:
How do you create multiple modules within a single js file and access the module in the file it's created? Also, how do you access specific modules from a file containing multiple modules?
What is the difference between require and define?
I successfully required a module from a file, but I can't figure out how to get the variables out of the file, how do you do this?
I was looking at how Dojo required its modules and notice that it does a http request for each file, but isn't that really inefficient when you're dealing with lots of modules and/or on a large site, you really would like to minimize the number of http requests necessary? What's the way around this?
Reading through The Dojo Loader will provide answers.
Basically module = file and very often (as a matter of best practice) module = file = class (more precisely public class defined via dojo/_base/declare).
Ad #4: You will need to employ The Dojo Build System, that will resolve all the dependencies and put all your modules into a single file (or more files, this depends on your build profile). Have a look at Dojo Boilerplate project, it may help with building your application.
How do you create multiple modules within a single js file?
While this is possible to do, and is done by the build system when it creates layer files, it is not recommended. Putting multiple modules in a single file means you have to use a different form of define that gives an explicit ID to eahc of them. This is less flexible then having the module IDs automatically derived from the file name and path (this, together with relative paths makes it much easier to move and rename AMD modules, compared to old-style modules)
What is the difference between require and define?
define is a beefed up version of require that defines a new module with its return value.
I successfully required a module from a file, but I can't figure out how to get the variables out of the file.
I am not sure wha toyu mean with this (without giving a concrete runnable example) but all you have to do is create an object to be the value of your module and return it from define. This is not very far off from how you would define modules the old way, with manual "namespaces"
//foo.js
define([], function(){
var M = {}; //the exported stuff will go here
var myVariable = 16; //private function variables are private (like they are everywhere else)
//and cannot be seen from the outside
M.anumber = myvariable + 1; //things on the returned object can be seen from the outside
return M; //people who require this module will get this return value
});
//bar.js
define(['foo'], function(foo){
console.log( foo.anumber );
});
I was looking at how Dojo required its modules and notice that it does a http request for each file...
As phusick pointed out, the build system can be used to bundle all the modules into a single file (giving you the best of both worlds - modularity during development and performance during deployment). It can also do other cool stuff, like bundling CSS and passing the Javascript through a minifier or through the Closure compiler, checking ifdef for creating platform-dependent builds, etc.

Categories