How can I create a JS library in scala-js? I am using standard Play/Scala server + scala-js client with shared objects. I want my library to be on URI /api/mylib.js.
I don't know how make scala-js client project without main method. Also how to generate scala-js code to the specific URL I need.
To write a JS library, you need to export the public API to JavaScript.
You will also likely want to disable the generation of the "launcher", which looks for a JSApp in your classpath and calls its main method. Otherwise fastOptJS will complain that it cannot find any JSApp. You can do this with the following sbt setting:
persistLauncher := false
Edit: See also the blog post How to make an idiomatic Javascript library with Scala.js
I am working on a mobile single page site that uses breeze js, angular js, web API, entity framework, etc.
To optimize the site, I included the breeze metadata in a bundled JavaScript that contains all the other JavaScript the site needs. Ideally, all I would like the browser to request is index.html, which should contain everything the app needs to run including bundled and minified inline styles and JavaScript.
However, just as the breeze metadata is very important for the site to function and is therefore embedded in the bundled JavaScript, there is also a required complex entity (with some deep navigation properties to some other entities) that must also be present for the site to be fully functional. I would like to embed this entity and all the entities it references in the bundled JavaScript as well. How can I do this?
I can always create a JSON string that represents this entity and all the entities it references. Then embed that JSON string in the bundled JavaScript along with the rest. However, how can I easily import this complex entity into the breeze entity system using the entity JSON string I have embedded in JavaScript? Or is there a better solution to preload the breeze entity system with a complex entity without having to make a request for that entity from the server?
I would also like to avoid writing server code to spit out JavaScript that creates the entity on the client.
Simplest approach would be to use the "initializer" argument to the EntityManager.createEntity call.
See
http://www.breezejs.com/documentation/creating-entities and http://www.breezejs.com/sites/all/apidocs/classes/EntityManager.html#method_createEntity
This call looks this.
myEntityManager.createEntity("Employee", { lastName: Smith", firstName: "John" });
So in your case you could try:
var initialValues = JSON.parse(json);
myEntityManager.createEntity("Employee", initialValues);
Depending on your use case you may want to also set the 'entityState' of this newly created entity as well.
Here's a technique I often use to create entity data for automated tests:
Preparation
prime an EntityManager with the entities (and entity graphs) that you want available at launch.
export as a string with var exported = manager.exportEntities();. The exported string has the metadata embedded in it so you won't have to bring that down separately. Two-for-one!
capture the contents of exported to a JavaScript file that you load as script in index.html. My "capture" process is usually just to display in the console and scrape it.
Usage
Now when you need it:
load that JavaScript metadata+data file.
create a new EntityManager (remember to target the same dataservice endpoint).
import the entities you captured in your script: manager.importEntities(launchData);.
And you are good to go.
Read up on the EntityManager exportEntities and importEntities methods.
Example
One place you can see a variation on this technique is in the test directory of the "Zza-Node-Mongo".
I personally do not combine the data with the metadata so I export using the "no metadata" option. I put the metadata in one script and the data-to-load-on-launch (lookups usually) in a separate script and load both in index.html.
Caution
You say
to optimize the site, I included the breeze metadata in a bundled JavaScript that contains all the other JavaScript the site needs. Ideally, all I would like the browser to request is index.html, which should contain everything the app needs to run including bundled and minified inline styles and JavaScript.
Beware of premature optimization
I rather doubt that you will measurably improve the launch time of the app by embedding metadata and launch date in script files. Maybe some of the time if the browser caches these scripts. But that comes with its own risks and isn't a reliable strategy.
The data you want has to come over the wire to the client one way or another. It isn't self-evident that loading a script file - even a minimized script file - is any faster than pulling the metadata and launch data (both gzipped) down from the server via a web api AJAX call.
The techniques I described do speed up testing because I have to recreate metadata and the launch data before each test. I can measure the performance gain from avoiding repeated trips to the server. I gain nothing for the first trip ... which is the equivalent of your application launch.
Be mentally prepared to discover that your hard earned optimization efforts did not improve launch times ... and might even make them worse for some users.
Here is what I intend to build:
There is a service providing data with RESTful JSON-only API. The server setup is Python + Flask.
There are several clients making use of this API, like a normal web app, mobile-compatible client and a Facebook App.
Now, my assumptions/decisions:
I decided on the server providing only data through JSON, thus handing over the presentation completely to the client-side.
I desire to make the web app mobile compatible, thus eliminating need of a separate mobile client.
Also, for Facebook app, I decided to use Facebook Canvas, which would render parts of the normal web app, thus reusing the code.
Feel free to correct me if anything is wrong in above assumptions. Though the above is theoretically possible, I would like to know if the practical implementation is feasible or not.
Now, the web app, after having fetched the base page/template from server, will have to handle the rendering dynamically after fetching data through JSON API. The data is quite simple: multiple-option questions, answering which user receives another question. At the end, user can share the result or invite other users.
With this setup, do I need a framework like angularjs or jQuery would suffice?
My main concern here is how do I handle internationalization? I initially intended to user Flask-Babel to internationalize HTML templates. But having zeroed in on JSON-only API, I don't have a clue as to how/where I handle it now: on client-side or server-side? What are the tools I use for it?
One approach I could think of was to have data in different languages on server itself, and send the JSON response with data in appropriate language, depending on some attribute the client sends in request.
Another approach is to let client do all the translation for a common dataset that server sends. I am not sure of this approach though.
You could find this plugin really helpful.
As far as the usage , it is quite simple to set it up for a single page application that is powered by a JSON API.
If we take a look at a sample usage :
HTML:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="[PATH]/jquery.js" /> // optional
<script type="text/javascript" src="[PATH]/i18next.js" />
</head>
<body>
<ul class="nav">
<li></li>
<li></li>
<li></li>
</ul>
</body>
Json (loaded resource):
{
"app": {
"name": "i18next"
},
"nav": {
"home": "Home",
"page1": "Page One",
"page2": "Page Two"
}
}
JS:
i18n.init(function(t) {
// translate nav
$(".nav").i18n();
// programatical access
var appName = t("app.name");
});
https://github.com/wikimedia/jquery.i18n may be close match. It can handle a lot of languages and messages are in json files and it is complete client side library.
If all of your interface code lives on the client side, so should your i18n. You would use a i18n library that works with the JavaScript framework you are using. For angular, that might be angular-gettext.
If you are developing several client you might use different i18n libraries in different client applications. Try to make sure they all compile gettext .po files – it will make it easier for your translators.
Using jQuery, Angular, etc. is a decision you should make based on your comfort with the technology, the needs of your application, and compatibility with the Facebook Canvas approach. Angular has powerful data binding, but it requires a mind shift compared to jQuery, for instance, so I suggest poking around with each to see if they meet your needs.
As for internationalization, you can use a plugin like jQuery.i18n, or you could roll your own, something I have done with jQuery and jQuery.Mustache for templating. The short version is that you use HTML templates to store your layout, then render them from inside jQuery like so:
var data = {myLabel: 'Some label', myOtherLabel: 'Some Other Label'};
$("#myDiv")
.html( $.Mustache.render( "MyTemplateId", data ) );
in html template:
<script type="text/html" id="MyTemplateId">
<div>
<label for="myInput">{{MyLabel}}</label> <input name="myInput" id="myInput type="text"/>
<label for="myOtherInput">{{MyOtherLabel}}</label> <input name="myOtherInput" id="myOtherInput type="text"/>
</div>
and on your page layout:
<div id="myDiv>
<!-- dynamic content inserted here -->
</div>
You use a loader command with jQuery.Mustache (https://github.com/jonnyreeves/jquery-Mustache) to load your templates from the server, and since you are using templates, you can fill in your values based on user language selection. How you store your internationalized data is dependent on your app. As Michael suggested, if it is a small amount of static content, maybe you just store it all in your JS files as constants and load into your Mustache render() methods as needed. If you have a larger amount/dynamic multilingual content, you should probably store it on the server and load it dynamically. One consideration is the number of languages you plan to support. If you go beyond a handful of languages, consider storing it on the server and loading language data on demand.
I like this approach because it gives you granular, runtime control over your layout and over internationalization. It also stores the data on the server but loads programatically from the client, maintaining a clean separation of concerns for your application layers.
As for responsive/mobile friendly design, using templating (Mustache) and checking the viewport at load time allows you to determine browser capabilities and serve the approrpriate layout without having to prompt the user to select a mobile/desktop experience.
If you go this route, you should also research script loaders like RequireJS and StealJS to handle dependency loading for your scripts, and to handle the initial browser check and layout generation.
Your question is too broad. I can only answer part of it and here are some of the answers:
I desire to make the web app mobile compatible, thus eliminating need of a separate mobile client.
In order to make sure that things are working fine you need to handle
Also, for Facebook app, I decided to use Facebook Canvas, which would render parts of the normal web app, thus reusing the code.
I am not sure.
With this setup, do I need a framework like angularjs or jQuery would suffice?
As you tagged that you are targeting this as a single page application. Therefore, I would recommend you to go for single page frameworks like Anglarjs, knockout.js or Node.js. A quick and good comparison between these frameworks can be found from here
Also this post shares how to implement Internationalization in Angularjs
My main concern here is how do I handle internationalization?
some of these frameworks provide support for handling internationalization and localization natively. For other you can find some links that will help you achieve internationalization.
Whereas if you use jQuery you will to define your own framework for handling single-page-application and apart for that you will need a huge bunch of add-on's to accomplish your objective.
Hope this helps!!!
Steps to implement i18n via js & json:
define css class for i18n tag, e.g. <span class="i18n" id="i18n_username"></span>
define i18n values for different language in different .properties file, e.g. in userhome_en_US.properties, there is a key value: username = Username
write backend API to load .properties file by language, and return in json key-value format, e.g. send param: lang=en_US, page=userhome to I18nAction -> loadI18n(), then it will return json value via ajax: {"username":"Username"},
write js function to load i18n key-value by lang & page param,
update i18n text on web page, by get the tag via css class, and replace content, e.g. use jquery to get all span tag that has class="i18n", then remove the i18n_ prefix of the id, then use it as key to get the value from returned json, then replace the content of span,
I did write util programs like this, it's quite flexible & easy to use. The basic concept is come from struts2 framework's i18n feature.
Although I don't know your technical constraints in detail, I believe it all depends on your volume of data :
If you have few "questions / answers" that probably won't evolve much over time, you can treat I18N as constants. Putting everything on the client side makes sense.
If you have a big amount of "questions / answers" that will probably evolve, I believe you have to treat I18N as data.
Since you have made a JSON API, the odds are that your Q/A is your data, and it already belongs to your server side.
The real question is : do you want to deliver a new version of your client app everytime you add or correct a question?
That's why I would do this :
One approach I could think of was to have data in different languages on server itself, and send the JSON response with data in appropriate language, depending on some attribute the client sends in request.
edit (precision) : I'm talking about the questions and answers. For the application messages (menus, text, help messages, etc), you should use your client framework's i18n components. The other answers provide a lot of good tools.
Am trying to create this infrastructure using wro4j, with which a user can decide which js files to bundle by just editing the template and not touching any java code.
So, some request like http ://.../bundle/scrip1.js/scrip2.js/script3.js/script4.js
would return a bundle that has all four scripts in the order asked for.
But, having to specify the group with resources beforehand in xml or in a custom WroModelFactory implementation still does not give enough freedom to create bundles based on requests.
Any ideas on how to go about this ?
The best way to handle this seems to be, to wrap the WroFilter in a custom filter, intercept the call for bundling and store the bundle information in a location that the WroModelFactory can pick up and create the model accordingly.
I am using require.js to require JS modules in my application.
I need a way to bust client cache on new JS modules, by way of a different requested URL.
i.e., if the file hello/there.js has already been cached on the client, I can change the file name to force the browser to get the new file.
In other words, for the module hello/there, I'd like require.js to request the url hello/there___v1234___.js (the file name can look different, it's just an example), according to a version string which is accessible on the client.
What is the best way to achieve that?
I got really frustrated with the urlArgs solution and finally gave up and implemented my own fix directly into require.js. This fix implements your ideal solution, if you are willing to modify your version of the library.
You can see the patch here:
https://github.com/jbcpollak/requirejs/commit/589ee0cdfe6f719cd761eee631ce68eee09a5a67
Once added, you can do something like this in your require config:
var require = {
baseUrl: "/scripts/",
cacheSuffix: ".buildNumber"
}
Use your build system or server environment to replace buildNumber with a revision id or software version.
Using require like this:
require(["myModule"], function() {
// no-op;
});
Will cause require to request this file:
http://yourserver.com/scripts/myModule.buildNumber.js
The patch will ignore any script that specifies a protocol, and it will not affect any non-JS files.
On our server environment, we use url rewrite rules to strip out the buildNumber, and serve the correct JS file. This way we don't actually have to worry about renaming all our JS files.
This works well for my environment, but I realize some users would prefer a prefix rather than a suffix, it should be easy to modify my commit to suit your needs.
Here are some possible duplicate questions:
RequireJS and proxy caching
Prevent RequireJS from Caching Required Scripts
OK, I googled "requirejs cache bust" for you and found this existing SO answer, which says you can configure requireJS with an urlArgs parameter, which is only a partial solution, but it might be enough to meet your immediate needs.
That said, the cachebusting problem is full of challenges and many "solutions" don't actually solve the problem in its entirety. The only maintainable way to do this (IMHO as of now) is with a full-on asset management system like the Ruby on Rails asset pipeline or connect-assets or the equivalent for your server side framework of choice. Those can correct compute a checksum (usually MD5 or SHA1) of the content of each file and give you the file names you need to put as URLs in your HTML script tags. So, don't bother with manually changing filenames based on version numbers, just use checksums since they are easily automated and foolproof.
From what I can tell, out of the box requirejs can't do the cachebusting aspect for you. You might want to read this google groups thread. Otherwise, you may need to pair requirejs with an additional tool/script to get you good cachebuster checksums.
Just do it like the creator of requirejs suggests:
var load = requirejs.load;
requirejs.load = function (context, moduleId, url) {
// modify url here
url = url.substring(0, url.lastIndexOf('.')) + '.' + VERSION + url.substring(url.lastIndexOf('.'));
return load(context, moduleId, url);
};
https://github.com/jrburke/requirejs/wiki/Fine-grained-URL-control
HTML5 Boilerplate has ant-build-script that renames your files and any reference to them for this exact reason and can do alot more. It's worth checking out if you haven't already.