How to uglify an angular project using grunt? - angularjs

I'm trying to deploy a meanjs project but can't seem to figure out how to minify,concat&uglify the project using grunt.
What I've found out so far :
Need to run concat -> ngAnnotate -> uglify (else code won't run)
need to concat in dependency order (else it won't run)
With this logic I've managed to create a single 'uglified' version of the relevant 3rd party libraries (node modules), but I'm unable to do the same for the modules I've written.
I've tried using concat tools that are supposed to reorder the files according to dependencies (grunt-concat-in-order, grunt-concat-dependencies, grunt-concat-deps) but nothing helped. Just errors of missing modules/declarations.
I've tried reordering the js files that should be concatenated, and each time something else is missing and the site loads partially (at best).
reordering the files according to the order they appear in the compiled header doesn't help.
Is there something that concats Angular files according to their dependencies or or a general logic in which I should reorder them?
Thanks.

FOUND IT!
apparently JS and Angular are flexible with missing ';' in the end of module/directive declarations.
I've went through the entire code and added missing ';' in the appropriate places.
For example:
angular.module('core').filter('xyz', [function() {
.....
}])
Finally can go to sleep.
*original post:
Angular module().factory() is not a function after concat (gulp) (cheers to Max Yari)

The first thing to check is that you actually use the DI pattern everywhere in your code as the function parameters will be replaced during uglification and thus won't be resolved let anymore.
ControllerName.$inject = ['component']
Or
angular.module('module')
.controller(['module', function (module) { /*... */}) ;
When you've done that, check if you may explicitly specify file order like this (pseudo code):
['module1_decl_file.js','module2_decl_file.js', '*.js','**/*.js']

Related

What is the correct usage of the mixin classs for TCL language?

Im attempting to update an old version of the selenium-tcl package to work with the new W3C WebDriver (or Selenium 4.0).
Original packages uses a few mixins for the webdriver class.
So I modeled what I saw and created a mixin file named mixin_action_chains.tcl [1] which has a mixin class called Mixin_Action_Chains.
Whenever I attempt to use it I get the error:
% package require selenium
::selenium::Mixin_Action_Chains does not refer to an object
Im not sure why I've modeled it pretty much exactly as I have seen in the other files such as mixin_for_scrolling.tcl [2]* file. What am I missing.
Here is the entire GitHub Repo
Im not sure what else must be done for TclOO. Any thoughts.
Thanks
Im not sure what else must be done for TclOO. Any thoughts.
Update
pkgIndex.tcl: The placement of the mixin-defining script mixin_action_chains.tcl is wrong, it comes after the mixin has already been required in the previously sourced script webdriver.tcl, like entering directly:
% oo::class create C {
mixin ::not::defined
}
::not::defined does not refer to an object
You need to change the order of source command calls in the package ifneeded script.
For the records
Still, in the original version, there were unbalanced curly braces and brackets in your script, which broke sourcing of the file for me:
https://github.com/SavSanta/w3cselenium-tcl/pull/1

How to jsx format supported in spacevim editor?

My spacevim config file: init.toml
[[layers]]
name = "lang#javascript"
auto_fix = true
enable_flow_syntax = true
To get Vim to support a certain syntax, it has to be given the relevant .syntax file. This can be done manually, or by installing a plugin that loads it for you.
I've never used SpaceVim (I used SpaceMacs once, a couple eons ago), but looking through its documentation, the [[custom_plugins]] section looks promising. I've mocked up an example to get you started:
[[custom_plugins]]
name = "MaxMEllon/vim-jsx-pretty"
merged = false
However, this method will only yield limited results. This will only get Vim to recognize the syntax and highlight accordingly; if you want full linting capability, it looks like this GitHub user created a script to modify the bootstrap#after section of SpaceVim to use ESLint, which supports JSX. Note that you have to have ESLint installed for that to work.
For anything this "extreme", it looks like modifying the bootstrap.vim file is the only real way to go. In case you ever want to do further customization outside of SpaceVim defaults, I highly recommend getting Vim/neovim and installing the plugins yourself.

How to merge multiple html files into one with brunch.js

I'm using underscore.js for my templates which are stored in multiple separate XXX_tpl.html files inside sections similar to:
<script type="text/x-template" id="tpl_XXX">
<h1>hi</h1>
</script>
Which I am then using inside backbone.js views as follows:
render: function () {
this.$el.html($('#tpl_XXX').text());
}
I am now using brunch.js build tool which nicely outputs all my libs/js/css code into several optimized files but I am having issue with managing / organizing my templates. How do I make brunch.js build tool to append all *_tpl.html files at the end of index.html? All the examples I am seeing online show how to use brunch.js to merge templates into .js files but I don't yet understand how that works (the templates are a mix of html/js and I lose both access by ID and syntax formatting/highlighting when storing templates in .js files).
Q1. If what I'm doing is right (multiple templates in multiple different .tpl.html files all appended at the end of index.html when built) then how do I make build.js merge all of that?
Q2. If what I'm doing isn't right, what's a better approach to:
have multiple templates that are organized and easily managed
not create additional http requests to pull / all compiled into a single file
have easy access from backbone.js models
want to achieve syntax highlighting in my IDE for the template markup (i.e. no JS string concatenations, etc)
Nice question, but I don't know if you understood how underscore templates should work precisely. Let's try to clear that up first.
Template compilation
An underscore template source is any text with interpolated code. For example:
var myTemplateString = "hello: <%= name %>";
When you want to use that template, you need to compile it into a function first. What? Here's how it works:
var myTemplateFunction = _.template(myTemplateString);
This creates a myTemplateFunction which contains your template logic. In a very simplified, pseudo-code way, you can expect myTemplateFunction to work somewhat like this:
function (context) { return "hello: " + context.name };
So, now you understand why you can call this function and produce a string!
myTemplateFunction({name: 'moe'}) // hello: moe
Using compiled templates
OK, but why do you need to compile it previously? Why not always call directly:
_.template(myTemplateString)({name: 'moe'})
Because compilation can be CPU-intensive. Therefore, it's much faster to use a pre-compiled template. You should not force the user's browser to do it! You should do it for him!
Delivering compiled templates
By now, you understand you don't care about delivering the text of your functions to your client, only the compiled template functions. There are many ways to accomplish that.
Brunch has a bunch of plugins for pre-compiled templates, but apparently none for underscore: http://brunch.io/plugins.html
You can use webpack and it's EJS template loader.
Your code would look something like this:
var myTemplateFunction = require('./template.html')
console.log(myTemplateFunction);
You can also use Grunt and it's underscore template task: grunt-contrib-jst.
Whichever you choose, they will all work similarly: they'll compile your template into a function and you'll be able to use that function. Personally, I recommend learning webpack!

underscore backwards compatibility

I'm trying to play around with a backbone app that was made with an older version of underscore (1.2.0) inside a newer rails app that has a more recent version of underscore loaded (the underscore that comes with the current version of backbone-on-rails gem), so this is a backwards compatibility issue, which I can't figure out even with the help of the changelog http://underscorejs.org/#changelog, however, it's happening when I'm trying to save data.
Context:
A Company, created by the Companies collection, is trying to save (with the setBucket function) the id of the Bucket it is contained in (see code below).
This is the error I get when I try to save data.
Error
<error>
_.extend
_.clone
_.extend.toJSON
_.extend.save
_.extend.update
Backbone.sync
_.extend.sync
_.extend.save
window.Company.Backbone.Model.extend.setBucket
window.AppView.Backbone.View.extend.createCompanyOnEnter
jQuery.event.dispatch
elemData.handle.eventHandle
Source Code
...(code ommitted)...
var company = Companies.create({text: text}); #this works. company is created
company.setBucket(initialBucket.id); #this triggers the error
....(code ommitted)
setBucket: function(bucketId) {
this.save({bucket: bucketId}, {silent: true}); #the function that's not working
You can run two versions of Underscore simultaneously. Simply load your version of Underscore on the page first, then add this line:
var underscore = _.noConflict();
to alias your version of Underscore to the underscore variable (you can of course use a different alias if you prefer). Then run a find/replace on all of your existing Underscore-using code to replace "_" with "underscore" (or your alias).
Finally, load your Rails app and it version of Underscore to the page. It will get the _ alias, and your code can use its version without impacting your library's version.
* EDIT *
Ok, here's a little more background. In Javascript (just as in Ruby I believe) functions are first-class objects. This means that _ isn't technically the Underscore function itself, it's just a variable that points to the "true" Underscore function (which is itself an object). This also means that you can make aliases to functions the same way you do with any other variable. Just as you can do: var a = 5; var b = a you can also do var b = _; and then you could do b.map() or whatever. Well, almost; because Underscore keeps an internal reference to Underscore, you need to update it, which is where noConflict comes in; that code really should have been: var b = _.noConflict();
By the way, it also means you can go the other direction and change _, if you want: _ = alert; _('hello world').
So, what's currently happening with you is that you bring in Underscore on to your page. Presumably you're doing this by putting an <script src='underscore.js'></script> in your main html.erb file. This brings in Underscore version #1. Then you load your Rails app; I'm not sure exactly how this is working, as it depends on your app, but somehow that app is putting another script tag on the page, pointing to Underscore version #2.
This is a problem, because Underscore version #2 just replaced your version #1 (the same way I replaced _ with alert just now). This breaks your code. You could fix it by just adding your <script> tag after the one from your Rails app. This would restore version #1 and fix your code ... but break your app's code.
What you really want is for your code to use version #1 and your app's code to use version #2. Which is where my original answer comes in: by re-aliasing version #1 of _ to underscore (or anything else), your Rails app can keep referencing version #2 as _, and your code can keep using version #1 as underscore.

ExtJS MVC, dynamic loading and i18n

I would like to translate my ExtJS application in different languages. My issue is that I'm using ExtJS MVC framework, and most of my JS files are downloaded dynamically by the framework itself.
The ideal solution (that I thought of) would be to have an extra option in the Ext.Loader (or in my Ext.app.Application) that would define the language to use, and depending on this to automatically download such file as "a.MyClass.fr.js" after loading my "a.MyClass.js" (which would contain an Ext.apply, overriding my string resources). That's probably not available in the ExtJS framework at the moment.
The alternative solution I can see, is to perform a trick on the server-side. First, a cookie would be created on the client, to set to the language. On the server-side, I could catch all the requests to JS files, then if a cookie is set (='fr' for example), I'd combine the requested JS file (MyClass.js) with its i18n's friend (MyClass.fr.js) dynamically on the server and return the result. That would work, but it's really tricky because it implies other things (caching...).
Maybe the best way is to implement the first behavior I described in the ExtJS framework myself...
What do you think? I'm looking for a really clean and neat way of doing it! Thanks :)
I recently struggled with the same problem.
Finding a clean way to do this was quite a challenge - most alternatives were either..
1) Duplicate your code base per locale (WTH)
2) Download localized files overriding each of your components (Maintenance hell? What about the poor translators?)
3) Use/generate a static file containing translations and refer to it (All languages are downloaded? Extra build step to generate it? How do you keep them in synch?)
I tried to get the best of all worlds and ended up with a utility class responsible for:
1) Loading the ExtJS translation files (which basically apply overrides to extjs base components)
2) Loading a locale specific property resourcebundle (specifying which locale to load) from the server.
3) Prototyping String with a translate() method which queries the loaded store (containing the message bundle from the server) and returns the translation based on the value of the string.
This is the gist of things:
Bundle & prototyping:
localeStore.load({
callback : function(records, operation, success) {
// Define translation function (NB! Must be defined before any components which want to use it.)
function translate() {
var record = localeStore.getById(this.valueOf()) ;
if(record === null) {
alert('Missing translation for: ' + this.valueOf()); // Key is not found in the corresponding messages_<locale>.properties file.
return this.valueOf(); // Return key name as placeholder
} else {
var value = record.get('value');
}
return value;
}
String.prototype.translate = translate;
callback.call(); // call back to caller(app.js / Ext.Application), loading rest of application
}
});
As an example from a view:
this.copyButton = Ext.create('Ext.button.Button', {
disabled: true,
text: 'DOCUMENT_LIBRARY_MENU_COPYTO_BUTTON'.translate(),
action: 'openCopyDialog'
});
Bundle on the server (mesages_en.properties):
DOCUMENT_LIBRARY_MENU_COPYTO_BUTTON=Copy file
etc..
Pros:
No-fuss code, 'Your_key'.translate() makes it easy to read and aware that this is a localized string
None/little maintenance overhead (Keeping an override file for each locale? Jesus..)
You only load the locale you need - not the whole shabang.
If you really want to, you could even have your own translation for the ExtJS locale files in the same bundle.
You could write unit tests to ensure that all bundles contain the same keys, thus avoiding orphaned translations later
Cons:
Synchronous - the store must be loaded before your main app starts. I solved this by adding a callback from the utility class which was called once all texts were loaded.
No real-time population of texts.. though I didn't want to make my users overload the server either :P
So far my approach has worked out pretty well for my requirements.
Site load isn't noticeably slower and the bundles (containing ~200 keys/values per bundle) measure out at ~10kb during load.
There is currently no solution so I decided to create my own hack/addon on the Ext.Loader. I uploaded the code on GitHub: https://github.com/TigrouMeow/extjs-locale-loader. It's exactly what I needed and I really hope it will help others as well!
You should first complete your development phase and build your project or use ext-all.js file to I18s translate your UI
see: http://docs.sencha.com/ext-js/4-0/#!/example/locale/multi-lang.html
The appropriate language modifier script (/ext/local/ext-lang-xxx.js) needs to be loaded after ext is loaded (including dynamically loaded classes). In the example above, I would have probably used Ext.Loader.loadScriptFile but they eval a downloaded one directly. The only other thing is that your classes need to be built in different languages or you just use variables and reference the lang-specific variable file.
you could also use a variable in the Loader paths:
var lang='fr';
Loader
{
paths:
{
'Ext': '.',
'My': './src/my_own_folder'+'/'+lang
}

Resources