Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: custom prefix #482

Merged
merged 5 commits into from
Jan 27, 2022
Merged

feat: custom prefix #482

merged 5 commits into from
Jan 27, 2022

Conversation

vuode
Copy link
Contributor

@vuode vuode commented Dec 26, 2021

Custom prefix

In #480 @niieani suggested a great feature—ability to use custom prefixes.

Here is my attempt to implement this feature

// default
new Dotenv({})
// process.env.PORT

// explicit
new Dotenv({
  prefix: 'process.env.'
})
// process.env.PORT

// custom prefix
new Dotenv({
  prefix: `import.meta.env.`
})
// import.meta.env.PORT

Copy link

@niieani niieani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for implementing this! This looks great, I've left a few notes though.
🙇

src/index.js Outdated
@@ -150,8 +152,9 @@ class Dotenv {
// However, if someone targets Node or Electron `process.env` still exists, and should therefore be kept
// https://webpack.js.org/configuration/target
if (this.shouldStub({ target, version })) {
const replace = this.config.prefix.slice(0, -1) // Remove the dot in the end of prefix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this assumption here. Basically it means that the dot has to be at the end of the prefix. But if it has to be there, why not just make it implicit, and remove it from the config option altogether?
i.e. prefix: 'process.env' instead of prefix: 'process.env.'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your time for this review! Initially, I tried to account for the case, suggested by @mrsteele:

new Dotenv({
  prefix: `MY_TEST_`
})
// MY_TEST_PORT

But I guess for now it's better to stay with implicit . separator, as it makes config more readable and less error prone for most use cases.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, I see. Okay, I'll let @mrsteele make the final call on this one, since it's his package. 👍

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I suggest we be as explicit as we can here. I don’t want to back us into a corner.

make the dot explicit please 🙏

src/index.js Outdated
@@ -150,8 +152,9 @@ class Dotenv {
// However, if someone targets Node or Electron `process.env` still exists, and should therefore be kept
// https://webpack.js.org/configuration/target
if (this.shouldStub({ target, version })) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think shouldStub should be made to return true only when prefix is process.env (based on the reasoning in the comment above)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I've made changes, now it stubs only when prefix is process.env

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the water is getting a little muddy here. Originally the system implied based on env (which I think is safe). Perhaps the stub can work as is now, but if we see the prefix as manually set we force the stub you defined always.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't fully understand the intended behaviour when the prefix is manually set. Should we continue to stub process.env or the set prefix?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep this as a non-major version update so people can update without things breaking I suggest we let the system work as it used to, but should they explicitly set the “prefix” property it would always apply the stub with whatever they have requested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I getting it right?

// Current behaviour

new Dotenv()
// process.env.MISSING --> "MISSING_ENV_VAR".MISSING

new Dotenv({
  ignoreStub: true
})
// process.env.MISSING --> process.env.MISSING
// With set option

new Dotenv({
  prefix: 'META_ENV_'
})
// META_ENV_MISSING --> "MISSING_ENV_VAR".MISSING
// process.env.MISSING --> process.env.MISSING

new Dotenv({
  prefix: 'META_ENV_',
  ignoreStub: true
})
// META_ENV_MISSING --> META_ENV_MISSING
// process.env.MISSING --> process.env.MISSING

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. We shouldn’t be changing anything about how it works currently and you have changed how the plug-in works out-of-the box (if I am reading this right).

Reading some of these assumptions I’m also worried the original point of the stub has been lost.

the basic requirements of this pr is quite simple:

  1. Should support a “prefix” configuration property and should be able to override the existing process.env. prefix (which is the default).
  2. Stubbing (which was the last major feature introduced to account for all the unique webpack targets) should work as it does today, but if you override the default prefix you should also force the stub (using of course the defined prefix in the configuration).

With that being said, I do think it’s work getting rid of the stub feature and allowing users to just manually set to an empty string to remove the stub for unique targets, but it’s a little more debatable as that also introduces other complexities.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plug-in stubs process.env with "MISSING_ENV_VAR" out-of-the-box when the env var is missing, I didn't change that, plug-in works as it did before, unless a prefix property is set. I've illustrated this with the code example with comment "Current behaviour".

The second example is my understanding of how the plugin should work when the property is set.

I've made the dot explicit in the most recent commit, but I didn't change the bit, which disables stubbing when the prefix is set to other value, than process.env.. Currently DefinePlugin can replace full expression or a part of expression, with a dot following it. For us it means that we can't replace every possible user defined prefix, but only those, ending with a dot. That is why I kept this restriction for now.

I can try to explore other possibilities for stubbing custom prefixes, but as I see now, it most likely will involve changes in DefinePlugin.

Copy link
Owner

@mrsteele mrsteele left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, happy holidays. Glad to see this thing getting some traction!

left a few comments with my thoughts. The biggest one being that I think we should remove the assumptions about dot notations. I have seen some other systems use underscores for instance, and I would love to support those ideas. (NEXT_PUBLIC_HELLO would have a prefix NEXT_PUBLIC_ for the env variable HELLO).

Let me know if they don’t make sense or if you see some issues or alternatives.

README.md Outdated
@@ -115,6 +117,7 @@ Use the following properties to configure your instance.
* **expand** (`false`) - Allows your variables to be "expanded" for reusability within your `.env` file.
* **defaults** (`false`) - Adds support for `dotenv-defaults`. If set to `true`, uses `./.env.defaults`. If a string, uses that location for a defaults file. Read more at [npm](https://www.npmjs.com/package/dotenv-defaults).
* **ignoreStub** (`false`) - Override the automatic check whether to stub `process.env`. [Read more here](#user-content-processenv-stubbing--replacing).
* **prefix** (`'process.env'`) - The prefix to use before the name of your env variables.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would just include the dot notation here at the end (we pack DefinePlugin is just looking for raw strings, it also keeps opportunities for other notations as a viable option).

“process.env.” as the prefix.

README.md Outdated
@@ -128,7 +131,8 @@ module.exports = {
allowEmptyValues: true, // allow empty variables (e.g. `FOO=`) (treat it as empty string, rather than missing)
systemvars: true, // load all the predefined 'process.env' variables which will trump anything local per dotenv specs.
silent: true, // hide any errors
defaults: false // load '.env.defaults' as the default values if empty.
defaults: false, // load '.env.defaults' as the default values if empty.
prefix: 'import.meta.env' // reference your env variables as 'import.meta.env.ENV_VAR'.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these examples here are the defaults. I would adjust yours to show “process.env.” to maintain consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello! As I see, the defaults are set only for path, all other options are undefined and coerced to false in conditions. That's why I assumed putting here possible option instead of default. Am I missing something here?

this.config = Object.assign({}, {
path: './.env'
}, config)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, you are right I’m not sure where my head was at. You can disregard this bit.

src/index.js Outdated
* @returns {webpack.DefinePlugin}
*/
constructor (config = {}) {
this.config = Object.assign({}, {
path: './.env'
path: './.env',
prefix: 'process.env'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the trailing dot

src/index.js Outdated
const formatted = Object.keys(variables).reduce((obj, key) => {
const v = variables[key]
const vKey = `process.env.${key}`
const vKey = `${prefix}.${key}`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the assumed dot here to allow the prefix system to handle that.

src/index.js Outdated
@@ -150,8 +152,9 @@ class Dotenv {
// However, if someone targets Node or Electron `process.env` still exists, and should therefore be kept
// https://webpack.js.org/configuration/target
if (this.shouldStub({ target, version })) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the water is getting a little muddy here. Originally the system implied based on env (which I think is safe). Perhaps the stub can work as is now, but if we see the prefix as manually set we force the stub you defined always.

src/index.js Outdated
@@ -166,6 +169,8 @@ class Dotenv {

return targets.every(
target =>
// If configured prefix is 'process.env'
this.config.prefix === 'process.env' &&
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With my comment above we can trash this bit.

@mrsteele
Copy link
Owner

I haven’t forgotten about this (promise, just went on a vacation with the wife and so technology was mostly a no-no).

mom wrestling with this a bit because I’m wondering if we should rethink the last breaking change for this approach. Should we assume your prefix is “process.env.”? Do we let you set it to nothing if you want nothing? Do we try to make them compatible with one another?

I’m worried about the complexities with juggling the former system which makes some assumptions and adds a bit of confusion with this proposed system which is meant to make things a little more explicit. I like things being as easy as possible to get started, but am also a big fan of giving power to the developer to configure what they need when they need it.

Thoughts or ideas or opinions would be appreciated. Also, appreciate the patience (and my wife does too).

@niieani
Copy link

niieani commented Jan 26, 2022

I'm fine with this as is. Perhaps being explicit has the additional benefit in that process is usually not a global in the browser environment, so the assumption that it's the default is a bit odd, and only due to it being the legacy. In that respect, using import.meta.env. is a bit more sound, because import.meta is actually a standard that browsers with support for modules have to abide by. Changing the default would be a breaking change though (which I'm fine with). Honestly, I think the final decision here is not that important, as long as it's documented.

@vuode vuode closed this Jan 27, 2022
@mrsteele
Copy link
Owner

Yeah, good point. I'm going to push this out today. Hopefully all systems work 🤞 .

Thank you so much for your patience through all of this @niieani and @vuode. I hope the community enjoys this added feature 🎉

@mrsteele
Copy link
Owner

@vuode did you mean to close this? It didn't get merged.

@vuode
Copy link
Contributor Author

vuode commented Jan 27, 2022

@vuode did you mean to close this? It didn't get merged.

Sorry, no, wrongly clicked the button

@mrsteele mrsteele reopened this Jan 27, 2022
@mrsteele mrsteele merged commit 96b42f4 into mrsteele:master Jan 27, 2022
@github-actions
Copy link

🎉 This PR is included in version 7.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants