I have a Next.js project. I have created .env file and using enviroments from this file in server.js file. But when I want to reach these enviroments from component, I can't access. What should I do?
This is .env file:
SERVER_PORT=3000
DOMAIN=127.0.0.1
DATABASE=dburl
This is server.js file:
require('dotenv/config')
const port = process.env.SERVER_PORT || 3000
server.listen(port, (err) => {
if(err) throw err
console.log(`Server listen on http://127.0.0.1:${port}`)
})
This is any component of react:
axios
.get(`http://${process.env.DOMAIN}/api/improve-language`)
.then(res => {
...
})
.catch(err =>{
console.log(err)
})
Based on the documentation if you want to use the env variables in the browser, they must be named with prefix NEXT_PUBLIC_.
Related
I'm attempting to deploy a NextJS app on my shared hosting server using the cPanel Setup Node.JS App section, but when I start the build - despite getting ready on http://localhost:3000 - the site throws a 503 error.
I've uploaded the build folder alongside the next.config.js, package-lock.json, package.json and server.js to the application root, and this is my current file structure:
next_main
build (.next folder)
node_modules
next.config.js
package-lock.json
package.json
server.js
This is my server.js file (exactly the same as what Next provided in their custom server docs):
const { createServer } = require("http");
const { parse } = require("url");
const next = require("next");
const dev = process.env.NODE_ENV !== "production";
const hostname = "localhost";
const port = 3000;
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
app.prepare().then(() => {
createServer(async (request, response) => {
try{
const parsedURL = parse(request.url, true);
const { pathname, query } = parsedURL;
switch(pathname){
case "/a":
case "/b":
await app.render(request, response, pathname, query);
break;
default:
await handle(request, response, parsedURL);
}
} catch(error){
console.error("Error occurred.", request.url, error);
response.statusCode = 500;
response.end("Internal server error.");
}
}).listen(port, error => {
if(error) throw error;
console.log(`> Ready on http://${hostname}:${port}`);
});
}).catch(error => {
if(error) throw error;
});
Failed to load next.config.js was also output in my stderr file, despite next.config.js being provided.
I've attached the current settings I have applied in my cPanel.
Please note that I do not have root access to the terminal, and am restricted to the next_main environment when running any NPM scripts.
Make sure you add all environmental variables in the .env file. add your variable here
so the problem i'm having is, there is a directory in my public_html file named blog that is not related to my nextJs app, so basically after i deploy the app on host, everything works fine until i choose to check my blog part, for example the url below:
www.sth.com/blog
when i get there, i get the default next 404 page, the problem is, there is actual pages there, and i want my nodeJs server to ignore that exact route so when user goes to www.sth.com/blog, node app kind of ignore it and let it load the basic html pages.
i think it has something to do with my server.js file so here's the code in server.js
also i hosted the app on cpanel if that's important.
const { createServer } = require('http')
const next = require('next')
const isDevMode = process.env.NODE_ENV !== 'production'
const port = process.env.PORT ? process.env.PORT : 3000
const nextjsApp = next({ dev: isDevMode })
const nextjsRequestHandler = nextjsApp.getRequestHandler()
nextjsApp
.prepare()
.then(() => {
createServer((req, res) => {
const url = new URL(req.url, "http://w.w")
nextjsRequestHandler(req, res, url)
}).listen(port, (err) => {
if (err) throw err
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
thank you in advance.
In your server configuration you have to check if request is meant for next or not. If not - you need to respond with your page, instead of passing request further to next:
(req, res) => {
const url = new URL(req.url, "http://w.w");
if (/^\/blog\//.test(url.pathname)) {
// send response with blog
} else {
// pass everything to Next
nextjsRequestHandler(req, res, url);
}
};
Another option would be to split next and not next in two different parts and route requests to them through reverse proxy.
I am used to working with NodeJS and Koa. I've been playing with Deno and have run the example of a static fileserver:
/* static_server.js */
import { Application } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
// Error handler middleware
app.use(async (context, next) => {
try {
await next()
} catch (err) {
console.error(err)
}
})
// Send static content
app.use(async (context) => {
console.log(`${context.request.method} ${context.request.url.pathname}`)
await context.send({
root: `${Deno.cwd()}/static`,
index: "index.html",
})
})
await app.listen({ port })
I have also created a dynamic server using routes:
/* routes.js */
import { Application, Router } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
const router = new Router()
router.get('/', context => {
context.response.body = 'Hello world!'
})
router.get('/foo', context => {
context.response.body = 'Book Page'
})
router.get('/foo/:thing', context => {
context.response.body = `Foo ${context.params.thing}`
})
app.use(router.routes())
app.use(router.allowedMethods())
await app.listen({ port })
How can I combine these so that I can serve dynamic content but also provide static files such as the stylesheet?
In my Koa code I use the koa-static package:
import serve from 'koa-static'
app.use(serve('public'))
What is the equivalent for an Oak server?
Adding suggested code (thanks Jonas Wilms)
/* static_content.js */
import { Application, Router } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
const router = new Router()
router.get('/', context => {
context.response.body = 'Hello world!'
})
router.get('/foo', context => {
context.response.body = 'Book Page'
})
router.get('/foo/:thing', context => {
context.response.body = `Foo ${context.params.thing}`
})
router.get(context => context.send({ root: `${Deno.cwd()}/static` }))
app.use(router.routes())
app.use(router.allowedMethods())
await app.listen({ port })
but this still does not work...
After combining a lot of the information in the comments I managed to get things working:
/* static_content.js */
import { Application, Router, Status } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
const router = new Router()
// error handler
app.use(async (context, next) => {
try {
await next()
} catch (err) {
console.log(err)
}
})
// the routes defined here
router.get('/', context => {
context.response.body = 'Hello world!'
})
router.get('/error', context => {
throw new Error('an error has been thrown')
})
app.use(router.routes())
app.use(router.allowedMethods())
// static content
app.use(async (context, next) => {
const root = `${Deno.cwd()}/static`
try {
await context.send({ root })
} catch {
next()
}
})
// page not found
app.use( async context => {
context.response.status = Status.NotFound
context.response.body = `"${context.request.url}" not found`
})
app.addEventListener("listen", ({ port }) => console.log(`listening on port: ${port}`) )
await app.listen({ port })
I know I'm a bit late on the thread, but there are some things I would like to point out.
In Oak 10.1 (the current version at the time of this writing), the send function throws an error if the file it tired to load did not exist. Thus, our static+dynamic server can take on the following form.
import { oak, pathUtils } from './deps.ts'
const app = new oak.Application()
const router = new oak.Router()
app.use(async (ctx, next) => {
try {
await oak.send(ctx, ctx.request.url.pathname, {
root: 'static',
index: 'index.html',
})
} catch (_) {
await next()
}
})
router.get('/dynamic', ctx => {
ctx.response.body = 'dynamic route worked'
})
app.use(router.allowedMethods())
app.use(router.routes())
app.listen({ port: 8000 })
If you want to serve your static files at a certain root path, change the static middleware so that it checks for the root and then omits that root path from the second argument of the send function.
function staticMiddleware(rootPath: string, staticDirectory: string) {
return async (ctx, next) => {
if (!ctx.request.url.pathname.startsWith(rootPath)) return await next()
const newPath = ctx.request.url.pathname.slice(rootPath.length)
if (!newPath.startsWith('/') && newPath.length) return await next()
try {
await oak.send(ctx, newPath, {
root: staticDirectory,
index: 'index.html',
})
} catch (_) {
await next()
}
}
}
app.use(staticMiddleware('/assets', 'static'))
I think you should use the static router at last. Because when use static server first, dynamic router is nonreachable for static router error.
app.use(router.routes())
app.use(router.allowedMethods())
// move the static router down
app.use( async context => {
context.response.status = Status.NotFound
context.response.body = `"${context.request.url}" not found`
})
Not sure whether this is still relevant or already outdated, but as of now (August 2022), there seems to be no general answer to this.
Serving Static Files Alongside Your API Using Oak/Deno
When setting up OpenAPI for an oak-based REST service, I was coming across this issue as well. Requirements were:
Serve openapi.yml statically from /openapi/openapi.yml
Serve a HTML statically from /openapi for convenience
Serve prefixed routers unaffectedly
A straight-forward approach to serve static files from a certain directory under a sub-path of the application is using a middleware and checking the path:
import {
Application, Context, Router
} from 'https://deno.land/x/oak#v11.1.0/mod.ts';
const app = new Application();
const port = 3000;
// Middleware only hooking in and sending static files if prefix matches
// the desired subpath:
const openapi = async (ctx: Context, next: () => Promise<unknown>) => {
const prefix = '/openapi'; // Sub-path to react on
if (ctx.request.url.pathname.startsWith(prefix)) {
await ctx.send({
root: `${Deno.cwd()}/src/openapi/`, // Local directory to serve from
index: 'index.html',
path: ctx.request.url.pathname.replace(prefix, ''), // Map to target path
});
} else {
// If the request does not match the prefix, just continue serving from
// whatever comes next..
await next();
}
};
// This is a dummy API endpoint wrapped into a prefixed router for demo:
const statusRouter = new Router({ prefix: '/status' });
statusRouter.get('/', (ctx: Context) => {
ctx.response.body = {
healthy: true,
ready: true,
};
});
// Boilerplate..
app.use(openapi);
app.use(statusRouter.routes());
app.use(statusRouter.allowedMethods());
app.addEventListener('listen', () => {
console.log(`Listening on localhost:${port}`);
});
await app.listen({ port });
Running this MWE using deno run --allow-net --allow-env --allow-read src/serve.ts, you'll
find the statically served /openapi/openapi.yml,
find the index.html from your local static path served under /openapi (resp. /openapi/ and /openapi/index.html)
find the /status API behaving just normally.
i'm using like that. In html you can provide a path to your file:
<script src="/js/app.js"></script>
then you can use routes to provide what do you want to use on path js/app.js:
import {RouterContext} from 'https://deno.land/x/oak/mod.ts'
const decoder = new TextDecoder("utf-8")// set doecoder
const fileCont = await Deno.readFile('./views/test.js') //getting file conetent
const fileJS = decoder.decode(fileCont) //decoding it
router.get('/js/app.js', (ctx: RouterContext) => { //yep, route can has defferents of real file location
ctx.response.type = "application/javascript"
ctx.response.body = fileJS
})
and whatever you are providing this link somewhere it'll render you file.
Deno REST API
I have my Node.js project having environment file setup like below
let config = {
apiVersion: "/api/v1",
PORT: 3001,
mongodb: {
url: "mongodb://localhost:27017/BTracker",
},
};
module.exports = { config: config };
As i deploy my application , i need to change mongodb url and port fields as per my Prod URL.
How can i change these variables based on the environment?
Here is snippet of my index.js
let { config } = require("./app/config/appConfig");
app.listen(config.PORT, () => {
mongoose.connect(config.mongodb.url, { useMongoClient: true });
console.log("App is listening on " + config.PORT);
});
First of all create 2 .env file where you store all the configurations and keep it at the level of your index.js and make sure its not added in your git repository, one for the development and another for production.
Sample .env file for development:
#ENVIRONMENT
ENV="DEVELOPMENT"
#URI
MONGO_URI="mongodb://localhost:27017/BTracker"
Then in your index.js load this env file. You can use the dotenv package to do that.
Code to load the env file.
The first line of your index.js should be this:
require('dotenv').config();
Then you can read all the keys from the env file using
const enviromentValue = process.env[KEY_VALUE];
For your code, you can use this:
let urlDB = process.env.MONGO_URI;
This will set the value of urlDB="mongodb://localhost:27017/BTracker". You will need change the .env file according to your setup, whether you are in production or development environment.
Set enviroment variables for configuration
process.env.PORT = process.env.PORT || 3001;
process.env.NODE_ENV = process.env.NODE_ENV || 'dev';
let urlDB;
if (process.env.NODE_ENV === 'dev') {
urlDB = 'mongodb://localhost:27017/BTracker'
} else {
urlDB = process.env.MONGO_URI;
}
process.env.URLDB = urlDB;
and for your index
require('./app/config/appConfig')
mongoose.connect(process.env.URLDB, { useNewUrlParser: true, useCreateIndex: true }, (err, res) => {
console.log(process.env.URLDB);
if (err) throw err;
console.log();
});
app.listen(process.env.PORT, () => {
console.log(App is listening on , process.env.PORT));
})
I have .sh file like :
echo "Hello"
Which outputs :
Hello
Here is the query :
What I want to achieve is, to get output from the .sh file and use it in
my react application.
I have searched for npm packages but can't find any useful
Assuming you are not on Windows machine, you can write simple Node Express server, which can receive GET request, then execute your shell script with Node's built-in child_process.exec() and then send response containing stdout, which, in this case, will be your shell script's output - "Hello"
Code for the server. 'static' folder contains index.html and index.js, code for last is below this:
const express = require('express')
const { exec } = require('child_process')
const { join } = require('path')
const port = process.env.PORT || 24587
const app = express()
app.use(express.static(join(__dirname, 'static')))
app.get('/hello', (req, res) => {
exec(join(__dirname, 'hello.sh'), (err, stdout, stderr) => {
if (err) {
return res.status(400).json({ output: null, error: err.message })
}
res.status(200).json({ output: stdout, error: null })
})
})
app.listen(port, () => {
console.log('server listening on port', port)
})
Example code for the client (you can also wrap React around this code because the only thing you need is XHR made here with the help of fetch):
const btn = document.querySelector('#btn') // <button id="btn">get</button>
const result = document.querySelector('#result') // <div id="result"></div>
btn.addEventListener('click', () => {
if (self.fetch) {
fetch('/hello')
.then(res => res.json())
.then(data => {
result.innerText = data.output
})
.catch(data => {
result.innerText = data.error
})
}
})
I think you should put output to any file (echo $var > $destdir or using sed), read this file using nodejs and for example pass value through ajax request to react.