UNPKG

rn-config-env

Version:

Expose config variables to React Native apps

137 lines (114 loc) 3.8 kB
const { readFileSync, statSync } = require('fs') const dotenv = require('dotenv') function parseDotenvFile(path, verbose = false) { let content try { content = readFileSync(path) } catch (error) { // The env file does not exist. if (verbose) { console.error('rn-config-env:error:', error) } return {} } return dotenv.parse(content) } function safeObjectAssign(targetObject, sourceObject, exceptions = []) { const keys = Object.keys(targetObject) for (let i = 0, length = keys.length; i < length; i++) { if (targetObject[keys[i]] && sourceObject[keys[i]]) { targetObject[keys[i]] = sourceObject[keys[i]] } } for (let j = 0, length = exceptions.length; j < length; j++) { if (sourceObject[exceptions[j]]) { targetObject[exceptions[j]] = sourceObject[exceptions[j]] } } return targetObject } function mtime(filePath) { try { return statSync(filePath).mtimeMs } catch { return null } } module.exports = (api, options) => { const t = api.types this.env = {} options = { moduleName: '@env', safe: true, verbose: true, ...options, } const envMode = process.env.ENVMODE || 'development' const envPath = `.env.${envMode}` api.cache.using(() => mtime(envPath)) const dotenvTemporary = Object.assign({}, process.env) if (options.safe) { const envParsed = parseDotenvFile(envPath, options.verbose) this.env = safeObjectAssign(envParsed, dotenvTemporary, []) this.env.NODE_ENV = envMode || babelMode } else { dotenv.config({ path: envPath, silent: true, }) this.env = process.env this.env = Object.assign(this.env, dotenvTemporary) } api.addExternalDependency(envPath) return ({ name: 'rn-config-env', pre() { this.opts = { moduleName: '@env', safe: true, verbose: false, ...this.opts, } const dotenvTemporary = Object.assign({}, process.env) if (this.opts.safe) { const envParsed = parseDotenvFile(envPath, options.verbose) this.env = safeObjectAssign(envParsed, dotenvTemporary, []) this.env.NODE_ENV = process.env.ENVMODE || babelMode } else { dotenv.config({ path: envPath, silent: true, }) this.env = process.env this.env = Object.assign(this.env, dotenvTemporary) } }, visitor: { ImportDeclaration(path, { opts }) { if (path.node.source.value === opts.moduleName) { for (const [idx, specifier] of path.node.specifiers.entries()) { if (specifier.type === 'ImportDefaultSpecifier') { throw path.get('specifiers')[idx].buildCodeFrameError('Default import is not supported') } if (specifier.type === 'ImportNamespaceSpecifier') { throw path.get('specifiers')[idx].buildCodeFrameError('Wildcard import is not supported') } if (specifier.imported && specifier.local) { const importedId = specifier.imported.name const localId = specifier.local.name const binding = path.scope.getBinding(localId) for (const refPath of binding.referencePaths) { refPath.replaceWith(t.valueToNode(this.env[importedId])) } } } path.remove() } }, MemberExpression(path, { opts }) { if (path.get('object').matchesPattern('process.env')) { const key = path.toComputedKey() if (t.isStringLiteral(key)) { const importedId = key.value const value = (opts.env && importedId in opts.env) ? opts.env[importedId] : process.env[importedId] path.replaceWith(t.valueToNode(value)) } } }, }, }) }