Making compiled typescript code globally accessible - javascript

I've been working on a little project recently, and ran into this issue of actually having my project me accessible in the rest of the page.
Here's the deal:
It's a javascript router. Doing this just for the sake of interest. I've already set up my typescript compiler via grunt and my module loading and concatenation via grunt-requirejs.
Here's the grunt file: https://github.com/Forestdev/jsRoute/blob/master/gruntfile.js
The output, however, doesn't seem to generate any export to window. I have been googling as to how to export my code to window or anywhere really so that other javascript files could access it.
Could this be the problem with wrapper? Do I need to insert a custom wrapper for all of this? What's the general rule of thumb of making your typescript project global?
Edit:
Forgot to list the index file: https://github.com/Forestdev/jsRoute/blob/master/src/index.ts
Ignore the line with the new instance of an object. I want to export this object so that anyone else could create a new instance of it themselves.

Found a way to handle exposing to the global scope.
Within grunt build requirejs script I added a custom wrapper, which is:
wrap: {
start: '(function(global) {',
end: 'global.JSRoute = global.JSRoute || require("index").Router; }(window));'
}
This seems to fix the issue I had of exporting my script to a global scope. This also correctly loads the script on window load as well, so other scripts have access to it right away.
Hope this makes sense. Hopefully this is the correct way of doing it as well.

Related

Debugging JavaScript code that uses ES6 Modules

TL;DR: How can I access variables/functions/names that are defined in ES Modules from the debugger?
More context: I'm a relatively experienced JavaScript programmer, but new to Modules. I've followed the tutorial at MDN here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules. They have a good set of examples here: https://github.com/mdn/js-examples/tree/master/modules
In that collection, say in the "basic-modules" example, (live code here: https://mdn.github.io/js-examples/modules/basic-modules/) there is, for example, a function called random in the file modules/square.js. Suppose I want to execute that function in the debugger, just to try it out, or because it's my code and I want to test/debug it, or I want to demonstrate to another coder what the function does. All the stuff you expect to do in a REPL or debugger. Is there a way to do that? I've tried both the Firefox debugger and the Chrome debugger, with no luck.
Back in the pre-Modules era, that code would be put into the global namespace (making access easy) or it would be locked up in an IIFE (making access impossible) or maybe in some home-made module system (access depends). I am hoping that the new Modules system still allows the debugger access to the names inside modules.
Thanks.
It says in the docs:
Last but not least, let's make this clear — module features are imported into the scope of a single script — they aren't available in the global scope. Therefore, you will only be able to access imported features in the script they are imported into, and you won't be able to access them from the JavaScript console, for example. You'll still get syntax errors shown in the DevTools, but you'll not be able to use some of the debugging techniques you might have expected to use.
To take your example from before, you'll need to invoke that function from a scope where it is visible, i.e where it's been imported:
import { random } from 'path/to/square.js'
debugger; // you should be able to invoke random() from here

Calling a function defined outside of the Javascript library

I am working on video.js library. I was trying to modify it, so that it uses a custom player instead of the HTML5 player.
So I replaced the function calls to play() etc with the calls to my custom player(say custFunc1()). These calls are defined in a separate javascript file: custPlayer.js.
So in my index.html file, I will first include the custPlayer.js file and then the built video.js file.
However the problem is that while building the video.js package using grunt, I get the error that custFunc1 is not defined and thus grunt is not able to create the video.js library.
Now I was able to find out from a colleague that adding
/* global custFunc1 */
at the beginning of the particular file in the video.js package from where I was calling custFunc1 resolves the issue. The grunt build succeeds and it works fine.
So what I want to know is:
How does this actually resolve the issue, since this is exactly like a comment in javascript, how does it treat this differently and understand that it indicating that the function definition will be present outside the library?
Is the word global some sort of keyword in javascript?
Are there other ways of achieving this apart from what I mentioned?
On a slightly different note, I wanted to ask if grunt is the rough equivalent of make ?
Your javascript is being linted as part of your grunt process, if you look at the root of your project folder you should see a file like .jshintrc or something along those lines (different depending on the linter).
Your current settings means that the linter is going through your .js files one at a time and if it comes across a variable or function from another files it's throwing the error your seeing. You can either turn off this check or add custFunc1 to an array of known global variables. In jshint you do it like so - https://github.com/gruntjs/grunt-contrib-jshint#jshintrc
{
"globals": {
"custFunc1": true
}
}
The globals will probably already be present in the file, so just add custFunc1: true to it.
Oh and to answer question 1 - the comment type syntax tells the linter to ignore it's settings for that current file, basically overriding the settings in the .jshintrc file.
2 - Yes it's a setting in jshintrc and your adding custFunc1 to it inside the file itself instead of globally in the .jshintrc file.
3 - Mentioned above.
4 - Never used maker but yes i believe its similar in that its a pre process tool

using requirejs within a firefox xul extension

I would like to use requirejs to manage my code within a firefox xul plugin, and I can't get it to find my modules.
I know that xul doesn't play nice with the data-main attribute, so I have my main.js script as a second script:
<script src="chrome://myPackage/content/require.js" type="application/x-javascript"></script>
<script src="chrome://myPackage/content/main.js" type="application/x-javascript"></script>
This successfully calls the script, and the require function is available within main.js, but when I run
require(['lib1'], function(lib1){
alert(lib1.val1);
})
the alert never gets popped (lib1 is in the same directory as main.js).
I have tried this within and without setting the baseUrl as
require.config({
baseUrl: "chrome://myPackage/content/"
})
and it does not work either way.
Does anyone know how I can get require.js to look in the right place for my modules?
Addendum **
I added an error handling function and the error code returned is
http://requirejs.org/docs/errors.html#timeout
I have loaded the test module into a normal web page successfully. This seems to confirm that the issue is path configuration (it also takes the 15 second timeout before failing)
Firebug seems to have a working requirejs version. But more importantly, they have a far better mini-require.js that will not pollute the shared global scope when used in overlays (if used correctly :p)
https://github.com/firebug/firebug/blob/master/extension/modules/require.js
https://github.com/firebug/firebug/blob/master/extension/modules/mini-require.js
I suggest you have a look at these implementations and also the code using it.
Proactive warning:
Please note, that if your add-on uses code that defines lots of new properties on the scope in overlays (window) either by defining global functions or variables or implicitly declaring variables within functions, then this may interfere with other code running in the same scope (the browser code itself and other add-ons). Besides, should you want to submit your add-on to addons.mozilla.org, then a reviewer might not give it public status if your add-on "pollutes" the global scope/namespace in the main overlay.

"Can't find variable" error with Rails 3.1 and Coffeescript

I have views in my application that reference my application.js file which contains functions I use throughout my application.
I just installed the Rails 3.1 release candidate after having used the edge version of 3.1. Until I installed the RC I wasn't having any problems but now I'm getting this error:
ReferenceError: Can't find variable: indicator_tag
indicator_tag is a function I defined in application.js.
The only difference I notice in the javascript file is that now all my functions are wrapped in:
(function() { ... }).call(this);
I understand this is for variable scoping? But could it be preventing my pages from using those variables? And before anyone asks, I've made sure the javascript paths are correct in my include tags.
By default, every CoffeeScript file is compiled down into a closure. You cannot interact with functions from a different file, unless you export them to a global variable. I'd recommend doing something like this:
On top of every coffeescript file, add a line like
window.Application ||= {}
This will ensure that there's a global named Application present at all times.
Now, for every function that you'll have the need to call from another file, define them as
Application.indicator_tag = (el) ->
...
and call them using
Application.indicator_tag(params)
Dogbert's solution is a great way to go if you have a very sophisticated JS back-end. However, there's a much simpler solution if you only have a handful of functions you're working with. Just add them directly to the window object, like this:
window.indicator_tag = (el) ->
...
Then you can use your functions from anywhere without having to wrap them up in another object.

JavaScript dependency management

I am currently maintaining a large number of JS files and the dependency issue is growing over my head. Right now I have each function in a separate file and I manually maintain a database to work out the dependencies between functions.
This I would like to automate. For instance if I have the function f
Array.prototype.f = function() {};
which is referenced in another function g
MyObject.g = function() {
var a = new Array();
a.f();
};
I want to be able to detect that g is referencing f.
How do I go about this? Where do I start? Do I need to actually write a compiler or can I tweak Spidermonkey for instance? Did anyone else already do this?
Any pointers to get me started is very much appreciated
Thanks
Dok
Whilst you could theoretically write a static analysis tool that detected use of globals defined in other files, such as use of MyObject, you couldn't realistically track usage of prototype extension methods.
JavaScript is a dynamically-typed language so there's no practical way for any tool to know that a, if passed out of the g function, is an Array, and so if f() is called on it there's a dependency. It only gets determined what variables hold what types at run-time, so to find out you'd need an interpreter and you've made yourself a Turing-complete problem.
Not to mention the other dynamic aspects of JavaScript that completely defy static analysis, such as fetching properties by square bracket notation, the dreaded eval, or strings in timeouts or event handler attributes.
I think it's a bit of a non-starter really. You're probably better of tracking dependencies manually, but simplifying it by grouping related functions into modules which will be your basic unit of dependency tracking. OK, you'll pull in a few more functions that you technically need, but hopefully not too much.
It's also a good idea to namespace each module, so it's very clear where each call is going, making it easy to keep the dependencies in control manually (eg. by a // uses: ThisModule, ThatModule comment at the top).
Since extensions of the built-in prototypes are trickier to keep track of, keep them down to a bare minimum. Extending eg. Array to include the ECMAScript Fifth Edition methods (like indexOf) on browsers that don't already have them is a good thing to do as a basic fixup that all scripts will use. Adding completely new arbitrary functionality to existing prototypes is questionable.
Have you tried using a dependency manager like RequireJS or LabJS? I noticed no one's mentioned them in this thread.
From http://requirejs.org/docs/start.html:
Inside of main.js, you can use require() to load any other scripts you
need to run:
require(["helper/util"], function(util) {
//This function is called when scripts/helper/util.js is loaded.
//If util.js calls define(), then this function is not fired until
//util's dependencies have loaded, and the util argument will hold
//the module value for "helper/util".
});
You can nest those dependencies as well, so helper/util can require some other files within itself.
As #bobince already suggested, doing static analysis on a JavaScript program is a close to impossible problem to crack. Google Closure compiler does it to some extent but then it also relies on external help from JSDoc comments.
I had a similar problem of finding the order in which JS files should be concatenated in a previous project, and since there were loads of JS files, manually updating the inclusion order seemed too tedious. Instead, I stuck with certain conventions of what constitutes a dependency for my purposes, and based upon that and using simple regexp :) I was able to generated the correct inclusion order.
The solution used a topological sort algorithm to generate a dependency graph which then listed the files in the order in which they should be included to satisfy all dependencies. Since each file was basically a pseudo-class using MooTools syntax, there were only 3 ways dependencies could be created for my situation.
When a class Extended some other class.
When a class Implemented some other class.
When a class instantiated an object of some other class using the new keyword.
It was a simple, and definitely a broken solution for general purpose usage but it served me well. If you're interested in the solution, you can see the code here - it's in Ruby.
If your dependencies are more complex, then perhaps you could manually list the dependencies in each JS file itself using comments and some homegrown syntax such as:
// requires: Array
// requires: view/TabPanel
// requires: view/TabBar
Then read each JS file, parse out the requires comments, and construct a dependency graph which will give you the inclusion order you need.
It would be nice to have a tool that can automatically detect those dependencies for you and choose how they are loaded. The best solutions today are a bit cruder though. I created a dependency manager for my particular needs that I want to add to the list (Pyramid Dependency Manager). It has some key features which solve some unique use cases.
Handles other files (including inserting html for views...yes, you can separate your views during development)
Combines the files for you in javascript when you are ready for release (no need to install external tools)
Has a generic include for all html pages. You only have to update one file when a dependency gets added, removed, renamed, etc
Some sample code to show how it works during development.
File: dependencyLoader.js
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css',
'applyStyles.js'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'views/buttonView.view', //contains just html code for a jquery.tmpl template
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});
Html Files
<head>
<script src="standardResources/pyramid-1.0.1.js"></script>
<script src="dependencyLoader.js"></script>
<script type="text/javascript">
Pyramid.load('main');
</script>
</head>
It does require you to maintain a single file to manage dependencies. I am thinking about creating a program that can automatically generate the loader file for you based on includes in the header but since it handles many different types of dependencies, maintaining them in one file might actually be better.
JSAnalyse uses static code analysis to detect dependencies between javascript files:
http://jsanalyse.codeplex.com/
It also allows you to define the allowed dependencies and to ensure it during the build, for instance. Of course, it cannot detect all dependencies because javascript is dynamic interpretet language which is not type-safe, like already mentioned. But it at least makes you aware of your javascript dependency graph and helps you to keep it under control.
I have written a tool to do something like this: http://github.com/damonsmith/js-class-loader
It's most useful if you have a java webapp and you structure your JS code in the java style. If you do that, it can detect all of your code dependencies and bundle them up, with support for both runtime and parse-time dependencies.

Categories

Resources