My CRA project isn't parsing my environment variables. I see this in the docs:
By default you will have NODE_ENV defined for you, and any other
environment variables starting with REACT_APP_
And here is some code for testing:
// .env in the project root folder
REACT_APP_GOOGLE=google.com
REACT_APP_API_POST_URL=http://localhost:4000/api/
// App.js
import dotenv from 'dotenv';
componentDidMount() {
if (dotenv.error) {
console.log('dotenv.error', dotenv.error);
} else { console.log('dotenv.parsed', dotenv.parsed); // undefined
}
}
// App.js insider render()
<button
onClick={e => {
e.preventDefault();
console.log("process.env", process.env); //
// {NODE_ENV: "development", PUBLIC_URL: ""}
// NODE_ENV: "development"
// PUBLIC_URL: ""
console.log("process.env.NODE_ENV", process.env.NODE_ENV); // development
console.log("process.env.REACT_APP_GOOGLE", process.env.REACT_APP_GOOGLE); // undefined
}}
>log .env</button>
Anyone know why it's not parsing the env variables?
Here is your component:
import React, { Component } from 'react';
import './App.css';
const googleEnvVariable = process.env.REACT_APP_GOOGLE;
class App extends Component {
render() {
return <div className="App">{googleEnvVariable}</div>;
}
}
export default App;
And here is your .env
REACT_APP_GOOGLE=hereisyourenvvar
You should see hereisyourenvvar
EDIT: updated answer to display on the screen instead of the console.log...
From the code you gave, it seems like you forgot to call the config function (unless you didn't show it). If you want your .env to be implemented, you will have to do the following at the top level of your project :
import dotenv from 'dotenv';
// Load ENV vars
const dotEnvOptions = {
path: 'env/dev.env' //Example path relative to your project folder
}
dotenv.config(dotEnvOptions)
To figure out what is going wrong you may turn on logging to help debug why certain keys or values are not being set as you expect :
dotenv.config({ debug: true })
From there, if a path/variable isnt recognized, it will be printed int he console :
If you are not seeing anything, it either means that your path is wrong or that the code isn't executed
Related
In production mode, after building, when open subpath directly, Next JS app gives 404.
For example, when I open domain.com/page, gives - 404. But, when I open domain.com/en/page it works.
My next.config.js file:
module.exports = {
i18n:{
locales:["en", "ru"],
defaultLocale: "en",
}
}
One of my page components:
import { MainLayout } from "../components/MainLayout";
import en from "../locales/en/en.js";
import ru from "../locales/ru/ru.js";
import { useRouter } from "next/router";
export default function About() {
let router = useRouter();
const { locale } = router;
const t = locale === "en" ? en : ru;
return (
<MainLayout title={"About page"}>
<div className="container">
<div className="content">
<h1>{t.about}</h1>
</div>
</div>
</MainLayout>
);
}
In your _app.js
You have to write this line;
export default appWithTranslation(YourApp);
And you should define localePath in your i18n object in next.config.js
like this :
localePath: path.resolve("./public/locales")
After you can access your translations in component or page like this;
const { t } = useTranslation('common');
I know that this is an old question, but I'm leaving this answer from stackoverflow for anyone that is having this error using Docker, in my case it was the solution to my problem.
Be sure to copy the next.config.js file in your Dockerfile:
COPY ./next.config.js /app/next.config.js
I have a path.json file that contains the path of a component
// path.json
{
"main": "./login/index.js",
"paths": [
{
"name": "login",
"path": "./login/index.js",
"image": ""
}
]
}
I want to load './login/index.js' file dynamically in react native and render this particular file
My current implementation
const MyComponent = createLazyContainer(() => {
const componentPath = PathJson.main; // ./login/index.js
return import(`${componentPath}`); //import error here # line 7
});
export default MyComponent;
I am getting following error :
Invalid call at line 7: import("" + componentPath)
What people have been telling you in the thread is correct but I'd like to add one possible solution. All the imports/require are resolved at compilation time and not at running time which you are trying to do. By the time you are running your app, if you haven't imported the files, you can't use them.
There is a workaround tho, assuming that you know all the files that you might in advance which is to do something like a factory:
const possiblePaths = {
'one': require('path/to/file/1'),
'two': require('path/to/file/2')
}
function(type){
return possiblePaths[type];
}
And then you use it somehow like:
render(){
const MyComponent = function('one');
return <MyComponent/>;
}
This is more or less pseudo code and my not work right away, but hopefully yo get the idea. You need to store a reference to each of the imports you might need and then dont use the import, use the reference that was created for you at compilation time.
Actually, the React Native development concerns are not like development for the Web.
Just for this reason, it is not so important at all to have lazy loading in the production of a react-native project. Just import anything you want and then use them in any files of the project. all of them are in the bundle of production and exactly it is not important at all.
So for this problem, I prefer to have a helper file to collect all selectable libraries and export them:
// helper file
export { default as Index } from './Login';
export { default as OtherComponent } from './OtherComponent';
Then when you wanna use:
import { Index, OtherComponent } from 'helper';
~~~
render() {
const MyComponent = someCondition ? Index : OtherComponent;
return (
<MyComponent />;
);
}
Solution:
const allPaths = {
path1: require('file path1').default,
path2: require('file path2').default
};
render(){
const MyComponent = allPaths["path1"];
return <MyComponent/>
}
In React Native all the files that are being imported are bundled together, only those files can be dynamically imported.
Let's say you have three files index.js, test_1.js and test_2.js and if you have imported only test_1.js in index.js than React Native will only bundle those two files leaving test_2.js.
So to answer your question even if dynamic import works in React Native but because these files are not part of the bundle you are not able to import them.
I've once been in a similar situation where I need to do imports by variable, but that is limited to importing components inside a component and it uses code-splitting (Edit: I'm playing around to look for a solution without relying on code-splitting, I just realized there was a react-native tag in the question, and I don't think code-splitting is a good choice to go with in RN). I'm not sure by how much my method could help you, but here goes.
Side notes:
Importing folder that contains an index.js(jsx|ts|tsx) file should automatically resolve to that index file.
Importing from from './login/index.js' usually throws a 'Module not found' error. Either import from './login/index' or from './login but I prefer the last one as it's the shortest & simplest.
In path.json:
{
"main": "./login", // '.js' is removed
"paths": [
{
"name": "login",
"path": "./login/index.js", // Not sure what this is for, but if necessary, remove the '.js' here as well
"image": ""
}
]
}
In MyComponent.js:
import React, { lazy, Suspense } from 'react'
import PathJson from './path'
// 1. We need a UI to show while component is being loaded
const Loader = () => <div>{'Loading...'}</div>
// 2. We need a fallback UI if component is not found
const DocUnavailable = () => <div>{'We\'re sorry, but this document is unavailable.'}</div>
// 3. Create a resolver function ('resolver' is just a name I give)
function resolveImport(pathToComponent, FallbackComponent) {
let componentFound = false
let RenderComponent = () => <FallbackComponent /> // Assign fallback first
try {
if (require.resolve(pathToComponent)) {
componentFound = true
}
} catch (e) { } // Kinda hacky, if you don't mind, but it works
if (componentFound) {
// If found, replace fallback with the valid component
RenderComponent = lazy(() => import(pathToComponent))
}
return RenderComponent
}
// 4. Finally, implement it in a component
class MyComponent extends React.Component {
render() {
const componentPath = PathJson.main
const RenderComponent = resolveImport(componentPath, DocUnavailable)
return (
<Suspense fallback={<Loader />}>
<RenderComponent />
</Suspense>
)
}
}
export default MyComponent
References:
Implementation for 'resolver' function based on Langutil
Code-splitting with lazy & Suspense based on React Docs
Components aren't rendering because of the Uncaught ReferenceError error. The error is thrown in one of the React API files (see the code in question below). I'm using the react-rails gem and am trying to render a blank component called 'Test'.
The file from React API(line 3)
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}
ERB Rendering Component
<div style="width:100vw">
<%= react_component('Test') %>
</div>
The Component
import React from "react";
import PropTypes from "prop-types";
export default class Test extends React.Component{
render(){
return (
<div>
test
</div>
)
}
}
The React API should render 'test' to the (v)dom.
React-rails gem uses webpacker, so I would follow their documentation to make sure you source your environment variables correctly, particularly the portion involving the setup of dotenv files if you don't use webpack-dev-server:
Environment variables are supported out of the box in Webpacker. For
example if you run the webpack dev server like so:
FOO=hello BAR=world ./bin/webpack-dev-server
You can then reference these variables in your JavaScript app code with process.env:
console.log(process.env.FOO) // Compiles to console.log("hello")
You may want to store configuration in environment variables via .env files, similar to the dotenv Ruby gem.
Here is what you could do to support a "Ruby-like" dotenv:
yarn add dotenv
// config/webpack/environment.js
...
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
const dotenv = require('dotenv')
const dotenvFiles = [
`.env.${process.env.NODE_ENV}.local`,
'.env.local',
`.env.${process.env.NODE_ENV}`,
'.env'
]
dotenvFiles.forEach((dotenvFile) => {
dotenv.config({ path: dotenvFile, silent: true })
})
environment.plugins.prepend('Environment', new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(process.env))))
module.exports = environment
If you'd like to pass custom variables to the on-demand compiler, use Webpacker::Compiler.env attribute.
Webpacker::Compiler.env['FRONTEND_API_KEY'] = 'your_secret_key'
I'm wondering how does webpack handle devDependencies when in production mode:
App.js
import { hot } from 'react-hot-loader';
function App() {
// App code
}
export default process.env.NODE_ENV === 'development' ? hot(module)(App) : App;
I can successfully use a ternary into the export statement. But I can't do that and neither set a condition in the import statement.
QUESTION
What is the proper way to handle this (the import of a devDependency)?
Will webpack add devDependencies to the bundle if no condition is placed at the import?
EDIT:
Just found out that webpack does add devDependencies to the bundle:
This was generated with webpack mode set to production:
Here's how I solved it with ignorePlugin
App.js
import { hot } from 'react-hot-loader';
function App() {
// App code
}
export default process.env.NODE_ENV === 'development' ? hot(module)(App) : App;
webpack.prod.js (webpack production config file)
module.exports = merge(common, {
mode: 'production',
plugins:[
new webpack.IgnorePlugin(/react-hot-loader/), // <------ WILL IGNORE THE react-hot-loader
new webpack.HashedModuleIdsPlugin(),
new BundleAnalyzerPlugin()
],
This way react-hot-loader is ignored in production mode.
In development I use another config file for webpack, which doesn't use the ignorePlugin.
You can have two new files for app, app.dev.js and app.prod.js while in app you just switch the require based on env.
// App.js
let App;
if (process.env.NODE_ENV === 'development') {
App = require('./app.dev.js')
} else {
App = require('./app.prod.js')
}
export default App
EDIT:
It's essential that require is used instead of import as only require can be used dynamically like this.
I want to control the output of the log in the development environment and production environment
I can't control the log output in the react component, and I want to control the output in different development environments.
There is code compression in next.js. I want to delete console.log when compressing, but I don't know how to do it. In webpack I try to delete console.log but I get an error.
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions:{
compress: {
// warnings: false,
drop_debugger: true,
drop_console: true
}
}
})
)
return config
error :
static/development/pages/_app.js from UglifyJs
Unexpected token: keyword «const» [static/development/pages/_app.js:11375,0]
function Hook_test(props) {
const[open, setOpen] = useState(false);
const {
dispatch,
num
} = props
console.log("log test"); // I don't want to appear in a production environment,Development environment can appear
function setReducer() {
console.log(111111, change_add(num + 1)) dispatch(change_add(num + 1))
}
return ( < ><button onClick = { () = >{
setOpen(!open);
setReducer()
}
} > HOOK < /button>
<span>{open?"打开":"关闭"} {num}</span > </>
)
}
class Index extends Component {
render() {
return <Hook_test a={1222121} / >
}
}
Have you considered using a logging package instead of console.log? For example, debug is simple to set up.
Using a logging package will likely require using webpack, which can be a process to start using, but if you're already using React.... If you start with Create React App, you get webpack for "free" and just need to import or require a debugging library.
Here's an example using debug with create-react-app
// in src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
const debug = require('debug')('App');
class App extends Component {
render() {
const myVar = { a: 1, b: 2 };
debug('rendering...', myVar);
return (....
Then to view debugging output, just set localStorage.debug='*' or to App from your browser Javascript console. To view output of code run on the server side, run your server with the environment variable DEBUG set to * for all debug output, or App.