UNPKG

@expo/metro-config

Version:

A Metro config for running React Native projects with the Metro bundler

125 lines (120 loc) 4.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.environmentVariableSerializerPlugin = environmentVariableSerializerPlugin; exports.getTransformEnvironment = getTransformEnvironment; exports.replaceEnvironmentVariables = replaceEnvironmentVariables; function _CountingSet() { const data = _interopRequireDefault(require("metro/src/lib/CountingSet")); _CountingSet = function () { return data; }; return data; } function _countLines() { const data = _interopRequireDefault(require("metro/src/lib/countLines")); _countLines = function () { return data; }; return data; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Copyright © 2022 650 Industries. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const debug = require('debug')('expo:metro-config:serializer:env-var'); function replaceEnvironmentVariables(code, env) { // match and replace env variables that aren't NODE_ENV or JEST_WORKER_ID // return code.match(/process\.env\.(EXPO_PUBLIC_[A-Z_]+)/g); return code.replace(/process\.env\.([a-zA-Z0-9_]+)/gm, match => { var _env$name; const name = match.replace('process.env.', ''); if ( // Must start with EXPO_PUBLIC_ to be replaced !/^EXPO_PUBLIC_/.test(name)) { return match; } const value = JSON.stringify((_env$name = env[name]) !== null && _env$name !== void 0 ? _env$name : ''); debug(`Inlining environment variable "${match}" with ${value}`); return value; }); } function getTransformEnvironment(url) { const match = url.match(/[&?]transform\.environment=([^&]+)/); return match ? match[1] : null; } function getAllExpoPublicEnvVars() { // Create an object containing all environment variables that start with EXPO_PUBLIC_ const env = {}; for (const key in process.env) { if (key.startsWith('EXPO_PUBLIC_')) { // @ts-ignore env[key] = process.env[key]; } } return env; } function environmentVariableSerializerPlugin(entryPoint, preModules, graph, options) { // Skip replacement in Node.js environments. if (options.sourceUrl && getTransformEnvironment(options.sourceUrl) === 'node') { debug('Skipping environment variable inlining in Node.js environment.'); return [entryPoint, preModules, graph, options]; } // Adds about 5ms on a blank Expo Router app. // TODO: We can probably cache the results. // In development, we need to add the process.env object to ensure it // persists between Fast Refresh updates. if (options.dev) { // Set the process.env object to the current environment variables object // ensuring they aren't iterable, settable, or enumerable. const str = `process.env=Object.defineProperties(process.env, {${Object.keys(getAllExpoPublicEnvVars()).map(key => `${JSON.stringify(key)}: { value: ${JSON.stringify(process.env[key])} }`).join(',')}});`; const [firstModule, ...restModules] = preModules; // const envCode = `var process=this.process||{};${str}`; // process.env return [entryPoint, [ // First module defines the process.env object. firstModule, // Second module modifies the process.env object. getEnvPrelude(str), // Now we add the rest ...restModules], graph, options]; } // In production, inline all process.env variables to ensure they cannot be iterated and read arbitrarily. for (const value of graph.dependencies.values()) { // Skip node_modules, the feature is a bit too sensitive to allow in arbitrary code. if (/node_modules/.test(value.path)) { continue; } for (const index in value.output) { // TODO: This probably breaks source maps. const code = replaceEnvironmentVariables(value.output[index].data.code, process.env); value.output[index].data.code = code; } } return [entryPoint, preModules, graph, options]; } function getEnvPrelude(contents) { const code = '// HMR env vars from Expo CLI (dev-only)\n' + contents; const name = '__env__'; const lineCount = (0, _countLines().default)(code); return { dependencies: new Map(), getSource: () => Buffer.from(code), inverseDependencies: new (_CountingSet().default)(), path: name, output: [{ type: 'js/script/virtual', data: { code, // @ts-expect-error: typed incorrectly upstream lineCount, map: [] } }] }; } //# sourceMappingURL=environmentVariableSerializerPlugin.js.map