How to get front end to see .env contents? - node.js

I'm working on an app that has client side and server side hosted on two seperate heroku deployments. When I hard code the url in the axios call from the front end to the back end it works in the production environment:
auth.js file:
const baseUrl = 'https://url.herokuapp.com/'
function Auth() {
axios.get(baseUrl + 'api/user', test)
But if I add the following to the .env file and change the code as below it doesn't work:
auth.js file:
const baseUrl = process.env.REACT_APP_SERVER_URL || '/'
function Auth() {
axios.get(baseUrl + 'api/user', test)
.env file:
if (process.env.NODE_ENV !== 'production') {
REACT_APP_SERVER_URL = "http://localhost:3001/"
} else {
REACT_APP_SERVER_URL = "https://url.herokuapp.com/"
}
I've tried adding and installing dotenv to a route server.js file on the front end but now luck
require('dotenv').config();
Any ideas?

.env file is not a js file that you can write code. It is just plain text.
So you can use it like:
.env
REACT_APP_SERVER_URL=http://example.com
NODE_ENV=production
Then you can read it.
require('dotenv').config();
console.log(process.env.NODE_ENV);
console.log(process.env.REACT_APP_SERVER_URL );
const baseUrl = process.env.REACT_APP_SERVER_URL || '/'
axios.get(baseUrl + 'api/user', test)
In this documentation, you can find how to apply env variables via heroku config vars. https://devcenter.heroku.com/articles/config-vars

Related

not getting data from .env file in node.js

js and i'm getting error with accessing data from .env file.
my file structure looks like this:
enter image description here
in .utils folder i have file mail.js where i need to access port and other data from .env
mail.js
require("dotenv").config({ path: "../.env" });
const port = process.env.email_port;
const host = process.env.email_host;
const user = process.env.email_user;
const pass = process.env.email_pass;
console.log("port", port); //undefined
getting undefined here.
Note: path is correct to .env and variable names are also correct.
Try to add require("dotenv").config() to the server app or to remove the { path: "../.env" } from the require-statement.

How to achieve code splitting + SSR with #loadable/component ? Is webpack needed for the server code?

I'm trying to add code splitting + SSR to my React web app using #loadable/component.
My current situation: This is how I've implemented SSR for robots on my website. Since it's just for robots, I'm not using hydrate. Basically, I send either the index.html with the JS bundle's script tags for a regular user, or I send a fully rendered HTML page for the robots, without the need to hydrate.
My goal: I'd like to use #loadable/component to always return SSR pages from my server, and use hydrate to attach my JS bundle. And also achieve code splitting with that.
Here is how I currently build my app (pseudo code):
1. webpack BUILD FOR entry { app: "src/index.tsx" } AND OUTPUT BUNDLES TO MY /public FOLDER
2. babel TRANSPILE WHOLE `/src` FOLDER AND OUTPUT FILES TO MY /dist_app FOLDER
It's basically 2 builds, one of them is using webpack to bundle, and the other one basically transpiles the files from src to distApp.
And this is what my server does (pseudo code)
1. CHECK IF USER IS ROBOT (FROM THE USER AGENT STRING)
2. IF REGULAR USER
res.send("public/index.html"); // SEND REGULAR index.html WITH JS BUNDLES GENERATED BY WEBPACK
IF ROBOT
const App = require("./dist_app/App"); // THIS IS THE src/App COMPONENT TRANSPILED BY BABEL
const ssrHtml = ReactDOM.renderToString(<App/>);
// ADD <head> <helmet> <styles> ETC
res.send(ssrHtml);
The steps described above works just fine for my initial requirements (ssr just for robots).
But after I added #loadable/component to achieve code splitting + SSR, the set up above does not work anymore.
Because now I have dynamic imports on some of my routes. For example:
const AsyncPage = loadable(() => import("#app/pages/PageContainer"));
So my renderToString(<App/>) call comes back mostly empty, because it does not load those AsyncPages.
Over on the docs for Loadable components: server side rendering they have an example repo on how to achieve this.
But their example is kind of complex and it seems they are using webpack inside the server. I'll post what they do on their server below.
QUESTION
Do I really have to use webpack to bundle my app's server code in order to use #loadable/component for SSR like they are showing in their example? Can't I just use some kind of babel plugin to convert the dynamic imports into regular require calls? So that I'll be able to render it the way I was doing before?
It's weird, that they use webpack-dev-middleware. It's like this example should be used just for development. Does anybody know a repo with a production example of this?
import path from 'path'
import express from 'express'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { ChunkExtractor } from '#loadable/server'
const app = express()
app.use(express.static(path.join(__dirname, '../../public')))
if (process.env.NODE_ENV !== 'production') {
/* eslint-disable global-require, import/no-extraneous-dependencies */
const { default: webpackConfig } = require('../../webpack.config.babel')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpack = require('webpack')
/* eslint-enable global-require, import/no-extraneous-dependencies */
const compiler = webpack(webpackConfig)
app.use(
webpackDevMiddleware(compiler, {
logLevel: 'silent',
publicPath: '/dist/web',
writeToDisk(filePath) {
return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath)
},
}),
)
}
const nodeStats = path.resolve(
__dirname,
'../../public/dist/node/loadable-stats.json',
)
const webStats = path.resolve(
__dirname,
'../../public/dist/web/loadable-stats.json',
)
app.get('*', (req, res) => {
const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats })
const { default: App } = nodeExtractor.requireEntrypoint()
const webExtractor = new ChunkExtractor({ statsFile: webStats })
const jsx = webExtractor.collectChunks(<App />)
const html = renderToString(jsx)
res.set('content-type', 'text/html')
res.send(`
<!DOCTYPE html>
<html>
<head>
${webExtractor.getLinkTags()}
${webExtractor.getStyleTags()}
</head>
<body>
<div id="main">${html}</div>
${webExtractor.getScriptTags()}
</body>
</html>
`)
})
// eslint-disable-next-line no-console
app.listen(9000, () => console.log('Server started http://localhost:9000'))

How can I have multiple route files in server file using express (nodejs)

I am trying to put my routes into multiple files. if I only use one route file in server.ts like this, all works fine
server.ts:
require('./articles/routes/blog-article.routes')(app);
article.route.ts
module.exports = app => {
const article = require('../controllers/artilce.controller');
app.post('/api/blog/addArticle', article.addArticle);
app.get('/api/blog', article.getAllArticles);
app.get('/api/blog/:articleId', article.getArticleById);
app.delete('/api/blog/deleteArticle/:articleId', article.deleteArticle);
app.put('/api/blog/editArticle/:articleId', article.editArticle);
};
But if I add in server.ts require('./tags/routes/article-tags.routes')(app); it doesn't work.
article-tags.routes.ts:
module.exports = app =>
const articleTags = require('../controllers/article-tags.controller');
app.get('/api/blog/articleTags', articleTags.getAllArticleTags);
};

Can't use fs in heroku

I was codding a simple bot for discord, and I noticed that when i use fs, the app doesn't deploy. I need to access a file that is inside a folder. But when I use:
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const command = require(`./commands/${file}`);
client.commands.set(command.name, command);
}
The app doesn't deploy, I tried to do everything in one .js file, but i really need to use modules.export
I cant even use:
const configFile = require('./config')
If whatever look here with same case as me:
console error looking as bad directory on heroku, my manually app working.
Local node.js need using / or
On Heroku you must use /
So I change this line:
const folderPath = __dirname + "\\my_modules";
to this:
const folderPath = __dirname + "\\my_modules";
I used type module so __dirname is my variable setup by package URL and path.

How do I serve static files using Sails.js only in development environment?

On production servers, we use nginx to serve static files for our Sails.js application, however in development environment we want Sails to serve static files for us. This will allow us to skip nginx installation and configuration on dev's machines.
How do I do this?
I'm going to show you how you could solve this using serve-static module for Node.js/Express.
1). First of all install the module for development environment: npm i -D serve-static.
2). Create serve-static directory inside of api/hooks directory.
3). Create the index.js file in the serve-static directory, created earlier.
4). Add the following content to it:
module.exports = function serveStatic (sails) {
let serveStaticHandler;
if ('production' !== sails.config.environment) {
// Only initializing the module in non-production environment.
const serveStatic = require('serve-static');
var staticFilePath = sails.config.appPath + '/.tmp/public';
serveStaticHandler = serveStatic(staticFilePath);
sails.log.info('Serving static files from: «%s»', staticFilePath);
}
// Adding middleware, make sure to enable it in your config.
sails.config.http.middleware.serveStatic = function (req, res, next) {
if (serveStaticHandler) {
serveStaticHandler.apply(serveStaticHandler, arguments);
} else {
next();
}
};
return {};
};
5). Edit config/http.js file and add the previously defined middleware:
module.exports.http = {
middleware: {
order: [
'serveStatic',
// ...
]
}
};
6). Restart/run your application, e.g. node ./app.js and try to fetch one of static files. It should work.

Resources