Require js ruins code navigation - javascript

require.js states the way of defining objects inside modules with define([requiremens], object) as best way.
So every page, or other js file, will do require() call and receive modules as parameters.
This works pretty fine, each function/module has own namespace.
The problem is that I have:
// AJAX/Requests.js
define(['UI/Message'],function(Message){
var Requests={
checkResponse:function(response){
//1==ok
//0==error
//2==good message
//3==good message, but still stop
if(response.status==1){
return true;
}
else if(response.status==2){
Message.good(response.message);
return true;
}
else if(response.status==3){
Message.good(response.message);
return false;
}
else{
Message.bad(response.message);
return false;
}
}
};
return Requests;
});
Now the UI/Message is defined in the same way, and it returns object.
But when I edit file with requests, I can't navigate by code, so if I want to edit Message object, the only way is to go and open file the myself and to find function I need, rather than have the IDE jump there for me.
Is there some workaround for pycharm specifically or to require.js in common to solve this issue? When you have a lot of code it becomes a mess to navigate it, which is why I use an IDE in the first place!
And what worse: The editor never knows what functions objects have!
The one possible solution I can see is to not to use enclosed namespaces, and to declare global variable before the define() call, but in this case all objects shall be called like UI_Message, AJAX_Requests. In order to be sure, that I don't have some Message in two different locations....
And I am not sure, if require.js optimizer will use this correctly. Require.js documentation states very clear, to stay away from global variables.

It's a known issue, please star/vote.
From the issue description:
The dojo library switched to AMD's format define() for loading modules
instead of dojo.require(). Previously I was able to use Ctrl+B on
dojo.require('path.to.someJs') to jump to the declaration. This does
not work on the new format define(['path/to/someJs]', ...).
As PyCharm, WebStorm, PhpStorm and IntelliJ IDEA share the same JavaScript plug-in, this issue also applies to the product that you are using. You will continue to observe the described problem until this bug is fixed. Sorry for the inconvenience.

WebStorm (at least 6.0.2) supports code navigation with RequireJs if you're defining your modules with the CommonJs wrapper and use the exports and module arguments:
//foo.js
define(function(require, exports, module) {
//use exports to expose properties for code navigation in other modules
exports.bar = function() {}
});
Apparently, it works even if the module using it doesn't use the CommonJs wrapper format:
define(['./foo'], function(foo) {
foo.bar(); //code navigation works here
}
If the other IDEs use the same JavaScript plug-in as CrazyCoder said, it may work on their newer releases as well.

Related

inline usage of import with typescript 1.6 and es6 syntax

I am looking at updating some older js libs I have to typescript using the ES6 conventions, however I have come across a stumbling point.
So historically when I loaded a JSON file dynamically I would do something like this:
this.someFunctionWhichDoesStuff = function() {
var config = require(theConfigDir); // theConfigDir was a variable
// ... other stuffs
}
This worked fine, and I would also in some cases dynamically include some modules from a folder too:
this.someFunctionWhichDoesStuff = function() {
var actualImplementationToUse = require(theDirectoryWithImplementation); // theConfigDir was a variable
// ... other stuffs
}
This allowed me to switch implementations based upon configuration at earlier points, and worked well enough. Key points to note here are that the resolvers for the modules are variables not static text and that they are being run inside of functions not at root level.
So with this in mind I went over to the es6 style module inclusion in TS and realised I cannot do the above, as this is not valid syntax:
public someFunctionWhichDoesStuff() {
import actualImplementationToUse from theDirectoryWithImplementation;
// ... other stuffs
}
And it makes sense, as I know ES6 modules need to statically resolve modules, so I am cool with that, however in the typescript 1.6 world I am unsure how to resolve this as var includedModule = require(theDirectory); seems to be invalid as it doesnt know about require, which may be solved with inclusion of the node js d.ts file, however I was hoping someone could give some steering as to what the desired approach is in the new es6 world going forward?
sure I know I can do this, but is there a more es6 way of doing this? i.e if I use require I am locked into using require on all consumers (be it browser or node), I imagine there isn't but I just wanted to check before I went down this route.
ES6 spec doesn't specify a module loader anyways (SystemJS is just a sample non-standard implementation) and mostly you want to transpile down to es5. So using require is not a bad idea (especially for non .ts/.js files)

TypeScript use typescript-require shared files

I use TypeScript to code my javascript file with Object Oriented Programing.
I want to use the node module https://npmjs.org/package/typescript-require to require my .ts files from other files.
I want to share my files in both server and client side. (Browser) And that's very important. Note that the folder /shared/ doesn't mean shared between client and server but between Game server and Web server. I use pomelo.js as framework, that's why.
For the moment I'm not using (successfully) the typescript-require library.
I do like that:
shared/lib/message.js
var Message = require('./../classes/Message');
module.exports = {
getNewInstance: function(message, data, status){
console.log(requireTs);// Global typescript-require instance
console.log(Message);
return new Message(message, data, status);
}
};
This file need the Message.js to create new instances.
shared/classes/Message.ts
class Message{
// Big stuff
}
try{
module.exports = Message;
}catch(e){}
At the end of the fil I add this try/catch to add the class to the module.exports if it exists. (It works, but it's not really a good way to do it, I would like to do better)
If I load the file from the browser, the module.export won't exists.
So, what I did above is working. Now if I try to use the typescript-require module, I'll change some things:
shared/lib/message.js
var Message = requireTs('./../classes/Message.ts');
I use requireTs instead of require, it's a global var. I precise I'm using .ts file.
shared/classes/Message.ts
export class Message{
// Big stuff
}
// remove the compatibility script at the end
Now, if I try like this and if I take a look to the console server, I get requireTs is object and Message is undefined in shared/lib/message.js.
I get the same if I don't use the export keyword in Message.ts. Even if I use my little script at the end I get always an error.
But there is more, I have another class name ValidatorMessage.ts which extends Message.ts, it's not working if I use the export keyword...
Did I did something wrong? I tried several other things but nothing is working, looks like the typescript-require is not able to require .ts files.
Thank you for your help.
Looking at the typescript-require library, I see it hasn't been updated for 9 months. As it includes the lib.d.ts typing central to TypeScript (and the node.d.ts typing), and as these have progressed greatly in the past 9 months (along with needed changes due to language updates), it's probably not compatible with the latest TypeScript releases (just my assumption, I may be wrong).
Sharing modules between Node and the browser is not easy with TypeScript, as they both use very different module systems (CommonJS in Node, and typically something like RequireJS in the browser). TypeScript emits code for one or the other, depending on the --module switch given. (Note: There is a Universal Module Definition (UMD) pattern some folks use, but TypeScript doesn't support this directly).
What goals exactly are you trying to achieve, and I may be able to offer some guidance.
I am doing the same and keep having issues whichever way I try to do things... The main problems for me are:
I write my typescript as namespaces and components, so there is no export module with multiple file compilation you have to do a hack to add some _exporter.ts at the end to add the export for your library-output.js to be importable as a module, this would require something like:
module.exports.MyRootNamespace = MyRootNamespace
If you do the above it works, however then you get the issue of when you need to reference classes from other modules (such as MyRootNamespace1.SomeClass being referenced by MyRootNamespace2.SomeOtherClass) you can reference it but then it will compile it into your library-output2.js file so you end up having duplicates of classes if you are trying to re-use typescript across multiple compiled targets (like how you would have 1 solution in VS and multiple projects which have their own dll outputs)
Assuming you are not happy with hacking the exports and/or duplicating your references then you can just import them into the global scope, which is a hack but works... however then when you decide you want to test your code (using whatever nodejs testing framework) you will need to mock out certain things, and as the dependencies for your components may not be included via a require() call (and your module may depend upon node_modules which are not really usable with global scope hacking) and this then makes it difficult to satisfy dependencies and mock certain ones, its like an all or nothing sort of approach.
Finally you can try to mitigate all these problems by using a typescript framework such as appex which allows you to run your typescript directly rather than the compile into js first, and while it seems very good up front it is VERY hard to debug compilation errors, this is currently my preferred way but I have an issue where my typescript compiles fine via tsc, but just blows up with a max stack size exception on appex, and I am at the mercy of the project maintainer to fix this (I was not able to find the underlying issue). There are also not many of these sort of projects out there however they make the issue of compiling at module level/file level etc a moot point.
Ultimately I have had nothing but problems trying to wrestle with Typescript to get it to work in a way which is maintainable and testable. I also am trying to re-use some of the typescript components on the clientside however if you go down the npm hack route to get your modules included you then have to make sure your client side uses a require compatible resource/package loader. As much as I would love to just use typescript on my client and my server projects, it just does not seem to want to work in a nice way.
Solution here:
Inheritance TypeScript with exported class and modules
Finally I don't use require-typescript but typescript.api instead, it works well. (You have to load lib.d.ts if you use it, else you'll get some errors on the console.
I don't have a solution to have the script on the browser yet. (Because of export keyword I have some errors client side) I think add a exports global var to avoid errors like this.
Thank you for your help Bill.

RequireJS - Loading AMD modules both inside a require flow and inline

Consider this:
<script src='global.js'></script>
<script src='require.js'></script>
<script>
require(['modular_foo'], function() {
//do stuff
});
...and in side global.js we have, among other things:
//global.js
$.getScript("modular_bar.js");
where both modular_foo and modular_bar are anonymously defined AMD modules. Using requireJS, loading something like the above would give you our favourite error, mismatched anonymous define() modules.
It's fine enough as to why that error occurs (read up on that page if you'd like to know), but the problem is, what if you can't get out of this situation?
I'm working in an established platform which is very gradually migrating to a RJS flow, for now there's no way out of using both inline legacy scripts (some of which have AMD checks to trigger define()) and our requireJS entry-point simultaneously.
In some cases I can simply place inline AMD-compatible scripts above loading the require.js library, but that doesn't work when you need to load other things (modular_bar.js) asynchronously depending on the DOM content. I could also just comment out all AMD checks from those files loading externally to RJS but that's preventing making them incompatible with ever being loaded in a modular flow.
Anyone out there had a similar experience? How do you blend your flows to overcome these sorts of conflicts?
I do not have experience using this solution in a production environment but I spent a couple days on this question figuring out the best way to approach it.
You can use a modified RequireJS library that does not allow the anonymous define's to execute, if it is being passed through eval. Also, you can disallow any define calls by removing type check for string on name in the snippet below.
The following snippet is a modification to RequireJS that will ignore anonymous defines if being called by eval. You can find the fully modified require.js in this GitHub Gist.
The code relies on the parse-stack library. If you can't include the library before RequireJS, I suggest just concatenating it to the top of of the file.
Demo
// This is a snippet of RequireJS
// ...
define = function (name, deps, callback) {
var node, context;
// We will allow named modules to be defined by `eval`
if (!(typeof name == 'string' || name instanceof String))
{
var stack = parseStack(new Error());
// If we find any eval in the stack, do not define the module
// This is to avoid the "Mismatched anonymous define() module" error
// Caused by executing an anonymous define without requireJS
for(var i = 0; i < stack.length; i++)
{
if(stack[i].name == "eval")
{
return;
}
}
}
// ...

Why do concatenated RequireJS AMD modules need a loader?

We love RequireJS and AMD during development, where we can edit a module, hit reload in our browser, and immediately see the result. But when it comes time to concatenate our modules into a single file for production deployment, there apparently has to be an AMD loader still present, whether that loader is RequireJS itself or its smaller partner “almond” as explained here:
http://requirejs.org/docs/faq-optimization.html#wrap
My confusion is: why is a loader necessary at all? Unless you have very unusual circumstances that make it necessary for you to make require() calls inside of your modules, it would appear that a series of AMD modules could be concatenated without a loader present at all. The simplest possible example would be a pair of modules like the following.
ModA.js:
define([], function() {
return {a: 1};
});
ModB.js:
define(['ModA'], function(A) {
return {b : 2};
});
Given these two modules, it seems that a concatenator could simply produce the following text, and not burden the production server or browser with the extra bandwidth or computation required by either RequireJS or Almond.
I imagine a concatenator that produces (and I am using chevron-quotes «,» to show where the snippets from the two modules above have been inserted):
(function() {
var ModA = «function() {
return {a: 1};
}»();
var ModB = «function(A) {
return {b : 2};
}»(ModA);
return ModB;
})();
This, so far as I can see, would correctly reproduce the semantics of AMD, with a minimum of extraneous glue JavaScript. Is there such a concatenator available? If not, would I be a fool for thinking that I should write one — are there really very few code bases that consist of simple and clean modules written with define() and that never need further require() calls inside that kick off later asynchronous fetches of code?
An AMD optimiser has the scope to optimise more than the number of files to be downloaded, it can also optimise the number of modules loaded in memory.
For example, if you have 10 modules and can optimise them to 1 file, then you have saved yourself 9 downloads.
If Page1 uses all 10 modules then that's great. But what if Page2 only uses 1? An AMD loader can delay the execution of the 'factory function' until a module is require'd. Therefore, Page2 only triggers a single 'factory function' to execute.
If each module consumes 100kb of memory upon being require'd, then an AMD framework that has runtime optimisation will also save us 900kb of memory on Page2.
An example of this could be an 'About Box' style dialog. Where the very execution of it is delayed until the very last second as it won't be accessed in 99% of cases. E.g. (in loose jQuery syntax):
aboutBoxBtn.click(function () {
require(['aboutBox'], function (aboutBox) {
aboutBox.show();
}
});
You save the expense of creating the JS objects and DOM associated with the 'About Box' until you are sure it's necessary.
For more info, see Delay executing defines until first require for requirejs's take on this.
The only real benefit is if you use modules across sections so there's a benefit to caching modules independently.
I had the same need, so I created a simple AMD "compiler" for that purpose that does just that. You can get it at https://github.com/amitayh/amd-compiler
Please note that it has many features missing, but it does the job (at least for me). Feel free to contribute to the codebase.
In case you compile you code with require.js into a single large file for production, you can use almond.js to completely replace require.
Almond only handles the module references management not the loading itself which is no longer needed.
Be careful of the restrictions almond imposes in order to work
There is no reason why there couldn't be a build tool such as the one you propose.
The last time* I looked at the optimizer's output, it converted the modules to explicitly named modules, and then concatenated those together. It relied on require itself to make sure that the factory functions were called in the right order, and that the proper module objects were passed around. To build a tool like you want, you would have to explicitly linearize the modules -- not impossible, but a lot more work. That's probably why it hasn't been done.
I believe** that the optimizer has a feature to automatically include require itself (or almond) into the built file, so that you only have to have one download. That would be larger than the output of the build tool you want, but otherwise the same.
If there was a build tool that produced the kind of output you're asking for, It would have to be more careful, in case of the synchronous require, the use of exports instead of return, and any other CommonJS compatibility features.
*That was a few years ago. 2010, I think.
**But can't seem to find it right now.

Curl throwing ‘Promise already completed’ error

I’m currently testing various asynchronous-resource-loaders to see which one I want to use. At the moment Curl is throwing a ‘Promise already completed’ error…and their documentation says ‘this should never happen’.
I “suspect” I must to use a ‘define’ within each file being loaded (hope not). Further, their documentation says Curl can work with non-AMD javascript files. But...I am new to AMD and since Curl is far-faster than the other ones I'm testing...I am willing to put some time into understanding this better.
Lastly...
Even though FireBug shows the errors...all the files STILL LOAD asynchronously! But, BECAUSE there are errors...the 'then' portion of the code never gets called.
So My Questions Are:
Do I have to update all the JavaScript file-objects to be contained in a 'define'? (...hope not)
Can you see any other problem syntactically?
The Head’s Code Looks Like This:
<script type="text/javascript">
///<summary>Configuration</summary>
curl = { baseUrl: 'Includes/JavaScript/' };
</script>
<script src="Loaders/Curl/curl.js" type="text/javascript"></script>
<script type="text/javascript">
function onSuccess() {
}
function onError(ex) {
//alert(ex);
}
require(["MooTools/Core/mootools-1.2.2-core-jm",
"MooTools/mGeneral",
"jQuery/Core/jquery-1.3.2",
"jQuery/Core/jquery.tools.min",
"jQuery/ThirdPartyPlugIns/jquery.tmpl"])
.then(onSuccess, onError);
//require(["jQuery/TopUp/top_up-min"], null);
require(["jQuery/ThirdPartyPlugIns/jquery.dimensions",
"jQuery/ThirdPartyPlugIns/jQuery.Color.Animations",
"jQuery/ThirdPartyPlugIns/jquery.corners.min",
"jQuery/ThirdPartyPlugIns/jquery.tipsy",
"jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0",
"jQuery/ThirdPartyPlugIns/jquery.tipsy"]);
require(["general",
"WindowCenter",
"ThirdPartyPlugin/KeyBoardCapture",
"ThirdPartyPlugin/bsn.AutoSuggest_2.1.3",
"ee/8Ball",
"ee/EE"]);
</script>
Again...I'm sure it is caused by inexperience with AMD-styled code, but I still need help...so any is appreciated.
Typically, you should wrap your modules in a define() or append a define() at the end of the file if those modules have no dependencies. It seems, though, that those modules all depend on jQuery, if not other modules/files.
Since you're not using standard AMD require()/define() protocol, AMD is not really helping you with these modules. Unless you plan to write your own modules using define(), then you could use just about any async loader.
That said, there is a way to make curl.js work with non-AMD modules/files. Use the js! plugin. Here's your first block of files translated to use the js! plugin (note I also added the ".js" ext back on which I like to do with non-modules):
// we load the core files first, then get the next block that depends on them
curl([
"js!MooTools/Core/mootools-1.2.2-core-jm.js",
"js!jQuery/Core/jquery-1.3.2.js"
]).next([
"js!MooTools/mGeneral.js",
"js!jQuery/Core/jquery.tools.min.js",
"js!jQuery/ThirdPartyPlugIns/jquery.tmpl.js"
]).then(onSuccess, onError);
If any of those files within each array depend on each other, you can also use the !order suffix on them to ensure they wait for other files before executing/evaluating (be sure you're setting proper cache headers, though). Actually, the !order suffix is the fastest method as long as there are no caching issues (mobile browsers add some additional constraints on file size).
Were there any other error messages? Specifically, I would expect curl.js to throw at least one error besides just "Promise not completed".
Also, please check the Net tab (Firebug) or the Network tab (Chrome) to check that curl.js is looking in the correct location for the modules.
FWIW, I am planning to remove the alias require --> curl. The reason is that the global require function is non-standard (and explicitly not standardized in the AMD proposal). I suggest you use curl() instead of require().
curl.js also allows it's top-level api to be aliased explicitly via the "apiName" config param if you really, really want to use the name "require". :)
<script>curl = { apiName: "require" }; </script>
<script src="path/to/curl.js"></script>
<script>require(["some/modules"]).then(success, failure);</script>
More FWIW: the standard require is typically only needed in a module and can be requested by including it as a dependency:
define(["require"], function (require) {
require(["another/module"], function (another) {
// use another module here
});
});
-- John
If you're only doing normal javascript file loading (not modules), as it appears, i would encourage you to check out LABjs (http://labjs.com). LABjs focuses on being the most performance optimized loading solution (to the exclusion of some other features like module/dependency style stuff).
In fact, LABjs 2.0a (https://github.com/getify/LABjs/blob/master/next/LAB.src.js), which will be fully released in the next few days, is really exceptionally fast (even more than 1.2) at loading general scripts in parallel. I encourage you to give it a try, unless (as John eludes to above) you plan to go to module syntax... then stick with Curl or RequireJS.

Categories