Images not loading unless I rebuild App Next JS - reactjs

I am having trouble with images lately in next js. I know next has deprecated support for static in favour of public directory. So even after refactoring, I still cant get images to load. Here is the flow:
I choose an image for a project and send an axios request to the server. The server only saves the path to mongodb like this:
staticPath = `/ProjectImages/projImg_${req.decodedTokenData.userId}_${_id}_${key}.png`;
let imagePath = path.normalize(__dirname + `/../../public${staticPath}`);
dbImages.push(staticPath);
and writes the image's base64encoded value to a file and saves it to ProjectImages directory in public dir.
Now when I create a project, the images doesnt load even though it has reference to the path and the image itself is in the correct place. Only after rebuilding the app do I see the image.
Note: this issue does not occur in development mode only in production.
please help.!

Masla he koi ni
rather than calling the images from source directly i would recommend you to create a route and serve all those images from there
const express = require("express");
const router = express.Router();
const path = require('path');
const fs = require('fs');
router.get('/media/project/:path',function (req,res,next) {
const _path = `/static/ProjectImages/${req.params.path}`;
let imagePath = path.normalize(__dirname + `/../../public${_path}`);
try{
if (fs.existsSync(imagePath)) {
res.sendFile(imagePath);
}else{
res.sendStatus(404);
}
}catch (err) {
res.sendStatus(404);
}
});

Related

Loading contents of files into a NextJs app at runtime as env vars

I'm trying to load the contents of files in a specific folder as env vars accessible at process.env.SomethingHere at runtime not build time as those files don't exist at build time yet (if process.env is the right place to load those secrets, more about that in the end). I managed to write the code to read the files and create a key-value object/dictionary from them, but not sure where is the best spot in the app lifecycle to add this so it's available for both server-side middleware and client-side frontend
function readFiles(dir) {
var vars = {};
if(!fs.existsSync(dir))
{
console.log("failed to load files in directory: " + dir);
return vars;
}
// read directory
let fileNames = fs.readdirSync(dir);
if (!fileNames) {
console.log("failed to load files in directory: " + dir);
return vars;
}
fileNames.forEach((filename, index) => {
// get current file name
const name = path.parse(filename).name;
// get current file path
const filepath = path.resolve(dir, filename);
// get information about the file
let stat = fs.statSync(filepath);
if (!stat) {
console.log("failed to load file stats: " + name);
return;
}
// check if the current path is a file or a folder
const isFile = stat.isFile();
// exclude folders
if (isFile) {
let data = fs.readFileSync(filepath);
if (!data) {
console.log("failed to load file: " + name);
return;
}
let content = data.toString('utf8', 0, data.length);
// callback, do something with the file
vars[name] = content;
}
});
return vars;
}
Some background:
I'm using Azure keyvault for storing secrets and have a Kubernetes cluster with a frontend and a backend pod.
In the backend pod I was able to mount the secrets using CSI driver fetch the values at app startup and load that into the python os.environ. I'm trying to achieve the same for the frontend pod, the mounting is successful, but I haven't been able to place my code in the right spot to load the secrets into process.env if this is even the right place to add them.
ChatGPT solved the issue eventually, here is the answer:
In a Next.js application, the server-side entry point is the server.js file located in the root directory of the project. By default, this file exports the createServer function, which is used to create the Express server that handles server-side rendering of the application.
You can add your code to load the environment variables in this file by importing the readFiles function and using the Object.assign() method to merge the key-value object with the existing process.env object, like this:
env.js
function readFiles(dir) {
// existing code here
}
module.exports = readFiles;
server.js in the root directory of the project
const readFiles = require('./env');
const dir = './dir_name'
const envVars = readFiles(dir);
Object.assign(process.env, envVars);
const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = 3000
const {createServer} = require('next');
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler();
app.prepare().then(() => {
createServer(handle).listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://${hostname}:${port}`)
});
});

How to list all pages in a path?

I have a structure like this:
pages:
- route1
- lots of js page
- index.js
I would like to display a list of all pages under route1 on my index page.
How can I fetch all available pages?
I tried to use getStaticProps in index to load all the files using fs and path but I am not able to require all the pages.
export async function fetchPages() {
const fs = require('fs')
const path = require('path')
const files = fs.readdirSync(path.join(process.cwd(), '/pages/route1/'))
return map(files, (f) => {
return require(path.join(process.cwd(), '/pages/route1/', f))
})
}
but this is not working.
Edit: require is used to load all the export from those pages such as title of the page or excerpt to display on the index page.
Edit: The error is Error: Cannot find module '/path/to/pages/route1/pageName.js'. Coming from the require.
Edit: I tried to use How to generate a menu based on the files in the pages directory in Next.js but it does not work since in the next config file we have to use require/module.export but the require('path/to/page') is going to bring react pages with imports and exports
Can you create a page variable as an Array and push routes ?
const fs = require('fs')
const path = require('path')
const pages = []
const files = fs.readdirSync(path.join(process.cwd(), '/pages/route1/'))
files.forEach((file) => {
pages.push(require(path.join(process.cwd(), '/pages/route1/', file)))
})
return pages

Error creating StandardAppVersion: googleapi: Error 404: App does not exist

Hi i am trying to create a simple node app on google app standard app engine using this terraform code. This code used to work before but today i was trying to restart the whole project and re-deploy everything again and i see that i am getting an error.
compute_engine.tf
resource "google_app_engine_standard_app_version" "nodetest" {
version_id = "v1"
service = "mainApp"
runtime = "nodejs10"
instance_class = "B1"
basic_scaling {
max_instances = 1
}
entrypoint {
shell = "node test.js"
}
deployment {
files {
name = google_storage_bucket_object.object.name
source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
}
}
delete_service_on_destroy = true
depends_on = [
google_project_service.appengine_api
]
}
resource "google_storage_bucket" "bucket" {
project = var.project_id
name = var.bucket_name
location = var.region
}
resource "google_storage_bucket_object" "object" {
name = "test.js"
bucket = google_storage_bucket.bucket.name
source = "test.js"
}
My test.js is located in the same directory as where tf is located.
test.js
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
I see that the files have already been deployed correctly
And the error i am getting
I tried changing the url from
"https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
To
"https://storage.cloud.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
Try changing the shell = "node test.js" to shell = "node ./test.js"
Also i did take a look at GitHub Issue 4974 but is doesnt solve my problem. I did notice that when i try to terraform apply the error pretty much pop up quite fast so it seem that is stuck on a very first validation error.
Does the user that runs compute_engine.tf has "appengine.applications.create" and deploy permissions?
Also check if you set project and region in your google provider.

create react app Configuration file after build app

I want a Config File (JSON) in root folder after build to config my app.
like Translation and API Urls and ...
Can I do this with create react app?
Create config.js or json file outside src directory and include it in index.html like
<script src="%PUBLIC_URL%/config.js" type="text/javascript"></script>
configure parameters in config.js
config.js
var BASE_URL = "http://YOUR-URL";
you can get paramenters like
const BASE_URL = window.BASE_URL;
You can store you JSON file in the public/ folder and it'll automatically provide this file when you host your Create React App.
Something like: /public/my-configuration-file.json
then when you restart your application:
localhost:3000/my-configuration-file.json
will provide you this json file.
You could create a custom hook that reads a "public" config file using fetch.
// This path is relative to root, e.g. http://localhost/config.json
const configFile = './config.json'
export function useConfig() {
const [config, setConfig] = useState(initialConfig);
useEffect(() => {
(async function fetchConfig() {
try {
const response = await (await fetch(configFile)).json();
setConfig(response);
} catch (e) {
console.log(e);
}
}());
}, []);
return config;
}
Then use it anywhere in you app
function App() {
const config = useConfig();
return (
<div>{config.foo}</div>
);
}
You'll always have an up to date non-cached version of it's data.
updating this topic with a brand new package that is available now that brings the joys of .Net Configuration to the JavaScript world: wj-config.
This package is pretty much an exact answer to what you need. Read this blog post for more information.
It is incredible to me how during over 6 years nobody filled in this gap in React (and JavaScript in general). Anyway, give wj-config a try. I think it will be a positive experience.

Koa.js serve React, api url also render with React page in Chrome

I'm using koa-static to serve static file with root url localhost:3000/, and koa-router to serve RESTful api, like localhost:3000/api/account/login
Make a fakeBuild folder contain only one file index.html. All work fine. root url and api url show correct content.
// serve static file
const serve = require('koa-static')
const staticPath = path.join(__dirname,'..','Client','poker','fakeBuild')
log(staticPath)
app.use(serve(staticPath))
// router
const router = require('./router/Index.js')(app)
Then I try to connect Koa with React
I use yarn build to build React static files, React project is created by create-react-app, not modified.
Then I change the koa-static's target to build folder, just one line changed
const staticPath = path.join(__dirname,'..','Client','poker','build')
Then access localhost:3000/, chrome show React start page, works
Then access localhost:3000/api/account/login, chrome show React start page, what??
Use postman check localhost:3000/api/account/login, it response what I put in router, fine.
So I can use apis, just ignore chrome's result?
It must be React and Chrome doing something extra. I try to remove service-worker.js in React build folder, api url render correctly in chrome.
So anyone can give some documents or explain to help me understand what react done, to keep all the url render it.
And why my api localhost:3000/api/account/login not require service-worker.js (just return some text in response body), also got the js worked. Just because koa-static served the file?
====
Update: my router code, And project available on here
router/Index.js
const Router = require('koa-router');
const R = (app)=>{
const router = new Router();
const api = require('./Api.js');
router.use('/api', api.routes(), api.allowedMethods())
app.use(router.routes())
.use(router.allowedMethods());
};
module.exports = R;
router/Api.js
const Router = require('koa-router')
const log = require('../helper/Utils').log;
module.exports = (function () {
const Api = new Router();
Api.get('/account/login', async (ctx, next)=>{
log("hello");
ctx.status = 200;
ctx.body = `login`
});
Api.get('/account/register', async (ctx, next)=>{
ctx.status = 200;
ctx.body = `register`
});
return Api;
})();

Resources