How to add momentjs to a minified bundle file? - javascript

I am going to add momentjs library in a project (and its moment-timezone plugin). In this project I'm using dojo and its AMD loader (very similiar to requirejs) to work in debug mode. But for production environment I have created three minified bundles: one with all external libraries (as jquery, bootstrap and other plugins), another one with a private js framework and the third one which contains the specific code for the application.
Well, in development mode there is no problem with momentjs because after defined its path in the configuration file it is loaded properly, but I would like to add it to the external bundle file. And it's here where I'm having problems because although the bundle file contains the momentjs code, both files moment.js and moment-timezone-with-data.js are loaded too because they are required at the beginning of a module.
To solve this issue with similar files I use the conditional load of files. This works, for instance, for jquery: if I'm debugging the library is explicitely loaded. If I'm not debugging, I assume that it is loaded through a bundle file, and it works because $ is loaded as a global variable.
Here comes the origin of my problem: momentjs does a check at the beginning in order to see if define function is defined:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global.moment = factory()
}(this, function () {
'use strict';
[...]
});
Obviously, define function is defined by dojo and that provokes the momentjs must be loaded always as a amd module and that causes that its file to be loaded even in production environment. So how could I avoid this issue without modify the original source code? I've thought that if it were loaded as a global variable, it should work, but is there any other way to solve this?
Sorry about this large post, but I've tried to exlpain as better as possible.

If you have a library that detects an AMD loader and declares itself as an AMD module only if the loader is present, and want to load this library so that it does not declare itself as an AMD module, then you need to load this library in a script element before you load the AMD loader.
Alternatively, must load your library after your AMD loader is loaded , you could temporarily undefine define and define it again afterwards:
<script>
my_variable_for_saving_define = define;
window.define = undefined;
</script>
<script [that loads your module]></script>
<script>
define = my_variable_for_saving_define;
</script>
my_variable_for_saving_define is for illustration purposes. Choose something reasonably likely to not cause a clash.

Related

What are the best practices for writing and organizing javascript plugins?

So I have a nice chunk of code that is the same across many different javascript files, but I occasionally have to update it due to path changes or other various conditions. Now copy and pasting it all over to the new files works fine but is annoying to execute. Is there a good way to maintain one javascript file with my "plugin" code and have it be accessible by other javascript files that use the plugin?
I am looking for both a good nodejs solution, and vanilla js solution. If they could be mutually shared that'd be ideal, but not required by any means. Ideally, I'd like to host my workspace in workspace/ and have some folders, workspace/front-end-js/ and workspace/back-end-nodejs/, be able to run code off a plugin in workspace/plugins/ so that I can execute things like MyPluginVar.Foo();
I am aware of some systems, like the node's var foo = require('bar'); and the frontend browserified version, but really do not know all my options. What's the best way of writing and organizing javascript plugins?
--
Edit: I'm really trying to avoid npm, but it might be the best option.
You typically add your shared libraries and plugins as dependencies to your project's package.json file and install them using npm.
CommonJS modules, which use the module.exports object and require function, are the de facto standard at the moment.
ES2015 modules, which use the export and import statements, are an emerging formal standard, but support for them is not yet universal. They are a good option if your environment supports them.
To load either type of module on the front end, you will need to use a bundler such as Webpack or Browserify.
Older javascript modules typically publish to the global scope (window), and are a simple option for front end code.
You can also support multiple module systems if you like by using a UMD (Universal Module Definition) wrapper. Here's an example from the UMD Github repo that leverages CommonJS if supported, while falling back to a browser global:
(function (root, factory) {
if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
// CommonJS
factory(exports, require('b'));
} else {
// Browser globals
factory((root.commonJsStrictGlobal = {}), root.b);
}
}(this, function (exports, b) {
// b represents some dependency
// attach properties to the exports object to define
// the exported module properties.
exports.action = function () {};
}));

use of 'require' in 3rd party browser js

My javascript app is a client-side app. It does not run in NodeJS and it does not use Require.js, AMD, or ComponentJS.
However, certain 3rd party JS libraries intended for use in the client, use the require method. Here are 2 examples in heavily used client-side libraries:
https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.fileupload.js#L26
https://github.com/moment/moment/blob/develop/moment.js#L264
Does usage of those libraries mean that I need to include RequireJS, AMD, or ComponentJS? Is 'require' function usage in the client becoming so common place that I have to make sure it's defined?
No, you don't have to use require() or an environment/library that defines it. But, it is an option.
Each script is just trying to support multiple module patterns/systems at once, using require() if it's available. Before using it, they check for the existence of other objects related to CommonJS Modules:
} else if (typeof exports === 'object') {
if (!locales[name] && typeof module !== 'undefined' &&
module && module.exports) {
Though, in the case of moment.js, you'll just need to include locales via <script>s. loadLocale() can be used to access any already loaded, but can't actually load more without require().
<script src="moment.js"></script>
<script src="locales/es.js"></script>
<script>
var es = loadLocale('es');
</script>
Some common patterns for supporting mixed systems, like these are doing, are documented by the umdjs/umd project.

What is 'typeof define === 'function' && define['amd']' used for?

What purpose does the following code serve? What does factory function do here? Here root is window object. Is factory a default java script function? In what kind of scenarios this type of code can be used. This code is from toggle.js from Simon Tabor. Zepto and ender are libraries. Is this mostly used in libraries.
if (typeof define === 'function' && define['amd']) {
define(['jquery'], factory);
} else {
factory(root['jQuery'] || root['Zepto'] || root['ender'] || root['$']|| $);
}
This code checks for the presence of require.js, a JavaScript dependency management library.
If 'define' is not undefined and it is a function and 'amd' (asynchronous module definition) is also defined then the code assumes that require.js is in play.
If this is so then it defines 'factory' and passes jQuery to it as a dependency. Otherwise it sets up the dependencies that the code needs by attaching them to the root object.
As for what 'factory' is: it is not defined by the Javascript framework, it will be a function in the same file most likely. It will take the parameter jQuery.
This is part of a Universal Module Definition (short UMD). It detects the environment and then handles dependencies and exports.
Depending on what environments the module supports (require.js, nodejs, browser, ...), the UMD might look different. See https://github.com/umdjs/umd for some templates of this loader.
What is special here is the loading of the one dependency when running in the browser. It loads jQuery OR Zepto OR ender OR $, whatever it finds first. So it allows the user to load any of this with the <script> tag (and not a specific one).

Module definition to work with node.js, require.js and with plain scripttags too

I am working on a javascript module/library that should work in 3 environments:
in node.js
in requirejs
when simply included using tags into the webpage. In this case the whole module should be hooked up under window.myModule
Do you have any suggestions as to how to write the structure of the library so that it works in all these environments?
EDIT: basically I mean some sort of wrapper code around the library so that I can call the file form any of those three methods and I'm fine...
This requirement and its solution is known as Universal Module Definition (UMD). It is currently a draft proposal. Background and current status is described in Addy Osmani - Writing Modular JavaScript With AMD, CommonJS & ES Harmony article. Look for "UMD" link pointing to various templates you can use.
Quite many other templates can be found on the web - UMD is the search keyword.
(did not find the final link myself yet :)
We're working on the same thing, I think.
And we have some success. We have library (we call it 'slib'), compiled to AMD js files. It does not depend on npm modules or browser, so it can be called from node and from browser.
1) To call it from node, we use requirejs:
file require.conf.js
module.exports = function(nodeRequire){
global.requirejs = require('requirejs');
requirejs.config({
baseUrl: __dirname+"/../web/slib/",
paths: {
slib: "."
},
nodeRequire: nodeRequire
});
}
In any other serverside (nodejs) file we add this line at the beginning
require("./require.conf")(require);
then we call slib's code by:
var Computation = requirejs("slib/Computation");
2) To call slib from browser, we just use requirejs. It handles everything fine.
3) We do not need to call slib from < script > directly.
For production, we use r.js to make a bundle js file with most of dependencies and use it on the page with one < script >. And this script downloads all other deps, if they are not included, using standard requirejs and it does not need requirejs (as far as I remember), it just works alone. This is very flexible for large projects: use requirejs while development, use r.js to bundle core files in production to speed up page load, use whole bundle if you need only one < script > without any other requests. r.js bundles all dependencies correctly, including old js libraries, which were commonly loading using only < script > and accessible by window.myOldLibrary using shim param on config.
It seems you can use browserfy to make some npm modules accessible from slib's code, but we did not tried yet.
Also, using requirejs on node's side, I think, can be simpler (why we need second 'requirejs' function together with node's one?) We just have not investigated it well, but this works.
In any slib module you can write
if (window)
window.module1 = this // or whatever
and it will be exported as old js lib upon load

compile RequireJS to remove AMD dependency

I'm using RequireJS to manage my dependencies in development, but at production I would like to remove all dependencies on an AMD loader. It looks like the RequireJS optimizer creates a file that still uses an AMD load at runtime - I'm just looking to have a static (non-AMD dependent, but still AMD compatible) file, such as what jquery produces (from looking at jquery source, it appears they manually order their dependencies in their grunt file). Is this possible?
I'm open to using other libraries other than RequireJS as well.
Note: This is similar to my other question Javascript requirejs in development but compiled in production, but in this case I want to remove AMD all together.
If you want to have your script loadable via a <script> tag or AMD then you might want to use something based on how my EventEmitter class exposes its self.
// Expose the class either via AMD, CommonJS or the global object
if (typeof define === 'function' && define.amd) {
define(function () {
return EventEmitter;
});
}
else if (typeof module !== 'undefined' && module.exports){
module.exports = EventEmitter;
}
else {
this.EventEmitter = EventEmitter;
}
This exposes the object via AMD, CommonJS (node) and the global object (i.e. window). This has one main caveat, it is intended for single file scripts that just want to expose their class via AMD.
If you have a lot of modules then you may want to first compile the script with r.js, shim AMD with Almond and then use something like the above to expose it in multiple ways above.
https://github.com/kodmax/grunt-stonejs is the answer.
Compiles requirejs based project to a JS Stone.
Basicly zero overhead.
I had the same problem that you.
Finally I solved it, and I have created a basic structure of requireJS project and a Gruntfile that perform the automatization.
Process LESS
Optimize requireJS.
Remove AMD
Replace the scripts tags in the HTML from the require syntax to the script tag sintax.
I hope this helps you.
https://github.com/sheldorn/require-base-structure

Categories

Resources