Move pure RequireJS project to Maven - javascript

I have project that use bare Javascript (+ Jquery + Backbone) with RequireJS. I include dependencies like:
require.config({
baseUrl: "./js/",
paths: {
jquery: 'lib/jquery-1.8.2',
underscore: 'lib/underscore-1.4.2',
backbone: 'lib/backbone-1.1.2',
'backbone.localStorage': 'lib/backbone.localStorage'
},
shim: {
underscore: {
exports: "_"
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'backbone.localStorage': {
deps: ['backbone'],
exports: 'Backbone'
}
}
});
I want: move project to maven. I don't want to include all that deps in such ugly way. Moreover, I want to use Hibenate, Spring and another deps that should be imported via maven.
Problem: I haven't deep understanding of how do maven plugins or RequireJs work. I looked at this, but understand nothing.
Question: Can you write a step-by-step action points how to move my app to maven?

Maven is not really an answer to the (alleged) "ugliness" of the configuration you showed because it works on a completely different level. To begin with, Maven is a server-side tool and RequireJS is client-side (apologies if you already knew it, but -> "I haven't deep understanding of how do maven plugins or RequireJs work"). This configuration is specific to RequireJS so there's no way to go around it.
Even with Maven you still need to configure your front-end application and tell it where to find the required dependencies and how to initialise them. Client application's paths are web resources which can be arbitrarily different from the file structure of your project so it's not easy to automate the configuration process.
I've been using the RequireJS maven plugin (found it in one of the answers in the same question you posted) for wrapping r.js but it was rather painful to set up, especially with resource timestamping. I just feel that this approach is flawed due to fundamental differences between Java and JavaScript tooling - you'll always end up with a less-than-ideal compromise and any non-standard steps will eat a lot of time and research.
Another approach that's gaining popularity is to completely split your client- and server-side applications into separate projects, allowing you to use language-specific tooling to make the process as smooth as possible. Server-side uses Maven, client-side uses Grunt+Bower+RequireJS+etc. Both sides talk through well-defined interfaces using JSON over HTTP.
It should be easy to find some introductory reading material, but since you're mentioning Spring it could be worth starting by having a look at the reference Spring application: Sagan. It demonstrates how to split front- and back-end into separate Maven submodules that share the same common "core".
A stop-gap solution that makes working with JS libraries with Maven a little bit more civilised is using webjars. You define your dependencies directly in pom.xml and they're easily exposed to the front-end like other static assets. However, this limits your options when it comes to bundling or customisation of the libraries.

Related

MegaPixImage Error From FineUploader When Loading Page with RequireJS

I am refactoring my application to use RequireJS (using the sbt-web abstraction in Play Framework, but that isn't germane).
First, I simply sought to use a shim to load FineUploader since it isn't AMD-compatible, but I encountered a "MegaPixImage is not defined" error. That seemed weird to me since FineUploader has no dependencies (as third-party stuff is built-in).
But after seeing this Stack Overflow post, I downloaded the library separately and set up my RequireJS configuration this way (in CoffeeScript):
requirejs.config(
paths:
megapiximage: './megapiximage'
fineUploader: './custom.fineuploader'
shim:
fineUploader:
exports: 'fineUploader'
deps: ['jquery', 'megapiximage' ]
)
require(['./main'], (main) ->
require(['fineUploader', './myfile'])
return
)
However, I still get the same error even though the library is AMD-compatible.
Any insight into how I should set up my RequireJS configuration is appreciated.
The FineUploader package references the 'MegaPixImage' variable, so you need to make that available. I think the following should work:
require(['fineUploader', 'megapiximage'], function(fineUploader, MegaPixImage) {
// initialize your fineuploader here
})
Note that you have actually included the MegaPixImage library twice now. I therefore decided to keep FineUploader out of my RequireJS setup and add it as a seperate javascript file in the HTML.

What is the best way to distribute reusable JavaScript modules with dependencies?

There are many ways to format JavaScript modules: AMD, CommonJS, UMD, ES6, global script. I've seen projects that structure their source code in whatever way they want and run a build process to generate a dist directory containing code in all the above formats. This has the advantage that the user of the code can just pick whichever format is most applicable to his environment.
This method works fine as long as the module has no dependencies on other modules. In the case where the modules must import other modules, there are implied complications. For example RequireJS uses a config file that looks like:
requirejs.config({
paths: {
'jquery': 'js/lib/jquery',
'ember': 'js/lib/ember',
'handlebars': 'js/lib/handlebars',
'underscore': 'js/lib/underscore'
}
});
Other loaders have equivalent mechanisms for mapping import paths.
If jQuery is a dependency, should the module import it from the path 'jquery'? What if the system in which it is being incorporated stores jQuery at the path 'libs/jquery'? In this case, is it the responsibility of the author of the system incorporating jQuery to provide aliases in the configuration of the import path?
This questioning strongly suggests that a truly reusable module must provide code formatted in all module formats as well as document clearly upon what libraries (and versions thereof) it depends and document what import paths at which those libraries are assumed to exist.
For example I could author a fancy jQuery plugin that I distribute in AMD, CommonJS, ES6, and global variations. I would document that this plugin depends on jQuery version 2.0 imported through the path 'jquery_on_a_path_that_confuses_you'. The would-be user of this plugin must copy the plugin into his project and then configure his module loader or build tool to export jQuery at the path 'jquery_on_a_path_that_confuses_you'.
As far as I can tell:
There is no standard for what to use for import paths.
There is no standard way to express the dependency, version, and import path requirements to the user of a piece of code.
There is no standard remedy to deal with clashing import paths or load multiple versions of a library.
Does there exist any plan to deal with this strange arrangement? To me it seems a little crazy to have module systems that don't know how to name their modules. Am I wrong?
You may want to check jspm.io + SystemJS which is a relatively new package manager and universal module loader which is increasing in popularity.
Please find below some presentations and article on the subject I found useful:
https://www.youtube.com/watch?v=MXzQP38mdnE,
https://vimeo.com/65042246,
https://www.youtube.com/watch?v=szJjsduHBQQ,
http://javascriptplayground.com/blog/2014/11/js-modules-jspm-systemjs/
Late with the answer, but if you're after writing plain JS code (without jQuery or other frameworks), I've found that there's the deploader.js repo, which you can use to wrap any kind of JS into modules and do dependency loading.
May worth checking out.

How to manage requireJS based packages for Node.js applications

Since coming across RequireJS I have started to adopt it wholeheartedly as it seems a great way of organising dependencies etc.
For my current project I have created a 'package' of requireJS-organised modules, which will provide the needed database API, to many node.js applications.
But I have come across a stumbling block ... how can I allow third party applications to use my package, without needing to faff with requireJS?
My directory structure for my applications and API is currently as follows:
api_package/node_modules
api_package/controllers/*
api_package/views/*
api_package/helpers/*
api_package/models/*
api_package/main.js
application_1/node_modules
application_1/app.js
application_2/node_modules
application_2/app.js
I need my applications to be self-contained - so they can be easily deployed - so my current work around is to copy api_package/* into the 'node_modules' directory of application_1 & 2 and setting the their requirejs config to the following:
(function() {
var requirejs;
requirejs = require('requirejs').config({
baseUrl: __dirname,
nodeRequire: require,
packages: [
{
name: 'api_package',
location: './node_modules/api_package'
}
]
});
This feels a little dirty and wrong!
Is there a better way? Am I missing some packaging feature for requireJS?
Is it even possible to hide the implementation details of my api_package (the detail being that I am using requireJS) and allow applications to use it as they would any other module:
require('api_package')
You can use the amdefine package, which allows you to code to the AMD API and have the module work in node programs without requiring those other programs to use AMD.
In addition to the documentation on the amdefine github page, this is also documented on the RequireJS website.

backbone with requirejs

I am building a complex web app and trying to use requirejs with backbone. I found out that backbonejs is a non AMD framework which restricts me to use requirejs out of the box.
I researched on internet and found that there are patches available to make backbone AMD compliant.
Please guide if patching this way is a no-issue setup. Will i run into any issues during the app development due to patching of core file in backbonejs?
I apologise if its a stupid question :)
Nope, it's not a stupid question. We actually have done this and is working fine for us, so far :)
You can follow this guide on how to do it: http://kilon.org/blog/2012/08/build-backbone-apps-using-requirejs/
Don't forget to read the chapter on unit testing it with Jasmine. Pretty nice combination all together.
Before Require.js 2.0, you have to patch Backbone to be AMD compliant. You can find some AMD-compliant forks of Backbone on github(e.g. amdjs). Fortunately, Require.js 2.0+ added support for loading non-AMD compatible scripts by using the Shim configuration. Example:
requirejs.config({
shim: {
"backbone": {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
},
paths: {
// as usual
});

Javascript app as an AMD module with external dependencies

I am writing a Javascript application that is supposed to be hosted on various sites. The application itself uses jQuery and jQuery UI. I am aware of jQuery.noConflict(true) trick and using it currently so not to pollute the global space. My aim is to always keep jQuery and any of its plugins local to my application so as not to conflict with anything on the hosting site. It should be possible for the hosting site to load its own jQuery (maybe different version) and add some plugins.
Now, I would like to structure the app as an AMD module. It is OK with me to require from the hosting site to use an AMD loader (require.js, curl, etc.) but I wouldn't like to require any particular one - just anything conforming to AMD API (yep, I know it's not 100% ready yet).
Is it at all possible? Can I do it in an interoperable way, so that the hosting site can use e.g. either requirejs, curl or Dojo AMD loader?
For example, with this:
define(['jquery'], function($) {
var myLocaljQuery = $.noConflict(true);
... my app module implementation here ...
});
how can I specify the path for jQuery that my application wants to use? As far as I understand, I cannot do anything like this:
require.config({
paths: {
'jquery' : 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min'
}
});
define(['require'], function(require) {
require(['jquery'], function($) {
var myLocaljQuery = $.noConflict(true);
... my app module implementation here ...
});
});
because the first require is a global object and this is specific to requirejs.
After doing some more research, I think it is not feasible at the moment. At least for one thing - the module ids are global within AMD context, so I cannot simply use "jquery" or "jquery-ui" module IDs in my application and be sure that there won't be any conflict when someone hosts my application and wants to use jQuery (potentially other version) through AMD too. See for example here:
curl.js does not prevent conflicts with third-party scripts that may load other versions of jQuery as an AMD module.
As far as I understand, AMD is aimed at modularizing stuff within your own app. It doesn't have much support for integration with third-party apps, at least not when you want to do some encapsulation to avoid conflicts.

Categories