use of 'require' in 3rd party browser js - javascript

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.

Related

How to make a JavaScript library which can work with Browser, NodeJS and Single Page Applications (React etc.)

So what I want to ask is: Is there a way to convert this simple file into a library which can work with Browsers (script tag), Node JS and Single Page Applications using single codebase?
Until now, all I have been doing was using libraries but it never came to my mind that it isn't actually that simple to make one. I am working on a React application where I created a simple helper file with exports. I thought "why not make it an independent library in NPM?". Just as I started testing it independently in NodeJS environment, I came to realize that there is actually a lot of difference in the way both environments make imports.
I have slight knowledge of Webpack, but I don't know how to approach it. Would I need different codes for different environments?
Another thing that confused me was when I thought about "How do we actually import things/functions from libraries?" Like when we install any library from NPM INSTALL and we do "import { abc } from 'library'", does it look for an index.js file in the library folder or what? Or in case of Node, "let lib = require('library')", where it does it look since its a different environment than SPA?
In conclusion, I have a simple single file I want to launch in NPM as a library which could work in any environment.
This is a very broad question, so a very broad answer: Look at tools like webpack, rollup, and browserify which are often used to make Node.js things available in the browser.
Another possibility is to look at how a module like slug is coded such that it works in the browser and in Node.js, but requires some hacks (and a decent test setup) to do it. For example, it checks typeof window !== 'undefined' to switch between code that needs to run in the browser vs. code that needs to run in Node.js. And this bit at the end detects the module system being used and acts accordingly:
if (typeof define !== 'undefined' && define.amd) { // AMD
define([], function () { return slug })
} else if (typeof module !== 'undefined' && module.exports) { // CommonJS
module.exports = slug
} else { // Script tag
root.slug = slug
}

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 () {};
}));

How to add momentjs to a minified bundle file?

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.

Build package for both node and browser environment

I have developed a node NPM package which is mainly a wrapper (using node's http, https and querystring modules) for a specific JSON API. It is build in Coffeescript and enables a Node.js server to communicate with this API. The Api is mainly REST.
Now I want this library to be also available for the browsers. This means the calls to the http modules needs to be replaced with XMLHttpRequest (asynchronous). It seems to me I would make a wrapper for the adapter. For the Node environment, this adapter would pass all the calls to the http module, and for the browser environment to the XMLHttpRequest object.
Is there a nice way to make a build system so that the npm package contains both version, and I can publish the plain "browser-version" also on Github? The node package then is available via require('package-name') and should place a JS file (for the browser) in a directory.
I have looked in Component, which is nice for client-side package managing, but the problem remains how to create different build environments.
An example solution for cross-developing for node.js and browsers using browserify: https://github.com/amitayd/grunt-browserify-jasmine-node-example (and discussion at my blog post) .
Specifically for having different implementations for Browser/Node.js check PersistentReaderWriter.js.
Once you have some template to start working with browserify, and you're aware of some pitfalls, you might find you'd like to use it for small libraries as well.
Edit: Note that if you browserify the module, the isBrowser() check shouldn't be by checking if module and module.exports are defined, since Browserify's wrapper will define them in the module context. Instead, in my example, I check for window to be defined.
You could use node-browser-resolve which adds a browser section to package.json:
{
"browser": {
"./index.js": "./browser.js"
}
}
See https://nolanlawson.com/2017/01/09/how-to-write-a-javascript-package-for-both-node-and-the-browser/
add this at the end of the module. and export your module like this.
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = YourModule;
}
else {
if (typeof define === 'function' && define.amd) {
define([], function() {
return YourModule;
});
}
else {
window['YourModule'] = YourModule;
}
}
I found a solution, although it is not what is first had in mind, with different build environments.
In my case, I had a pretty small library which were using the Node's http, https, querystring and url packages. I did not want to use something like Browserify, because it seemed not appropriate to bundle all these packages for a small api-library. Instead I replaced the http and https functionality with the XMLHttpRequest package. The small functionalities provided by querystring and url could easily be rewritten.
In my library I check, run-time, if the window.XMLHttpRequest object is available. If so, use that (native) object. Otherwise, it uses the one provided by the package. As such:
_getRequestObject: () ->
if window? and window.XMLHttpRequest?
return new window.XMLHttpRequest()
if window? and window.ActiveXObject?
try
request = new ActiveXObject('Msxml2.XMLHTTP')
catch e
try
request = new ActiveXObject('Microsoft.XMLHTTP')
catch e
XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
return new XMLHttpRequest()
An other problem was that exports is not defined in the browser. There are packages to simulate this behaviour, but again, it did not want to bloat the library. So I check, again runtime, if the module variable is set. If so, the object I have defined is set to that, otherwise it is set to the window object:
if typeof module is 'undefined'
window['My-module'] = My_module_object
else
module.exports = exports = My_module_object
This all works for me, because I have no real required dependencies of Node.js which are not present in the browser environment. I am afraid that with larger projects a solution like Browserify is really needed, but I am still curious if there are other solutions, like creating different build-environments when packaging the library for Node.js or when for (e.g.) Bower.

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