File path in NextJS api route not resolving - next.js

I'm trying to resolve a file path in NextJS.
I understand that API routes are working a little bit differently when deployed to Vercel. In order to create a correct path to the file I assumed I had to do this:
const svg = fs.readFileSync(
path.join(process.cwd(), "img", "file.svg"),
"utf-8",
);
// ENOENT: no such file or directory
But I cannot make it work. The file cannot be found under that path.
How can I find the correct path for a file in NextJS api routes?
I've followed the documentation of this.
Next version is: 11.1.3
When logging the path, it is giving /var/task/packages/project-root/img/file.svg

Try using
path.resolve("img", "file.svg")
Maybe it should help.

Pretty sure you'll find the file if you serve it as a static file - Next.js documentation here
I'm thinking it's not bundled in the deployment, but whatever you have in /public will definitely be deployed.
Good luck 💪🏻

I manage to create a small sandbox that will clarify your issue. Open it using StackBlitz
Project Structure
.
├── pages
| ├── api
| | ├── hello.js
| ├── _app.js
| ├── index.js
├── public
| ├── 1.txt --> this is a demonstration file
I reproduce your code in the hello api for testing purposes
const { readFileSync } = require('fs');
const { join } = require('path');
export default (req, res) => {
const path = join(process.cwd(), '/public/1.txt');
const value = readFileSync(path, { encoding: 'utf-8' });
res.status(200).json({ value });
};
This API entry is called from the index.js file
import Head from 'next/head';
import { useEffect, useState } from 'react';
export default function Home() {
const [value, setValue ] = useState('');
useEffect(() => {
fetch('/api/hello')
.then((res) => res.json())
.then(data => setValue(data.value));
});
return (
<div>
<Head>
<title>Create Next App</title>
</Head>
<main>
<h1>{value}</h1>
</main>
</div>
);
}
Yes, this is a very simplified version (for testing purposes only.. I assume we won't use readFileSync in production) - but - it reproduces your code.
Unfortunately, it works perfectly fine in dev mode and in production mode (npm run build + npm start), which means:
You either misconfigured your img folder
Perhaps you are lacking read permissions for the path you are using. For instance if you deploy your work to a remote machine, most directories will have limited access and therefore prevent you from reading the file (for testing this theory please read this post and execute it on your deployed machine)

For anyone coming across this, I actually opened a ticket at Vercel to ask them about this.
It turns out it was a caching issue that is caused by using Yarn 3
The support redirected me to this page explaining that they would have issues with anything above Yarn 1.
According to them there is nothing really they can do about right now but suggest us to use a different package manager.

I'm using Yarn 1.22, but still have this issue. The reason is because files are not generated during build and run times, so they are never found. The way to get around this is to create a separate .js file that to wrap around the said static files (html, txt, etc). Export this JS object which contains the files, and Vercel will generate them. I'm using this to generate email templates.
//account_verify.js
import path from 'path';
import { promises as fs } from 'fs';
import { prefixPath } from './constants';
// TODO: force this to conform to a typescript type
export default {
subject: 'Confirm Your Account',
data: {
email_verification_link: '{{email_verification_link}}',
first_name: '{{first_name}}'
},
templates: {
txt: fs.readFile(path.join(process.cwd(), prefixPath, 'account_verify.txt'), 'utf8'),
html: fs.readFile(path.join(process.cwd(), prefixPath, 'account_verify.html'), 'utf8'),
}
};

Related

next js api returns no response after deployment

while working on the local host, api and the posts.jaon file also works fine. was able to perform CRUD.But after I deploy it to vercel, the api does not loads.
error in the log is something like this:
[GET] /api/insta 11:39:32:83 [Error: ENOENT: no such file or directory, open './posts.json'] { errno: -2, code: 'ENOENT', syscall: 'open', path: './posts.json' }
expecting a json response in the browser when I hit the api.
the json file is in the pages/api folder of next app.
I tried moving the json file outside pages at the top level of the folder strecture, and changing the path inside the fs("file.json",....). but nothing worked
This article from Vercel might help you:
How to Load Data from a File in Next.js
Here is an excerpt:
import path from 'path';
import { promises as fs } from 'fs';
export default async function handler(req, res) {
const jsonDirectory = path.join(process.cwd(), 'json');
const fileContents = await fs.readFile(jsonDirectory + '/data.json', 'utf8');
res.status(200).json(fileContents);
}
You would then have a folder named json where all the data is saved. That is declared in line 4. If you want to rename it, it is of course possible.

NextJS API file import location

I'm using EJS to build email templates. The problem I'm having is I don't know what is the best location to keep these EJS files and any other file import for production (could be even a zip file in future).
Currently I'm keeping email templates under src/emails folder (next root is src). I performed a test with the following and everything works fine :
import type { NextApiRequest, NextApiResponse } from 'next';
import path from 'path';
const ejs = require('ejs')
type Data = {
name: string;
};
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
const basePath = path.join(process.cwd(), 'src/emails');
ejs.renderFile(basePath + '/userVerification.ejs', { verifyURL: 'testurl' }, (err: {}, data: any) => {
console.log(data);
res.status(200).end('test');
});
}
But I noticed NextJS is getting the file from src folder which won't be available on server. I thought maybe I can put them into src/public folder since it'll be exported but I couldn't make sure.
My question is where is the best location for keeping these files?
After performing a few tests, I noticed that api can actually access to anything within project folder. Only public folder content can be accessed publicly by URL. That being said folder location for custom files can be anywhere.
.next
public
server_files *(all files can be imported by API)*
--ejs (templates email templates)
--pdf (generated invoice etc.)
--zip
src
--components
--pages

Runtime configs in nextjs

I'm trying to setup my nextjs app to use runtime configurations. Basically, I have an endpoint url that needs to be available trough docker env vars.
I configured following these docs but it isn't working. My app still using default values from .env file. Could anyone help to understand what I missed or did wrong?
Thanks!
docs:
https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration
https://nextjs.org/docs/advanced-features/custom-app
steps:
1- added to my next.config.js
publicRuntimeConfig: {
NEXT_PUBLIC_BACKEND_HOST: process.env.NEXT_PUBLIC_BACKEND_HOST,
},
2- retrieved config in my pages
const { publicRuntimeConfig } = getConfig()
const baseURL = publicRuntimeConfig.NEXT_PUBLIC_BACKEND_HOST
3- created a custom app to setup getInitialProps
Runtime configuration won't be available to any page (or component in a page) without getInitialProps.
import App from 'next/app'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
MyApp.getInitialProps = async (appContext) => {
const appProps = await App.getInitialProps(appContext);
return { ...appProps }
}
export default MyApp
Everything seems fine in your code, tested in a fresh project and everything worked correctly. Therefore I think the issue is that you don't actually have NEXT_PUBLIC_BACKEND_HOST env var set when you're running next start. Btw, you don't need to use the NEXT_PUBLIC prefix in this kind of usage. If you want build time args you can use NEXT_PUBLIC_ prefix to have the var be available both client and server side by just using process.env.NEXT_PUBLIC_ anywhere. Note that in that case the value will be inlined at build time, so the env var needs to be present during build.

How to connect to an existing Electron app using Spectron

Is it possible to connect to an existing Electron application using Spectron? I am not particularly sure on how to go about implementing this..
I'd like to be able to do something like:
import { Application } from 'spectron';
import electronPath from 'electron';
import path from 'path';
// but don't spawn new electron application
new Application({
path: electronPath,
args: [path.join(__dirname, '..', '..', 'app')],
});
There are some documentation out there for using debuggerAddress option in Spectron, but I'm not really sure on whether that is what I am looking for, since the arguments for debuggerAddress is url, like so: '127.0.0.1:1234'.
I struggled making this work for Electron 6, was able to in the end, here is a working repo (made changes on top of an older one)
https://github.com/florin05/electron-spectron-example
Please make sure that you have created Test Folder in the same directory and create spectron file in this file.
Json File Changes:
"scripts": {"test": "mocha"}
const app = new Application({path: electronPath,args:[path.join(__dirname,'..')],})
beforeEach(function () {return app.start()})
afterEach(function () {if (app && app.isRunning()) {return app.stop()}})

Import file structure and collection publish

Following Meteor docs on how to use the import directory structure, Example directory layout.
//-------------- publication.js`
import {Vehicles} from '../vehicles.js';
Meteor.publish('vehicles', function () {
return Vehicles.find();
});
//-------------- carClass.jsx
import './vehicles/server/publications.js';
const composer = (props, onData) => {
const subscription = Meteor.subscribe('vehicles');
if (subscription.ready()) {
const vehicle = Vehicles.findOne({name: 'jack'});
onData(null, { vehicle });
}
};
Does the publish method need to be exported?
Error in browser console saying:
Uncaught Error: Cannot find module './vehicles/server/publications.js'
How can this error be fixed? Thanks
Meteor publications are server-only code, so you can't import that script in carClass.jsx.
You should have some file like {app root}/server/main.js. You import your publications here to make them available for client scripts to subscribe to. It's important that this file isn't inside of the /imports folder, so that it is eagerly loaded when the server starts.
The problem is that the path ./vehicles/server/publications.js is not reachable from the carClass.jsx file. You should reference it by ./server/publications.js

Resources