'How to pass env var to Docusaurus v2
I've been trying to get environment variables to work in my documentation build.
I've had some success with adding a dotenv-webpack plugin and substituting values that way.
This has the downside of needing a .env file of some kind
I would like to have my build know of environment variables automatically ie. everything that is output from printenv
I've tried adding this to package.json:
TEST_ENV_VAR=working docusaurus start"
But when I log the process.env object there is nothing there.
How can I make this work?
Solution 1:[1]
Build time environment variables
There are two steps:
- Run
npm i --save-dev dotenv - In your
docusaurus.config.js, just add:
require('dotenv').config()
- Confirm your
.envdirectory contains environment variables, e.g.
ENVIRONMENT_VARIABLE_1=hello_there
Your .env file will be loaded, and you can use process.env.ENVIRONMENT_VARIABLE_1 now.
Runtime environment variables:
To use process.env variables in React components for example, do the builtime environment variables steps above, then use the customFields field of the docusaurus config object:
const config = {
...
customFields: {
'ENVIRONMENT_VARIABLE_1': process.env.ENVIRONMENT_VARIABLE_1,
'ENVIRONMENT_VARIABLE_2': process.env.ENVIRONMENT_VARIABLE_2,
},
...
}
and in my typescript component, access them with:
const {siteConfig} = useDocusaurusContext();
return <div>{`${siteConfig.ENVIRONMENT_VARIABLE_1}`}</div>;
Read Custom Configurations in the docusaurus documentation for more information.
Comment
Jonny Nabors's answer (and package) was unnecessary for me and actually confused me. If you want your build process to use your environment variables, use the extremely popular npm package that has been downloaded 22 million times this week (dotenv, rather than his package (docusaurus2-dotenv), which did not work for me.
Perhaps his package is more useful if you needed to use the environment variables at runtime whilst avoiding adding it to the configuration object like I did above? However, in that case, I also found another solution, which is to use environment variables beginning with REACT_APP_.
Solution 2:[2]
The question I have is Why can't we use process.env.VARIABLE?
Reading how Docusaurus.useDocusaurusContext works, a developer can read the config variables using import siteConfig from '@generated/docusaurus.config';. So the solution looks like:
docusaurus.config.js
const config = {
customFields: {
// application environment (i.e. staging or prod)
env: process.env.REACT_APP_ENV,
},
...
}
myUtil.ts
import siteConfig from '@generated/docusaurus.config';
if (siteConfig.customFields.env === 'prod') {
// do something for prod
}
Then, restart the server using
export REACT_APP_ENV="prod"
yarn start
Importing docusaurus.config.js directly into the application results in the error process is not defined. This requires a webpack configuration, which I didn't want to get into.
Note: This method is not documented so use with care.
Solution 3:[3]
You're calling the play method on the button instead of on the audio element.
(When you have invalid HTML with duplicate ids, getElementById will find the first match).
You could hack this with document.getElementById(id).querySelector('audio').play();
But it would be cleaner to make the button and everything in it a component and use a ref.
const AudioButton = ({letter, src}) => {
const audioElement = useRef(null);
const onButtonClick = () => {
audioElement.current.play();
}
return (
<button className="drum-pad" onClick={onButtonClick}>
{letter}
<audio className="clip" src={src} />
</button>
);
}
and then:
<div class="grid" id="display">
<AudioButton letter="Q" src="q.mp3" />
<AudioButton letter="W" src="w.mp3" />
etc
</div>
Solution 4:[4]
Your IDs should be all unique. You are calling play on button element and not a child audio element as they both have the same id. Also as you are already getting target after the click event you don't need to search it by ID again. The event will pass you the target element, and you can get its child audio element.
playClip = (e) => {
const id = event.target.id;
document.getElementById(id).play();
}
this method does not work as you are passing e but then are using non existing in the scope event variable. It should be both e or event. My version would be:
playClip = (e) => {
e.target.querySelector("audio").play();
}
then you don't need the ID on audio elements at all as long as each button has a child audio element.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | |
| Solution 4 |
