I'm trying to move my workspace to c9 because the Ace editor's autocompletion really pleased me when I worked on NodeJS projects.
But now I would like to work on JS files client-sided. It is from this point autocompletion going wrong. Indeed, there is nothing such as "require" command in client-side JS inside of the JS files themselves (except using some plugins) to inform of the other source files used in.
So when I use, in one of my JS files, a function that is defined in an other file (even libraries, frameworks : jquery, etc), Ace notifies me that the function is not defined (cause it has no way to know that the function is defined in another file, I guess).
Here we go : is there some comment line I could put in my code, or some configuration of c9 I could set, to correct that behavior ?
To remove the errors and warning, you can just add the following line near the top of your javascript file:
/* globals jquery lodash someOtherLibrary */
However, Cloud9 doesn't do autocomplete for client side libraries yet.
Abuse C9's require support
When you use var yourLibrary = require("./somefile.js");, auto-completion works perfectly.
But, as you stated, require() doesn't exist, nor do you want to have yourLibrary set to undefined. (Or to just throw an error)
As it turns out, C9 isn't that smart:
//Your library was defined in some other file
var yourLibrary; //"This does nothing other than making C9 happy
function require() {return 1;} //Define the require function
if(false) {
yourLibrary = require("yourLibraryFile.js");
}
Now, you can use autocomplete (it even shows the documentation comments)!
Note: It doesn't always work.
Related
PROBLEM DESCRIPTION.
I'm trying to follow https://github.com/lucascosta/facebook-js-ads-sdk to install the Javascript SDK for Facebook. Before anyone objects, I am absolutely aware of the compact version (https://developers.facebook.com/docs/javascript/quickstart), but that API is absolutely useless to me. I need the one produced by Lucas Costa, in order to be able to make changes to my ads account, which the recommended script by Facebook does not enable.
As usual installation instructions (see github.com/lucascosta/facebook-js-ads-sdk) are horribly predicated on mysterious conditions, that are unbeknown to me. I cannot get the SDK to work and would like someone to tell me explicitly what to do. The crux of the problem is the paradoxical situation: I am supposed to use a require('...') command (where??) to include the SDK (where is this supposed to be saved??) and yet require cannot be used on folders, but on scripts. Maybe somewhere there is a require.config file, I'm supposed to set up, but I have no idea, as, like I said, the instructions completely bypass any mention of the necessary starting conditions.
Here is what I have done so far. My folder-structure looks like this (I don't even know if this is right, as no-one explains it anywhere!):
[Serverroot]
— [folder with my website]
– facebook-ads-sdk (the folder one gets by downloading)
– css — pagestyles.css
– js — lib
require.js
— app
( some header scripts )
– img
( some images )
index.php
In index.php I have a block of html followed by some javascript. It is here, that I try to insert the setup / example code from . The browser cannot even get past the line const adsSdk = require('facebook-ads-sdk');. I have tried a number of things: require('./facebook-ads-sdk');, moving all this to the folder ./js/app in a script main.js and then writing in my html in index.php where main and require are located. Setting up a require.config (or requirejs.config) replacing require by requirejs, etc. and including the appropriate scripts in the <head> part of index.php. Nothing helps. Here are the errors: first with const adsSdk = require('facebook-ads-sdk'); I get
Error: Module name "facebook-ads-sdk" has not been loaded yet for context: _. Use require([])
Okay. How do I ‘load the Module for the context _’?? Reading requirejs.org/docs/start.html is of no help here. I tried require([], function() {require('facebook-ads-sdk')}); Same error. I tried require(['facebook-ads-sdk']);
I tried using the following commands in my script in index.php:
require.config({
shim: {
'facebook': {
exports: 'adsSdk',
},
},
paths: {
'sdk': './facebook-ads-sdk',
}
});
var adsSdk = require(['sdk']);
Then I get the error
Failed to load resource: http:// .... /facebook-ads-sdk.js the server responded with a status of 404 (Not Found)
Ie, the browser thinks I'm trying to include a script facebook-ads-sdk.js, but I’m supposed to(???) ‘require’ the entire folder! What is going on? Can someone please give me thorough instructions about the necessary folder structure and command, in order to get this SDK working?
Why is this so infuriatingly vaguely described online? Is there some kind of mysterious way of installing SDKs, about which ‘everyone’ knows, but never mentions?
UPDATE: SOLUTION. For any future google-searches for this same problem: via the following simple methods, one can install & embed the Javascript-FB-Ads-SDK:
install via npm install --save facebook-ads-sdk a copy of the npm modul Lucas Costa’s facebook-ads SDK.
Copy this folder to your website’s architecture (actually you possibly just need one subfolder / file).
in your HTML include the script (via <script type='text/javascript' src='...'></script>) with the src pointing to the file in the facebook-ads-sdk folder: /dist/iife.js.
In your page’s script, you now have access to then API via the global variable fb.
alternatively to 3:
3’. in your HTML headers make sure to include the require.js script via a <script>-tag. Then in your website’s javascript apply the following commands anywhere:
require.config({
paths: {
'sdk': './[FOLDERNAME OF SDK]/dist/iife',
}
});
require(['sdk']);
Credit and special thanks goes to #SLaks and #KhauriMcClain (I would give you up-points if I could) for this solution.
The instructions are assuming that you're using a bundling system like Webpack or Browserify.
If you are, the instructions "just work"; you can require() it and everything will work fine.
If you're building a non-trivial codebase, you really should use such a system.
If you aren't, you can reference iife.js in a <script> tag and that will create global variables.
You need to change the way you are using require.
You cannot use the synchronous require method to load dependencies if they have not been loaded before. Hence const adsSdk = require('facebook-ads-sdk'); will not work. You will need to use the form require(['name-of-script'], callback).
Require does not allow you to load an entire folder. You have to find the exact script you are trying to work with so var adsSdk = require(['sdk']); will not work.
Ultimately your code should look something like:
require(['some-facebook-script'], function(someFacebookScript) {
// Do some work here
});
The parameter passed to the callback function will be the loaded module you are trying to consume. When using the asynchronous version (as I just demonstrated) the return from require is not useful.
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
I'm trying to get Visual Studio Code 0.3.0 to recognize my JavaScript libraries. However, intellisense is complaining. Here's a repro:
Open Visual Studio Code
File > Open Folder (select a freshly created empty folder)
Add a file mytest.js to that folder
Download jquery-2.1.4.js (full/uncompressed) to that folder (appears in the side bar)
Enter this in mytest.js:
var x = jQuery('body');
Result: squiggly green lines under jQuery. Note that jQuery is just an example, I've had the same issue with libraries such as KnockoutJS and QUnit, etc.
I've tried adding a triple-slash reference like so:
/// <reference path="jquery-2.1.4.js" />
Heck, it even autocompleted the path for me. I've tried varying the path a bit, e.g. a ./ at the start, but the result is thus far invariably:
Hovering jQuery gives a popup saying:
Cannot find name 'jQuery'.
any
Still squiggly green lines. I hate squiggly lines though. How can I get rid of them?
You Need To Refefence the jQuery TypeScript Definition File.
You need a 'typings' folder in the root of your app or site. Within the 'typings' folder you need a jquery.d.ts file.
Your reference to the file should be similar to the following depending upon where the file reference is located in relation to the typings/jquery.d.ts file and folder:
/// <reference path="../../typings/jquery/jquery.d.ts"/>
Here's a TypeScript Definitions File reference for Node.js:
/// <reference path="typings/node/node.d.ts"/>
The easiest way to accomplish this is to click on the green squiggly in VSCode then click the light bulb and select Add /// reference to 'XYZ.d.ts'. This will automatically add everything you need.
In a comment above the Definitely Typed web site was referenced if you want or need to do this manually.
I don't know about VS Code, but regular Visual Studio often complains when you try to access "global" variables like this. I find that this pattern helps me to both avoid these warnings and keep my code more modular:
(function($) {
var x = $('body');
})(jQuery);
This has the added advantages of keeping your declared variables (x, e.g.) scoped within the file instead of globally, and allowing you to safely use short names (e.g. $) for your libraries internally, while avoiding naming conflicts. It also opens up an easy migration path if you end up needing to use requireJS or something like that for dependency loading.
Hopefully it will also get rid of your green squigglies?
I have an iWidget designed for IBM Connections, and my javascript code depends on Dojo (which is included by default in Connections).
It currently works in Connections 4.0 and 4.5, but is broken in Connections 5.0 (released last week), as Dojo has been updated to v1.9 and complains about my use of dojo.require.
These messages appear in the browser console when my widget tries to load on Connections 5.0:
Avoid calling dojo.require() to load classes at runtime, use net.jazz.ajax.xdloader.load_async() instead. Function '(anonymous)' required class 'dojox.atom.io.model'.
Avoid calling dojo.require() to load classes at runtime, use net.jazz.ajax.xdloader.load_async() instead. Function '(anonymous)' required class 'dojox.atom.io.Connection'.
I want to make conditional code that uses different ways of defining my widget class and requiring other Dojo modules depending on the Dojo version.
The widget javascript currently looks like this:
dojo.provide('insightCommunityWidgetClass');
dojo.require('dojox.atom.io.model');
dojo.require('dojox.atom.io.Connection');
dojo.declare('insightCommunityWidgetClass',null,{
// Class fields and methods. Currently 680 lines uncompressed.
});
I haven't yet created a version that works with Dojo 1.9 / Connections 5.0, but I think it would look something like this (and I'll have to make my javascript file name match the desired class name):
define(['dojo/_base/declare','dojox.atom.io.model','dojox.atom.io.Connection'], function(declare){
return declare(null, {
// Class fields and methods.
});
});
How can I have both of these in one file and choose between them without duplicating the class body?
Update:
I've attempted some conditional code, checking (define && define.amd) as suggested by Dimitri, tested this on Connections 4.0 and 4.5, and am getting very weird behaviour.
Temporarily ignoring any attempt to not duplicate my class, here's some conditional code which I've used exactly as shown, with a severely reduced widget class:
if (define && define.amd) {
console.log('Declaring insightWidgetClass with AMD (new method).');
define(['dojo/_base/declare','dojox/atom/io/model','dojox/atom/io/Connection'],
function(declare){
return declare(null,{
SVC_INV: 1,
onLoad: function() {
console.log('insightWidgetClass onLoad.');
}
});
}
);
} else {
console.log('Declaring insightWidgetClass with dojo.declare (old method).');
dojo.provide('insightWidgetClass');
dojo.require('dojox.atom.io.model');
dojo.require('dojox.atom.io.Connection');
dojo.declare('insightWidgetClass',null,{
SVC_INV: 1,
onLoad: function() {
console.log('insightWidgetClass onLoad.');
}
});
}
This seems not to run at all. None of my console.log messages appear in the browser console.
If I comment out the conditionals and make it so the only active code is the block after else, it runs. I get the "declaring ... (old method)" and the "insightWidgetClass onLoad" console messages.
I thought maybe enclosing the Dojo provide, require and declare calls in any kind of block might cause a problem, so I tested just putting the working code in an if (true) { block, and it still works.
The last things I've tried at this point are adding this one line before everything else, to see what define is:
console.log('dojo define',define);
... which breaks it. No console messages at all from my code.
Then I remove the define argument from that new line, so it's only sending a string to the console, and the code works again.
It seems like any mention of a define identifier silently stops the rest of the code from running.
There are no errors or warnings in the console indicating a problem. All I can say to that is: WTF?!
Now back to checking dojo.version instead.
Normally both should still work, dojo.provide() and dojo.require() are deprecated, but not entirely removed. Just make sure that your loading dojo in synchronous mode.
Besides that, the AMD way of coding is introduced in Dojo 1.7, which means that it should be supported on IBM Connections 4.5 as well (though I don't know about IBM Connections 4).
But if you really want to use both code bases, you can simply refer to the same object in stead of duplicating it, for example:
var myModule = {
// Class fields and methods.
};
if (dojo.version.major == 1 && dojo.version.minor == 9) {
define(['dojo/_base/declare','dojox.atom.io.model','dojox.atom.io.Connection'], function(declare){
return declare(null, myModule);
});
} else {
dojo.provide('insightCommunityWidgetClass');
dojo.require('dojox.atom.io.model');
dojo.require('dojox.atom.io.Connection');
dojo.declare('insightCommunityWidgetClass',null, myModule);
}
Or you could use the following check:
if (typeof define === 'function' && define.amd) {
// AMD style code
} else {
// Non-AMD style code
}
This is the approach most cross-loader libraries use. Libraries that work both on AMD loaders (Dojo, Require.js), but also on Node.js or simply by using global namespacing use a similar piece of code to determine how they load their module.
This is not your code, it should work as it is. We recently faced the same problem and identified the cause.
Connections 5 is using an AMD version of the Jazz framework which provides its own dojo loader. This framework is used to aggregate the needed dojo modules into a single JS file, which limits the number of requests to the server. Unfortunately, this loader no longer handles synchronous modules loading. It fails with the warning you reported when dojo.require() requests a module that is not yet loaded by the aggregator. If the module was already loaded, because it was part of the Jazz aggregated file, then it works. It explains why you can dojo.require() some modules, but not all of them.
-> A workaround is to deploy a server side OSGi bundle to get the modules you need part of the aggregated JS file. There is a documented extension point for this. This can unblock you while enhancing the performance of your page.
Now, we opened a PMR to IBM support. The development team is working on a resolution. We hope that they will be able to deliver a fix soon.
We reported the following issues:
dojo.require()
dojo.requireLocalization()
dojo.registerModulePath()/require({paths:})
If you think about something else, please let me know.
Is there any way I can include an external JS library in my pebble code?
Conventionally on a webpage I would do this in my head tags:
<script type='text/javascript' src='https://cdn.firebase.com/js/client/1.0.11/firebase.js'></script>
But in pebble, I am unable to do that since I am only using JS. So how can I include an external library for a JavaScript file.
At present, you cannot include external JS files.
If you're using CloudPebble, then the only way to do this is to copy and paste the content of the JS library files into your JS file.
If you're doing native development, you can modify the wscript file to combine multiple JS files into one at build time.
I think there's some confusion over Pebble.js vs PebbleKit JS (v3.8.1). Pebble.js is a fledgling SDK where eventually the programmer will be able to write pure JavaScript. It's still cooking so there's some functionality missing like the ability to draw a line or obtain the screen dimensions. The repo is a mix of C and JS sources where you can add C code to augment missing functionality but otherwise all your code lives in src/js/app.js or src/js/app/. Anyway, Pebble.js does support require.
I don't use CloudPebble but I got the impression that it either supports Pebble.js (and hence require) or is planning to. I think all this SDK boilerplate code would be hidden.
PebbleKit JS does not support require out of the box AFAIK. I've made a demo that ports require support from Pebble.js to PKJS. The summary of changes is:
Move your project's src/js/pebble-js-app.js to src/js/app/index.js.
Remove any ready event listener from src/js/app/index.js. index.js will
be loaded when the ready event is emitted.
Add src/js/loader.js from Pebble.js.
Add a src/js/main.js that calls require('src/js/app') on the ready event.
Update your wscript with the following
deltas.
When adding new modules, place them under src/js/app/ and require('./name') will work.
I've tried to cover this all in the demo's readme.
BTW, here's the official breakdown of all the different SDKs but it's a little confusing.
I am not sure if there have been changes since the above answer, but it looks like there is in fact a way to include additional resources while keeping things tidy. On the pebbleJS page, there is the following section with an some information on the subject.
GLOBAL NAMESPACE - require(path)
Loads another JavaScript file allowing you to write a multi-file project. Package loading loosely follows the CommonJS format. path is the path to the dependency.
You can then use the following code to "require" a JS library in your pebble project. This should be usable on both Cloud Pebble as well as native development.
// src/js/dependency.js
var dep = require('dependency');
You can then use this as shown below:
dep.myFunction(); // run a function from the dependency
dep.myVar = 2; // access or change variables
Update:
After some digging into this for my own, I have successfully gotten CloudPebble to work with this functionality. It is a bit convoluted, but follows the ECMAScript 6 standards. Below I am posting a simple example of getting things set up. Additionally, I would suggest looking at this code from PebbleJS for a better reference of a complex setup.
myApp.js
var resource = require('myExtraFile'); // require additional library
console.log(resource.value); // logs 42
resource.functionA(); // logs "This is working now"
myExtraFile.js
var myExtraFile = { // create a JSON object to export
"value" : 42, // variable
functionA : function() { // function
console.log("This is working now!");
}
};
this.exports = myExtraFile; // export this function for
// later use