node.js: How to include external .js from another server? - javascript

I am trying to include .js files that are located on another server into my node.js program. Is this possible?
I can´t use require('./local_file.js') and get something over the Internet like this: require('http://www.server.com/path/file.js');
I´ve tried to make a http.request and then use eval(), but the scope is all wrong and the functions inside the external file remain undefined:
var source_string = load_contents_via_http('http://www.server.com/folder/file.js');
var source_string += '\n run_my_function();';
eval(source_string);
Does anyone have any suggestions?
Edit (Solution):
I solved my problem by repacking the essential parts into the script that runs on my local server, as mentioned by #zackehh. Then I used http.request to load and eval specific parts from the remote server when needed. Since the most important code was running on the server locally, the imported extra code was easier to add.
Here is a example on how I solved the problem:
var EssentialObject = {};
EssentialObject.ServerFunctions = {};
EssentialObject.ServerFunctions.Init = function (){
var external_code = load_contents_via_http('http://www.server.com/file.js');
var eval_this = external_code.substr(
external_code.indexOf('EssentialObject.Addons = {}'),
external_code.indexOf('// End of EssentialObject.Addons')-external_code.indexOf('EssentialObject.Addons = {}')
);
eval ( eval_this );
eval ( "EssentialObject.Addons.test=true; console.log('Eval Done')" ); // Check if it works
};

Disclaimer: this technically isn't an answer to the question, I feel it should be classed as one, as it moves towards a solution to the problem.
You could do it with a simple http request, but I don't recommend it. You would be better off repacking the things you need on both servers in npm modules and requiring them in. This allows you share your code pretty painlessly. If you don't want your code public, npm also has new private module options.

Related

Is there a way to read JS code as part of a JS file from another JS file ? (The app uses NodeJS)

I am working on a web app using NodeJS. The concept is : the main structure, to which you add the tools you want depending on what you want in your app.
To achieve that, I want my main JS file (index.js) to read the content of another file (tool.js) as if it was part of the code.
I know I can require a module in NodeJS and call a function from it, but this isn't what I want as I don't want to put the content of the file in a function. Here is an example of what I would like to achieve :
tool.js :
// tool.js
// This executes various actions.
var web_func = require(web_funcs.js); // another module, not important
web_func.executeAction();
console.log('whatever');
index.js :
// index.js
// This is the main file
/*Here I want to call tool.js*/
The goal is to have index.js be read as this :
// index.js
// This is the main file
// tool.js
// This executes various actions.
var web_func = require(web_funcs.js); // another module, not important
web_func.executeAction();
console.log('whatever');
The reason behind this is that I want my mainframe to be easy to deploy with minimal adjustments, and everything regarding the tools to be handled in a different file to make it easier to read.
And since there are several tools and the number will probably grow, I want it to be easily set-up.
If you have any idea or solution, please let me know, as it would be of great help. I've tried looking around but didn't find anything.
EDIT : changed the title of the question for better clarity.
You can read the file first and then use the eval() method to execute the code in string.
Read the code and call eval using this sample:
my-file.js
var a = "test";
console.log(a);
Code:
var fs = require('fs');
var code = fs.readFileSync('my-file.js', 'utf8');
eval(code);
Output:
test
Edit 1:
You can also reuse the variables from the other file in this way. For example, add console.log(a) after the eval(code) line.
...
eval(code);
console.log(a);
The output will be:
test
test

Required script that used to work suddenly returns undefined

I have a functioning NodeJS program that I used to host on my machine. That program requires other scripts that I made for utilitarian purposes, and was using them properly, but now I am dumbfounded as the same script suddenly returns undefined.
I'm not sure why such a thing is happening, I haven't touched a thing since the program was live on my machine. I guess some snippets are in order.
const FileSystem = require('fs')
const credentials = require('../auth/api.json')
const Utils = require('../utils/Utils.js')
let Database = () => { return JSON.parse(FileSystem.readFileSync('./database.json').toString()) }
let Config = () => { return JSON.parse(FileSystem.readFileSync('./utils/config.json').toString()) }
const _pnw = new PnW(credentials.key, credentials.pass)
function parseAlliance(id) {
_pnw.alliance(id)
.then(alliance => {
Utils.log(`Performing checks on ${alliance.members} ${alliance.name} members.`, Utils.LogTypes.CHECK)
let _alliance_members = alliance.member_id_list
let _player = _alliance_members.shift()
parsePlayers(_player, _alliance_members)
})
.catch(console.error)
}
This specific snippet is specifically importing a Utils.js file, which contains lots of useful methods I need for this script to function. However, when I console.log(Utils) now, I only get an empty object {}.
I know the path to the Utils.js file is correct, and I know that it is properly exporting it's methods and properties. I have attempted recloning my project, and rebooting my machine just in case it was a weird quirk of my RAM, but to no avail.
This is quite an important program, I'd like to have it working again soon...
Cheers in advance for the replies
I found a workaround.
I'm still not sure why, but this specific script cannot import anything from outside its own folder. It used to be able to. It used to work flawlessly. Moving the Utils.js folder into the same directory as this script made it work again.
Of course, this isn't a perfect solution, but it works for now. If you have pointers to why this behaviour happened, I'm interested in hearing them.

Moving created files with JXA

I'm new to JXA scripting, but I'm attempting to troubleshoot some older scripts currently in place here at work. They loop through an InDesign document and create several PDFs based on it. Previously, they would be stored in a folder called "~/PDFExports". However, this doesn't work with 10.10.
If I change the code to just place the PDFs in "~/", it works fine. From there, I'd like to move the files to "~/PDFExports", but I can't seem to find an answer on how to do that. I've seen things about making calls to ObjC, or to call Application('Finder'), but neither work - they both return undefined.
Am I just missing something basic here, or is it really this hard to simply move a file with JXA?
EDIT: Some syntax for how I'm creating the folder in question and how I'm attempting to work with Finder.
//This is called in the Main function of the script, on first run.
var exportFolder = new Folder(exportPath);
if(!exportFolder.exists) {
exportFolder.create();
}
//This is called right after the PDF is created. file is a reference to the
actual PDF file, and destination is a file path string.
function MoveFile(file,destination){
var Finder = Application("Finder");
Application('Finder').move(sourceFile, { to: destinationFolder });
alert("File moved");
}
Adobe apps have long included their own embedded JS interpreter, JS API, and .jsx filename extension. It has nothing to do with JXA, and is not compatible with it.
InDesign's JSX documentation:
http://www.adobe.com/devnet/indesign/documentation.html#idscripting
(BTW, I'd also strongly advise against using JXA for Adobe app automation as it has a lot of missing/broken features and application compatibility problems, and really isn't fit for production work.)
Here's the link to Adobe's InDesign Scripting forum, which is the best place to get help with JSX:
https://forums.adobe.com/community/indesign/indesign_scripting
You could use Cocoa to create the folder
var exportFolder = $.NSHomeDirectory().stringByAppendingPathComponent("PDFExports")
var fileManager = $.NSFileManager.defaultManager
var folderExists = fileManager.fileExistsAtPath(exportFolder)
if (!folderExists) {
fileManager.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(exportFolder, false, $(), $())
}
and to move a file
var success = fileManager.moveItemAtPathToPathError(sourceFile, destinationLocation, $());
if (success) alert("File moved");
Consider that destinationLocation must be the full path including the file name
and both sourceFile and destinationLocation must be NSString objects like exportFolder
Could it be that the folder is missing ? Could be your reference to the folder object not valid ? Any syntax to show ?
I will share some of what I learned about JXA move and duplicate methods. I am not a professional programmer just an attorney that is passionate about automation. My comments come from much trial and error, reading whatever I could find online, and A LOT of struggle. The move method does not work well with Finder. Use the System Events move method instead. The duplicate method in Finder works just fine. The duplicate method does not work well in system events. This is a modified snippet from a script I wrote showing move() using System Events.
(() => {
const strPathTargetFile = '/Users/bretfarve/Documents/MyFolderA/myFile.txt';
const strPathFolder = '/Users/bretfarve/Documents/MyFolderB/';
/* System Events Objects */
const SysEvents = Application('System Events');
const objPathFolder = SysEvents.aliases[strPathFolder];
SysEvents.move(SysEvents.aliases.byName(strPathTargetFile), {to: objPathFolder});
})();

Javascript Build Tools To Toggle Urls/Variables Between Production/Deployment

I am beginning my first big javascript project! I had a question about deployment. I am using ajax calls to a webservice. To set this up I have a static JS file with code like:
var API_URL_ROOT = 'http://api.example.com/';
var IN_DEVELOPMENT = True;
if (IN_DEVELOPMENT) {
API_URL_ROOT = 'http://localhost.com/api';
}
$.get(API_URL_ROOT)
I am using python/fabric to deploy. I was wondering if there were any prebuilt tools for handling the static analysis/manipulation of the javascript files., Right now it leaves toggling up to the commiters
I was planning on a deployment process like:
issue deploy command
"build" JS, by setting all values to production values (ie. IN_DEVELOPMENT = False)
Minify JS
Deploy code to production servers
I was thinking of just using sed or something to do the IN_DEVELPMENT = False replacement. I have looked at some of the popular minification tools and none seem to offer this sort of functionality.
I would assume that this is a pretty common problem for applications. How is it usually handled? Any help would be appreciated. Thank you
I recently read an article on hackernews from mozilla:
In the Mozilla Persona code base, we frequently expose difficult to
test private functions to the public interface, clearly marking the
extra functions as part of a test API. While other developers are
still able to call these private functions, the author’s intentions
are clear.
...
publicFunction: function() {
return "publicFunction can be invoked externally but "
+ privateFunction();
}
// BEGIN TESTING API
,
privateFunction: privateFunction
// END TESTING API
};
// privateFunction is now accessible via the TESTING API
function privateFunction() {
...
Code between the // BEGIN TESTING API and //END TESTING API
pseudo-markers can be removed for production during the build process.
So other companies are definitely doing this. Are there premade tools to facilitate the JS build proccess that can remove this code? I glanced at a number of their projects on github and didn't see any. Thank you
We are using dojo
And in dojo you can use conditional exclusions for the build version of your js in order to exclude parts of your code that you would not want in your build js. Hope this helps.
eg:
var API_URL_ROOT = 'http://api.example.com/';
//>>excludeStart("dev",!pragmas.dev);
var IN_DEVELOPMENT = True;
//>>excludeEnd("dev");
if (IN_DEVELOPMENT) {
API_URL_ROOT = 'http://localhost.com/api';
}
$.get(API_URL_ROOT)

How to create AJAX semi-synchronous behaviour

I spent the better part of last month beating my head against the wall before I came up with an easy way to dynamically load, and chain together HTML canvas classes which are stored on the server, but, obviously, initialized on the client (harder than it sounds when the ordering is important in an asynchronous environment).
I was wondering if someone could help me find a way to load simple javascript scripts. Lets define a load('foo.js') function which instructs the client to load script foo.js from the server and execute it as javascript code.
Given the three files, stored on the server:
A.js
a = 10;
B.js
load('A.js');
b = a + 10;
C.js
load('B.js');
c = b + 10;
If the client issues the command load('C.js'); what's the easiest/most reliable way to implement this. One idea I had was to scan the code serverside and return all the scripts at once. This requires the minimal amount of php requests. However, if the client has already requested C.js before, the script should exist client side, and this would be inneficient, especially if C.js and all its dependent files are large. Another option I considered was to wrap all of these serverside scripts in an object like so, for C.js above:
{
depenencies: ['B.js'] ,
code : 'c.age = b.age + 10;'
}
I just don't know how to 'pause' execution of script C.js after the load('B.js') statement, and then resuming it after B.js has been loaded.
EDIT Thanks to redsqaure for suggesting yepnope and requirejs. Unfortunately, I do not like them for several reasons. For one, requirejs is difficult (I am sure I will come under criticism for this one). My main gripe with this is that, if it is so difficult to learn, I might as well recreate it myself, learning it in the process, AND having greater control over it. Second, it requires you to change your style of writing. Switching to Dojo and having to use dojo.declare("ClassName", [ParentA,ParentB], {...}); to declare classes is one thing, but wrapping every snippet of code in require(['A','B',...], function(){}); is another. Finally, I don't know how simple it will be to instruct where to look for files. I want the user to be able to define a 'PATH' variable server side, and have the search occur in each of the folders/subfolders of the 'PATH'
Depends on how optimized you want it to be. Either you can go the route of synchronous XHR or use a callback (async and recommended). If you were to go the second route your code would look something like:
// Say C.js is dependent on A.js and B.js..
load(["A.js","B.js"], function() {
// code goes here
});
EDIT
Taking a second look after you feedback what you want is somewhat possible, but would be brittle and hard to write in javascript. Below i have a sample/untested implementation of a dependency loader where a file can only have one call to load("file.js") possible. This would be more complex for multiple possible dependencies. Also I'm assuming these files are coming from the same domain.
// Usage: load("A.js")
// A.js -> B.js -> C.js
window.load = (function() {
var loaded = {};
return function(str, /* internally used */ callback) {
if(!loaded[str]) {
loaded[str] = true;
$.get(str, function(data) {
var matches = data.match(/load\(['|"](.*)["|']\)/);
if(matches.length > 1) { // has deps
window.load(matches[1], function() {
window.eval(data);
if(!!callback) callback();
});
} else { // no deps
window.eval(data);
}
});
}
}
})();
Why not look into a script loader like yepnope.js or require.js

Categories

Resources