I'm currently building an app where the frontend is doing a lot of the heavy lifting.
To keep everything neat and organised I'd like to use requirejs. However, to use require.js to its' full extent all the modules I use should be AMD compliant.
Which means that every time a module that I use is updated I need to either wait for an AMD-compliant version to appear or make one myself ( Which I currently don't know how to ).
This is a real turnoff.
Looking at this https://github.com/jrburke/backbone/blob/optamd/backbone.js it seems to me that making a module like Backbone AMD-compliant isn't as straightforward as wrapping the plugin into a generic function.
Is there a more or less straightforward way of making a module AMD-compliant?
Well his version is pretty bullet-proofed so it'll run under a variety of circumstances. Since you know the environment you are running in and what is available/what isn't then you can make some assumptions that will let you do something that is much more straightforward.
Check out this gist where I make bacbkonejs an AMD module assuming jQuery, underscore and define are in the global scope and I don't need commonjs support:
https://gist.github.com/2762813
I just add
define(function() {
var obj = {};
obj._ = window._;
obj.jQuery = window.jQuery;
to the top and
.call(obj);
return obj.Backbone;
});
to the bottom.
Thanks to #SimonSmith for bringing UseJS to my attention. UseJS is an AMD loader plugin that will allow you to load non-amd formatted modules without modifying them. I haven't used use myself yet but it looks promising: https://github.com/tbranyen/use.js/
UPDATE
RequireJS 2.0 now directly supports the functionality you are looking for via shim configs: https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.0#wiki-shim
Related
I've been reading about es6 module loaders and I just don't quite understand how it works and am hoping someone can enlighten me.
In the practical workflows link above they have an example like this
System.import('app/app').then(function(app) {
// app is now the Module object with exports as getters
});
No problem with that - I get it. But then I see stuff like this
var $ = require('jquery');
and get really confused. What happens if at the time of this call jquery has not yet been transferred to the browser? Does the thread just spin? Does the browser parse your script behind-the-scenes and reform it into a callback like RequireJs does? Is what it does configurable? Are there specific limitations?
Can someone give me a rundown?
The ES6 Module Loader will fetch the source, determine dependencies, and wait until those dependencies have loaded before executing the module. So by the time the require executes, the dependency is already sitting there waiting to be executed.
When loading CommonJS through an ES6 module loader, we rely on statically parsing out the require statements from the source, and only executing the source once those requires have loaded.
In this way we can support CommonJS in the browser loaded dynamically. Circular references are treated identically to the way they are handled in Node.
The regular expressions parsing out the require are actually pretty reliable and quick, while taking into account comments and surrounding tokens. See https://github.com/systemjs/systemjs/blob/master/lib/extension-cjs.js#L10 for the one used by SystemJS.
There is one remaining limitation with this approach and that is dynamic and conditional CommonJS requires like if (condition) require('some' + 'name') aren't detected properly. This is a necessary cost though to make CommonJS behave as a fully asynchronous module format in the browser.
I'm attempting to build a site using a combination of RequireJS and MooTools. It's my first time using both libraries. There is plenty of documentation for using RequireJS with jQuery but less for using it with MooTools. I've found only this really. But I'm having some trouble and much of it probably is a result of ignorance; still, perhaps you all can help.
At the moment, I'm just trying to test out basic functionality and understand how I would go about setting this up. Here is what I have tried:
In my site footer, I have this script tag:
<script src="assets/js/vendor/require.js" data-main="../app.js"></script>
This loads requirejs with the file app.js. Inside app.js I mainly deal with paths:
requirejs.config({
"baseUrl": "assets/js",
"paths": {
"mootools": "//ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed"
}
});
// Load the main app module to start the app
requirejs(["main"]);
Finally, in main.js, I have (so far) the following:
define(["mootools"], function($) {
var a = $$('.menu'); // .menu is a nav menu in the DOM
console.log(a);
var b = $('.menu');
console.log(b);
});
So here, a works, but b causes an error: undefined is not a function. So there are a couple of questions embedded here. First, can someone tell me what the difference in meaning for $ and $$ with mootools? I gather from this tutorial, that both are used in mootools. Also, why is it that mootools is not mapped to $? As I understand it, with jQuery, this is how you would do this, see here for example.
I'm sure there are some basic confusions here, but please have mercy. I'm a newbie to these tools.
MooTools (as is) is not AMD-compliant. David Walsh is cool but he does not like or use RequireJS. The info in his post is well out of date and not practical any more. In fact, I believe none of the MooTools-core team likes AMD or uses it. Anyway, that's beside the point. jQuery now IS based around AMD so using it is easy. MooTools tried it 2 years ago - https://github.com/arian/mootools-core/tree/1.5amd - and gave up. 1.5 is still not out (hopefully next week, still no AMD).
Anyway
You cannot do this quite in that fashion by expecting the script to magically return $ where a module has not been defined.
There is another issue here which is with the fact that you are loading a remote script and that you leave the protocol to be determined automatically - which are sort of quirky things for RequireJS to handle in their own accord.
Two or three ways to handle it.
you can just define a local module, eg your own mootools.js
define([
'http://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js'
], function(){
return window.$;
});
then use by requiring it:
require(['mootools'], function($){
$(document.body).adopt(new Element('div[html=hi]'));
});
eg. http://jsfiddle.net/dimitar/5zYnW/
however, mootools will export all sorts of globals anyway, so it's not really useful. you are better off using the requirejs shim config.
shim example
require.config({
paths: {
mootools: 'https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed'
},
shim: {
mootools: {
exports: '$'
}
}
});
// some code.
require(['mootools'], function(){
document.id('foo').adopt(new Element('div[html=hi]'));
});
eg: http://jsfiddle.net/dimitar/5zYnW/1/
old school
I find that it's easier to load MooTools before RequireJS and assume it's all global in all modules that I write - it makes more sense as there are too many global exports to catch. eg. Class, Element, Request etc etc.
eg. https://github.com/epitome-mvc/Epitome/blob/master/example/js/model-demo-require.js -s from my MooTools MVC framework Epitome.
Here's example module code via a UMD wrap - https://github.com/epitome-mvc/Epitome/blob/master/src/epitome-model.js - the only code that implicitly requires MooTools is the node.js code.
I use TypeScript to code my javascript file with Object Oriented Programing.
I want to use the node module https://npmjs.org/package/typescript-require to require my .ts files from other files.
I want to share my files in both server and client side. (Browser) And that's very important. Note that the folder /shared/ doesn't mean shared between client and server but between Game server and Web server. I use pomelo.js as framework, that's why.
For the moment I'm not using (successfully) the typescript-require library.
I do like that:
shared/lib/message.js
var Message = require('./../classes/Message');
module.exports = {
getNewInstance: function(message, data, status){
console.log(requireTs);// Global typescript-require instance
console.log(Message);
return new Message(message, data, status);
}
};
This file need the Message.js to create new instances.
shared/classes/Message.ts
class Message{
// Big stuff
}
try{
module.exports = Message;
}catch(e){}
At the end of the fil I add this try/catch to add the class to the module.exports if it exists. (It works, but it's not really a good way to do it, I would like to do better)
If I load the file from the browser, the module.export won't exists.
So, what I did above is working. Now if I try to use the typescript-require module, I'll change some things:
shared/lib/message.js
var Message = requireTs('./../classes/Message.ts');
I use requireTs instead of require, it's a global var. I precise I'm using .ts file.
shared/classes/Message.ts
export class Message{
// Big stuff
}
// remove the compatibility script at the end
Now, if I try like this and if I take a look to the console server, I get requireTs is object and Message is undefined in shared/lib/message.js.
I get the same if I don't use the export keyword in Message.ts. Even if I use my little script at the end I get always an error.
But there is more, I have another class name ValidatorMessage.ts which extends Message.ts, it's not working if I use the export keyword...
Did I did something wrong? I tried several other things but nothing is working, looks like the typescript-require is not able to require .ts files.
Thank you for your help.
Looking at the typescript-require library, I see it hasn't been updated for 9 months. As it includes the lib.d.ts typing central to TypeScript (and the node.d.ts typing), and as these have progressed greatly in the past 9 months (along with needed changes due to language updates), it's probably not compatible with the latest TypeScript releases (just my assumption, I may be wrong).
Sharing modules between Node and the browser is not easy with TypeScript, as they both use very different module systems (CommonJS in Node, and typically something like RequireJS in the browser). TypeScript emits code for one or the other, depending on the --module switch given. (Note: There is a Universal Module Definition (UMD) pattern some folks use, but TypeScript doesn't support this directly).
What goals exactly are you trying to achieve, and I may be able to offer some guidance.
I am doing the same and keep having issues whichever way I try to do things... The main problems for me are:
I write my typescript as namespaces and components, so there is no export module with multiple file compilation you have to do a hack to add some _exporter.ts at the end to add the export for your library-output.js to be importable as a module, this would require something like:
module.exports.MyRootNamespace = MyRootNamespace
If you do the above it works, however then you get the issue of when you need to reference classes from other modules (such as MyRootNamespace1.SomeClass being referenced by MyRootNamespace2.SomeOtherClass) you can reference it but then it will compile it into your library-output2.js file so you end up having duplicates of classes if you are trying to re-use typescript across multiple compiled targets (like how you would have 1 solution in VS and multiple projects which have their own dll outputs)
Assuming you are not happy with hacking the exports and/or duplicating your references then you can just import them into the global scope, which is a hack but works... however then when you decide you want to test your code (using whatever nodejs testing framework) you will need to mock out certain things, and as the dependencies for your components may not be included via a require() call (and your module may depend upon node_modules which are not really usable with global scope hacking) and this then makes it difficult to satisfy dependencies and mock certain ones, its like an all or nothing sort of approach.
Finally you can try to mitigate all these problems by using a typescript framework such as appex which allows you to run your typescript directly rather than the compile into js first, and while it seems very good up front it is VERY hard to debug compilation errors, this is currently my preferred way but I have an issue where my typescript compiles fine via tsc, but just blows up with a max stack size exception on appex, and I am at the mercy of the project maintainer to fix this (I was not able to find the underlying issue). There are also not many of these sort of projects out there however they make the issue of compiling at module level/file level etc a moot point.
Ultimately I have had nothing but problems trying to wrestle with Typescript to get it to work in a way which is maintainable and testable. I also am trying to re-use some of the typescript components on the clientside however if you go down the npm hack route to get your modules included you then have to make sure your client side uses a require compatible resource/package loader. As much as I would love to just use typescript on my client and my server projects, it just does not seem to want to work in a nice way.
Solution here:
Inheritance TypeScript with exported class and modules
Finally I don't use require-typescript but typescript.api instead, it works well. (You have to load lib.d.ts if you use it, else you'll get some errors on the console.
I don't have a solution to have the script on the browser yet. (Because of export keyword I have some errors client side) I think add a exports global var to avoid errors like this.
Thank you for your help Bill.
Looking for requirejs.noConflict(), or some way to remove the global footprint from the library. My use case is that I'm writing a widget to run in a 3rd party page which might already define require and define (with a previous version of requirejs or even another library entirely).
I've tried implementing this myself and it mostly works. For simplicity lets assume I do not restore original values, only remove the footprint. I do something like this in my data-main:
var mycontext = requirejs.config({context : 'asdf', baseUrl : 'http://foo.com' });
mycontext(['require','foo'], function (require, foo) {
var f = require('foo');
});
// namespace cleanup
window.requirejs = undefined;
window.require = undefined;
window.define = undefined;
The problem here is that the f value from require('foo') returns null, but only iff I do my namespace cleanup. This smells like a bug in requirejs, but I'm hoping there's an official no-conflict solution.
Hard to google this one due to all the jQuery related noConflict() questions.
The RequireJS documentation has a section on this titled "HOW CAN I PROVIDE A LIBRARY TO OTHERS THAT DOES NOT DEPEND ON REQUIREJS?"
You can also have a look at the example build file, which shows how wrap can be used.
A good example of how this works is the Flight library.
By default the library uses AMD but there is a standalone version that wraps all the modules in an anonymous function and includes a tiny require/define API at the top (They use their own build tool for this). Source can be found here.
Note that for this to work all the modules will require IDs, but the r.js optimiser will handle that for you.
Using these techniques should allow you to leave any already defined require/define variables alone.
We love RequireJS and AMD during development, where we can edit a module, hit reload in our browser, and immediately see the result. But when it comes time to concatenate our modules into a single file for production deployment, there apparently has to be an AMD loader still present, whether that loader is RequireJS itself or its smaller partner “almond” as explained here:
http://requirejs.org/docs/faq-optimization.html#wrap
My confusion is: why is a loader necessary at all? Unless you have very unusual circumstances that make it necessary for you to make require() calls inside of your modules, it would appear that a series of AMD modules could be concatenated without a loader present at all. The simplest possible example would be a pair of modules like the following.
ModA.js:
define([], function() {
return {a: 1};
});
ModB.js:
define(['ModA'], function(A) {
return {b : 2};
});
Given these two modules, it seems that a concatenator could simply produce the following text, and not burden the production server or browser with the extra bandwidth or computation required by either RequireJS or Almond.
I imagine a concatenator that produces (and I am using chevron-quotes «,» to show where the snippets from the two modules above have been inserted):
(function() {
var ModA = «function() {
return {a: 1};
}»();
var ModB = «function(A) {
return {b : 2};
}»(ModA);
return ModB;
})();
This, so far as I can see, would correctly reproduce the semantics of AMD, with a minimum of extraneous glue JavaScript. Is there such a concatenator available? If not, would I be a fool for thinking that I should write one — are there really very few code bases that consist of simple and clean modules written with define() and that never need further require() calls inside that kick off later asynchronous fetches of code?
An AMD optimiser has the scope to optimise more than the number of files to be downloaded, it can also optimise the number of modules loaded in memory.
For example, if you have 10 modules and can optimise them to 1 file, then you have saved yourself 9 downloads.
If Page1 uses all 10 modules then that's great. But what if Page2 only uses 1? An AMD loader can delay the execution of the 'factory function' until a module is require'd. Therefore, Page2 only triggers a single 'factory function' to execute.
If each module consumes 100kb of memory upon being require'd, then an AMD framework that has runtime optimisation will also save us 900kb of memory on Page2.
An example of this could be an 'About Box' style dialog. Where the very execution of it is delayed until the very last second as it won't be accessed in 99% of cases. E.g. (in loose jQuery syntax):
aboutBoxBtn.click(function () {
require(['aboutBox'], function (aboutBox) {
aboutBox.show();
}
});
You save the expense of creating the JS objects and DOM associated with the 'About Box' until you are sure it's necessary.
For more info, see Delay executing defines until first require for requirejs's take on this.
The only real benefit is if you use modules across sections so there's a benefit to caching modules independently.
I had the same need, so I created a simple AMD "compiler" for that purpose that does just that. You can get it at https://github.com/amitayh/amd-compiler
Please note that it has many features missing, but it does the job (at least for me). Feel free to contribute to the codebase.
In case you compile you code with require.js into a single large file for production, you can use almond.js to completely replace require.
Almond only handles the module references management not the loading itself which is no longer needed.
Be careful of the restrictions almond imposes in order to work
There is no reason why there couldn't be a build tool such as the one you propose.
The last time* I looked at the optimizer's output, it converted the modules to explicitly named modules, and then concatenated those together. It relied on require itself to make sure that the factory functions were called in the right order, and that the proper module objects were passed around. To build a tool like you want, you would have to explicitly linearize the modules -- not impossible, but a lot more work. That's probably why it hasn't been done.
I believe** that the optimizer has a feature to automatically include require itself (or almond) into the built file, so that you only have to have one download. That would be larger than the output of the build tool you want, but otherwise the same.
If there was a build tool that produced the kind of output you're asking for, It would have to be more careful, in case of the synchronous require, the use of exports instead of return, and any other CommonJS compatibility features.
*That was a few years ago. 2010, I think.
**But can't seem to find it right now.