NodeJs : modules.export : Cannot find one of my own custom module - javascript

I am trying to include my own users.js module to my router file. It keeps throwing the error:
Cannot find module './router/users.js'
My directory structure is as follows:
nodejs (Main folder on my drive)
-- expressserver.js (My server file)
-- package.json
-- router (folder containing main.js router and users.js user details file)
----- main.js
----- users.js
----- orders.js
Here my users module is in the same folder as my router (main.js)
My code for router is:
var url = require('url');
var users = require('./router/users.js');
module.exports = function (app) {
app.get('/', function (req, res) {
res.render('index.html');
console.log("Home page displayed");
});
app.get('/login', function (req, res) {
res.render('login.html');
console.log("Log in page displayed");
});
app.get('/api/orders/:id', function (req, res) {
console.log(req.params.id);
res.json(ORDER.orders[req.params.id]);
});
app.get('/api/orders/', function (req, res) {
console.log(ORDER);
res.json(ORDER);
});
app.get('/api/users/:id', function (req, res) {
console.log(req.params.id);
res.json(USERS.users[req.params.id]);
});
app.get('/api/users/', function (req, res) {
console.log(USERS);
res.json(USERS);
});
My code for users.js:
module.exports = function () {
// Create User prototype and objects
var USERS = { users: [] };
function User(type, useremail, password) {
this.type = type;
this.useremail = useremail;
this.password = password;
}
var Bob = new User("rep", "bob#bob.com", "qwerty");
USERS.users.push(Bob);
var Helen = new User("rep", "helen#helen.com", "test");
USERS.users.push(Helen);
var Dominic = new User("customer", "dom#dom.com", "1234");
USERS.users.push(Dominic);
var James = new User("grower", "james#james.com", "pass1");
USERS.users.push(James);
};
I'm pretty new to this are but have been reading up alot on modules but still can't figure it out. Any suggestions on where I have gone wrong? or what I need to do to rectify the problem?
Note: Previously I did the same thing for including router into the server file using module.exports = function (app) { around my router and in my server as: require('./router/main')(app);

Since you have specified a relative path to the module, that path is relative to the directory of the source file where require is performed. In your case, it is already relative to the 'router' directory. This will work:
var users = require('./users.js');
Or even just the following, since the extension is automatically resolved:
var users = require('./users');

The path for require(), is set for node_modules folder by default.
That is why you are able to require all modules such as var url = require('url'); in your case.
If the module is not found there in your current project, the module will be searched globally(if there are path variables set on machine).
Now when you define custom modules , you can either keep them within the folder node_modules, OR you can give a path relative to your current JS file within which you are requiring the module.
For example,
var users = require('./users');
If there is another folder, in your current working directory, say modules,
then you can do require it like this:
router
----- main.js
----- orders.js
----------------modules(folder)
-----------------------users.js
var users = require('./modules/users');
So the path for require always starts from node_modules folder

Related

Fs file handler for api

So I want to make a routes folder that has subfolders that contain routes but I don't know how to use fs with it...
I only know how to get files in the routes folder and not in subfolders
here is my file handler code
const { readdirSync } = require('fs');
module.exports = function(app){
readdirSync(__dirname).forEach(function(file) {
if (file == "index.js") return;
var name = file.substr(0, file.indexOf('.'));
const route = require('./' + name)
app.get(`/${route.name}`, async (req, res) => {
route.run(req, res)
})
});
}
it gets the files from the routes folder
-routes
|__index.js
|__route.js
|__route.js
I want to make it so it gets routes from subfolders
-routes
|__index.js
|
|__image routes
|__route1.js
I can't find any help online...
If you do not mind using external libraries i recommend using glob
What you want to do can be achieved with one function call:
const glob = require("glob");
glob("**/*.js", {cwd: __dirname}, (error, matches) => {
if (error) return;
console.log(matches);
})
This uses glob patterns to much files in a given directory, returning the whole paths like: image-routes/route1.js or index.js etc.

Strapi custom routes to redirect to public directory

I deployed my react app to /public directory in strapi, everything work's correctly but, when I refreshed page, strapi override my react-router routs.
So... how can I redirect strapi to open public directory when i use specific routs?
e.g redirect /posts to public directory?
Strapi /public folder is here to server public assets and not to host your front end application. And it's not a good practice to do that.
I had to write that before answering your question.
Here is how static files are served.
https://github.com/strapi/strapi/blob/master/packages/strapi/lib/middlewares/public/index.js
It uses the public middleware.
So you will have to create your own middleware by following this documentation.
https://strapi.io/documentation/3.x.x/advanced/middlewares.html#custom-middlewares
So in ./middelwares/custom/index.js add the following code:
const path = require('path');
module.exports = strapi => {
return {
initialize: function(cb) {
strapi.router.route({
method: 'GET',
path: '/post',
handler: [
async (ctx, next) => {
ctx.url = path.basename(`${ctx.url}/index.html`);
await next();
},
strapi.koaMiddlewares.static(strapi.config.middleware.settings.public.path || strapi.config.paths.static, {
maxage: strapi.config.middleware.settings.public.maxAge,
defer: true
})
]
});
cb();
}
};
};
Then you will have to enable your middleware.
You will have to update the ./config/custom.json file with the following code:
{
"myCustomConfiguration": "This configuration is accessible through strapi.config.myCustomConfiguration",
"custom": {
"enabled": true
}
}
That's it!
I build my Strapi and CRA (create-react-app) at the build time, and says I want to mount my react app under /dashboard path.
and the file structure is:
yourapp/
└── apps/
├── frontend (react app)
└── backend (strapi)
add a homepage property in frontend's package.json if you are using CRA, this will tell Webpack to add a prefix to your static assets, e.g
// in frontend's package.json
{
...
"homepage": "/dashboard"
}
move your built react app to a subfolder /dashboard of backend project, by modifying the yarn build script, I'm doing like this, be careful before copy/paste my code, there is a rm -rf cmd.
// package.json in root path
{
...
"scripts": {
"build": "yarn build:front && yarn build:back && rm -rf apps/backend/dashboard && mv apps/frontend/build apps/backend/dashboard",
...
}
}
add a custom middleware in Strapi to be your "view router", that will handle all requests to /dashboard/* to serve the react app assets under apps/backend/dashboard
create a file under <strapiapp>/middlewares/viewRouter/index.js
const path = require("path");
const koaStatic = require("koa-static");
const fs = require("fs");
module.exports = strapi => {
return {
async initialize() {
const { maxAge } = strapi.config.middleware.settings.public;
const basename = "/dashboard";
const dashboardDir = path.resolve(strapi.dir, "dashboard");
// Serve dashboard assets.
strapi.router.get(
`${basename}/*`,
async (ctx, next) => {
ctx.url = ctx.url.replace(/^\/dashboard/, "");
if (!ctx.url) ctx.url = basename;
await next();
},
koaStatic(dashboardDir, {
index: "index.html",
maxage: maxAge,
defer: false
})
);
const validRoutes = [
"/dashboard",
"/subpath1",
"/subpath2"
];
// server dashboard assets and all routers
strapi.router.get(`${basename}*`, ctx => {
const routePath = ctx.url.split("?")[0];
let fileName = ctx.url;
if (validRoutes.includes(routePath)) fileName = "index.html";
ctx.type = "html";
ctx.body = fs.createReadStream(
path.join(dashboardDir + `/${fileName}`)
);
});
}
};
};
enable the custom middleware in <strapiapp>/config/custom.json
{
"myCustomConfiguration": "This configuration is accessible through strapi.config.myCustomConfiguration",
"viewRouter": { // use the middleware name
"enabled": true
}
}
and visit http://localhost:1337/dashboard you'll see the react page.
The actual answer for strapi#4.3.2 is here
I faced the same problem. All you need to do are these two steps:
Create a custom middleware. I named it spa.js and put it in the folder /src/middlewares/spa.js (I am not sure about naming). I didn't have this folder before. I created it by myself. The file spa.js should contain a code like this:
module.exports = () => {
return async (ctx, next) => {
const url = ctx.url;
// Here you should process your redirects on index.html always,
// except URLs like `admin`, `content-manager`, `i18n`, `static`, `api`, `graphql`, `uploads` etc.
// These settings should be completely the same as in your Nginx config
// for SPA (Single Page Application). Usually, we set up `Location` in Nginx
if (!url.match(/\/admin|\/content-manager\/|\/i18n\/|\/static|\/graphql|\/uploads\/|\.json/)) {
ctx.url = '/';
}
// let strapi go further
await next();
};
};
Register your new middleware in /config/middlewares.js. I had this file and it contained only strings ('strapi::errors', 'strapi::security', 'strapi::cors',). I added an object with a resolve field with a relative path to my new middleware spa.js. There are different options for how you can set up this path, you can also use just a name.
My /config/middleware.js looks like this now:
module.exports = [
{
resolve: './src/middlewares/spa.js',
},
'strapi::errors',
'strapi::security',
'strapi::cors',
'strapi::poweredBy',
'strapi::logger',
'strapi::query',
'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
];
Relaunch your server by strapi start. It should work. Routes after reloading any page that was reached by React-router before will work as they should work in SPA. All routes go to / (index.html)
UPD: Please, be careful. I see many routes for "internal use". For example, /content-manager/ and /i18n/. My admin panel didn't work unless I add the content-manager route. I suppose there may be many new routes in the future and we should mark in our middleware only allowed routes that are redirected and don't change behavior for other routes.

Express routes: .get() requires callback functions but got a [object Object]

Ok, this should be easy for somebody to point out.
I checked the other similar questions and none helped.
I'm trying to move all my routes to a separate routes.js file. In it I have:
module.exports = function (app) {
var user = {
list : require('./routes/user.js')
}
, index = {
index : require('./routes/index.js')
}
app.get('/', function(request, response){
response.send('You made it to the home page.')
});
app.get('/users', user.list);
}
And in my app.js file I have this:
var register_routes = require('./routes.js')
register_routes(app)
My index route works fine, but it kicks back on app.get('/users', user.list); with this error:
.get() requires callback functions but got a [object Object]
This is an out of the box express app so theres not too much to describe.
Thanks.
EDIT: Per request, here is what is in ./routes/user.js :
exports.list = function(req, res){
res.send("respond with a resource");
};
You export an object with the key list having the your function as value.
So to access your function you would need to do this require('./routes/user.js').list
Or with your code user.list.list.
To solve this you have two possibilities.
Either write:
var user = {
list : require('./routes/user.js').list
}
Or:
module.exports = function(req, res){
res.send("respond with a resource");
};
EDIT
If your routes/user.js will probably later look like this:
module.exports.list = function(req, res){
res.send("respond with a resource");
};
module.exports.delete = function(req, res){
res.send("delete user");
};
If yes then you can just write it that way in your routes.js:
var user = require('./routes/user.js');
I think what you want is:
module.exports = function (app) {
var user = {
list : function(request, response){
require('./routes/user.js');
}
}
}
, index = {
index : function(request, response){
require('./routes/index.js')
}
}
app.get('/', function(request, response){
response.send('You made it to the home page.')
});
app.get('/users', user.list);
}
In this way give a callback to the route and this callback execute the require.
If you are using router in your application for all routing purpose,
var express = require('express');
var router = express.Router();
var index = require('./index');
/* GET home page. */
router.get('/', index.list);
module.exports = router;
then in your index.js file, just do
router.list = function(req, res){
res.send("respond with a resource");
};
After so many time seeking around in web, I found something.
First of all, You instantiate the code like this on another file, (e.g.: humancomms.ts):
import express from 'express';
export function shout(request: express.Request, response: express.Response, next: () => void) {
response.send('Shout so loud!');
}
export function speak(request: express.Request, response: express.Response, next: () => void) {
response.send('Speak less loud!');
}
What exactly this code does? Nobody knows.(Hehe, just kiddin')
This make a middleware functions to separate from main server file to... organize, of course.
And how We can use it? Just like this (inside your server file):
const shout = require('./humancomms').shout;
const speak = require('./humancomms').speak;
app.use('/shout', shout);
app.use('/speak', speak);
This code takes all middlewares funcs and executes when some path is called.
This not solve all problems like multi path to same type, as if You want call differently intensities of shout ('/shout/high?asd=asd', '/shout/low?asd=asd'), but there is a catch You can try on secondary file:
import express from 'express';
export function shout(request: express.Request, response: express.Response, next: () => void) {
if (request.path.includes('/high')) {
response.send('Shout so loud!');
} else if (request.path.includes('/low')) {
response.send('Really shout?');
}
}
Look at this good article about:
TypeScript Express tutorial #1. Middleware, routing, and controllers (https://wanago.io/2018/12/03/typescript-express-tutorial-routing-controllers-middleware/)
and the official documentation website:
Writing middleware for use in Express apps (http://expressjs.com/en/guide/writing-middleware.html)

Node.js EXDEV rename error

I've been playing with some code I found in a book about Node.js. It is a simple app which uploads images.
It shows the EXDEV error (500 Error: EXDEV, rename).
Could someone give me a hint? Here's my code:
exports.submit = function(dir) {
return function(req, res, next) {
var img = req.files.photo.image;
var name = req.body.photo.name || img.name;
var path = join(dir, img.name);
fs.rename(img.path, path, function (err) {
if(err) return next(err);
Photo.create({
name: name,
path: img.name
}, function (err) {
if(err) return next(err);
res.redirect('/');
});
});
};
};
Renaming files cannot be done cross-device. My guess is that your upload directory (which by default is /tmp) is on another partition/drive as your target directory (contained in the dir variable).
Some solutions:
configure the upload directory to be on the same partition/drive as your target directory; this depends on which module you're using to handle file uploads, express.bodyParser (and the module it uses, connect.multipart) accepts an uploadDir option that you can use;
before starting your Node app, set the TMPDIR environment variable to point to a temporary directory on the same partition/drive as your target directory. If you're using a Unix-type OS:
env TMPDIR=/path/to/directory node app.js
instead of setting the environment variable from your shell, set it at the top of your Node app:
process.env.TMPDIR = '/path/to/directory';
instead of renaming, use a module like mv that can work cross-device;
Using Windows XP, I added to app.js:
process.env.TMPDIR = '.'; //new

Node js packages for modules

Description:
I have a node js project, I have package models(which contains module with my model object) , have routes package (where module with routes handler functions stored), and app.js file with 'express' configurations and http server.
Question is: How can I import model object from models package to routes package, index.js module?
index.js:
var ArticleProvider = require('smth goes here').ArticleProvider;
var articleProvider= new ArticleProvider();
exports.index = function(req, res){
articleProvider.findAll(function(error, docs){
//console.log(error)
res.send(docs);
});
};
mymodel.js
ArticleProvider = function(){};
ArticleProvider.prototype.dummyData = [];
ArticleProvider.prototype.findAll = function(callback){
callback(null, this.dummyData);
};
ArticleProvider.prototype.save = function(articles, callback) {
var article = null;
if (typeof(articles.length) == "undefined") { articles = [articles]; }
//callback();
};
exports.ArticleProvider = ArticleProvider;
Note: I can import anything from bottom level(for example: if I would have models package inside routes package. Example: require("./models/mymodel.js")).
The solution is
var ArticleProvider = require('../models/articleprovider.js').ArticleProvider;
take a look at npm link https://npmjs.org/doc/link.html
It's allow you to build a packages as a dependency, into node_modules, and then you can require it wherever you want

Categories

Resources