Using RequireJS alongside non-AMD JavaScript files - javascript

I'm trying to convert a JavaScript-heavy page to use TypeScript, with RequireJS to manage the module dependencies.
The problem I've got is that, as well as the inter-dependencies between the TypeScript files, the page also depends on some common JavaScript files that are shared with other parts of the system, not yet converted to AMD.
Is it very dangerous to put non-AMD scripts in normal <SCRIPT> tags above the tag for Require, and just assume that they're loaded?
If that's a bad idea, what's a better way to handle this? Do I need to have AMD and non-AMD version of each script? Or do I need to convert all scripts so that they optionally call define()?

Recent versions of RequireJS allow you to pretend that the plain JS files are actually AMD modules that just return nothing.
The most recent version I tried - 2.1.4 - actually allows you to treat plain JS files like modules. Example:
require(
[
'path/to/module' // <- AMD module
,'path/to/plainjs' // <- actually a plain JS file
]
, function(module, plain){
// module will be per define in that file.
// plain will be 'undefined' type
}
)
You can just mix module-like refs to plain JS files freely. As long as they are loaded in the right order, they will update whatever globals they update and you get what you want. Example:
require(['js/underscore'], function(){
// nesting to insure Underscore, a prereq to BackBone
// completes loading before backbone starts
require(
[
'path/to/module' // <- AMD module
,'js/backbone' // <- actually a plain JS file
]
, function(module){
// module will be per define in that file.
window.BackBone // is available for you
}
)
})
Note, while RequireJS used to require that you add ".js" to the end of the plain JS files to indicate that they are plain JS, in the examples above you do NOT use ".js" This, extension-less module reference allows the module ID to follow paths and maps aliases, while ids with .js are treated as literal and are never translated.

You can manually include the additional scripts in script tags, but this could become the reason things always break for your team (someone forgot to add a particular script).
You can reference the require.d.ts definition from Definitely Typed and make direct calls to the require function rather than an import statement, which might make things more consistent for you.

Related

Understanding the Communication between Modules in jQuery Source Code Structure [duplicate]

Uncompressed jQuery file: http://code.jquery.com/jquery-2.0.3.js
jQuery Source code: https://github.com/jquery/jquery/blob/master/src/core.js
What are they doing to make it seem like the final output is not using Require.js under the hood? Require.js examples tells you to insert the entire library into your code to make it work standalone as a single file.
Almond.js, a smaller version of Require.js also tell you to insert itself into your code to have a standalone javascript file.
When minified, I don't care for extra bloat, it's only a few extra killobytes (for almond.js), but unminified is barely readable. I have to scroll all the way down, past almond.js code to see my application logic.
Question
How can I make my code to be similar to jQuery, in which the final output does not look like a Frankenweenie?
Short answer:
You have to create your own custom build procedure.
Long answer
jQuery's build procedure works only because jQuery defines its modules according to a pattern that allows a convert function to transform the source into a distributed file that does not use define. If anyone wants to replicate what jQuery does, there's no shortcut: 1) the modules have to be designed according to a pattern which will allow stripping out the define calls, and 2) you have to have a custom conversion function. That's what jQuery does. The entire logic that combines the jQuery modules into one file is in build/tasks/build.js.
This file defines a custom configuration that it passes to r.js. The important option are:
out which is set to "dist/jquery.js". This is the single
file produced by the optimization.
wrap.startFile which is set to "src/intro.js". This file
will be prepended to dist/jquery.js.
wrap.endFile which is set to "src/outro.js". This file will
be appended to dist/jquery.js.
onBuildWrite which is set to convert. This is a custom function.
The convert function is called every time r.js wants to output a module into the final output file. The output of that function is what r.js writes to the final file. It does the following:
If a module is from the var/ directory, the module will be
transformed as follows. Let's take the case of
src/var/toString.js:
define([
"./class2type"
], function( class2type ) {
return class2type.toString;
});
It will become:
var toString = class2type.toString;
Otherwise, the define(...) call is replace with the contents of the callback passed to define, the final return statement is stripped and any assignments to exports are stripped.
I've omitted details that do not specifically pertain to your question.
You can use a tool called AMDClean by gfranko https://www.npmjs.org/package/amdclean
It's much simpler than what jQuery is doing and you can set it up quickly.
All you need to do is to create a very abstract module (the one that you want to expose to global scope) and include all your sub modules in it.
Another alternative that I've recently been using is browserify. You can export/import your modules the NodeJS way and use them in any browser. You need to compile them before using it. It also has gulp and grunt plugins for setting up a workflow. For better explanations read the documentations on browserify.org.

how to jquery and bootstrap file using in requirejs?

define(["jquery","bootstrap","jquery.min"],function($){
var inittest = function(){
alert("hello");
}
var init = function(){
inittest();
};
return {
init: init
}
});
It's not working. How to use jQuery to define array?
You need to do two things here (the details are in the useful thread I linked you to, so please read).
Configure requirejs so that when you declare modules (e.g. "jquery", "bootstrap"), requirejs can resolve them to actual files, minified or otherwise.
Shim bootstrap by specifying jquery as its dependency, so that jquery is loaded before it.
To accomplish these, make a call to requirejs.config({...}) with the appropriate options (here is an example). The use case there is exactly the same as yours: jquery is specified as a bootstrap dependency by shimming bootstrap. There you will also see an example of how to tell requirejs where your files are (this is accomplished via the paths property). Note how the .js extension is not explicitly specified there; do the same.
Needless to say, configuring requirejs can get complicated, but the basic idea is there, configure it by specifying the base directory and where the files are to be found, then shim non-AMD modules. An important thing to be aware of is that bootstrap is going to be what's called a declarative module, which means that it's only used for its side-effects (viz. for what changes it makes to $).

Dojo build css and custom javascript

I've set up a single html page that uses three dojo widgets and I'm trying to create a custom build from it using dojo 1.7.5. The build succeeds leaving me with a dojo.js that includes the files I need using this build file:
var dependencies = {
action: "release",
selectorEngine: "acme",
stripConsole: "none",
cssOptimize: "comments.keepLines",
layers: [
{
name: "dojo.js",
dependencies: [
"dijit.form.ValidationTextBox",
"dijit.form.DropDownButton",
"dijit.form.Button",
"dijit.form.Form",
"dijit._base",
"dijit._Container",
"dijit._HasDropDown",
"dijit.form.ComboButton",
"dijit.form.ToggleButton",
"dijit.form._ToggleButtonMixin",
"dojo.parser",
"dojo.date.stamp",
"dojo._firebug.firebug"
]
}, {
name: "../test/test.js",
dependencies: [
"test.test"
]
}
],
prefixes: [
[ "dijit", "../dijit" ],
[ "dojox", "../dojox" ],
[ "ourpeople", "../ourpeople" ]
]
};
The questions I can't seem to find an answer to:
I'm using cssOptimize, I was expecting a single css file in which all the used css files were imported. However I can't find such a file. Is this the way dojo compresses it's css or are my expectations wrong? If so where can I find it in my release folder?
My test.js contains a function test1() if I call it from my built js it states test1 is not defined. I call that function directly without dojo. I'm assuming that building custom js only works if it is a dojo class using declare?
Final question, I needed to include several dojo files in the build manually such as dojo._firebug.firebug since after my initial build it was still using xhr calls to get those files. After including the files manually I still see xhr calls from dojo to specific resources: dojo/nls/dojo_ROOT and dijit/form/nls/validate.js. Those files are created during the build process and therefore can't be included in the dependencies in the build profile. Anyone any thoughts on this matter since I'm looking to distribute dojo in a single file.
I'm fairly new to the dojo build system and (especially) so perhaps I'm expecting things that the dojo build system isn't designed to do or maybe om going about this the wrong way if so any tips or suggestions are more than welcome.
Cheers!
Test.js:
function test1() {
console.log("test1");
}
Index.php:
<script type="text/javascript" src="js/release/dojo/dojo/dojo.js"></script>
<script type="text/javascript" src="js/release/dojo/test/test.js"></script>
<script type="text/javascript">
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.Form");
dojo.ready(function() {
test1();
});
</script>
I'm using cssOptimize, I was expecting a single css file in which all the used css files were imported. However I can't find such a file. Is this the way dojo compresses it's css or are my expectations wrong? If so where can I find it in my release folder?
When you use cssOptimize, the Dojo build optimizes and flattens CSS files in place. So for example, if you're using Dijit's Claro theme, when you load dijit/themes/claro/claro.css from source, it contains a series of #import statements which in turn load more files. When you load claro.css from a build with cssOptimize, it is one file containing all of the styles previously referenced via those separate files.
My test.js contains a function test1() if I call it from my built js it states test1 is not defined. I call that function directly without dojo. I'm assuming that building custom js only works if it is a dojo class using declare?
Dojo doesn't expect every JS file to be a "class" using declare but it does expect each file to be a module which doesn't implicitly define globals (since globals should be avoided in modules anyway). When the build process encounters a module that it thinks or knows isn't AMD, it assumes it's a legacy Dojo module and wraps it in a boilerplate to convert it to AMD. This boilerplate ends up encapsulating your globals into a function scope, so they are no longer globals.
Given that you're using Dojo 1.7, you should ideally be using the AMD format to define and consume modules. dojotoolkit.org has a tutorial introducing AMD modules, and if you're migrating from Dojo 1.6 or earlier, there's also a tutorial to help you transition.
Final question, I needed to include several dojo files in the build manually such as dojo._firebug.firebug since after my initial build it was still using xhr calls to get those files. After including the files manually I still see xhr calls from dojo to specific resources: dojo/nls/dojo_ROOT and dijit/form/nls/validate.js. Those files are created during the build process and therefore can't be included in the dependencies in the build profile. Anyone any thoughts on this matter since I'm looking to distribute dojo in a single file.
I'm not sure why you're seeing dojo/_firebug/firebug being automatically loaded, but based on what you've said/shown above I would immediately suggest the following:
Convert your modules/code to AMD format
Add async: true to your dojoConfig which will cause the loader to operate in asynchronous mode, which means:
It loads modules through script injection instead of synchronous XHR
It won't unconditionally load all of dojo/_base
Add customBase: true to your dojo/dojo layer which will prevent the build from defaulting to include all of dojo/_base
As for the nls modules, to an extent it's normal to still see NLS files requested, though if your build is configured properly there would ordinarily just be one NLS file per layer and that's it (the fact that you're seeing a separate request for validate leads me to think you haven't covered all of your dependencies). The reason NLS remains separate is because there is one NLS bundle per locale, and it doesn't make sense to build all locales into one layer - that would force people to pay for resources in 20 languages they don't care about.

Error loading KnockoutJS as part of a third party package when host site uses RequireJS

I've developed a JavaScript plugin to be included on our customers' websites. The plugin I've created depends on some external libraries, which are bundled and delivered to the client as one big package: jQuery 1.8.2 and KnockoutJS v3.0.0.
The plugin plays fine on most sites, but if the host site uses RequireJS, my package fails to load because KnockoutJS automatically detects that RequireJS exists and attempts to use it. Here is the error that gets thrown:
Mismatched anonymous define() module
Obviously, I've found an "explanation" of the error message on the RequireJS site. Unfortunately, I don't understand how to avoid it. In my local copy of the KnockoutJS library, I've found the offending line:
(function(factory) {
// Support three module loading scenarios
if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
// [1] CommonJS/Node.js
var target = module['exports'] || exports; // module.exports is for Node.js
factory(target);
} else if (typeof define === 'function' && define['amd']) {
// [2] AMD anonymous module
define(['exports'], factory);
} else {
// [3] No module loader (plain <script> tag) - put directly in global namespace
factory(window['ko'] = {});
}
}
If I manually edit this file so that condition [2] never executes and only condition [3] every executes, then everything works fine. Of course, I don't want to do this because it requires me editing an external library, which I'd prefer to keep in pristine condition so I can upgrade it later.
I have a feeling there may be a way to make this work, I just don't understand how RequireJS works. Obviously, KnockoutJS is TRYING to play nice with RequireJS, but in my case, it's failing. For me, in this case, even though RequireJS exists, I don't need KnockoutJS to use it.
How can I get these two libraries to work side by side?
EDIT
I have no control over when my library is loaded vs. all other libraries the host site already loads. In fact, most of the time my plugin will be included, it will be by someone with NO web dev experience using a terrible WYSIWYG platform like WordPress, Webs.com or Weebly so sometimes my script tag might make it to the top of the head element, other times it might be included in the body element somewhere.
Also, to be clear, my library does NOT use RequireJS. It just so happens that one of our customers that is trying to use my library DOES use RequireJS and when my library gets included, KnockoutJS (bundled with my library, but NOT already on the host site) throws an exception because it thinks it needs to register itself with RequireJS (or at least that's my speculation as to the exception).
While, in principal, I'm not opposed to loading the libraries my code depends on on demand, the truth is that it will create a slow, poor experience for my users as it will take additional request/response cycles to load them.
Well, the easiest thing to do would probably be to load knockout before requirejs. ko will no longer detect that require is present, and will go with option [3]. If you can't do this, the other option is to add your plugin and ko file in a require hierarchy.
So let's say that you plugin looked like this:
(function(ko){
//stuff
ko.applyBindings({});
})(ko)
You would need to change it to this:
require([
"knockout-3.0.0.js" // this should be the url you use for knockout
], function(ko){
//stuff
ko.applyBindings({});
})
and NOT load the knockout.js file as a separate tag. Require will handle the loading. The server must still be able to deliver the "knockout-3.0.0.js" url of course. This is how require works. It loads whatever urls you pass as elements in the array parameter of require, and passes what they return as parameters to the function.
If you need to minify/bundle both the plugin file and the ko file into a single file, you can use the reuquirejs minifier/optimizer (http://requirejs.org/docs/optimization.html). It will navigate the dependency tree and output only one js file with all modules inside. One quirk here: you need to drop the .js extension for the minifier to work, read more about it the documentation, I just mentioned it to save some headaches.
Also, more documentation on how to use ko with require can be found here: http://knockoutjs.com/documentation/amd-loading.html
EDIT, after op edit:
OK, so in this case you should create a separate scope, in which you can do what you want. You'll need to copy the ko code inside your file, but like this you'll at least get a single file.
So, first create a scope:
(function(){
})()
Then copy ko code inside:
(function(){
//ko code here, should be a single, minified line
})()
Then you need to trick ko into using option 3, so do this:
(function(){
var define = null; //so define will no longer be a function, don't forget the var
var require = null;
//ko code here, should be a single, minified line
})()
Optionally, you might also want to reassign window in the step above, if you don't want ko to be available to the entire page.
And now add your plugin code:
(function(){
var define = null; //so define will no longer be a function, don't forget the var
var require = null;
//ko code here, should be a single, minified line
//plugin code here;
})()

Approaches to modular client-side Javascript without namespace pollution

I'm writing client-side code and would like to write multiple, modular JS files that can interact while preventing global namespace pollution.
index.html
<script src="util.js"></script>
<script src="index.js"></script>
util.js
(function() {
var helper() {
// Performs some useful utility operation
}
});
index.js
(function () {
console.log("Loaded index.js script");
helper();
console.log("Done with execution.");
})
This code nicely keeps utility functions in a separate file and does not pollute the global namespace. However, the helper utility function will not be executed because 'helper' exists inside a separate anonymous function namespace.
One alternative approach involves placing all JS code inside one file or using a single variable in the global namespace like so:
var util_ns = {
helper: function() {
// Performs some useful utility operation.
},
etc.
}
Both these approaches have cons in terms of modularity and clean namespacing.
I'm used to working (server-side) in Node.js land where I can 'require' one Javascript file inside another, effectively injecting the util.js bindings into the index.js namespace.
I'd like to do something similar here (but client-side) that would allow code to be written in separate modular files while not creating any variables in the global namespace while allowing access to other modules (i.e. like a utility module).
Is this doable in a simple way (without libraries, etc)?
If not, in the realm of making client-side JS behave more like Node and npm, I'm aware of the existence of requireJS, browserify, AMD, and commonJS standardization attempts. However, I'm not sure of the pros and cons and actual usage of each.
I would strongly recommend you to go ahead with RequireJS.
The modules support approach (without requires/dependencies):
// moduleA.js
var MyApplication = (function(app) {
app.util = app.util || {};
app.util.hypotenuse = function(a, b) {
return Math.sqrt(a * a + b * b);
};
return app;
})(MyApplication || {});
// ----------
// moduleB.js
var MyApplication = (function(app) {
app.util = app.util || {};
app.util.area = function(a, b) {
return a * b / 2;
};
return app;
})(MyApplication || {});
// ----------
// index.js - here you have to include both moduleA and moduleB manually
// or write some loader
var a = 3,
b = 4;
console.log('Hypotenuse: ', MyApplication.util.hypotenuse(a, b));
console.log('Area: ', MyApplication.util.area(a, b));
Here you're creating only one global variable (namespace) MyApplication, all other stuff is "nested" into it.
Fiddle - http://jsfiddle.net/f0t0n/hmbb7/
**One more approach that I used earlier in my projects - https://gist.github.com/4133310
But anyway I threw out all that stuff when started to use RequireJS.*
You should check out browserify, which will process a modular JavaScript project into a single file. You can use require in it as you do in node.
It even gives a bunch of the node.js libs like url, http and crypto.
ADDITION: In my opinion, the pro of browserify is that it is simply to use and requires no own code - you can even use your already written node.js code with it. There's no boilerplate code or code change necessary at all, and it's as CommonJS-compliant as node.js is. It outputs a single .js that allows you to use require in your website code, too.
There are two cons to this, IMHO: First is that two files that were compiled by browserify can override their require functions if they are included in the same website code, so you have to be careful there. Another is of course you have to run browserify every time to make change to the code. And of course, the module system code is always part of your compiled file.
I strongly suggest you try a build tool.
Build tools will allow you to have different files (even in different folders) when developing, and concatenating them at the end for debugging, testing or production. Even better, you won't need to add a library to your project, the build tool resides in different files and are not included in your release version.
I use GruntJS, and basically it works like this. Suppose you have your util.js and index.js (which needs the helper object to be defined), both inside a js directory. You can develop both separately, and then concatenate both to an app.js file in the dist directory that will be loaded by your html. In Grunt you can specify something like:
concat: {
app: {
src: ['js/util.js', 'js/index.js'],
dest: 'dist/app.js'
}
}
Which will automatically create the concatenation of the files. Additionally, you can minify them, lint them, and make any process you want to them too. You can also have them in completely different directories and still end up with one file packaged with your code in the right order. You can even trigger the process every time you save a file to save time.
At the end, from HTML, you would only have to reference one file:
<script src="dist/app.js"></script>
Adding a file that resides in a different directory is very easy:
concat: {
app: {
src: ['js/util.js', 'js/index.js', 'js/helpers/date/whatever.js'],
dest: 'dist/app.js'
}
}
And your html will still only reference one file.
Some other available tools that do the same are Brunch and Yeoman.
-------- EDIT -----------
Require JS (and some alternatives, such as Head JS) is a very popular AMD (Asynchronous Module Definition) which allows to simply specify dependencies. A build tool (e.g., Grunt) on the other hand, allows managing files and adding more functionalities without relying on an external library. On some occasions you can even use both.
I think having the file dependencies / directory issues / build process separated from your code is the way to go. With build tools you have a clear view of your code and a completely separate place where you specify what to do with the files. It also provides a very scalable architecture, because it can work through structure changes or future needs (such as including LESS or CoffeeScript files).
One last point, having a single file in production also means less HTTP overhead. Remember that minimizing the number of calls to the server is important. Having multiple files is very inefficient.
Finally, this is a great article on AMD tools s build tools, worth a read.
So called "global namespace pollution" is greatly over rated as an issue. I don't know about node.js, but in a typical DOM, there are hundreds of global variables by default. Name duplication is rarely an issue where names are chosen judiciously. Adding a few using script will not make the slightest difference. Using a pattern like:
var mySpecialIdentifier = mySpecialIdentifier || {};
means adding a single variable that can be the root of all your code. You can then add modules to your heart's content, e.g.
mySpecialIdentifier.dom = {
/* add dom methods */
}
(function(global, undefined) {
if (!global.mySpecialIdentifier) global.mySpecialIdentifier = {};
/* add methods that require feature testing */
}(this));
And so on.
You can also use an "extend" function that does the testing and adding of base objects so you don't replicate that code and can add methods to base library objects easily from different files. Your library documentation should tell you if you are replicating names or functionality before it becomes an issue (and testing should tell you too).
Your entire library can use a single global variable and can be easily extended or trimmed as you see fit. Finally, you aren't dependent on any third party code to solve a fairly trivial issue.
You can do it like this:
-- main.js --
var my_ns = {};
-- util.js --
my_ns.util = {
map: function () {}
// .. etc
}
-- index.js --
my_ns.index = {
// ..
}
This way you occupy only one variable.
One way of solving this is to have your components talk to each other using a "message bus". A Message (or event) consists of a category and a payload. Components can subscribe to messages of a certain category and can publish messages. This is quite easy to implement, but there are also some out of the box-solutions out there. While this is a neat solution, it also has a great impact on the architecture of your application.
Here is an example implementation: http://pastebin.com/2KE25Par
http://brunch.io/ should be one of the simplest ways if you want to write node-like modular code in your browser without async AMD hell. With it, you’re also able to require() your templates etc, not just JS files.
There are a lot of skeletons (base applications) which you can use with it and it’s quite mature.
Check the example application https://github.com/paulmillr/ostio to see some structure. As you may notice, it’s written in coffeescript, but if you want to write in js, you can — brunch doesn’t care about langs.
I think what you want is https://github.com/component/component.
It's synchronous CommonJS just like Node.js,
it has much less overhead,
and it's written by visionmedia who wrote connect and express.

Categories

Resources