How to use javascript on nodejs and web at the same time? - javascript

i want to use a config file in nodejs and in a web javascript.
config.js:
var conf = {};
conf.name = 'testname';
conf.pass = 'abc123';
conf.ip = '0.0.0.0';
conf.port = 100;
conf.delay = 5;
exports.config = conf;
use it in nodejs with:
var conf = require('config.js');
console.log(conf.config.name);
want to use this same file inside html but how? I was thinking by this way but i don't know how to use it in web. When i try to use it in web i get Reference error: exports is not defined.
config.html:
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
<script src="./config.js"></script>
<script>
var cnf = conf;
function getCnf(){
alert(cnf.config.name);
}
</script>
</head>
<body>
<button onclick="getCnf();">test</button>
</body>
</html>
Anyone know how i must change config.js to use it in both systems nodejs and web?
PS: Webside is running on nodejs http npm module.

You can put a condition around that, like this
if (typeof module !== 'undefined' && module.exports) {
module.exports.config = conf;
}
This makes sure that you have module and exports are available before setting any value on exports.
Note: exports is just another variable referring module.exports. So, they both are one and the same unless you assign something else to either of them. In case, you assign something to either of them, whatever is there in module.exports will be exported in Node.js. You can read more about exports in this blog post

Thanks, that typeof was all i needed.
#Phoenix: I know that there is a way to do that but that's not necessary. The variable are only used for some ajax requests and deley timers later.

You can use browserify to bundle your CommonJS for the browser without resorting to environment switches.
Install browserify using npm i browserify -g
Bundle your config.js and export it for external use with the -r tag
browserify -r ./config.js -o bundle.js
Include the bundle in your code and use it:
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
<script src="./bundle.js"></script>
<script>
var cnf = require("./config.js");
function getCnf(){
alert(cnf.config.name);
}
</script>
</head>
<body>
<button onclick="getCnf();">test</button>
</body>
</html>

Related

How to import modules for unit tests with QUnit

I've been trying to add unit tests for some modular ES6 code. I have a project structure like this:
project
└───src
| └───js
| cumsum.js
| index.js <--- entry point
└───test
tests.js <--- QUnit test code
This is what's in cumsum.js:
export const cumsum=x=>{
var result = x.reduce((r, a)=> {
if (r.length > 0) {
a += r[r.length - 1];
}
r.push(a);
return r;
}, []);
return result;
}
Now, if I run this sample test by running qunit in the command line, it will work:
const A=[1,2,3,4,5];
const expected=[1,3,6,10,15];
QUnit.test( "cumsum", function( assert ) {
assert.deepEqual([1,3,6,10,15],expected);
});
but if I try to import the actual cumsum function, it doesn't recognize proper ES6 import syntax:
import {cumsum} from '../src/js/cumsum';
const A=[1,2,3,4,5];
const expected=[1,3,6,10,15];
QUnit.test( "cumsum", function( assert ) {
assert.deepEqual(cumsum(A),expected);
});
I just get the error
SyntaxError: Unexpected token {
Is there a way to use QUnit with ES6 modules? If not, is there a unit testing framework that will let me test these modules?
Here's what I've come up with so far.
Chrome can sort of natively run ES6 modules. It's not good enough for web production but it is enough to run some unit tests. So in the test folder I have index.html like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>QUnit Example</title>
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.9.2.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="https://code.jquery.com/qunit/qunit-2.9.2.js"></script>
<script type="module" src="../src/js/cumsum.js"></script>
<script type="module" src="tests.js"></script>
</body>
</html>
In test/tests.js I have the original test code:
import {cumsum} from '../src/js/cumsum';
const A=[1,2,3,4,5];
const expected=[1,3,6,10,15];
QUnit.test( "cumsum", function( assert ) {
assert.deepEqual(cumsum(A),expected);
});
Now, for some reason you can't directly open test/index.html in the web browser because although Chrome will happily read ordinary javascript files locally it will break if you set type="module" on a local file. Instead we have to launch a web server and view it that way. Any dev server will do, so webpack-dev-server works fine. Open http://localhost:8080/test/ in Chrome and the unit tests load.
Does anyone have a better way of doing this? Node.js uses the same javascript engine as Chrome so in theory I think it should be possible to do this from the command line without launching a web server and opening a browser.

Using express-babelify-middleware with FeathersJS

I am trying to use express-babelify-middleware
with FeathersJS and the error shows up in the browser console:
ReferenceError: main_run is not defined
I take this to mean that babelify is not working or I am using it incorrectly as main_run is in the global namespace of the src in my html file.
Here is my setup using the structure from feathers generate:
public/index.html:
<!DOCTYPE html>
<html>
<head>
<title>babelify test</title>
<script src="main.js"></script>
<script>
main_run()
</script>
</head><body>
<p>Testing feathers with babelify</p>
</body></html>
public/main.js
const external_module = require('./test')
function main_run(){
external_module()
}
public/test.js
module.exports = function(){
console.log("Hello world for an external module")
}
among the .uses of src/app.js:
...
const babelify = require('express-babelify-middleware')
...
app.use(compress())
.options('*', cors())
.use(cors())
//the line that is not working:
.use('/main.js', babelify( path.join(app.get('public'), 'main.js') ))
.use(favicon( path.join(app.get('public'), 'favicon.ico') ))
.use('/', serveStatic( app.get('public') ))
When I visit localhost:3030/main.js I can see the file, but the functions look to be in a function of their own, so I don't know how to get into that function.
Silly problem, one can't access browserified code in the html file that calls it. So public/index.html can't access main_run unless it is attached to the window object. There is a similar question
here.
Other than that, my code works perfectly.
In main.js place the following code at the bottom:
window.main_run = main_run
Then in index.html replace the main_run() line with:
window.main_run()
This will write the contents of test.js to the console.

"ReferenceError: window is not defined" when compiling with r.js

I've been using RequireJS and it works perfectly. I use a lot of "window.document" to manipulate different DOM elements, but when I try to optimize it with r.js i get a ReferenceError: window is not defined which only happens with r.js.
Here is a minimal example of code that reproduces the issue:
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body >
<div id="commentbox">
</div>
<script data-main="code/main" src="code/require.js"></script>
</body>
</html>
main.js:
require(["roomManager"], function (roomManager){
return {
}
});
roomManager.js:
define(["commentManager"], function(commentManager){
var commentHand = new commentManager.commentHand();
commentHand.init();
return{
}
});
commentManager.js:
define([], function(){
function commManager(getDisplayIdVariable){
var messagebox = window.document.getElementById("commentbox");
this.init = function(){
messagebox.innerHTML = "hi!";
}
}
return{
commentHand : commManager
}
});
This version works correctly without r.js but when I try to compile it by running r.js main.js. I get this:
var messagebox = window.document.getElementById("commentbox);
ReferenceError: window is not defined
at new new commManager
You cannot just do r.js main.js.
For one thing, you have to specify -o so that r.js performs the optimization. (r.js can be used for other things.)
You also have to pass configuration to r.js, either in a file, or on the command line. One possibility for you would be:
r.js -o name=main out=built.js
I've tried this with the code you show in your question and I get no errors.
I strongly suggest going over this documentation for r.js.
if your code is optional you can use
if (typeof window !== 'undefined') {
// Inside browser
}
{
// outside browser
}

How do I access the global object (window) using webpack?

I'm trying to interface ActionScript with JavaScript using ExternalInterface and webpack.
ExternalInterface can only provoked (call) functions found on the global object (window). How can I get a webpack module reference on window (global object)?
Allow me to elaborate some, I want to have a namespace for the company (window.companyName) with an interface for ExternalInterface:
window.companyName = { isReady: function() { ... },
driver1: function() { ... },
driver2: function() { ... } }
The ActionScript will drive my JavaScript. The more fundamental question is, how do I set globals using webpack so that ExternalInterface can see them (preferably as exports of a module)?
I've tried using expose-loader, exports-loader imports-loader with no luck. expose-loaderis ideally what I need, but doesn't seem to work. When I set window.companyName in my modules and try to verify it in my chrome console, it results in undefined.
Aren't you using webpack-dev-server?
Because when I try webpack command everything is working fine. I'm testing it by typing window.mySampleGlobalVariable in chrome developer tools.
BUT when I run webpack-dev-server command then my window variable is undefined.
I have this sample app:
app.js
window.mySampleGlobalVariable = 'TEST';
console.log('App is ready');
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Webpack test</title>
</head>
<body>
Webpack test
<script src="bundle.js"></script>
</body>
</html>
webpack.config.js
var path = require('path');
module.exports = {
entry: './app.js',
output: {
filename: './bundle.js'
},
resolve: {
extensions: ['', '.js']
}
};
You do have access to window object from your webpacked script. Webpack does not interfere with it since the wrapper function only injects module, exports and __webpack_require__ arguments.
Try it writing a script with a single line accessing window object and then check out the output script.
Your assignment should work, unless the execution never reaches it or some loader is altering the relevant code.
If you running webpack-dev-server with the iframe you cannot access the variable via the Chrome console.

How can I make Google's closure library load faster?

I'm writing a simple phone number parser based on [libphonenumber]. Unfortunately, "http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js" takes forever to load, and when I wget the file and just include it as src="base.js", a bunch of errors pop up.
My guess is that this is because the library has not yet loaded yet, so the goog.require() statements are failing.
What can I do?
<!DOCTYPE html>
<html>
<head>
<title>Phone Number Parser</title>
<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
<script>
goog.require('goog.dom');
goog.require('goog.json');
goog.require('goog.proto2.ObjectSerializer');
goog.require('goog.string.StringBuffer');
</script>
<script src="phonemetadata.pb.js"></script>
<script src="phonenumber.pb.js"></script>
<script src="metadata.js"></script>
<script src="phonenumberutil.js"></script>
</head>
<body>
<script>
numbers = ['6509066389', '+40723875777', '720-935-6433', '914-262-7178', '7123040634'];
for (i in numbers) {
console.log(format_for_five9(numbers[i]));
}
function format_for_five9(phoneNumber) {
var $ = goog.dom.getElement;
var regionCode = 'US';
var output = new goog.string.StringBuffer();
try {
var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
var number = phoneUtil.parseAndKeepRawInput(phoneNumber, regionCode);
number_json_serial = goog.json.serialize(new goog.proto2.ObjectSerializer(goog.proto2.ObjectSerializer.KeyOption.NAME).serialize(number));
number_json = goog.json.parse(number_json_serial);
if(phoneUtil.isValidNumberForRegion(number, regionCode)) {
five9_format = number_json.national_number.toString();
}
else {
five9_format = number_json.country_code.toString() + number_json.national_number.toString();
}
} catch (e) {
output.append('\n' + e);
console.log(e);
}
return five9_format;
}
</script>
</body>
</html>
The closure library is meant to be used in conjunction with the closure compiler to compile and minify your javascript for production. It's not intended to be used as a raw file in production. Even in your dev environment you can use http://plovr.com/ to dynamically compile and serve your javascript.
Closure is very verbose in raw form because of the type annotations and the java like structure, the closure compiler will not only minify the script, but also optimize and remove unused scripts to make things faster.
Here's an example of using plovr to dynamically serve your javascript code
java -Xmx256m -jar plovr.jar serve -p 9811 /path/to/your/closure/config.js
This will serve the compiled javascript files on localhost:9811. For production:
java -jar plovr.jar build /path/to/your/closure/config.js > production.js
Have a look at the documentation http://plovr.com/docs.html on how to configure plovr to compile or serve your javascript.
You shouldn't be directly linking the library in the first place.
The solution is to download the entire library and host them it the same web server that hosts the above code. You should probably store the javascript in the same directory as phonemetadata.pb.js, metadata.js, etc. That would allow you to include the script just like all the others:
<script src="base.js">
You can download Closure via git (git clone https://github.com/google/closure-library.git), or as a zip file.

Categories

Resources