├── .gitignore ├── LICENSE ├── README.md ├── doc └── README.md ├── jest.config.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── scripts ├── @types │ └── chartjs-node │ │ └── index.d.ts ├── site.ts └── tsconfig.json ├── src └── index.ts ├── test ├── browser.test.ts ├── cli.js ├── myApp │ ├── README.md │ ├── rollup.config.2.js │ ├── rollup.config.3.js │ ├── rollup.config.js │ ├── src │ │ ├── index.3.ts │ │ ├── index.ts │ │ └── style.3.css │ └── tsconfig.json ├── node.2.test.ts ├── node.3.test.ts └── node.test.ts ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Dependency directories 7 | node_modules/ 8 | 9 | # Output directories 10 | build/ 11 | dist/ 12 | 13 | # Generated data 14 | scripts/*-report.json 15 | 16 | # Misc 17 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 @badcafe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # rollup-plugin-inject-process-env 4 | 5 | > Inject `process.env` environment variables in a browser rollup bundle. 6 | 7 | ## Why ? 8 | 9 | Because replacing a string typically with `rollup-plugin-replace` works in one case : 10 | 11 | ```js 12 | console.log(process.env.NODE_ENV); 13 | ``` 14 | 15 | ...but not in all other cases : 16 | 17 | ```js 18 | console.log(process.env['NODE_ENV']); 19 | ``` 20 | 21 | ```js 22 | const { NODE_ENV, NODE_PORT } = process.env; 23 | console.log(NODE_ENV); 24 | ``` 25 | 26 | Worse : sometimes, such substitution : 27 | 28 | ```js 29 | if (process.env.NODE_ENV === 'production') { 30 | ``` 31 | 32 | ...will be expand to : 33 | 34 | ```js 35 | if ('production' === 'production') { 36 | ``` 37 | 38 | ...and make some linter complain. 39 | 40 | ## How ? 41 | 42 | ### Installation 43 | 44 | ```bash 45 | npm install --save-dev rollup-plugin-inject-process-env 46 | ``` 47 | 48 | ### Usage 49 | 50 | Pass any JSON object to the plugin that will be set as the `process.env` value. This object accept members value of any type. 51 | 52 | ```typescript 53 | function injectProcessEnv( 54 | env: object, 55 | options?: { 56 | include?: string | string[], 57 | exclude?: string | string[], 58 | verbose?: boolean 59 | } 60 | ) 61 | ``` 62 | 63 | > Note: if you use the [commonjs](https://github.com/rollup/plugins/tree/master/packages/commonjs) plugin `injectProcessEnv` must be listed _after_ it in your plugins list. Otherwise you will see the error `'import' and 'export' may only appear at the top level`. 64 | 65 | #### Example : 66 | 67 | ```js 68 | import injectProcessEnv from 'rollup-plugin-inject-process-env'; 69 | 70 | // ... usual rollup stuff 71 | 72 | plugins: [ 73 | typescript(), 74 | commonjs(), 75 | injectProcessEnv({ 76 | NODE_ENV: 'production', 77 | SOME_OBJECT: { one: 1, two: [1,2], three: '3' }, 78 | UNUSED: null 79 | }), 80 | nodeResolve() 81 | ], 82 | ``` 83 | 84 | #### Example with environment variables passed in the CLI : 85 | 86 | ```js 87 | injectProcessEnv({ 88 | NODE_ENV: process.env.NODE_ENV, 89 | SOME_OBJECT: JSON.parse(process.env.SOME_OBJECT), 90 | UNUSED: null 91 | }), 92 | ``` 93 | 94 | #### Options 95 | 96 | * The `verbose` option allows to show which file is included in the process and which one is excluded. 97 | * The `include` and `exclude` options allow to explicitely specify with a [minimatch pattern](https://github.com/isaacs/minimatch) the files to accept or reject. By default, all files are targeted and no files are rejected. 98 | 99 | Example : 100 | 101 | ```js 102 | injectProcessEnv({ 103 | NODE_ENV: 'production', 104 | SOME_OBJECT: { one: 1, two: [1,2], three: '3' }, 105 | UNUSED: null 106 | }, { 107 | exclude: '**/*.css', 108 | verbose: true 109 | }), 110 | postcss({ 111 | inject: true, 112 | minimize: true, 113 | plugins: [], 114 | }), 115 | ``` 116 | 117 | Output example of the `verbose` option : 118 | 119 | ``` 120 | [rollup-plugin-inject-process-env] Include /path/to/src/index.ts 121 | [rollup-plugin-inject-process-env] Exclude rollup-plugin-inject-process-env 122 | [rollup-plugin-inject-process-env] Exclude /path/to/src/style.3.css 123 | [rollup-plugin-inject-process-env] Include /path/to/node_modules/style-inject/dist/style-inject.es.js 124 | ``` 125 | 126 | #### Icing on the cake 127 | 128 | You might notice that as mentionned in the documentation https://nodejs.org/api/process.html#process_process_env 129 | environment variables are always `string`, `number` or `boolean`. 130 | 131 | With **rollup-plugin-inject-process-env**, you may inject safely any JSON object to a `process.env` property, as shown in the example above. 132 | 133 | ## Troubleshootings 134 | 135 | ### `'globalThis' is undefined` 136 | 137 | This error may occur in target environments where `globalThis` is undefined. You should use a polyfill to fix it : 138 | 139 | ``` 140 | npm install @ungap/global-this 141 | ``` 142 | 143 | And include it in your code, e.g. : 144 | 145 | ``` 146 | import '@ungap/global-this'; 147 | ``` 148 | 149 | * https://github.com/ungap/global-this 150 | * https://mathiasbynens.be/notes/globalthis 151 | 152 | 153 | ## Reports 154 | 155 | > Code quality reports 156 | 157 | ### Metrics 158 | 159 | | Files | 1 | | 160 | | ----- | -: | - | 161 | | Lines of code | 59 | (w/o comments) | 162 | | Comments | 4 | (+ 1 with code) | 163 | | Empty lines | 4 | | 164 | | **Total lines** | **67** | (w/o tests) | 165 | | TODO | 0 | lines | 166 | | Tests | 455 | (w/o comments) | 167 | 168 | ### Linter 169 | 170 | **✅ 0 problems** 171 | 172 | 173 | 174 | ### Tests 175 | 176 | | | Tests suites | Tests | 177 | | - | ------------ | ----- | 178 | | ❌ Failed | 0 | 0 | 179 | | ✅ Passed | 4 | 12 | 180 | | ✴ Pending | 0 | 0 | 181 | | ☢ Error | 0 | | 182 | | **Total** | **4** | **12** | 183 | 184 | 185 | 186 | 187 | #### ✅ `/test/browser.test.ts` **1.727s** 188 | 189 | 190 | | Status | Suite | Test | 191 | | ------ | ----- | ---- | 192 | | ✅ | Browser | get NODE_ENV | 193 | | ✅ | Browser | get SOME_OBJECT | 194 | | ✅ | Browser | get MISSING | 195 | 196 | 197 | 198 | #### ✅ `/test/node.3.test.ts` **0.173s** 199 | 200 | 201 | | Status | Suite | Test | 202 | | ------ | ----- | ---- | 203 | | ✅ | Filter out CSS | get NODE_ENV | 204 | | ✅ | Filter out CSS | get SOME_OBJECT | 205 | | ✅ | Filter out CSS | get MISSING | 206 | 207 | 208 | 209 | #### ✅ `/test/node.test.ts` **0.162s** 210 | 211 | 212 | | Status | Suite | Test | 213 | | ------ | ----- | ---- | 214 | | ✅ | Node | get NODE_ENV | 215 | | ✅ | Node | get SOME_OBJECT | 216 | | ✅ | Node | get MISSING | 217 | 218 | 219 | 220 | #### ✅ `/test/node.2.test.ts` **0.161s** 221 | 222 | 223 | | Status | Suite | Test | 224 | | ------ | ----- | ---- | 225 | | ✅ | Node | get NODE_ENV | 226 | | ✅ | Node | get SOME_OBJECT | 227 | | ✅ | Node | get MISSING | 228 | 229 | 230 | 231 | 232 | ## License 233 | 234 | MIT 235 | 236 | ## Who ? 237 | 238 | * [Inria](http://inria.fr) 239 | * [Inria @ Github](https://github.com/inria) 240 | 241 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # rollup-plugin-inject-process-env 2 | 3 | > Inject `process.env` environment variables in a browser rollup bundle. 4 | 5 | ## Why ? 6 | 7 | Because replacing a string typically with `rollup-plugin-replace` works in one case : 8 | 9 | ```js 10 | console.log(process.env.NODE_ENV); 11 | ``` 12 | 13 | ...but not in all other cases : 14 | 15 | ```js 16 | console.log(process.env['NODE_ENV']); 17 | ``` 18 | 19 | ```js 20 | const { NODE_ENV, NODE_PORT } = process.env; 21 | console.log(NODE_ENV); 22 | ``` 23 | 24 | Worse : sometimes, such substitution : 25 | 26 | ```js 27 | if (process.env.NODE_ENV === 'production') { 28 | ``` 29 | 30 | ...will be expand to : 31 | 32 | ```js 33 | if ('production' === 'production') { 34 | ``` 35 | 36 | ...and make some linter complain. 37 | 38 | ## How ? 39 | 40 | ### Installation 41 | 42 | ```bash 43 | npm install --save-dev rollup-plugin-inject-process-env 44 | ``` 45 | 46 | ### Usage 47 | 48 | Pass any JSON object to the plugin that will be set as the `process.env` value. This object accept members value of any type. 49 | 50 | ```typescript 51 | function injectProcessEnv( 52 | env: object, 53 | options?: { 54 | include?: string | string[], 55 | exclude?: string | string[], 56 | verbose?: boolean 57 | } 58 | ) 59 | ``` 60 | 61 | > Note: if you use the [commonjs](https://github.com/rollup/plugins/tree/master/packages/commonjs) plugin `injectProcessEnv` must be listed _after_ it in your plugins list. Otherwise you will see the error `'import' and 'export' may only appear at the top level`. 62 | 63 | #### Example : 64 | 65 | ```js 66 | import injectProcessEnv from 'rollup-plugin-inject-process-env'; 67 | 68 | // ... usual rollup stuff 69 | 70 | plugins: [ 71 | typescript(), 72 | commonjs(), 73 | injectProcessEnv({ 74 | NODE_ENV: 'production', 75 | SOME_OBJECT: { one: 1, two: [1,2], three: '3' }, 76 | UNUSED: null 77 | }), 78 | nodeResolve() 79 | ], 80 | ``` 81 | 82 | #### Example with environment variables passed in the CLI : 83 | 84 | ```js 85 | injectProcessEnv({ 86 | NODE_ENV: process.env.NODE_ENV, 87 | SOME_OBJECT: JSON.parse(process.env.SOME_OBJECT), 88 | UNUSED: null 89 | }), 90 | ``` 91 | 92 | #### Options 93 | 94 | * The `verbose` option allows to show which file is included in the process and which one is excluded. 95 | * The `include` and `exclude` options allow to explicitely specify with a [minimatch pattern](https://github.com/isaacs/minimatch) the files to accept or reject. By default, all files are targeted and no files are rejected. 96 | 97 | Example : 98 | 99 | ```js 100 | injectProcessEnv({ 101 | NODE_ENV: 'production', 102 | SOME_OBJECT: { one: 1, two: [1,2], three: '3' }, 103 | UNUSED: null 104 | }, { 105 | exclude: '**/*.css', 106 | verbose: true 107 | }), 108 | postcss({ 109 | inject: true, 110 | minimize: true, 111 | plugins: [], 112 | }), 113 | ``` 114 | 115 | Output example of the `verbose` option : 116 | 117 | ``` 118 | [rollup-plugin-inject-process-env] Include /path/to/src/index.ts 119 | [rollup-plugin-inject-process-env] Exclude rollup-plugin-inject-process-env 120 | [rollup-plugin-inject-process-env] Exclude /path/to/src/style.3.css 121 | [rollup-plugin-inject-process-env] Include /path/to/node_modules/style-inject/dist/style-inject.es.js 122 | ``` 123 | 124 | #### Icing on the cake 125 | 126 | You might notice that as mentionned in the documentation https://nodejs.org/api/process.html#process_process_env 127 | environment variables are always `string`, `number` or `boolean`. 128 | 129 | With **rollup-plugin-inject-process-env**, you may inject safely any JSON object to a `process.env` property, as shown in the example above. 130 | 131 | ## Troubleshootings 132 | 133 | ### `'globalThis' is undefined` 134 | 135 | This error may occur in target environments where `globalThis` is undefined. You should use a polyfill to fix it : 136 | 137 | ``` 138 | npm install @ungap/global-this 139 | ``` 140 | 141 | And include it in your code, e.g. : 142 | 143 | ``` 144 | import '@ungap/global-this'; 145 | ``` 146 | 147 | * https://github.com/ungap/global-this 148 | * https://mathiasbynens.be/notes/globalthis 149 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const { defaults } = require('ts-jest/presets'); 2 | 3 | module.exports = { 4 | preset: 'jest-puppeteer', 5 | ...defaults 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-plugin-inject-process-env", 3 | "version": "1.3.1", 4 | "description": "Inject environment variables in process.env with Rollup", 5 | "main": "dist/rollup-plugin-inject-process-env.cjs.js", 6 | "module": "dist/rollup-plugin-inject-process-env.es.js", 7 | "typings": "dist/index.d.ts", 8 | "files": [ 9 | "dist/", 10 | "README.md" 11 | ], 12 | "scripts": { 13 | "compile": "tsc", 14 | "postcompile": "rollup -c", 15 | "pretest": "cd test/myApp && tsc && rollup -c && rollup -c rollup.config.2.js && rollup -c rollup.config.3.js && cd ../..", 16 | "test": "jest test --runInBand", 17 | "site:prepare:sloc": "sloc --format json src/ > scripts/sloc-report.json", 18 | "site:prepare:sloc:tests": "sloc --format json test/ > scripts/sloc-tests-report.json", 19 | "site:prepare:tslint": "tslint --force -t json -o scripts/tslint-report.json -c tslint.json 'src/**/*.ts'", 20 | "site:prepare:jest": "npm run pretest && jest test --runInBand --noStackTrace --silent --json --outputFile='scripts/jest-report.json'", 21 | "presite": "npm run site:prepare:sloc && npm run site:prepare:sloc:tests && npm run site:prepare:tslint && npm run site:prepare:jest", 22 | "site": "ts-node --project scripts/tsconfig.json scripts/site.ts", 23 | "site:only": "ts-node --project scripts/tsconfig.json scripts/site.ts" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/badcafe/rollup-plugin-inject-process-env.git" 28 | }, 29 | "author": "Philippe Poulard ", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/badcafe/rollup-plugin-inject-process-env/issues" 33 | }, 34 | "homepage": "https://github.com/badcafe/rollup-plugin-inject-process-env#readme", 35 | "keywords": [ 36 | "rollup", 37 | "plugin", 38 | "rollup-plugin", 39 | "process", 40 | "env", 41 | "process.env", 42 | "environment variables", 43 | "inject", 44 | "browser" 45 | ], 46 | "devDependencies": { 47 | "@babel/core": "^7.12.3", 48 | "@babel/preset-env": "^7.12.1", 49 | "@rollup/plugin-commonjs": "^11.1.0", 50 | "@rollup/plugin-inject": "^4.0.2", 51 | "@rollup/plugin-node-resolve": "^7.1.3", 52 | "@rollup/pluginutils": "^3.1.0", 53 | "@types/jest": "^24.9.1", 54 | "@types/jest-environment-puppeteer": "^4.4.0", 55 | "@types/node": "^12.19.3", 56 | "@types/puppeteer": "^2.1.5", 57 | "jest": "^24.9.0", 58 | "jest-puppeteer": "^4.4.0", 59 | "puppeteer": "^2.1.1", 60 | "rollup": "^1.32.1", 61 | "rollup-plugin-babel": "^4.4.0", 62 | "rollup-plugin-postcss": "^3.1.8", 63 | "rollup-plugin-typescript2": "^0.25.3", 64 | "sloc": "^0.2.1", 65 | "ts-jest": "^24.3.0", 66 | "ts-node": "^8.10.2", 67 | "tslint": "^5.20.1", 68 | "typescript": "^3.9.7" 69 | }, 70 | "dependencies": { 71 | "magic-string": "^0.25.7" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | import nodeResolve from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import pkg from './package.json'; 5 | 6 | export default [{ 7 | input: 'src/index.ts', 8 | output: [{ 9 | file: pkg.main, 10 | format: 'cjs' 11 | }, { 12 | file: pkg.module, 13 | format: 'es' 14 | }], 15 | plugins: [ 16 | typescript(), 17 | nodeResolve(), 18 | commonjs() 19 | ], 20 | external: ['fs', 'path'] 21 | }]; 22 | -------------------------------------------------------------------------------- /scripts/@types/chartjs-node/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'chartjs-node'; 2 | -------------------------------------------------------------------------------- /scripts/site.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | 3 | const loc = JSON.parse(fs.readFileSync(`${__dirname}/sloc-report.json`, 'utf8')); // this file is generated (see package.json) 4 | const locTests = JSON.parse(fs.readFileSync(`${__dirname}/sloc-tests-report.json`, 'utf8')); // this file is generated (see package.json) 5 | const tsl = JSON.parse(fs.readFileSync(`${__dirname}/tslint-report.json`, 'utf8')); // this file is generated (see package.json) 6 | const jest = JSON.parse(fs.readFileSync(`${__dirname}/jest-report.json`, 'utf8')); // this file is generated (see package.json) 7 | 8 | const readme = readmeText(); 9 | fs.writeFileSync(`${__dirname}/../README.md`, readme); 10 | 11 | /** 12 | * Generate REPORTS.md 13 | * 14 | * * Metrics from sloc + Pie chart 15 | * * Linter from tslint 16 | * * Tests from jest 17 | */ 18 | function readmeText() { 19 | const README = fs.readFileSync(`${__dirname}/../doc/README.md`, {encoding: 'utf8'}); 20 | return ` 21 | 22 | ${README} 23 | 24 | ## Reports 25 | 26 | > Code quality reports 27 | 28 | ### Metrics 29 | 30 | | Files | ${loc.files.length} | | 31 | | ----- | -: | - | 32 | | Lines of code | ${loc.summary.source} | (w/o comments) | 33 | | Comments | ${loc.summary.comment - loc.summary.mixed} | (+ ${loc.summary.mixed} with code) | 34 | | Empty lines | ${loc.summary.empty} | | 35 | | **Total lines** | **${loc.summary.total}** | (w/o tests) | 36 | | TODO | ${loc.summary.todo} | lines | 37 | | Tests | ${locTests.summary.source} | (w/o comments) | 38 | 39 | ### Linter 40 | 41 | **${tsl.length === 0 ? '✅': '❌'} ${tsl.length} problem${tsl.length === 1 ? '': 's'}** 42 | 43 | ${tsl.length === 0 ? '': ` 44 | | File | Position | Severity | Type | Failure | 45 | | ---- | --- | -------- | ---- | ------- | 46 | ${tsl.map((lint: any) => 47 | `| ${lint.name.substring(4)} | ${position(lint)} | ${lint.ruleSeverity} | ${lint.ruleName} | ${lint.failure} | 48 | `).join('')} 49 | ` /* end tsl.length === 0 */} 50 | 51 | ### Tests 52 | 53 | | | Tests suites | Tests | 54 | | - | ------------ | ----- | 55 | | ❌ Failed | ${jest.numFailedTestSuites} | ${jest.numFailedTests} | 56 | | ✅ Passed | ${jest.numPassedTestSuites} | ${jest.numPassedTests} | 57 | | ✴ Pending | ${jest.numPendingTestSuites} | ${jest.numPendingTests} | 58 | | ☢ Error | ${jest.numRuntimeErrorTestSuites} | | 59 | | **Total** | **${jest.numTotalTestSuites}** | **${jest.numTotalTests}** | 60 | 61 | ${jest.wasInterrupted ? '💥 Tests interrupted !': ''} 62 | 63 | ${jest.testResults.map((suite: any) => ` 64 | #### ${statusIcon(suite.status)} \`${suite.name.substring(suite.name.indexOf('/test/'))}\` **${(suite.endTime - suite.startTime) / 1000}s** ${(suite.endTime - suite.startTime) / 1000 > 5 ? '🐢': ''} 65 | 66 | ${suite.assertionResults.length === 0 ? '': ` 67 | | Status | Suite | Test | 68 | | ------ | ----- | ---- | 69 | ${suite.assertionResults.map((test: any) => 70 | `| ${statusIcon(test.status)} | ${test.ancestorTitles.join(' 🔹 ')} | ${test.title} | 71 | `).join('')} 72 | ` /* end suite.assertionResults.length === 0 */} 73 | `).join('')} 74 | 75 | ## License 76 | 77 | MIT 78 | 79 | ## Who ? 80 | 81 | * [Inria](http://inria.fr) 82 | * [Inria @ Github](https://github.com/inria) 83 | 84 | `; 85 | } 86 | 87 | /** 88 | * Display a position of a lint result : 89 | * 90 | * * `264,12` 91 | * * `264,12-13` 92 | * * `264,12 - 275,8` 93 | * 94 | * @param lint Linter value 95 | */ 96 | function position(lint: any) { 97 | let pos = `${lint.startPosition.line},${lint.startPosition.character}`; 98 | if (lint.startPosition.line === lint.endPosition.line) { 99 | if (lint.startPosition.character !== lint.endPosition.character) { 100 | pos += `-${lint.endPosition.character}` 101 | } 102 | } else { 103 | pos += ` - ${lint.endPosition.line},${lint.endPosition.character}` 104 | } 105 | return pos; 106 | } 107 | 108 | /** 109 | * Get the status Icon 110 | * 111 | * @param status 112 | */ 113 | function statusIcon(status: string) { 114 | return ({ 115 | 'passed': '✅', 116 | 'failed': '❌', 117 | 'pending': '✴' 118 | } as any)[status] 119 | } 120 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "diagnostics": true, 5 | "downlevelIteration": false, 6 | "lib": ["es5", "es6", "dom"], 7 | "types": ["node", "jest"], 8 | "typeRoots": [ "@types" ], 9 | "noEmitOnError": true, 10 | "noImplicitAny": true, 11 | "noImplicitThis": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "pretty": true, 15 | "skipLibCheck": true, 16 | "strictPropertyInitialization": true, 17 | "strictNullChecks": true, 18 | "target": "es5", 19 | "declaration": true 20 | }, 21 | "include": [ 22 | "." 23 | ], 24 | } 25 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from 'rollup'; 2 | import MagicString from 'magic-string'; 3 | import { createFilter } from '@rollup/pluginutils'; 4 | 5 | const name = 'rollup-plugin-inject-process-env'; 6 | 7 | // The virtual id for our shared "process" mock. 8 | // We prefix it with \0 so that other plugins ignore it 9 | const VIRTUAL_MODULE_ID = `\0${ name }`; 10 | 11 | type Options = { 12 | include?: string | string[] 13 | exclude?: string | string[] 14 | verbose?: boolean 15 | } 16 | 17 | export default function rollupPluginInjectProcessEnv(env = {}, options: Options = {} ): Plugin { 18 | const { include, exclude, verbose = false } = options; 19 | const filter = createFilter(include, exclude); 20 | return { 21 | name, 22 | transform(code: string, id: string) { 23 | if (filter(id)) { 24 | if (verbose) { 25 | console.log(`[${name}] Include ${id}`); 26 | } 27 | } else { 28 | if (verbose) { 29 | console.log(`[${name}] Exclude ${id}`); 30 | } 31 | return null; 32 | } 33 | // Each non-filtered module except our virtual module gets the process mock injected. 34 | if (id !== VIRTUAL_MODULE_ID) { 35 | const magicString = new MagicString(code); 36 | magicString.prepend(`import '${VIRTUAL_MODULE_ID}';\n`); 37 | return { 38 | code: magicString.toString(), 39 | map: magicString.generateMap({ hires: true }) 40 | }; 41 | } 42 | }, 43 | resolveId(id: string) { 44 | // this tells Rollup not to try to resolve imports from our virtual id 45 | if (id === VIRTUAL_MODULE_ID) { 46 | return VIRTUAL_MODULE_ID; 47 | } 48 | }, 49 | load(id: string) { 50 | if (id === VIRTUAL_MODULE_ID) { 51 | return `(function() { 52 | const env = ${ JSON.stringify(env) } 53 | try { 54 | if (process) { 55 | process.env = Object.assign({}, process.env); 56 | Object.assign(process.env, env); 57 | return; 58 | } 59 | } catch (e) {} // avoid ReferenceError: process is not defined 60 | globalThis.process = { env:env } 61 | })(); 62 | `; 63 | } 64 | return null; 65 | }, 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /test/browser.test.ts: -------------------------------------------------------------------------------- 1 | import * as puppeteer from 'puppeteer'; 2 | import * as fs from 'fs'; 3 | 4 | // jest set process.env this is why we need a real browser environment 5 | describe('Browser', () => { 6 | let browser: puppeteer.Browser; 7 | let frame: puppeteer.Frame; 8 | beforeAll(async (done) => { 9 | browser = await puppeteer.launch({ 10 | headless: true 11 | }); 12 | const page = await browser.newPage(); 13 | page.on('console', async msg => console.log(await Promise.all(msg.args().map(jsh => jsh.jsonValue())))); 14 | const js = fs.readFileSync(`./test/myApp/dist/index.js`, 'utf8'); 15 | // await page.evaluate('const process={};' + js); 16 | await page.evaluate(js); 17 | frame = page.mainFrame(); 18 | done(); 19 | }); 20 | afterAll(async (done) => { 21 | await browser.close(); 22 | done(); 23 | }) 24 | test('get NODE_ENV', async () => { 25 | const nodeEnv = await frame.evaluate('myApp.getNodeEnv()'); 26 | expect(nodeEnv).toBe('production'); 27 | }); 28 | test('get SOME_OBJECT', async () => { 29 | const someObject = await frame.evaluate('myApp.getSomeObject()'); 30 | expect(someObject).toEqual({ one: 1, three: '3', two: [1,2] }); 31 | }); 32 | test('get MISSING', async () => { 33 | const missing = await frame.evaluate('myApp.getMissing()'); 34 | expect(missing).toBeUndefined(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/cli.js: -------------------------------------------------------------------------------- 1 | // just to ensure that we do have objects in process.env.SOME_OBJECT 2 | // which is not the default behaviour in node 3 | // see https://nodejs.org/api/process.html#process_process_env 4 | 5 | require('./myApp/dist/index.js'); 6 | 7 | console.log(process.env); 8 | console.log(process.env.SOME_OBJECT.two); 9 | -------------------------------------------------------------------------------- /test/myApp/README.md: -------------------------------------------------------------------------------- 1 | # Test app 2 | 3 | > An outstanding app for testing the plugin rollup-plugin-inject-process-env 4 | 5 | The Jest test engine inject `process.env` values. 6 | The main purpose of the plugin is to bundle browser apps that don't defined by their own `process.env`. 7 | 8 | This is why we need to test within the browser. 9 | 10 | * Basic tests are run in node 11 | * Advanced tests are run in the browser 12 | 13 | There is a second Rollup config for testing with plugins that would already define `process.env` somehow. 14 | 15 | And a third one for testing file exclusion. -------------------------------------------------------------------------------- /test/myApp/rollup.config.2.js: -------------------------------------------------------------------------------- 1 | import babel from "rollup-plugin-babel"; 2 | import injectProcessEnv from '../../dist/rollup-plugin-inject-process-env.es.js'; 3 | import nodeResolve from "@rollup/plugin-node-resolve"; 4 | import commonjs from "@rollup/plugin-commonjs"; 5 | 6 | export default { 7 | input: 'build/index.js', 8 | output: { 9 | file: 'dist/index.iife.js', 10 | format: 'iife', 11 | name: 'myApp', 12 | sourcemap: true, 13 | }, 14 | plugins: [ 15 | nodeResolve({ 16 | browser: true, 17 | }), 18 | commonjs({ 19 | include: "node_modules/**", 20 | }), 21 | injectProcessEnv({ 22 | NODE_ENV: 'production', 23 | SOME_OBJECT: { one: 1, two: [1, 2], three: '3' }, 24 | UNUSED: null 25 | }), 26 | babel({ 27 | exclude: [/\/core-js\//], 28 | babelrc: false, 29 | presets: [ 30 | [ 31 | "@babel/preset-env", 32 | { 33 | corejs: 3, 34 | modules: false, 35 | useBuiltIns: "usage", 36 | targets: { 37 | ie: "11", 38 | }, 39 | }, 40 | ], 41 | ], 42 | }), 43 | ], 44 | }; 45 | -------------------------------------------------------------------------------- /test/myApp/rollup.config.3.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | import nodeResolve from "@rollup/plugin-node-resolve"; 3 | import commonjs from "@rollup/plugin-commonjs"; 4 | import injectProcessEnv from '../../dist/rollup-plugin-inject-process-env.es.js'; 5 | import postcss from 'rollup-plugin-postcss'; 6 | 7 | export default [{ 8 | input: ['src/index.3.ts'], 9 | output: [{ 10 | file: 'dist/index.3.js', 11 | format: 'umd', 12 | name: 'myApp' 13 | }], 14 | plugins: [ 15 | typescript(), 16 | injectProcessEnv({ 17 | NODE_ENV: 'production', 18 | SOME_OBJECT: { one: 1, two: [1,2], three: '3' }, 19 | UNUSED: null 20 | }, { 21 | exclude: '**/*.css', 22 | verbose: true 23 | }), 24 | nodeResolve(), 25 | commonjs(), 26 | postcss({ 27 | inject: true, 28 | minimize: true, 29 | plugins: [], 30 | }), 31 | ], 32 | external: ['fs', 'path'] 33 | }] 34 | -------------------------------------------------------------------------------- /test/myApp/rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | import nodeResolve from "@rollup/plugin-node-resolve"; 3 | import commonjs from "@rollup/plugin-commonjs"; 4 | import injectProcessEnv from '../../dist/rollup-plugin-inject-process-env.es.js'; 5 | 6 | export default [{ 7 | input: 'src/index.ts', 8 | output: [{ 9 | file: 'dist/index.cjs.js', 10 | format: 'cjs', 11 | }, { 12 | file: 'dist/index.es.js', 13 | format: 'es' 14 | }, { 15 | file: 'dist/index.js', 16 | format: 'umd', 17 | name: 'myApp' 18 | }], 19 | plugins: [ 20 | typescript(), 21 | injectProcessEnv({ 22 | NODE_ENV: 'production', 23 | SOME_OBJECT: { one: 1, two: [1,2], three: '3' }, 24 | UNUSED: null 25 | }), 26 | nodeResolve(), 27 | commonjs() 28 | ], 29 | external: ['fs', 'path'] 30 | }] 31 | -------------------------------------------------------------------------------- /test/myApp/src/index.3.ts: -------------------------------------------------------------------------------- 1 | export function getNodeEnv() { 2 | // test dot member 3 | return process.env.NODE_ENV; 4 | } 5 | 6 | export function getSomeObject() { 7 | // test [] member 8 | return process.env['SOME_OBJECT']; 9 | } 10 | 11 | export function getMissing() { 12 | return process.env.MISSING; 13 | } 14 | 15 | import './style.3.css'; 16 | 17 | console.log('========= start MyApp'); 18 | console.log(typeof getNodeEnv(), getNodeEnv()) 19 | console.log(typeof getSomeObject(), getSomeObject()) 20 | console.log(typeof getMissing(), getMissing()) 21 | console.log('========= end MyApp'); 22 | -------------------------------------------------------------------------------- /test/myApp/src/index.ts: -------------------------------------------------------------------------------- 1 | export function getNodeEnv() { 2 | // test dot member 3 | return process.env.NODE_ENV; 4 | } 5 | 6 | export function getSomeObject() { 7 | // test [] member 8 | return process.env['SOME_OBJECT']; 9 | } 10 | 11 | export function getMissing() { 12 | return process.env.MISSING; 13 | } 14 | 15 | console.log('========= start MyApp'); 16 | console.log(typeof getNodeEnv(), getNodeEnv()) 17 | console.log(typeof getSomeObject(), getSomeObject()) 18 | console.log(typeof getMissing(), getMissing()) 19 | console.log('========= end MyApp'); 20 | -------------------------------------------------------------------------------- /test/myApp/src/style.3.css: -------------------------------------------------------------------------------- 1 | .center { 2 | margin: 0 auto; 3 | } 4 | -------------------------------------------------------------------------------- /test/myApp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "diagnostics": true, 5 | "downlevelIteration": false, 6 | "lib": ["es5", "es6", "dom"], 7 | "outDir": "build", 8 | "noEmitOnError": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "pretty": true, 14 | "skipLibCheck": true, 15 | "strictPropertyInitialization": true, 16 | "strictNullChecks": true, 17 | "target": "es5", 18 | "module": "esnext", 19 | "declaration": true 20 | }, 21 | "include": [ 22 | "src" 23 | ], 24 | "exclude": [ 25 | "dist", 26 | "node_modules" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /test/node.2.test.ts: -------------------------------------------------------------------------------- 1 | import './myApp/dist/index.iife.js'; 2 | 3 | describe('Node', () => { 4 | test('get NODE_ENV', async () => { 5 | expect(process.env.NODE_ENV) 6 | .toBe('production'); 7 | }); 8 | test('get SOME_OBJECT', async () => { 9 | expect(process.env['SOME_OBJECT']) 10 | .toEqual({ one: 1, three: '3', two: [1,2] }); 11 | }); 12 | test('get MISSING', async () => { 13 | expect(process.env.MISSING) 14 | .toBeUndefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/node.3.test.ts: -------------------------------------------------------------------------------- 1 | import { getNodeEnv, getSomeObject, getMissing } from './myApp/dist/index.3.js'; 2 | 3 | describe('Filter out CSS', () => { 4 | test('get NODE_ENV', async () => { 5 | expect(getNodeEnv()) 6 | .toBe('production'); 7 | }); 8 | test('get SOME_OBJECT', async () => { 9 | expect(getSomeObject()) 10 | .toEqual({ one: 1, three: '3', two: [1,2] }); 11 | }); 12 | test('get MISSING', async () => { 13 | expect(getMissing()) 14 | .toBeUndefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/node.test.ts: -------------------------------------------------------------------------------- 1 | import { getNodeEnv, getSomeObject, getMissing } from './myApp/dist/index.js'; 2 | 3 | describe('Node', () => { 4 | test('get NODE_ENV', async () => { 5 | expect(getNodeEnv()) 6 | .toBe('production'); 7 | }); 8 | test('get SOME_OBJECT', async () => { 9 | expect(getSomeObject()) 10 | .toEqual({ one: 1, three: '3', two: [1,2] }); 11 | }); 12 | test('get MISSING', async () => { 13 | expect(getMissing()) 14 | .toBeUndefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "diagnostics": true, 5 | "downlevelIteration": false, 6 | "lib": ["es5", "es6", "dom"], 7 | "outDir": "build", 8 | "types": ["node", "jest"], 9 | "noEmitOnError": true, 10 | "noImplicitAny": false, 11 | "noImplicitThis": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "pretty": true, 15 | "skipLibCheck": true, 16 | "strictPropertyInitialization": true, 17 | "strictNullChecks": true, 18 | "target": "es5", 19 | "declaration": true 20 | }, 21 | "include": [ 22 | "src" 23 | ], 24 | "exclude": [ 25 | "dist", 26 | "scripts", 27 | "node_modules" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [], 3 | "jsRules": {}, 4 | "rules": { 5 | "interface-name": false, 6 | "quotemark": [ 7 | true, 8 | "single" 9 | ], 10 | "no-console": [ 11 | false 12 | ], 13 | "one-line": [ 14 | true, 15 | "check-open-brace", 16 | "check-whitespace" 17 | ], 18 | "object-literal-sort-keys": [ 19 | false 20 | ], 21 | "no-string-literal": false, 22 | "triple-equals": [ 23 | false 24 | ] 25 | }, 26 | "rulesDirectory": [], 27 | "linterOptions": { 28 | "exclude": [ 29 | "node_modules/**/*.ts" 30 | ] 31 | } 32 | } 33 | --------------------------------------------------------------------------------