This is my first time writing a very basic JavaScript library and now I intend to publish it. I wrote it as a function and users can simply import the JavaScript file over a CDN. I intend to publish this to NPM too, so users can use it with JS bundlers too.
I created another file to match the Node.js format, basically, I added module.exports = before my function and that's all working. So, now I have ended up with two files with basically the same code, one for CDN and one for NPM. Is there any way to unify this, basically merge it all in the same file?
I would really like to know how this is usually done. When a function is written to be imported as a CDN, how does it get converted to a Node Module? Is creating a separate file the only way, or am I missing something?
This question is easily answered with a quick google search, but I thought it an interesting and well written question nonetheless so I'm transcribing some of the results here to help anyone else:
From this blog post:
UMD
UMD (Universal Module Definition) is a block of code we can use to wrap around our library. This block of code makes it possible to use a library both on the frontend and in Node.
It kinda looks like this:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node.
module.exports = factory(require('b'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.b);
}
}(typeof self !== 'undefined' ? self : this, function (b) {
// Use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
You can read more about UMD here.
Usually I would recommend you use a bundler / build tool to automate this for you and make the code available in even more environments.
Webpack is a a good choice for this.
Related
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
}
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 () {};
}));
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).
I'm curious if anyone else is using a similar approach to mine and or if anyone has a thought or suggestion to help improve the workflow. To my knowledge, this is a somewhat original method.
So basically, I'm using NodeJS to development my client side code. I use Grunt+watch to automatically concatenate and minify all of my projects source into a single .min file, which gets written to the public/js folder. However, for testing I use Jasmine-node and so I need to have an index file (for this purpose only) which requires all of the project source files. However, because I want the same code to run in both Node as well as the browser, I add everything to a global project namespace such as:
myApp.framework.someClass
Within the myapp.js file, I then export to node (if module + exports exists). This allows all of my objects to be exposed to node without having to add the module.exports stuff to every source file, and instead, I can either simple do:
(function() { myApp.framework.someClass = function() {...} })();
in each file, or even simply:
myApp.framework.someClass = function() {...}
This works incredibly well for the client because everything is already there in memory, however the downside is that in Node, sometimes trying to access another class within the myApp namespace will fail because I'm not using something like RequireJS to manage dependencies.
My thought was maybe to add requires to the files just as you would in a standard node app, but then in the build process, have any node specific stuff, stripped out.
Thoughts / comments please!
I have seen tricks like this being used to make the JS code be used in Node and browser environments. This is from async library:
// Node.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
// AMD / RequireJS
else if (typeof define !== 'undefined' && define.amd) {
define([], function () {
return async;
});
}
// included directly via <script> tag
else {
root.async = async;
}
https://github.com/caolan/async/blob/master/lib/async.js
Hope that helps!
I have been investigating how various module concepts can be applied within NodeJS and browser applications using the the NodeJS require (obviously in NodeJS apps) and RequireJS for the web browser environment.
It then dawned on me that some modules may be useful for use by both the client and server applications and thus could be reused.
How can modules be developed so that they are compatible with both of these environments?
One is synchronous and one asynchronous. My first thought was to utilise the asynchronous syntax and then to define a custom module for NodeJS which simply invokes the asynchronous callback, synchronously. But how would the RequireJS-emulator be included into the cross-environment module without first using the NodeJS synchronous callback?
See this post : Bridging the module gap between Node.js and browsers
See also the set of boilerplates at https://github.com/umdjs/umd
About async vs. sync -- for define() in Node, it is common to just use synchronous execution of the factory function passed to define. That is how requirejs works when running in Node.
The http://uRequire.org project bridges the gaps of the AMD & nodejs / commonJs formats. U can write in either (or both), and execute / deploy to any of the two or a standalone.js.
check this resource here: it's Not Hard: Making Your Library Support AMD and CommonJS it explains everything very well
I will post the take-away code you need, but to understand everything you should read that article
by this code, you added AMD(requireJs) and Node support for your js library
(function (global, factory) {
if (typeof define === 'function' && define.amd)
define(['jQuery'], function ($) {
return (global['toaster'] = factory($))
});
else if (typeof module === "object" && module && typeof module.exports === "object")
module.exports = (global['toaster'] = factory(require('jquery')));
else global['toaster'] = factory(global['jQuery']);
})(this, function ($) {
// implementation goes here
var myModule = {};
return myModule;
function helper() {
}
})
one more thing, I found out this Universal Module Definition GitHub project for all variant implementations you can check them all