Node requiring directory rather than specific file - javascript

Are these two statements equivalent?
const deviceModule = require('..').device;
const deviceModule = require('../device');
I thought require needed a module (with our without path) as the parameter. How is it that a directory can be provided and what does the .device do?
Thanks to anyone who can help me understand node.js and javascript better.

require('..').device requires index.js from the parent directory, and then gets device from that file.
So if you had the following structure:
- index.js
- /foo
- - bar.js
With index.js having the following:
module.exports = {
device: "baz"
};
Then require("..").device in bar.js would give you "baz".
Here is the specification for loading a directory:
LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.
b. let M = X + (json main field)
c. LOAD_AS_FILE(M)
2. If X/index.js is a file, load X/index.js as JavaScript text. STOP
3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
4. If X/index.node is a file, load X/index.node as binary addon. STOP
So in your example, it will:
look for package.json and get the main property, and then load that if it exists
If step 1 does not exist, it will load index.js if it exists
If step 2 does not exist, it will load index.json if it exists
If step 4 does not exist, it will load index.node if it exists

You can use module require-file-directory.
1- Helps to require all the files only with name. No need to give absolute path of files.
2- Multiple files at a time.

Related

How to ignore multiple directories and files using electron releoad

I have an Electron project using electron-reload, the file structure is:
./public/templates/ --------- contains some html that should be watched and trigger reload
./public/templates/test/ ---- contains some test/experimental html that should be ignored/not trigger reload
./notes --------------------- just containing some notes, this should not trigger reload
./node_modules -------------- should be ignored
./main.js ------------------- should trigger reload on change
I know I can ignore directories by setting the option ignored on requiring electron reload in main.js.
This uses chokidar for filtering, ignored option is described here
But I don't get how to ignore multiple paths.
I tried to require electron reload like this:
require('electron-reload')(__dirname, {ignored: /node_modules|notes|public\/templates\/test/gi});
But when I change a file in
public/templates/test/ the application is reloading.
electron 5.0.6
electron-reload 1.5.0
Thanks in advance
Kevin
You can check the eletron-reload module.
electron_reload(paths, options):
paths: a file, directory or glob pattern to watch
options will default to {ignored: /node_modules|[\/\\]\./, argv: []}.
Then in the ignored field you put Regular Expressions of what you want to ignore. You can check the regular expressions here
For example, if I want to ignore all the folders: node_modules, files/img, resorces within my directory. The main.js would be:
//main.js
const ignoredNode = /node_modules|[/\\]\./;
const ignored1 = /resources|[/\\]\./; // all folder resorces => resources
const ignored2 = /files\/img|[/\\]\./; //all folder files/img => files/img
if (process.env.NODE_ENV !== 'production'){
require('electron-reload')(__dirname, {ignored: [ignored1, ignored2, ignoredNode] });
}
This prevents an application reload whenever there are changes within the folders: node_modules, files/img, resorces.
Now you have to use regular expressions for your purpose.

node.js: require json file returns MODULE NOT FOUND

I'm trying to store a json array to a variable, but node.js return this error: { Error: Cannot find module 'jokes.json'
Here is my code:
let jsonData = require('jokes.json');
var jokes = jsonData.jokes;
The jokes.json file is in the same directory as the javascript file
If you just want the quick answer, you need to change to:
let jsonData = require('./jokes.json');
to instruct the nodejs module loader to look in the current module's directory for jokes.json. Yes, this is somewhat surprising to a node.js newbie, but there is some method to the madness (see below).
All the rules for loading modules via a relative path are described here: https://nodejs.org/api/modules.html#modules_all_together. I'd really suggest reading it.
To make it easier to discuss, I'll include a portion here:
require(X) from module at path Y
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with '/'
a. set Y to be the filesystem root
3. If X begins with './' or '/' or '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. THROW "not found"
LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If X.js is a file, load X.js as JavaScript text. STOP
3. If X.json is a file, parse X.json to a JavaScript Object. STOP
4. If X.node is a file, load X.node as binary addon. STOP
LOAD_INDEX(X)
1. If X/index.js is a file, load X/index.js as JavaScript text. STOP
2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
3. If X/index.node is a file, load X/index.node as binary addon. STOP
LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.
b. If "main" is a falsy value, GOTO 2.
c. let M = X + (json main field)
d. LOAD_AS_FILE(M)
e. LOAD_INDEX(M)
f. LOAD_INDEX(X) DEPRECATED
g. THROW "not found"
2. LOAD_INDEX(X)
LOAD_NODE_MODULES(X, START)
1. let DIRS = NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = [GLOBAL_FOLDERS]
4. while I >= 0,
a. if PARTS[I] = "node_modules" CONTINUE
b. DIR = path join(PARTS[0 .. I] + "node_modules")
c. DIRS = DIRS + DIR
d. let I = I - 1
5. return DIRS
Because require('jokes.json') does not start with / or ., your require() statement goes to this:
4. LOAD_NODE_MODULES(X, dirname(Y))
which then calls
NODE_MODULES_PATHS(START)
which builds a list of search paths which includes the directory name from which the current script was loaded with an attached "/node_modules" sub-directory any global module install locations. It will not include the directory that the current module was loaded from.
if you are importing something custom module or file u have to require it below way (using relative path )
let jsonData = require('./jokes.json');
and for system module u can import this way const express = require('express')
if you create another module in ur folder name express and if you require it this way
const express = `require('./express')`
it will find ur custom express.js file not the express module

"." not being parsed as part of a require() Node.js

I've been working on a project and ran into an issue when I was reorganizing my files. The "." on my requires are not being parsed.
When I run my program I get a
Error: Cannot find module './src/map/createMap.js'
Here is my code:
server.js (main file):
process.chdir(__dirname);
//Completely unrelated code...
const gameConsole = require('./src/backend/console.js');
gameConsole.start();
console.js:
const {createMap} = require('./src/map/createMap.js'); << Error thrown here
const Server = require('./server.js').Server; << Error thrown here if I use path.resolve()
I've tried using path.resolve(), and that works fine. When I log process.cwd() it has the path of my root directory (the one with server.js). I am considering storing the paths as global variables. Thanks for your help.
EDITS:
Sample of file structure:
(root)
|_server.js
|_src
|_backend
| |_console.js
|_map
|_createMap.js
Here is createMap.js, on my git repo: https://github.com/ArkinSolomon/zombie-fight/blob/master/src/map/createMap.js
From the code you've linked, the path to ./src/map/createMap.js in console.js is wrong.
The correct path would be
../map/createMap.js
Go up 1 folder ../ then you've access to map folder
And for server in console.js, the path would be:
const { Server } = require('../../server.js')
Go up 2 folder ../../ as console.js is 2 folders deep relative to server.js
What about to use "../map/createMap.js"?

Copy files with Yeoman generator doesn't work

I'm developing my own generator with Yeoman. When I try to copy some files, nothing happens. No error, the process continues until it reach the end, but no files are copied. The generator has a /templates dir with a bunch of html files, each file has a few html lines, at the moment quite simple stuff.
This is my copy method:
copyMainFiles: function(){
console.log('copyMainFiles dir:' + process.cwd() + '+++++');
console.log('file exists? '+fs.existsSync('_footer.html') );
this.copy("_footer.html", "app/footer.html");
console.log('footer copied');
this.copy("_gruntfile.js", "Gruntfile.js");
console.log('gruntfile copied');
this.copy("_package.json", "package.json");
console.log('package copied');
this.copy("_main.css", "app/css/main.css");
console.log('main.css copied');
var context = {
site_name: this.appName
};
console.log('all files copied');
//template method makes the replacement and then copy
this.template("_header.html", "app/header.html", context);
console.log('header template processed');
},
this is the console output:
$ yo trx
method 1 just ran
method 2 just ran
? What is your app's name ?
Kosheen
? Would you like to generate a demo section ? Yes
all dirs created
copyMainFiles dir:C:\cygwin\Applications\MAMP\htdocs\prueba-trx+++++
file exists? false
footer copied
gruntfile copied
package copied
main.css copied
all files copied
header template processed
running npm
and that's it. Never returns to system prompt.
Besides the fact that fs.existsSync returns false (the file exists: htdocs\generator-trx\generators\app\templates_footer.html ), if I try to copy a non-existent file I get the typical error.
Folders are created previously with no issue. There's a .yo_rc.json file with {} in the root of the destination folder. The Yeoman version is 1.4.8, working on Windows 7.
Is copy() the proper way to do this or is no longer valid? How can I copy a simple file in this scenario?
Beside the fact of I was using deprecated methods, the proper way to achive this task is as follow:
this.fs.copy(
this.templatePath('_bower.json'),
this.destinationPath('bower.json')
);
Not sure what your issue is, but you should read the Yeoman official documentation on how to handle files: http://yeoman.io/authoring/file-system.html
You're using old and deprecated methods.

How to create QUnit tests with reference to another class?

I'm trying to add unit testing for JavaScript into my web site. I use VS2013 and my project is an ASP.NET web site.
Based on recommendations (http://www.rhyous.com/2013/02/20/creating-a-qunit-test-project-in-visual-studio-2010/) I've done so far:
Created new ASP.NET app
Imported QUnit (using NuGet)
Into "Scripts" added links to js-file in my original web site (files PlayerSkill.js - containts PlayerSkill class and trainings.js - contains Trainer and some other classes)
Created new folder "TestScripts"
Added TrainingTests.js file
Wrote simple test:
test( "Trainer should have non-empty group", function () {
var group = "group";
var trainer = new Trainer(123, "Name123", group, 123);
EQUAL(trainer.getTrainerGroup(), group);
});
Notice: my trainings.js file among others contains
function Trainer(id, name, group, level) {
...
var _group = group;
this.getTrainerGroup = function () { return _group ; }
};
When I execute my test I see error: Trainer is not defined.
It looks like reference to my class is not recognized. I feel like linking file is not enough, but what did I miss?
Please help add reference to the original file with class and run unit test.
Thank you.
P.S. Question 2: Can I add reference to 2 files (my unit test will require one more class which is in another file)? How?
You should add all the relevant logic of your application to your unit testing file so they all execute before you run your tests
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Test Results</title>
<link rel="stylesheet" href="/Content/qunit.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="/Scripts/qunit.js"></script>
<script src="/Scripts/PlayerSkill.js"></script>
<script src="/Scripts/trainings.js"></script>
<script src="/TestScripts/TrainingTests.js"></script>
</body>
</html>
You should not use linked files because they will not exist physically in the script folder.
If you really want to use them you should let the Visual Studio intellisense resolve the physical path of the file like this.
Type the script tag <script src=""></script>
Place the cursor inside the quotes in the src attribute and press CTRL + SPACE
Search your files and let the resolved path untouched
If your project location changes you must update the linked files and also the script references.
{Edit1}
Solution 2:
You could also use an MVC Controller and a Razor View to create your unit testing page and the linked files will work as expected with the only issue that you will have an extra controller in your project but this is not bad at all if for example you want to test the loading of content using ajax that is by default blocked by the browser if they are run from a local file.
Solution 3:
You can also setup a new MVC project just for your javascript unit testing just as you usually setup a new project for any server side code and this will help to prevent your testing to interfere with your production code
{Edit 2}
Solution 4:
As part of the javascript ecosystem you could use grunt or gulp to automate the copy of your scripts from anywhere to your project before running the tests. You could write a gulpfile.js like this
var sourcefiles = [/*you project file paths*/];
gulp.task('default', function () {
return gulp.src(sourcefiles).pipe(gulp.dest('Scripts'));
});
And then run it opening a console and running the command gulp or gulp default
Looks like trainings.js is not defined when calling TrainingTests.js . See this question for more details regarding why this happens! Once that is fixed it does work. And yes similar to trainings.js you can have any number of files in any folder as long as you reference them properly. I have created a sample fiddle accessible # http://plnkr.co/edit/PnqVebOzmPpGu7x2qWLs?p=preview
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="http://code.jquery.com/qunit/qunit-1.18.0.js"></script>
<script src="trainings.js"></script>
<script src="TrainingTests.js"></script>
</body>
In my case I wanted to run my tests from within my ASP.NET web application, and also on a CI server. In addition to the other information here I needed the following, otherwise I experienced the same error as the OP on my CI server:
Add one or more require() calls to test scripts.
Set the NODE_PATH environment variable to the root of my application.
Example of require()
Within my test scripts I include a requires block, the conditional allows me to use this script from a web browser without needing to adopt a third-party equivalent such as requirejs (which is convenient.)
if (typeof(require) !== 'undefined') {
require('lib/3rdparty/dist/3p.js');
require('js/my.js');
require('js/app.js');
}
Example of setting NODE_PATH
Below, 'wwwroot' is the path of where /lib/ and other application files are located. My test files are located within /tests/.
Using bash
#!/bin/bash
cd 'wwwroot'
export NODE_PATH=`pwd`
qunit tests
Using powershell
#!/usr/bin/pwsh
cd 'wwwroot'
$env:NODE_PATH=(pwd)
qunit tests
This allowed me to run tests both within my ASP.NET web application, and also from a CI server using a script.
HTH.
If you're wondering how to make your tests see your code when running from command line (not from browser!), here is a bit expanded version of Shaun Wilson's answer (which doesn't work out-of-the-box, but contains a good idea where to start)
Having following structure:
project
│ index.js <--- Your script with logic
└───test
tests.html <--- QUnit tests included in standard HTML page for "running" locally
tests.js <--- QUnit test code
And let's imagine that in your index.js you have following:
function doSomething(arg) {
// do smth
return arg;
}
And the test code in tests.js (not that it can be the whole content of the file - you don't need anything else to work):
QUnit.test( "test something", function( assert ) {
assert.ok(doSomething(true));
});
Running from command line
To make your code accessible from the tests you need to add two things to the scripts.
First is to explicitly "import" your script from tests. Since JS doesn't have sunch a functionality out-of-the box, we'll need to use require coming from NPM. And to keep our tests working from HTML (when you run it from browser, require is undefined) add simple check:
// Add this in the beginning of tests.js
// Use "require" only if run from command line
if (typeof(require) !== 'undefined') {
// It's important to define it with the very same name in order to have both browser and CLI runs working with the same test code
doSomething = require('../index.js').doSomething;
}
But if index.js does not expose anything, nothing will be accessible. So it's required to expose functions you want to test explicitly (read more about exports). Add this to index.js:
//This goes to the very bottom of index.js
if (typeof module !== 'undefined' && module.exports) {
exports.doSomething = doSomething;
}
When it's done, just type
qunit
And the output should be like
TAP version 13
ok 1 Testing index.js > returnTrue returns true
1..1
# pass 1
# skip 0
# todo 0
# fail 0
Well, due to help of two answers I did localize that problem indeed was in inability of VS to copy needed file into test project.
This can be probably resolved by multiple ways, I found one, idea copied from: http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
Solution is simple: add tag dynamically
In order to achieve this, I've added the following code into tag:
<script>
var fileref = document.createElement('script');
fileref.setAttribute("type", "text/javascript");
var path = 'path'; // here is an absolute address to JS-file on my web site
fileref.setAttribute("src", path);
document.getElementsByTagName("head")[0].appendChild(fileref);
loadjscssfile(, "js") //dynamically load and add this .js file
</script>
And moved my tests into (required also reference to jquery before)
$(document).ready(function () {
QUnit.test("Test #1 description", function () { ... });
});
Similar approach also works for pure test files.

Categories

Resources