I'm currently preparing an evaluation JavaScript modularization approaches for my corp. We are in process of defining "JavaScript Best Practices" for our projects, modularization is one of the central questions.
From my research so far revealed two leading approaches:
amd
commonjs
With a huge number of loaders, plugins, libraries etc. around them.
Apart from that there's also goog.provide/goog.require from the Google Closure Library.
Are there further approaches to consider? Any important/relevant specs I missed?
Our requirements, briefly:
Structure JavaScript code in separate files.
Load relevant modules in the runtime.
...without having to include every single file as script tag.
Must not be necessary to maintain an index of JavaScript files.
Support aggregation and minification - ability to build and use a single minified/optimized JavaScript file.
Be able to use modules in different combinations - there are often different web pages/clients which need different subsets of modules.
Supporting documentation (with JSDoc?).
Suitable for testing.
Suitable for web, cross-browser.
Reasonable IDE support.
Potentially:
Aligned with ES6 modules.
Suitable for Node.js and mobile platforms (like PhoneGap/Cordova).
New suggestions from answers:
ecmascript-harmony plus extra compiler.
angularjs (see the note below).
extjs (see the note below).
Side notes:
The question is not about which approach is better.
I am not asking for specific libraries and tools, but rather for approaches and specifications.
I am not specifically asking for an off-site resource. (If there's no SO tag for this, it's probably not reasonable for us to consider it.)
A note on frameworks like angualjs or extjs. This is not really suitable in the frame of this quesion. If the project needs a framework (be it AngularJS or ExtJS) then there's mostly no modularization question as the framework must deliver modularization OOTB. If the project does not need a framework, it is an overkill to bring a framework because of the modularization. This is one of the reasons I am specifically not asking about libraries/tools.
How about ES Harmony?
quote from here: http://addyosmani.com/writing-modular-js/
Note: Although Harmony is still in the proposal phases, you can
already try out (partial) features of ES.next that address native
support for writing modular JavaScript thanks to Google's Traceur
compiler. To get up and running with Traceur in under a minute, read
this getting started guide. There's also a JSConf presentation about
it that's worth looking at if you're interested in learning more about
the project.
hopeThatHelps
Another option: the AngularJS module system, as described here. This is really only useful on the client side, however.
You wrote "I am not asking for specific libraries and tools, but rather for approaches and specifications." however you can look closer to ExtJS 5 environment which fulfils all your requirements.
If you are not interested in such commercial product you can just get to know patterns and solutions in it.
Relation to your requirements:
Structure JavaScript code in separate files.
It implement Object-Oriented Programming paradigm so you can create classes, subclasses, objects, mixins, plugins. It connect class-based programming and prototype-based programming.
Worth noting MVVM architecture (View, Controller, ViewModel), data binding, data session (records/entities client-side management).
Config system is also quite interesting. It's very handy. The config property is merged from parent class to subclasses and also during object creation you can pass config which will be merged too. It is very useful when we want have customizable and flexible components.
Load relevant modules in the runtime.
Each class may has requires or uses directive which are used when builing application to one file. You can also manually load files.
...without having to include every single file as script tag.
In dev env files are loaded dynamically (asynchronous or synchronous).
In prod env necessary files has been built to one minified file.
Support aggregation and minification - ability to build and use a single minified/optimized JavaScript file.
You can build application with Sencha cmd tool (and do a few other things).
You can use three predefined env (development, testing, production) or create your own (based on config files and ant).
Be able to use modules in different combinations - there are often different web pages/clients which need different subsets of modules.
You can use workspaces and packages.
Supporting documentation (with JSDoc?).
JS Duck, tutorial
Suitable for testing.
You can do unit tests (PhantomJS, JSLint, PhantomLint, Jasmine).
You can use dedicated framework like Siesta or other popular testing frameworks like Selenium.
Suitable for web, cross-browser.
From offical website:
Deliver apps on the widest selection of browsers and operating systems
with a single code base. Ext JS 5 leverages HTML5 features on modern
browsers while maintaining compatibility and functionality for legacy
browsers. Confidently deliver apps to your end users regardless of
what browser they are using.
Support:
Safari 6+, Firefox, IE 8+, Chrome, Opera 12+, Safari/iOS, Safari / iOS 6+, Chrome/Android, Chrome / Android 4.1+, IE 10+ / Win 8
Supports Cordova and PhoneGap application.
Reasonable IDE support.
I don't know very good IDE with dedicated support for ExtJS but I work on Webstorm and it's fine. Library sources are inside project so autocompletion works (but not 100% perfect).
Conclusion
I don't want to glorify ExtJS 5. Environment is quite mature and stable but latest version of framework (v5) has a couple bugs and not everything is great. However I could go deeper and get to know principles of that framework which are reasonable, driven in good direction but sometimes bad implemented ;)
RequireJS is a good approach since it enables dynamic javascript module loading as well as it keeps the code clean. You can also minify the whole modules and it actually performs really fast. It also allows something called as shimming where you can specify the dependencies for a library or any js file such that whenever you try to load it, all the dependencies also follow
Take a look at systemJS:
Spec-compliant universal module loader - loads ES6 modules, AMD,
CommonJS and global scripts.
Designed as a collection of small extensions to the ES6 specification
System loader, which can also be applied individually.
Loads any module format, by detecting the format automatically.
Modules can also specify their format with meta config. Provides
comprehensive and exact replications of AMD, CommonJS and ES6 circular
reference handling. Loads ES6 modules compiled into the
System.register form for production, maintaining full circular
references support. Supports RequireJS-style map, paths, bundles, shim
and plugins. Tracks package versions, and resolves semver-compatibile
requests through package version syntax - package#x.y.z,
package^#x.y.z. Loader plugins allow loading assets through the module
naming system such as CSS, JSON or images. Designed to work with the
ES6 Module Loader polyfill (9KB) for a combined total footprint of
16KB minified and gzipped. In future, with native implementations, the
ES6 Module Loader polyfill should no longer be necessary. As jQuery
provides for the DOM, this library can smooth over inconsistiencies
and missing practical functionality provided by the native System
loader.
Runs in IE8+ and NodeJS.
The creator of the lib -- Guy Bedford -- is a great presenter as well: systemJS presentation.
Take a look on a browserify. It implements interesting approach. With browserify you can write code that uses require in the same way that you would use it in Node.
There are various libraries available for modular development,
From which some full fill your criteria.
System.js
System.js is modular development library with some basic features to work with IE8+ and nodejs. It also provides feature to develop modules and you can include it in your main file. For more information about System.js follow https://github.com/systemjs/systemjs
Require.js
The best library for modular development. Provides various useful features and supports older browser too. It supports from IE 6+. Another useful feature of require.js is that it can be used with Rhinojs and nodejs. Implementation is simple as like you include modules in nodejs.
Related
How can I load an existing PDF document as jsPDF object and edit using JavaScript library called parallax / jsPDF which is the top popular JavaScript library for generating PDFs as the time I'm writing this.
I am using the version 2.5.1 the latest as of now.
I searched everywhere and finally I got the answer, wasting too much
time. So I decided to put it here so that anyone can refer it faster.
As at now(28/12/2022) "JsPdf do not have that functionality and probably will never be able to parse existing PDF files. It would mean a major rewrite of its fundamental architecture." as its contributes states here.
There are other libraries support the same functionality like pdf-lib. I extracted the following from their GitHub page.
pdf-lib was created to address the JavaScript ecosystem's lack of robust support for PDF manipulation (especially for PDF modification).
Two of pdf-lib's distinguishing features are:
Supporting modification (editing) of existing documents.
Working in all JavaScript environments - not just in Node or the Browser.
There are other good open source JavaScript PDF libraries available. However, most of them can only create documents, they cannot modify existing ones. And many of them only work in particular environments.
UMD Module
You can also download pdf-lib as a UMD module from unpkg or jsDelivr. The UMD builds have been compiled to ES5, so they should work in any modern browser. UMD builds are useful if you aren't using a package manager or module bundler. For example, you can use them directly in the tag of an HTML page.
https://unpkg.com/pdf-lib/dist/pdf-lib.js
https://unpkg.com/pdf-lib/dist/pdf-lib.min.js
https://unpkg.com/pdf-lib/dist/pdf-lib.min.js
https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.js
https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js
NOTE: if you are using the CDN scripts in production, you should
include a specific version number in the URL, for example:
https://unpkg.com/pdf-lib#1.4.0/dist/pdf-lib.min.js
https://cdn.jsdelivr.net/npm/pdf-lib#1.4.0/dist/pdf-lib.min.js
I'm trying to organize my Javascript code and Require.js seems to be the ticket, but it looks like the optimization tool can only be used with Node (NOTE: I know it says the browser can be used too, but it isn't recommended).
If I'm using PHP, is there any way for me to optimize my Javascript?
My current stack: PHP, Slim 3.0, Twig and Webix
You do not have to use r.js to optimize your AMD modules. Any tool that knows how to read AMD modules and how to produce a bundle from them could be used instead of r.js. I don't know if such a tool exists that is implemented in PHP.
If you are going to use r.js then you must have a JavaScript virtual machine that will run its code. r.js only supports Node, Rhino, Nashorn, or the browser. This is a limited list because r.js needs to be able to read files, and how to do this varies from platform to platform. (This also explains why browser usage is not generally recommended: the limitations in the browser are such that it can only be viable for restricted cases and not for general optimization.)
I'm not seeing the need for Node as being particularly onerous. The first projects I used RequireJS with were for applications backed by Django, which is a Python-based web framework. That's similar to your own situation.
My problem is that I need to combine approximately 200 dojo javascript files. Dojo uses the AMD define/require module system. The dojo built-in tools which use Google Closure and Shrinksafe won't work due to a version mismatch (tool is from 1.11.3 source is 1.11.1).
The dojo build includes steps which reference an AST so I'm assuming that you can't just throw any old code at a "combiner". Presumably global variables and other naming conflicts would be the first problem.
Are the tools generally clever enough to handle any old javascript?
The dojo build tools was specifically designed to build dojo application. You won't be able to easily build using YUI or others (like require.js)
You should be able to build from 1.11.3 even if your code is 1.11.1.
In the process of evaluating the various approaches available to developers to use javascript modules, module loaders and build tools, i'd like some suggestions on what tools you use, and why.
I'm currently after something that is able to:
-encourage modular code
-allow features to be added based on necessity to a given module [think mixins/inheritance]
-produce a BUILD that contains a development release, and at the very minimum a production release with different layers (say, i want a layer [a script] which contains my bootstrap code, module 1, 2 and 3; and then another layer which contains modules 4,5 and 6. This way I can defer loading of code based on what's actually going on in the application.)
-Work [when built for production] in an extremely low bandwidth scenario, with xfer speeds of 1kbps and high latency (think worst case mobile connection over GPRS to get the picture).
I've seen the following:
Using prototype inheritance, as in:
myNS.thing = function(){};
myns.thing.prototype = {
something: "foo"
}
Which can be built by simply taking the contents of this script, and appending it to the next one one wants to include in a production optimized package as a single script. Loaders in this case are simple script tag injections/eval's or similar, based on a known file.
I've also seen other approaches, such as:
function(){
return function(){
something: "foo"
}
}();
Building this already gets more complex because one has to manipulate the script, removing the wrapping self executing function and combining the return values into one object. I am not aware of an "easy" way to use available build tools. The loader approach works the same as above.
Both of these approaches lack dependencies.
Then we have AMD:
define("mymodule", ["dep1"], function(dep1){
return {something: dep1}
});
Some might be nauseated by its indenting, and its "ceremony", but still its quite effective, the google closure compiler knows about it natively, it knows about dependencies, and seems to have widespread adoption across the board. There are a bunch of module loaders available for it (https://docs.google.com/spreadsheet/ccc?key=0Aqln2akPWiMIdERkY3J2OXdOUVJDTkNSQ2ZsV3hoWVE#gid=2) and quite a few build tools as well.
What other options do you know of, or have you seen used in production?
As said, i'm interested in a combination of code syntax, loader tools and build tools. These three must exist and be working together properly. The rest is an academic excercise i'm not interested in.
I personally use RequireJS, an AMD solution. If I'm whipping up quick proof-of-concepts I won't bother setting that up, but the most common source/dep-mapping solutions I know of now include:
RequireJS
CommonJS
Google Closure
YepNope (a conditional loader, can be used in combination with the others)
I have started a boilerplate that uses Require in combination with Backbone to get all the ugly setup code out of the way:
https://github.com/nick-jonas/assemblejs
So you can type assemble init to scaffold the basic project and assemble build to run the compilers and get a final production-ready build.
You might be interested in looking at Grunt a command line tool with various modules for building javascript projects. It uses npm for dependencies and it will work with amd modules, but you can just configure it to concatenate the files you need using grunt-buildconcat.
I'm trying to figure out how to best manage Javascript file dependencies and have that drive the packaging of a 100% front-end app. In short, I'm building an application using backbone.js along with some other libraries. I want an organized codebase and would like to be able to declare dependencies within each file. Ideally those declarations would a) drive the order in which files are loaded by the browser (while in development I want the files to load separately) and drive the order in which the packaging scripts load the scripts for concatenation (I'm aiming to serve a single file for the entire app).
I've been reading on requirejs and commonjs but I'm not convinced.
I have a simple shell script right now that uses cat <file> <file> <file> <file> > concatenated.file to do what I want but it's a pain to maintain that list of files up to date and in the right order. It'd be much easier to be able to declare the dependency at the begining of each javascript file and have the packager and loaders be smart about using that information to concatenate/load scripts.
Any suggestions?
Thanks you,
Luis
I am partial to stealjs myself. It's part of JavascriptMVC but no reason why you can't use it with Backbone.js
The nice part about this one is that it builds your app for production including minifying your css and js and neatly packing all of it into 2 files: production.css and production.js.
It can handle loading non JS files too so you can do things like steal('somefile.css').then(function() {...});
For files, its very much like you would do in other languages:
steal(dep1, dep2, dep3).then(function () {
// code
});
For complex frontend apps Asynchronous Module Definition (AMD) format is best choice. And it's alot of great loaders that supports AMD (curl.js, RequireJS).
I recomend this articles to learn about modern approaches in javascript dependecy management:
Writing Modular JavaScript With AMD, CommonJS & ES Harmony
Why AMD?
For packaging take into account CommonJS specifications, there are few implementations and it's a matter of taste, but in any case I recommend to choose tools, that is compliant with some of that specifications.
It'd be much easier to be able to declare the dependency at the begining of each javascript file and have the packager and loaders be smart about using that information to concatenate/load scripts.
I have had the same idea several months ago and are working on a dependency resolver for my Resource Builder which already makes it easier for me (including the need to distinuish between development and deployed version, with the optional debug parameter).
JsDoc Toolkit (and related efforts), which syntax is supported e. g. by Eclipse JSDT, provides a #requires tag, so you could use that. But resolving dependencies is still not a trivial task (as you can see in ResourceBuilder::resolveDeps()). (The ultimate goal is to use static code analysis to resolve dependencies automatically, without any tags.)
This would reduce the current
<script type="text/javascript" src="builder?src=object,types,dom,dom/css"></script>
to a mere
<script type="text/javascript" src="builder?src=dom/css"></script>
As for asynchronous loaders: The good thing about asynchronous loaders is that they are fast. The bad thing about asynchronous loaders is that – if they work; they are all based on a non-standard approach – they are so fast that you cannot be sure that the features the scripts provide are available in following scripts. So you have to have your code executed by their listeners. I recommend avoiding them unless you really have features in your application that are only needed on demand.