import/export according to environment variable - reactjs

For a clientSide app I would like to select a specific import according to the environment variables that were setup in the package.json.
eg:`
if (process.env.IS_DEV)
import { store } from '../../../index.js
else
import { store } from './index.js';
`
Is there anyway to do this.
I currently receive the error -
Parsing error: 'import' and 'export' may only appear at the top level

As the error says, import can be only at top level.
If you are using some bundler such as webpack or parcel, you can use a require instead.
Pay attention: that both of the implementations will be inside the bundle, and only one of them will be executed.

You can use web pack dynamic import to enable this if you are using web pack 1
$ npm install babel-plugin-dynamic-import-webpack --save-dev
then in .babelrc
{
"plugins": ["dynamic-import-webpack"]
}
https://github.com/airbnb/babel-plugin-dynamic-import-webpack
in the newer versions of web pack, you can do this without Babel
https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import
the other solution which mentioned before is using require
but i think here you can do it in a different way to avoid having this files in the bundled result you can add build script to run before building the dist which replace this import inside the file completely before bundle it to frontend app

Maybe is better to check process.env.IS_DEV inside the store file and export different values based on the current env

Related

Import TypeScript modules from local module into React app

I'm trying to separate my projects and keep logic as separate components that I will end up publishing. For now, before I do so, I'd like to keep it organized as such:
A library of TS scripts in a project called project-a
A separate React app that I created with create-react-app (using Typescript as the template) called project-b
The React app's .tsx components will pull from project-a's .ts files.
I've gone ahead in project-b and ran yarn add ../project-a. This installs the library as a dependency. I then import the .ts files and my code editor is able to see all the types and definitions really nicely. Great!
When I run the application, Webpack complains:
./node_modules/project-a/src/calc.ts 2:7
Module parse failed: Unexpected token (2:7)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
> export enum Position {
| Inner = 0,
| Outer = 1
I don't understand why it's not parsing the file as a .ts. The whole React application is setup with TypeScript and I'm even import some .ts files locally. Do I need to tell Webpack to handle the files imported from this module as Typescript source (assuming Webpack wouldn't attempt parsing them if it didn't need to)?
The React template didn't setup a webpack (I'm assuming it's using a hidden default) but I am able to adjust the tsconfig.json file. I added my modules direct path into the include array. That didn't seem to do much either.
Basically: how can I get passed the above error and continue importing the TypeScript files from my dependency module in my main application?
You have to compile down project-a to javascript and emit the typings file, because imports from packages have to be Javascript.
The type infos you get from external packages is delivered via the .d.ts file alongside the package.
When you import other packages, you always import the Javascript file.
Even locally, Webpack doesn't compile the typescript for you, a loader during bundling does. So once running inside the browser, it's all Javascript.
But you are trying to import a Typescript file during runtime.

cannot use import statement outside a module with Next.js

I need to import a npm package but failed when I use "import" statement
like this
import { cuteLuna } from 'lunacomponent';
and I got an error : cannot use import statement outside a module
after I change it to dynamic import, it works.
const cuteLuna = dynamic(() => import('lunacomponent').then((a) => a.cuteLuna), {ssr: false});
My question is, why should I use dynamic import instead of usual import?
thanks!!
Since Next.js is a framework that runs on server & client side it needs to consume the proper module styles for each.
Server side runs on Node, therefore your lib must expose a commonjs.
From your error I can guess that your lunacomponent lib is not exporting cjs files, therefore it fails on the server, when you use dynamic with ssr:false you tell Next.js to skip server-side run, therefore you don't have the same error.
I wasn't able to find this lunacomponent lib on the public npm registry, therefore I can't check my assumption.

Adding/Overriding Webpack Loaders for a create-react-app?

is there an option to add a loader for a certain file type to a boilerplate create-react-app application? Whatever I tried, I don't seem to be able to get it working without specifying the loader itself in the js file with:
!!import List from './data.txt'
I found the following link, but am hesitant to believe that the de-facto default way of creating a react app nowadays doesn't allow to override/add loaders (simply):
https://github.com/facebook/create-react-app/issues/2608
Thanks!
At my last project we used this:
npm i #craco/craco
https://www.npmjs.com/package/#craco/craco
It allows config changes without ejecting.
You can also do this:
in your react-app-env.d.ts add declare module "*.txt"
then in the code you can get the content in Promise:
import dataRaw from "./data.txt"
fetch(dataRaw)
.then(raw => raw.text())
.then(text => { <here you have it> }

How to import a file into a react app that uses create react app as raw text?

Goals
I want to display some code for reference from the project itself.
I want the display of the code to be updated with the implementation.
I don't want to eject from create-react-app
This react project, created with create-react-app and typescript, is going to be used to display some custom components for re-use in other projects. My goal is to have the component be used right next to the code that is using it.
How can I load the file if I don't have access to the webpack config, and I can't use fs.readFile?
I managed to get this working after a bit of looking around. There are two major pieces that had to be in place to make it work.
Use the appropriate loader
In this case I wanted to use the raw-loader, so I installed it as a dev dependency. yarn add -D raw-loader.
In order to actually import the file I needed to then override the webpack configuration like this:
// eslint-disable-next-line import/no-webpack-loader-syntax
import toolbarItems from '!!raw-loader!../ToolbarItems';
This loads the entire file into the variable toolbarItems. By using the !! before the loader I prevent any other webpack loaders from processing it in this specific case. This might work on its own in a plain javascript project, but in typescript...
You must provide a module to typescript
I was running into the typescript error:
Failed to compile.
/Users/cory/Code/something/custom-theme/src/pages/NavigationDemo.tsx
TypeScript error in /Users/cory/Code/something/custom-theme/src/pages/NavigationDemo.tsx(9,26):
Cannot find module '!!raw-loader!../ToolbarItems'. TS2307
7 |
8 | // eslint-disable-next-line import/no-webpack-loader-syntax
> 9 | import toolbarItems from '!!raw-loader!../ToolbarItems';
| ^
10 |
11 | const useStyles = makeStyles({
12 | root: {
Simply declaring a module for the loader in a file called ToolbarItems.ts.d.ts solved the issue for me:
declare module '!!raw-loader!*' {
const content: string;
export default content;
}
source
Since you use create-react-app for your project, the best solution at the moment would be a babel plugin called Raw.Macro.
This plugin allows you to access content of your files without a need to create-react-app eject. Provides really elegant solution without any boilerplate code and declaring "d.ts" files as in previous answer.
Note: There is a small drawback that you have to re-start your webpack dev server when the file changes, because the content of a file is being embedded during the build process.
import raw from 'raw.macro';
function foo(){
const jsonContent = raw('../utils/stops.json');
console.log(jsonContent);
}

react evironment variables .env return undefined

I am building a react app and i need to fetch data from my api, now i want to store the api url as an environment variable. I have my .env file, i have dotenv installed, here is my code process.env.API_URL is returning undefined.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Home from '../src/components/Home'
import dotenv from 'dotenv'
import path from 'path'
class App extends Component {
render() {
console.log(process.env.API_URL)
return (
<div>
<Home/>
</div>
);
}
}
export default App;
Three things to note here
the variable should be prefixed with REACT_APP_
eg: REACT_APP_WEBSITE_NAME=hello
You need to restart the server to reflect the changes.
Make sure you have the .env file in your root folder(same place where you have your package.json) and NOT in your src folder.
After that you can access the variable like this process.env.REACT_APP_SOME_VARIABLE
Additional tips
No need to wrap your variable value in single or double quotes.
Do not put semicolon ; or comma , at the end of each line.
Read more here(my own post) and the official docs
You will probably need to call dotenv.config() as suggested by the document
If you are using create-react-app, you don't need dotenv package. You will need to add REACT_APP_ prefix to the variable name in .env file. See the document here
when calling a .env variable from a JS file
you need to call it by process.env. prefix before you write the .env variable
thus it would look like process.env.REACT_APP_NOT_SECRET_CODE
and do not forget to start your variable name by REACT_APP_ prefix as mentioned in previous answers, otherwise react will ignore it for security reasons.
Add prefix REACT_APP_ on React environment variables.
apiKey: process.env.REACT_APP_API_KEY
Make sure .env file is in the root directory.
src/
.env
.gitignore
package.json
package-lock.json
Restart the development server after making changes in .env file.
Copy only the value inside the quotation marks and don't forget to remove trailing commas(It haunted me for several hours). These examples will give you an error.
REACT_APP_API_KEY=Ach2o1invVocSn25FcQhash209,
REACT_APP_API_KEY="Ach2o1invVocSn25FcQhash209",
REACT_APP_API_KEY="Ach2o1invVocSn25FcQhash209"
Make sure you used the prefix REACT_APP on every variable
Confirm that the variable names on the .env file match the ones on
your js file.For example,REACT_APP_KEY in .env versus
process.env.REACT_APP_KY
If the development server was running, stop it then rerun using npm
start it. I really struggled with this (variable is an undefined error).
Every time you update the .env file, you need to stop the server and
rerun it, as the environment variables are only updated during build
(variable is an undefined error).
Remove quotations from the values of the variables.
// Wrong:
REACT_APP_KEY=”AHEHEHR”
// Right:
REACT_APP_KEY=AHEHEHR
restart the vscode (close the project, close the editor)
open it again
launch the project
In my case it help a lot. Also remember to start the name of your key with REACT_APP_YOUR_NAME_KEY
If the above solutions don't work for you then please check where is your ".env" file place.
Like in my case everything I had done correctly but the mistake is I had placed the ".env" outside my project directory due to which I'm getting error.
Note: Your ".env" file should be in the same directory in which your "package.json" is.
Hey thanks guy what i did and worked was create a config.js file
const dev={
API_URL:"http://localhost:300"
}
const prod={
API_URL:"llll"
}
const config=process.env.NODE_ENV=='development'?dev:prod
export default config
Then i import wherever maybe in a component and get my data.
Another possible trap in which I fell was to define the variables not under the create-react-app folder but one above(where the Node server/backend .env is located). Make sure you don't do that because you will waste precious time, as I did today.
Solution:
1.Remove double quotation.("...").
2.Prefix Must be REACT_APP on every variable.
Right way:
REACT_APP_API_URL=http://localhost:8002
I hope its work.
In my case I started with naming the file process.env. As it happen and as the doc clearly states, the file should simply be named .env
try by clearing the cache also.
npx react-native start --reset-cache
FIX:
in babel.config.js, if you're using the optional configuration:
{
"plugins": [
["module:react-native-dotenv", {
"moduleName": "#env",
"path": ".env",
"blacklist": null,
"whitelist": null,
"safe": false,
"allowUndefined": true
}]
]
}
you should then import:
import {API_URL, API_TOKEN} from "#env"
instead of:
import {API_URL, API_TOKEN} from "react-native-dotenv"
the NPM Package description itself has this inconsistency
DO NOT STORE OR USE API KEYS IN FRONTEND CODE SINCE IT IS EASILY READABLE THROUGH DEV TOOLS
Saving API keys in .env and using them in your React app will still be unsecured since the API key can be read from DevTools.
Use some simple backend code that will act as a proxy to your service.
Send required data through a request and then the backend should use that data including the API key stored on the backend, and then make a request to some particular service that needs that API key.
No need to prefix it with REACT_APP_, just identify your environment -
if you are on development environment (npm start), you should be adding an environment variable in .env.development like - API_URL=http://example.com
if you are on production environment, updating .env should work
Then use the same in your JS file as process.env.API_URL
Note: I've tested this on React JS v16.8
If you are using dev server on localhost know this that .env doesn't work here, you need to deploy website on "normal" server, it is a safety reason to not allow browser to see .env in staging
I investigated a couple of options on how to set environment-specific variables and ended up with this:
You can directly use the dotenv-webpack(npm install dotenv-webpack --save) available in webpack to have access to any environment variable.
You just have to declare the plugin in your webpack.config.js file:
const path = require('path')
const Dotenv = require('dotenv-webpack')
module.exports = {
/*...*/
plugins: [
new Dotenv()
]
}
Just create the .env file in your root directory and set the variables there,
REACT_APP_API_URL=https://localhost:8080/api
REACT_APP_LOG_PATH=/usr/share/
Then you call it in your js file in the following way:
process.env.REACT_APP_API_URL
process.env.REACT_APP_LOG_PATH
I just found that I used different names for the variables :)
Also make sure that when you enter process.env.REACT_APP_YOURVARIABLE, your IDE don't add at the top of your file:
import process from "process";
This was my problem, I received undefined until I removed the accidentally added import

Resources