Skip to content

Commit 67c0aeb

Browse files
authored
feat: adding config for stubbing (#360)
* fix: only stub `process.env` if not targeting node * fix: use better replacement * only dont stub on main thread electron * add tests that use the compiler * start converting old tests * move more tests * replace old tests * fix errors * fix race condition * handle no dir error * remove behavior changes * drop node 8 * undo more fixes * fix stubbing replacement, only stub on targets where we should * remove deprecated code * drop support for webpack <4 * merge stubIgnore PR * update readme * fix logic * Update README.md * skip stubbing on webpack 4, do not stub if target includes `node` * handle target array * move version check * fix logic * replace usage of `rmdirSync(..., { recursive: true })` BREAKING CHANGE: dropping support for Node v8 BREAKING CHANGE: dropping support for webpack < 4 BREAKING CHANGE: automatically stubbing during compilation
1 parent b2da479 commit 67c0aeb

File tree

8 files changed

+555
-264
lines changed

8 files changed

+555
-264
lines changed

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
runs-on: ubuntu-18.04
4949
strategy:
5050
matrix:
51-
node: [ '8', '10', '12', '14' ]
51+
node: [ '10', '12', '14' ]
5252
steps:
5353
- name: 🛑 Cancel Previous Runs
5454
uses: styfle/[email protected]

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Tests
2+
test/output
3+
14
# Logs
25
logs
36
*.log

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ Add `.env` to your `.gitignore` file
9595

9696
Due to the fact that we use `webpack.DefinePlugin` under the hood, we cannot support destructing as that breaks how this plugin is meant to be used. Because of this, please reference your variables without destructing. For more information about this, please review the issue [here](https://github.com/mrsteele/dotenv-webpack/issues/70).
9797

98+
## `process.env` stubbing / replacing
99+
100+
`process.env` is not polyfilled in Webpack 5+, leading to errors in environments where `process` is `null` (browsers).
101+
102+
We automatically replace any remaining `process.env`s in these environments with `"MISSING_ENV_VAR"` to avoid these errors.
103+
104+
If you are running into issues where you or another package you use interfaces with `process.env`, it might be best to set `ignoreStubs: true` and make sure you always reference variables that exist within your code (See [this issue](https://github.com/mrsteele/dotenv-webpack/issues/271) for more information).
105+
98106
## Properties
99107

100108
Use the following properties to configure your instance.
@@ -106,6 +114,7 @@ Use the following properties to configure your instance.
106114
* **silent** (`false`) - If true, all warnings will be suppressed.
107115
* **expand** (`false`) - Allows your variables to be "expanded" for reusability within your `.env` file.
108116
* **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).
117+
* **ignoreStub** (`false`) - Override the automatic check whether to stub `process.env`. [Read more here](#user-content-processenv-stubbing--replacing).
109118

110119
The following example shows how to set any/all arguments.
111120

package-lock.json

+34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+9-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
},
2222
"jest": {
2323
"coverageDirectory": "./coverage/",
24-
"collectCoverage": true
24+
"collectCoverage": true,
25+
"watchPathIgnorePatterns": [
26+
"output/.*?"
27+
]
2528
},
2629
"keywords": [
2730
"dotenv",
@@ -41,8 +44,11 @@
4144
"url": "https://github.com/mrsteele/dotenv-webpack/issues"
4245
},
4346
"homepage": "https://github.com/mrsteele/dotenv-webpack#readme",
47+
"engines": {
48+
"node": ">=10"
49+
},
4450
"peerDependencies": {
45-
"webpack": "^1 || ^2 || ^3 || ^4 || ^5"
51+
"webpack": "^4 || ^5"
4652
},
4753
"dependencies": {
4854
"dotenv-defaults": "^2.0.1"
@@ -52,6 +58,7 @@
5258
"@babel/core": "^7.13.8",
5359
"@babel/preset-env": "^7.13.9",
5460
"@babel/register": "^7.13.8",
61+
"fs-extra": "^9.1.0",
5562
"husky": "^5.1.3",
5663
"jest": "^25.5.4",
5764
"jsdoc": "^3.6.6",

src/index.js

+47-19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ const interpolate = (env, vars) => {
1616
return env
1717
}
1818

19+
const isMainThreadElectron = (target) =>
20+
target.startsWith('electron') && target.endsWith('main')
21+
1922
class Dotenv {
2023
/**
2124
* The dotenv-webpack plugin.
@@ -30,21 +33,19 @@ class Dotenv {
3033
this.config = Object.assign({}, {
3134
path: './.env'
3235
}, config)
33-
34-
this.checkDeprecation()
35-
36-
return new DefinePlugin(this.formatData(this.gatherVariables()))
3736
}
3837

39-
checkDeprecation () {
40-
const { sample, safe, silent } = this.config
41-
// Catch older packages, but hold their hand (just for a bit)
42-
if (sample) {
43-
if (safe) {
44-
this.config.safe = sample
45-
}
46-
this.warn('dotenv-webpack: "options.sample" is a deprecated property. Please update your configuration to use "options.safe" instead.', silent)
47-
}
38+
apply (compiler) {
39+
const variables = this.gatherVariables()
40+
const target = compiler.options.target ?? 'web'
41+
const version = compiler.webpack.version
42+
const data = this.formatData({
43+
variables,
44+
target,
45+
version
46+
})
47+
48+
new DefinePlugin(data).apply(compiler)
4849
}
4950

5051
gatherVariables () {
@@ -121,10 +122,10 @@ class Dotenv {
121122
return ''
122123
}
123124

124-
formatData (vars = {}) {
125+
formatData ({ variables = {}, target, version }) {
125126
const { expand } = this.config
126-
const formatted = Object.keys(vars).reduce((obj, key) => {
127-
const v = vars[key]
127+
const formatted = Object.keys(variables).reduce((obj, key) => {
128+
const v = variables[key]
128129
const vKey = `process.env.${key}`
129130
let vValue
130131
if (expand) {
@@ -133,7 +134,7 @@ class Dotenv {
133134
} else if (v.indexOf('\\$') > 0) {
134135
vValue = v.replace(/\\\$/g, '$')
135136
} else {
136-
vValue = interpolate(v, vars)
137+
vValue = interpolate(v, variables)
137138
}
138139
} else {
139140
vValue = v
@@ -144,12 +145,39 @@ class Dotenv {
144145
return obj
145146
}, {})
146147

147-
// fix in case of missing
148-
formatted['process.env'] = '{}'
148+
// We have to stub any remaining `process.env`s due to Webpack 5 not polyfilling it anymore
149+
// https://github.com/mrsteele/dotenv-webpack/issues/240#issuecomment-710231534
150+
// However, if someone targets Node or Electron `process.env` still exists, and should therefore be kept
151+
// https://webpack.js.org/configuration/target
152+
if (this.shouldStub({ target, version })) {
153+
// Results in `"MISSING_ENV_VAR".NAME` which is valid JS
154+
formatted['process.env'] = '"MISSING_ENV_VAR"'
155+
}
149156

150157
return formatted
151158
}
152159

160+
shouldStub ({ target: targetInput, version }) {
161+
if (!version.startsWith('5')) {
162+
return false
163+
}
164+
165+
const targets = Array.isArray(targetInput) ? targetInput : [targetInput]
166+
167+
return targets.every(
168+
target =>
169+
// If we're not configured to never stub
170+
this.config.ignoreStub !== true &&
171+
// And
172+
(
173+
// We are configured to always stub
174+
this.config.ignoreStub === false ||
175+
// Or if we should according to the target
176+
(!target.includes('node') && !isMainThreadElectron(target))
177+
)
178+
)
179+
}
180+
153181
/**
154182
* Load a file.
155183
* @param {String} config.file - The file to load.

test/fixtures/index.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* eslint-disable no-unused-vars */
2+
3+
// Basic
4+
const TEST = process.env.TEST
5+
const TEST2 = process.env.TEST2
6+
7+
// System
8+
const PATH = process.env.PATH
9+
10+
// Expanded
11+
const NODE_ENV = process.env.NODE_ENV
12+
const BASIC = process.env.BASIC
13+
const BASIC_EXPAND = process.env.BASIC_EXPAND
14+
const MACHINE = process.env.MACHINE
15+
const MACHINE_EXPAND = process.env.MACHINE_EXPAND
16+
const UNDEFINED_EXPAND = process.env.UNDEFINED_EXPAND
17+
const ESCAPED_EXPAND = process.env.ESCAPED_EXPAND
18+
const MONGOLAB_DATABASE = process.env.MONGOLAB_DATABASE
19+
const MONGOLAB_USER = process.env.MONGOLAB_USER
20+
const MONGOLAB_PASSWORD = process.env.MONGOLAB_PASSWORD
21+
const MONGOLAB_DOMAIN = process.env.MONGOLAB_DOMAIN
22+
const MONGOLAB_PORT = process.env.MONGOLAB_PORT
23+
const MONGOLAB_URI = process.env.MONGOLAB_URI
24+
const MONGOLAB_USER_RECURSIVELY = process.env.MONGOLAB_USER_RECURSIVELY
25+
const MONGOLAB_URI_RECURSIVELY = process.env.MONGOLAB_URI_RECURSIVELY
26+
const WITHOUT_CURLY_BRACES_URI = process.env.WITHOUT_CURLY_BRACES_URI
27+
const WITHOUT_CURLY_BRACES_USER_RECURSIVELY = process.env.WITHOUT_CURLY_BRACES_USER_RECURSIVELY
28+
const WITHOUT_CURLY_BRACES_URI_RECURSIVELY = process.env.WITHOUT_CURLY_BRACES_URI_RECURSIVELY

0 commit comments

Comments
 (0)