How Do You Configure Create React App to Work with Netlify Lambda Functions - reactjs

I am trying to use netlify lambda functions with create react app, and it is breaking my site.
The repo was made by running npx create-react-app my-app-name, and is the standard create react app boilerplate.
File structure:
root-directory/package.json
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lambda": "netlify-lambda serve src/lambda"
},
"devDependencies": {
"netlify-lambda": "^2.0.15"
}
root-directory/netlify.toml:
[build]
command = "npm build"
functions = "lambda"
publish = "build"
src/setupProxy.js:
const proxy = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
proxy("/.netlify/functions/", {
target: "http://localhost:9000/",
pathRewrite: {
"^/\\.netlify/functions": "",
},
})
);
};
src/lambda/dictionary.js:
exports.handler = (event, context, callback) => {
callback(null, {
statusCode: 200,
body: "hello world",
});
};
Now, when I try to run npm run start, the app will not load.
The browser displays the error:
This site can’t be reachedlocalhost refused to connect.
When you run npm run lambda and to to the url http://localhost:9000/.netlify/functions/dictionary in the browser, the browser does display "hello, world" as expected.
Also, I am not able to use the netlify cli because when I try to install it, I get permission errors/ access denied, even when I use sudo. So, trying to get this non globally installed way to work.

I just had the same issue with the same approach with your setupProxy.js.
Then I modified the setupProxy.js to below and it worked for me
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(createProxyMiddleware('/functions/', {
target: 'http://localhost:9000/',
pathRewrite: {
"^\\.netlify/functions": ""
}
}));
};

I fixed it , please see below - its stripped down all the way to just keeping it as simple as possible with examples for even using node
https://github.com/Kirbyasdf/netlify-react-lambda-node-boilerplate

Related

Webpack 4 config scripts (ENV)

My scripts in package.json file
...
"scripts": {
"start": "WEBPACK_API_BETA=true webpack-dev-server --mode development --open",
"dev": "WEBPACK_API_DEV=true webpack-dev-server --mode development --open",
"build": "WEBPACK_API_LIVE=true webpack --mode production",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
Everything works fine, when i run npm start, npm run dev or npm run build
My webpack.config.js file
'use strict';
const { EnvironmentPlugin } = require("webpack");
let plugins = []
if(process.env.WEBPACK_DEV){
// USE DEV API (systemVarsDev.js) WHEN ```npm run dev```
console.log("process.env.WEBPACK_DEV", process.env.WEBPACK_DEV)
plugins = [
new EnvironmentPlugin({
apiMode: "DEV",
})
]
} else if(process.env.WEBPACK_API_BETA){
// USE BETA API (systemVarsBeta.js) WHEN ```npm run start```
console.log("process.env.WEBPACK_API_BETA", process.env.WEBPACK_API_BETA)
plugins = [
new EnvironmentPlugin({
apiMode: "BETA",
})
]
} else if(process.env.WEBPACK_API_LIVE){
// USE LIVE API (systemVarsLive.js) WHEN ```npm run build```
console.log("process.env.WEBPACK_API_LIVE", process.env.WEBPACK_API_LIVE)
plugins = [
new EnvironmentPlugin({
apiMode: "LIVE",
})
]
}
module.exports = {
entry: ['./src/app.js'],
mode: "development",
plugins: plugins,
. . .
And the result (successfully):
But when i run my source (webpack 4) on another machine it fails and it gives me the following error, i have searched for hours without knowing why
Can someone help me? thank you guy so much <3

Question about security in an electron app using express in production

I have converted a react/django application into an electron project. All data is stored externally, identical to the web app, however, one third-party token must be stored on the users machine.
To do this, I start an express server on localhost:4001 that exposes url's that read/write a few pieces of data to a file in appData.
My question is, is this safe? Essentially, is hiding node functions behind http request okay to do in electron?
I've read the security documentation, but most is in regards to using ipcMain/ipcRender communications. I'll refactor to this if I must, but what I have works and for what the app is I'm happy with that as long as it's just as secure.
Also, this SO question has made me feel better, and ive configured the server as the question suggestion.
Express localhost URLs in production for Electron app
I guess I'm just seeking validation of my current configuration, as this is not the part to be wrong on.
Here are my browser window settings. In production I will be loading the main window from a public url belonging to the original web app.
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
dev_tools: isDev,
//worldSafeExecuteJavaScript: true,
//preload: path.join(__dirname, 'preload.js')
}
})
const startURL = isDev ? 'http://localhost:3000/dashboard/' : `www.appurl.com/dashboard`}`
server.js -
as you can see CORS has been disabled and its http. For validation I'm using host-validation, and I have a jwt token already in the authorization header that I was going to send to my server for additional verification. Is this enough to offset disabling CORS?
require('dotenv').config()
const express = require('express');
const cors = require('cors');
const fs = require('fs');
const hostValidation = require('host-validation')
const app = express();
const PORT = process.env.EXPRESS_PORT || 4001
app.use(cors())
app.use(hostValidation({hosts: ['localhost:3000', 'www.appurl.com']}))
app.use(express.json())
app.post('/upload_api_token/', (req, res) => {
fs.writeFile('filname.txt', 'Hello world')
res.send(200)
})
app.listen(PORT, () => console.log(`Server running on ${PORT}`))
And here are relevant parts of my package.json
{
"scripts": {
"start": "fuser -k 3000/tcp; concurrently \"nodemon --watch server --inspect ./server/index.js\" \"react-scripts start\"",
"build": "python prebuild.py; react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev": "fuser -k 4001/tcp; concurrently \"yarn start\" \"wait-on http://localhost:3000 && electron .\""
},
"dependencies": {
...,
"react": "^17.0.2",
"electron": "^18.0.4",
"electron-builder": "^23.0.3",
"electron-is-dev": "^2.0.0",
"electron-reload": "^2.0.0-alpha.1",
"express": "^4.17.3",
}

React app on Vercel - 404 not found error after adding Web Worker

I have my React app deployed to Vercel, and it was working until I added a web worker and a background task.
The app still builds and deploys with no error, but when I visit the url I get a 404 not found error.
It still runs fine locally as well.
I'm assuming it's the way I've set up the web worker using React-App-Rewired.
I use Rewired to avoid 'ejecting' my app, and it had me create a config-overrides.js (which I think is to override defaults in Webpack)
config-override.js
module.exports = function override(config, env) {
config.module.rules.push({
test: /\.worker\.js$/,
use: { loader: 'worker-loader' },
})
return config;
}
I think the problem is that Vercel is not finding the file paths correctly.
I tried a few approaches to fix this that I found here: https://github.com/webpack-contrib/worker-loader/issues/176
Like adding this line before returning config:
config.output.globalObject = '(self || this)'
It looks like people who use Next.js have had a similar problem and they fixed it like this:
module.exports = {
webpack: config => {
config.module.rules.push({
test: /\.worker\.js$/,
loader: 'worker-loader',
options: {
name: 'static/[hash].worker.js',
publicPath: '/_next/'
}
})
config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`
return config
}
}
But I'm not using Next.
package.json scripts.
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d build",
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom-fourteen",
"eject": "react-scripts eject"
},
An image so you can see my file structure (again it was working locally so I think everything is setup ok)
And here is the tutorial I followed to get set up with React-App-Rewired and web workers: https://medium.com/#danilog1905/how-to-use-web-workers-with-react-create-app-and-not-ejecting-in-the-attempt-3718d2a1166b
Any help is appreciated. Thanks!!
I needed to add this line right above the first line of my worker function
/* eslint-disable-next-line no-restricted-globals */
let mytimer;
/* eslint-disable-next-line no-restricted-globals */
self.onmessage = function(evt) {
clearInterval(mytimer);
if(evt.data.message === 'pause' || evt.data.message === 'stop' || evt.data.message === 'skip'){
postMessage(evt.data.time)
}
if (evt.data.message == "start" || evt.data.message == "break") {
var i = evt.data.time;
mytimer = setInterval(function() {
i--;
postMessage(i);
}, 1000);
}
};
And also have this in my config-overrides.js
config.output.globalObject = 'this';
module.exports = function override(config, env) {
config.module.rules.push({
test: /\.worker\.js$/,
use: { loader: 'worker-loader' },
})
config.output.globalObject = 'this';
return config;
}

Building a React-Electron app using electron-builder, index.js loads inside pre tags

I have an app that I'm now trying to build to distribute for testing.
I'm using React and Electron with electron-builder to build the app itself. I'm not a web developer so I've been trying to keep things basic and just get something to work.
After about five hours I was finally able to get the app to build somewhat properly and launch, but when it loads index.js (the first page in the app) it displays the source for index.js instead of rendering the content. In the devtools everything is inside a pre tag.
I've already looked at this thread and tried that but it didn't change anything, and I'm not using service workers as far as I can tell.
What the actual Electron window displays after launching with the devtools alongside.
Here's the createWindow function from main.js.
I've tried doing all kinds of things to the pathname with no effect.
function createWindow() {
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../src/index.js'),
protocol: 'file:',
slashes: true,
});
mainWindow = new BrowserWindow({
width: 800, height: 600, title: "Electron App", webPreferences: {
nodeIntegration: true
}
});
mainWindow.loadURL(startUrl);
mainWindow.on('closed', function () {
mainWindow = null;
});
}
Here are my scripts from package.json
"scripts": {
"start": "nf start -p 3000",
"start-electron": "set ELECTRON_START_URL=http://localhost:3000 && electron .",
"react-start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build-electron": "npm run build && electron-builder build --win"
}
Here's the build part too. To be honest, I don't really understand what this is or does but after a few hours of trial and error this is what gets me to the point I am now.
"build": {
"appId": "Test",
"extends": null,
"files": [
"./build/**/*",
"./electron/main.js",
"./src/**/*"
]
}
As far as I can tell, it has something to do with the Electron start URL, because when I removed that from const startUrl in createWindow, running the app using npm start did the same thing as the built Electron app, whereas before using npm would launch the app normally every time.
EDIT after solution:
Modified build in package.json to
"build": {
"appId": "Test",
"extends": null,
"files": [
"./build/**/*",
"./electron/main.js",
"./src/**/*"
],
"directories": {
"buildResources": "./public"
}
}
I haven't tested it without this modification so I'm not sure that it's actually necessary.
Start URL was changed to
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../build/index.html'),
protocol: 'file:',
slashes: true,
});
You're supposed to set it up with an html file.
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../src/index.html'),
protocol: 'file:',
slashes: true,
});
Your browser window should load the build/index.html on production mode
const isDev = require("electron-is-dev");
if (isDev) {
mainWindow.loadURL(process.env.ELECTRON_START_URL);
} else {
mainWindow.loadFile(path.join("build", "index.html"));
}

How to use different .env files with nextjs?

I would like to have different configuration files for the environment variables and be able to use them in my next project. I saw the example with dotenv.
But I don't like to define the variables in the .env file and also define them in the config.next.js file. if for some reason I put the variables in the .env file but forget to put them in the config.next.js file the code starts having problems.
Theres is a way to do it more eficiently?
My scripts in package.json:
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"lint": "eslint pages --ext .ts,.tsx,.js",
"test": "jest",
"commit": "git-cz",
"dev:production": "dotenv next"
},
My .env vars
TITULO=react, typescript, material ui App
Component
import { NextPage } from 'next';
import { FunctionComponent } from 'react';
interface HelloWorldProps {
nombre: string,
saludo?: string
}
const HelloWorld: FunctionComponent<HelloWorldProps> = ({ nombre, saludo = 'noches' }: HelloWorldProps) => (
<>
<h1>Hola {nombre} buenas {saludo}</h1>
{/* eslint-disable-next-line multiline-ternary */}
<h2>{process.env.TITULO ? 'hola' : 'adios'}</h2>
</>
);
const Home: NextPage = () => <HelloWorld nombre="cristian" />;
export default Home;
Next 9.4 has built-in support for .env files: https://nextjs.org/docs/basic-features/environment-variables
But, in case you want to have multiple .env files, like:
.env.development
.env.staging
.env.prestaging
.env.production
It would be impossible to do with a built-in env variables support. There's only 3 environments that officially supported for now, it's: "development", "test", "production". With next dev you use "development", next build && next start uses "production" environment.
If you need to build for production environment, but using ".env.staging" for example, then you need to add env-cmd package, and add this line to your package.json:
"build:staging": "env-cmd -f .env.staging yarn build && yarn start"
Next would make a production build with ".env.staging" variables.
The issue with most of these answers is they go against the principal of "build once run everywhere", in reality most of us are using this technique build and run with Docker containers. It's not possible to have multiple build commands like this, and it would be bad practice.
Better have your environment available at runtime. We created a package that allows next static optimisation and still have runtime env vars via window.__ENV
https://github.com/andrewmclagan/react-env
This works by generating an environment config object at runtime from whitelisted env vars:
{
...
"scripts": {
"dev": "react-env -- next dev", // where .env.${APP_ENV}
"start": "react-env --env APP_ENV -- next start" // where .env.${APP_ENV}
}
...
}
You can have different .env files in nextjs with following two ways:
1. Using env-cmd package
Provide the path to your environment file in the scripts like:
"scripts": {
"start": "env-cmd path/to/prod/env/file next start",
"start:dev": "env-cmd path/to/prod/env/file next dev",
"build:dev": "env-cmd path/to/dev/env/file next build",
"build:test": "env-cmd path/to/test/env/file next build",
"build:stage": "env-cmd path/to/stage/env/file next build",
"build": "env-cmd path/to/stage/prod/file next build",
},
2. Using dotenv package
In your next.config.js file add following:
require("dotenv").config({ path: `${process.env.ENVIRONMENT}` });
module.exports = {
// your configs
}
and in your scripts, provide that ENVIRONMENT variable like:
"scripts": {
"start": "ENVIRONMENT=path/to/prod/env/file next start",
"start:dev": "ENVIRONMENT=path/to/dev/env/file next dev",
"build:dev": "ENVIRONMENT=path/to/dev/env/file next build",
"build:test": "ENVIRONMENT=path/to/test/env/file next build",
"build:stage": "ENVIRONMENT=path/to/stage/env/file next build",
"build": "ENVIRONMENT=path/to/stage/prod/file next build",
},
NOTE: The thing is do not to put your .env* files in the root folder, otherwise NEXT will auto-pick from your .evn* files and it only supports production and development stages. So it'll ignore other .env.my-stage files.
npm i dotenv
Then add below code to next.config.js, restart the application and you are good to go!
// next.config.js
require('dotenv').config()
const webpack = require('webpack')
module.exports = {
webpack: (config) => {
config.plugins.push(
new webpack.EnvironmentPlugin(process.env)
)
return config
}
}
If your .env file is not located in same folder as next.config.js add path to your config like below,
require('dotenv').config({ path: 'path/to/.env' })
For anyone interested to use .yml file for easy management of environment variables, here's how I did it.
Install a plugin yenv in devDependencies.
Add the below config in next.config.js :
const path = require("path");
const yenv = require("yenv");
const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");
module.exports = (phase) => {
const isDev = phase === PHASE_DEVELOPMENT_SERVER;
const NEXT_ENV = isDev ? "development" : process.env.APP_ENV;
const rawEnv = yenv(path.resolve(".env.yml"), { raw: true, env: NEXT_ENV });
return {
...some other config,
env: getEnvVars(rawEnv, isDev).raw,
compress: true,
};
};
function getEnvVars(rawEnv, dev) {
const NEXT_PUBLIC = /^NEXT_PUBLIC_/i;
const raw = Object.keys(rawEnv)
.filter((key) => NEXT_PUBLIC.test(key))
.reduce((env, key) => {
env[key] = rawEnv[key];
return env;
}, {});
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
"process.env": Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};
return { raw, stringified };
}
Now just add different build commands based on environment in package.json scripts.
"scripts": {
"dev": "node server.js",
"build:production": "APP_ENV=production next build",
"build:staging": "APP_ENV=staging next build",
"start": "NODE_ENV=production node server.js"
},
Now you can use your environment variables via a single file .env.yml like this :
base:
NEXT_PUBLIC_SECRET_KEY : ""
NEXT_PUBLIC_ANOTHER_SECRET: ""
development:
~compose: base
NEXT_PUBLIC_SECRET_KEY: "bnbnfjf"
staging:
~compose: base
NEXT_PUBLIC_SECRET_KEY: "absadsad"
production:
~compose: base
NEXT_PUBLIC_SECRET_KEY: "lasjdasodsdsad"
Now you can call npm run build:production to load production env vars and npm run build:staging for staging env vars.
This provides the benefit of having any number of envs for your use case. You will just have to add a build command, and update env vars in .env.yml and you are good to go.
This day and age you shouldn't need to install anything extra to implement multiple environment configuration! See GitHub repo NextJS template with config management
Next.js v9.4 and up has a more intuitive and ergonomic way for adding environment variables:
{
"name": "package.json",
"scripts": {
"dev": "next dev",
"build": "next build && next export",
"build-dev": "TARGET_ENV=development next build && next export",
"build-staging": "TARGET_ENV=staging next build && next export",
"test": "jest --watch"
}
}
{
"name": "env.json",
"development": {
"APP_ENV": "development"
},
"production": {
"APP_ENV": "production"
},
"staging": {
"APP_ENV": "staging"
},
"test": {
"APP_ENV": "test"
}
}
// next.config.js v9.4+
const envConfig = require('./env.json')
const environment = process.env.TARGET_ENV || process.env.NODE_ENV
const nextConfig = {
env: envConfig[environment], // getEnvConfig()
}
module.exports = nextConfig
function getEnvConfig() { // for multi-file config
try {
return require(`./env-${environment}.json`)
} catch (err) {
return require('./env.json')
}
}
npm run dev # process.env.APP_ENV=development
npm run build # process.env.APP_ENV=production
npm run build-dev # process.env.APP_ENV=development
npm run build-staging # process.env.APP_ENV=staging
npm run test # process.env.APP_ENV=test
You can use dotenv-cli and then set up different .env files for different environments in your package.json. Something like:
{
...
"scripts": {
"dev:production": "dotenv next", // Uses .env file
"dev:staging": "dotenv -e .env.staging next" // Uses .env.staging file
}
...
}
Next 9.4 support out of the box environment variables and included support for multiple environments.
New Environment Variables Support
Environment variables are only available in the Node.js environment by default
Environment variables prefixed with NEXT_PUBLIC_ are exposed to the browser
Exposing Environment Variables
Next.js allows you to expose variables using an environment variables file (.env), with included support for multiple environments. It works like this:
.env - Contains environment variables for all environments
.env.local - Local variable overrides for all environments
.env.[environment] - Environment variables for one environment. For example: .env.development
.env.[environment].local - Local variable overrides for one environment. For example: .env.development.local
If you would like to use it without any 3rd party library you can expose it from the script directly with NEXT_PUBLIC_ at the start of the script, for example:
"scripts": {
"start": "NEXT_PUBLIC_APP_ENV=development next dev"
}
than use it with
console.log(process.env.NEXT_PUBLIC_APP_ENV); // >>> development
Update 2022
Most answers here need a package installed
for the easiest solution also following the docs
say you have different files like this env.development and env.production
you can set the right env file using NODE_ENV=development or NODE_ENV=production
your package.json file should like this
"scripts": {
"dev": "NODE_ENV=development next dev",
"build": "NODE_ENV=development next build",
"start": "NODE_ENV=development next start",
"build-prod": "NODE_ENV=production next build",
"start-prod": "NODE_ENV=production next start",
if your env file name is env.dev then you can set it with NODE_ENV=dev.
Hope this helps someone cheers

Resources