Defining Durandal ViewModel with TypeScript - javascript

How can I do this?
Some of the examples I have seen, look horrible for example, the following, which does not read like an OO code at all, and hence what's the point of TypeScript if it's gonna be a hack. I can't exactly get intellisense on the following at all, since there's no class definition. So I have a compiled code, with no intellisense, without being able to enforce encapsulation etc - so why bother wasting time?
/// <reference path="../durandal/durandal.d.ts" />
/// <reference path="../../scripts/knockout.d.ts" />
import app = require("durandal/app");
import http = require("durandal/http");
export function activate() {
.
.
.
}
Other examples are even more funky, by exporting a variable declaration.
The resulting code is not much better, it's DI-ing this variable called exports And the code just keeps adding properties to it, which does not make sense.
If I were to write this all in javascript, I return a new object may be in JSON notation - that I can understand, a proper factory method/class. A lot less work, cleaner and no time wasted compiling.
So can someone explain what's going on?
Why is the code creating properties on a DI-ed exports object? It's like a mutant pass by reference.
Is there a more OO way of doing this? I can see myself exporting a class, but this is just too weird and goes against everything I believe to be right and just. Ok that was an exaggeration, but sure feels that way.

The resulting code is not much better, it's DI-ing this variable called exports And the code just keeps adding properties to it, which does not make sense.
This is the way web (amd) works. Its dependent on requirejs : http://requirejs.org/ and even jquery (pick any file from https://github.com/jquery/jquery/tree/master/src) uses a similar pattern e.g. : https://github.com/jquery/jquery/blob/master/src/deferred.js#L1-L5
If I were to write this all in javascript, I return a new object may be in JSON notation - that I can understand, a proper factory method/class. A lot less work, cleaner and no time wasted compiling.
You can do this with TypeScript as well by not using external modules and compiling with --out flag.
Why is the code creating properties on a DI-ed exports object? It's like a mutant pass by reference.
Is there a more OO way of doing this? I can see myself exporting a class, but this is just too weird and goes against everything I believe to be right and just. Ok that was an exaggeration, but sure feels that way.
You need to learn about External / Internal modules. In a nutshell external modules depend upon a module system (amd for the browser, provided by e.g. requirejs, commonjs for the server e.g nodejs). If you've never heard of amd/commonjs you probably shouldn't care. EXCEPT the library you are trying to use (durandal) needs you to use it. This means your javascript code would not be as simple as you think it would be.
PS: I have a video explaining typescript module systems : http://www.youtube.com/watch?hd=1&v=KDrWLMUY0R0

Related

Sails: Exclude directory from being auto loaded as helper

I am building a Sails.js application using sails 1.2.3, node 10.15. I want to include a javascript module in my api/helpers/* directory, without sails automatically using it to try to create a helper. I.e. I have javascript objects that use helpers and are used in a helper, but are not helpers themselves; as in this image, where the module 'rules' is imported into the create-rule helper and the objects exported by this module are used within the helper.
By default, sails tries to load each file in the helpers/* directory as a helper, and throws if the underlying implementation does not match that of a valid helper:
ImplementationError: Failed to load helper `create-rule/rules/foo/index` into a Callable! Sorry, could not interpret "index" because its underlying implementation has a problem:
------------------------------------------------------
• Missing the `fn` property.
------------------------------------------------------
Hoping someone can help out! Let me know if more info is needed. Thanks in advance!
I don't quite understand what you are trying to do. In my humble opinion I would grab all object constructors and placed them as a single file in api/services. That will make it automatically available in all controllers. I would not allow my object's methods to use helpers by them selves (I even think you can't, at least easily). Then when you need a helper to use your object, just pass it as parameter. Anyway, again, in my humble opinion; you are structuring your code to fit all inside /helpers and that will make it extremely hard to develop. Let assume you manage to make it work all inside /helpers, only you without exception, will be able to understand what it does or how it works. Doesn't seem as a good idea.

What to do when no export is needed in TypeScript file

I had a problem while making some demo files using TypeScript, each file is considered to run alone (no import or export needed).
The problem is that the files leaked to each other as they all went global (I'll appreciate if someone explains why this happened). I found a few ways to get rid of this as wrapping them in a module or a namespace, or even exporting an empty object.
What I need to know is the best practice that should be done in this situation? which solutions is considered the best? especially that I thought I can face the same situation if I have multiple files that are required for their side-effects only or something.
I had a problem while making some demo files using TypeScript
What I need to know is the best practice that should be done in this situation? which solutions is considered the best? especially that I thought I can face the same situation if I have multiple files that are required for their side-effects only or something.
The only time I've experienced it in my long career as well is with demo files. I had this when creating TypeScript deep dive so I would put in some junk at the top of the file e.g. see const
export var asdfasdfasfadf = 123;
Why its not a concern
You do not see it happening in real world code because you start you brain with module mind set. E.g.
In a file with zero dependencies you are normally thinking : What am I going to export
In a file where you are going to action something you are normally thinking: What will I need to import. As simple as import fs from 'fs' makes it a module 🌹

Is there a way to tell Google Closure Compiler to *NOT* inline my local functions?

Here's what I'm looking for:
I want to use the wonderful features of SIMPLE mode minification while disabling just one specific feature (disable local function inline).
UPDATE: The answer is NO, it's not possible given my setup. But for me there is a workaround given I am using Grails.
As #Chad has explained below, "This violates core assumptions of the compiler". See my UPDATE3 below for more info.
IN QUESTION FORM:
I'm using CompilationLevel.SIMPLE_OPTIMIZATIONS which does everything I want, except that it's inlining my local functions.
Is there any way around this? For example, is there a setting I can place in my JS files to tell Google Closure not to inline my local functions?
It would be cool to have some directives at the top of my javascript file such as:
// This is a JS comment...
// google.closure.compiler = [inlineLocalFunctions: false]
I'm developing a Grails app and using the Grails asset-pipeline plugin, which uses Google Closure Compiler (hereafter, Compiler). The plugin supports the different minification levels that Compiler supports via the Grails config grails.assets.minifyOptions. This allows for 'SIMPLE', 'ADVANCED', 'WHITESPACE_ONLY'.
AssetCompiler.groovy (asset-pipeline plugin) calls ClosureCompilerProcessor.process()
That eventually assigns SIMPLE_OPTIMIZATIONS on the CompilerOptions object. And by doing so, CompilerOptions.inlineLocalFunctions = true as a byproduct (this is hard coded behavior in Compiler). If I were to use WHITESPACE_ONLY the result would be inlineLocalFunctions=false.
So by using Asset Pipeline's 'SIMPLE' setting, local functions are being inlined and that is causing me trouble. Example: ExtJS ext-all-debug.js which uses lots of local functions.
SO post Is it possible to make Google Closure compiler *not* inline certain functions? provides some help. I can use its window['dontBlowMeAway'] = dontBlowMeAway trick to keep my functions from inlining. However I have LOTS of functions and I'm not about to manually do this for each one; nor would I want to write a script to do it for me. Creating a JS model and trying to identity local functions doesn't sound safe, fun nor fast.
The previous SO post directs the reader to https://developers.google.com/closure/compiler/docs/api-tutorial3#removal, where the window['bla'] trick is explained, and it works.
Wow thanks for reading this long.
Help? :-)
UPDATE1:
Okay. While spending all the effort in writing this question, I may have a trick that could work. Grails uses Groovy. Groovy makes method call interception easy using its MetaClass API.
I'm going to try intercepting the call to:
com.google.javascript.jscomp.Compiler.compile(
List<T1> externs, List<T2> inputs, CompilerOptions options)
My intercepting method will look like:
options.inlineLocalFunctions=false
// Then delegate call to the real compile() method
It's bed time so I'll have to try this later. Even so, it would be nice to solve this without a hack.
UPDATE2:
The response in a similar post (Is it possible to make Google Closure compiler *not* inline certain functions?) doesn't resolve my problem because of the large quantity of functions I need inlined. I've already explained this point.
Take the ExtJS file I cited above as an example of why the above similar SO post doesn't resolve my problem. Look at the raw code for ext-all-debug.js. Find the byAttribute() function. Then keep looking for the string "byAttribute" and you'll see that it is part of strings that are being defined. I am not familiar with this code, but I'm supposing that these string-based values of byAttribute are later being passed to JS's eval() function for execution. Compiler does not alter these values of byAttribute when it's part of a string. Once function byAttribute is inlined, attempts to call the function is no longer possible.
UPDATE3: I attempted two strategies to resolve this problem and both proved unsuccessful. However, I successfully implemented a workaround. My failed attempts:
Use Groovy method interception (Meta Object Protocol, aka MOP) to intercept com.google.javascript.jscomp.Compiler.compile().
Fork the closure-compiler.jar (make my own custom copy) and modify com.google.javascript.jscomp.applySafeCompilationOptions() by setting options.setInlineFunctions(Reach.NONE); instead of LOCAL.
Method interception doesn't work because Compiler.compile() is a Java class which is invoked by a Groovy class marked as #CompileStatic. That means Groovy's MOP is not used when process() calls Google's Compiler.compile(). Even ClosureCompilerProcessor.translateMinifyOptions() (Groovy code) can't be intercepted because the class is #CompileStatic. The only method that can be intercepted is ClosureCompilerProcessor.process().
Forking Google's closure-compiler.jar was my last ugly resort. But just like #Chad said below, simply inserting options.setInlineFunctions(Reach.NONE) in the right place didn't resurrect my inline JS functions names. I tried toggling other options such as setRemoveDeadCode=false to no avail. I realized what Chad said was right. I would end up flipping settings around and probably destroying how the minification works.
My solution: I pre-compressed ext-all-debug.js with UglifyJS and added them to my project. I could have named the files ext-all-debug.min.js to do it more cleanly but I didn't. Below are the settings I placed in my Grails Config.groovy:
grails.assets.minifyOptions = [
optimizationLevel: 'SIMPLE' // WHITESPACE_ONLY, SIMPLE or ADVANCED
]
grails.assets.minifyOptions.excludes = [
'**ext-all-debug.js',
'**ext-theme-neptune.js'
]
Done. Problem solved.
Keywords: minify, minification, uglify, UglifyJS, UglifyJS2
In this case, you would either need to make a custom build of the compiler or use the Java API.
However - disabling inlining is not enough to make this safe. Renaming and dead code elimination will also cause problems. This violates core assumptions of the compiler. This local function is ONLY referenced from within strings.
This code is only safe for the WHITESPACE_ONLY mode of the compiler.
Use the function constructor
var fnc = new Function("param1", "param2", "alert(param1+param2);");
Closure will leave the String literals alone.
See https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Function

Django-pipeline and javascript dependencies

I'm working on a Django project that uses Django-pipeline for assets, and I keep having issues where I define something in one javascript file that is required by another file, but the second file gets loaded before the first and thus the second file fails to load properly. I can mess with the order things get included into PIPELINE_JS but this is pretty awkward to deal with. In most languages you can do things like require foo to make sure that foo is defined but it seems like with javascript and django-pipeline this isn't possible. I've looked into RequireJS a little but I'm not sure how whether I can use it with django-pipeline. What should I do in this case? What do others who use django-pipeline or django in general do for javascript dependency management?
As a side note, I'm actually using Coffeescript, not straight Javascript, but that doesn't seem to help things any. In rails I could do #= require 'foo' to require another coffeescript file but that seems to be linked to the rails asset pipeline.
The only way to do this is to order 'source_filenames' list accordingly, also remember that those file will be concatenated in this order when running collectstatic.
Pipeline will respect this order, it will also avoid duplicate so that your are safe when doing this :
'base.coffee',
'*.coffee',
There is no "require" syntax for now in django-pipeline.
Hope this helps.

Dojo require() and AMD (1.7)

I'm having a heckuva time transitioning to Dojo and the new AMD structure, and I'm really hoping someone can shed some light on the whole concept. I've been living on Google for the last few weeks trying to find information on not the usage, but the structure and design pattern trends in using this.
I find it strange that for a relatively complex javascript application, such as for a main page where Dijits need to be created and styled, DOM elements created, etc, that I need to require, and therefore use, a TON of different modules that were otherwise available in the dojo namespace before the AMD system (or, at least, not assigned to 23 different vars).
Example:
require(['dijit/form/ValidationTextBox', 'dijit/form/SimpleTextarea', 'dijit/form/CheckBox', 'dijit/Dialog', 'dijit/form/Form'])
require(['dojo/ready', 'dojo/parser', 'dojo/dom-style', 'dijit/registry', 'dojo/dom', 'dojo/_base/connect', 'dojo/dom-construct'],
function(ready, parser, style, registry, dom, event, construct){
//...etc
}
That's only a few of the modules for one of the pages I'm working on. Surely there's a better, non-breaking-in-future-releases way of accessing these methods, etc. I mean, do I really have to import an entirely new module to use byId()? And yet another to connect events? On top of that, all the clutter being created by having to assign a variable name in the functions argument list to cling to just seems like such a backstep.
I thought maybe you would require() the module only when needed, such as the query module, but if I need it more than once, then chances are the variable it's assigned to is out of scope, and I'd need to put it in a domReady! or ready call. reaalllly....??!
Which is why I can only assume it's my lack of understanding for dojo.
I really have looked and searched and bought books (albeit, a pre-AMD one), but this library is really giving me a run for my money. I appreciate light anyone can shed on this.
Edit for Example
require(['dijit/form/ValidationTextBox'])
require(['dojo/ready', 'dojo/parser', 'dojo/dom-style', 'dijit/registry', 'dojo/dom', 'dojo/_base/connect', 'dojo/dom-construct'], function(ready, parser, style, registry, dom, event, construct){
/* perform some tasks */
var _name = new dijit.form.ValidationTextBox({
propercase : true,
tooltipPosition : ['above', 'after']
}, 'name')
/*
Let's say I want to use the query module in some places, i.e. here.
*/
require(['dojo/query', 'dojo/dom-attr'], function(query, attr){
query('#list li').forEach(function(li){
// do something with these
})
})
}
Based off of this format, which is used with many examples both from the dojo toolkit folks as well as third party sites, it would be, IMHO, absolutely ridiculous to load all the required modules as the first function(ready, parser, style, registy... would get longer and longer, and create problems with naming collisions, etc.
Firing up and require()ing all the modules I would need during the life of the script just seems silly to me. That being said, I'd have to look at some of the "package manager" scripts. But for this example, if I wanted to use the query module in select places, I would either have to load it up with the rest in the main require() statement. I understand why to an extent, but what's so bad with generic dot-syntax namespaces? dojo.whatever? dijit.findIt()? Why load module, reference in a unique name, pass through closure, blah blah?
I wish this were an easier question to ask, but I hope that makes sense.
Exasperation
Call me a newb, but this is really.. really.. driving me mad. I'm no noob when it comes to Javascript (apparently not) but wow. I cannot figure this out!
Here's what I'm gathering. In adder.js:
define('adder', function(require, exports){
exports.addTen = function(x){
return x + 10
}
})
In some master page or whatever:
require(['./js/cg/adder.js'])
...which doesn't follow the neat require(['cg/adder']) format but whatever. Not important right now.
Then, the use of adder should be:
console.log(adder.addTen(100)) // 110
The closest I got was console.log(adder) returning 3. Yep. 3. Otherwise, it's adder is not defined.
Why does this have to be so difficult? I'm using my noob card on this, cause I really have no idea why this isn't coming together.
Thanks guys.
The dependency array format:
define(["a", "b", "c"], function (a, b, c) {
});
can indeed be annoying and error-prone. Matching up the array entries to function parameters is a real pain.
I prefer the require format ("Simplified CommonJS Wrapper"):
define(function (require) {
var a = require("a");
var b = require("b");
var c = require("c");
});
This keeps your lines short and allows you to rearrange/delete/add lines without having to remember to change things in two places.
The latter format will not work on PS3 and older Opera mobile browsers, but hopefully you don't care.
As for why doing this instead of manually namespacing objects, #peller's answer gives a good overview of why modularity is a good thing, and my answer to a similar question talks about why AMD and module systems as a way of achieving modularity are a good thing.
The only thing I would add to #peller's answer is to expand on "paying attention to dependencies actually makes for much better code." If your module requires too many other modules, that's a bad sign! We have a loose rule in our 72K LOC JavaScript codebase that a module should be ~100 lines long and require between zero and four dependencies. It's served us well.
requirejs.org gives a pretty good overview of what AMD is and why you'd want to use it. Yes, Dojo is moving towards smaller modules which you would reference individually. The result is that you load less code, and your references to it are explicit. Paying attention to dependencies actually makes for much better code, I think. AMD enables optimizations, and once the migration is complete, you don't have to load everything into globals anymore. No more collisions! The require() block wraps the code which uses various modules. domReady! relates to the loading of the DOM and has nothing to do with variables being in scope.
Anyway, this is deviating from the Q&A format of SO. You might want to ask specific questions.

Categories

Resources