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.
Related
How to write code in node.JS in which we select a directory and the code automatically separates all the files of that selected directory with the same extension and put then in a separate folder.
Something like this will work. Using fs module and path module
Which will first check the extension and rename file (move) to new folder.
You can make changes accordingly. Use if
const testFolder = './';
const fs = require('fs');
var path = require('path')
var oldPath = 'old/path/file.txt'
var newPath = 'new/path/file.txt'
fs.readdir(testFolder, (err, files) => {
files.forEach(file => {
const ext = path.extname(file);
fs.rename(oldPath, newPath, function (err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
})
});
});
I have create react app code base in which i would like to be able to iterate over a nested structure of data to import one specific file.
I have the following structure:
root.js
-modules
-- mod1
--- index.js
-- mod2
--- index.js
In root.js I would like to go over every module in modules to import index.js so that the initialization data will be run at the start of the application. Its unclear to me what is the best way to do this preferably without using any plugins if there is a solution.
In my opinion, you should include them "manually"
// root.js
require('mod1.index')
require('mod2.index')
// ...
It's more clear and direct. Unless you have 100+ modules
EDIT for dynamic import:
No dependancies proposal (variation of https://gist.github.com/kethinov/6658166#gistcomment-1603591)
'use strict'
const fs = require('fs')
const walkSync = function (dir, filelist) {
const files = fs.readdirSync(dir)
filelist = filelist || []
files.forEach(function (file) {
if (fs.statSync(dir + '/' + file).isDirectory()) {
filelist = walkSync(dir + '/' + file, filelist)
} else {
filelist.push(dir + '/' + file)
}
})
return filelist
}
allFiles = walkSync('./src')
allFiles.filter(f => f.split('/').pop() == 'index.js').forEach(f => require(f))
One dependacie proposal: Get all files recursively in directories NodejS
Turns out this was simple:
Export everything in a modules.js files.
const req = require.context('./', true, /^\.\/[a-zA-Z0-9]+\/index.js$/);
const modules = req.keys().map(req);
module.exports = modules;
Then import the modules.js file in some root.js file.
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.
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
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