Команда предварительной сборки response-native expo с node_env

Справочная информация

Мы не используем eas или expo go, вместо этого мы используем наши собственные профили обеспечения и комбинацию app.json и Babel.config.js.

Мы хотим перейти от среды разработки к среде контроля/промежуточного тестирования. Мы используем конвейеры Azure для запуска команды предварительной сборки expo для сборок iOS и Android. Например: npx expo prebuild --platform ios --clean --npm

Мне удалось настроить среду разработки для запуска с помощью следующей команды... npx expo run dev-android (которая указывает на следующий скрипт в package.json "dev-android": "cross-env NODE_ENV=development npx expo run:android --port 8082"

Следующее успешно распечатывается в среде разработки...

Структура

Код...

App.tsx

import React, { useEffect } from 'react';
import * as SplashScreen from 'expo-splash-screen';
import '@app/utils/IgnoreWarnings';
import Toast from 'react-native-toast-message';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { GlobalContextProvider, useLoadingStore } from '@app/stores';
import { ToastInit } from '@app/components';
import { NavigationConductor } from '@app/navigation';
import { toastFailedProps } from '@app/utils';
import { RANDOM_ENV_DEV, RANDOM_ENV_QA } from '@env';
import type { LoadingStore } from '@app/types';

// Keep the splash screen visible while we fetch resources
SplashScreen.preventAutoHideAsync();

export default function App() {
  // variables
  const { loadInitialAppData } = useLoadingStore((store: LoadingStore) => store);

  // setup
  useEffect(() => {
    console.info('NODE_ENV:', process.env.NODE_ENV);
    console.info('RANDOM_ENV_DEV:', RANDOM_ENV_DEV);
    console.info('RANDOM_ENV_QA:', RANDOM_ENV_QA);
    const loadApp = async () => {
      try {
        await loadInitialAppData();
      } catch (error: any) {
        Toast.show(toastFailedProps(error.message));
      } finally {
        await SplashScreen.hideAsync();
      }
    };
    loadApp();
  }, [loadInitialAppData]);

  // render
  return (
    <GlobalContextProvider>
      <SafeAreaProvider>
        <NavigationConductor />
        <ToastInit />
      </SafeAreaProvider>
    </GlobalContextProvider>
  );
}

.env

RANDOM_ENV_DEV=HelloWorldDev
RANDOM_ENV_QA=HelloWorldQa

Babel.config.js

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['module:metro-react-native-babel-preset', 'babel-preset-expo'],
    plugins: [
      [
        require.resolve('babel-plugin-module-resolver'),
        {
          extensions: ['.js', '.jsx', '.ts', '.tsx', '.android.js', '.android.tsx', '.ios.js', '.ios.tsx'],
          alias: {
            '@': './',
            '@app': './app'
          }
        }
      ],
      [
        'module:react-native-dotenv',
        {
          envName: 'APP_ENV',
          moduleName: '@env',
          path: '.env',
          blocklist: null,
          allowlist: null,
          blacklist: null, // DEPRECATED
          whitelist: null, // DEPRECATED
          safe: false,
          allowUndefined: true,
          verbose: false
        }
      ]
    ]
  };
};

app.json (файл конфигурации)

{
  "expo": {
    "name": "PROJECTNAME",
    "slug": "PROJECTSLUG",
    "version": "1.0.0",
    "scheme": "msauth",
    "orientation": "portrait",
    "icon": "./assets/images/qa-icon-1024.png",
    "userInterfaceStyle": "light",
    "backgroundColor": "#001689",
    "splash": {
      "image": "./assets/images/qa-splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#001689"
    },
    "assetBundlePatterns": ["**/*"],
    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "com.example.qa",
      "buildNumber": "1.0.0"
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/images/qa-icon-1024.png",
        "backgroundColor": "#001689"
      },
      "package": "com.example.qa",
      "versionCode": 1
    },
    "web": {
      "favicon": "./assets/favicon.png"
    },
    "plugins": [
      [
        "expo-build-properties",
        {
          "android": {
            "minSdkVersion": 23
          }
        }
      ],
      [
        "expo-image-picker",
        {
          "photosPermission": "Allow $(PRODUCT_NAME) to access your photos",
          "cameraPermissions": "Allow $(PRODUCT_NAME) to access your camera"
        }
      ]
    ]
  }
}

пакет.json

{
  "name": "Project-Name",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "ts:check": "tsc",
    "dev-android": "cross-env NODE_ENV=development npx expo run:android --port 8082",
    "dev-ios": "cross-env NODE_ENV=development npx expo run:ios --port 8082",
    "android": "expo run:android",
    "ios": "expo run:ios"
  },
  "dependencies": {
    "@expo/vector-icons": "^13.0.0",
    "@react-native-async-storage/async-storage": "1.18.2",
    "@react-native-community/netinfo": "9.3.10",
    "@react-navigation/native": "^6.1.9",
    "@react-navigation/stack": "^6.3.20",
    "axios": "^1.6.2",
    "core-js": "^3.35.0",
    "expo": "~49.0.15",
    "expo-auth-session": "~5.0.2",
    "expo-build-properties": "^0.8.3",
    "expo-constants": "~14.4.2",
    "expo-file-system": "~15.4.5",
    "expo-image-manipulator": "~11.3.0",
    "expo-image-picker": "~14.3.2",
    "expo-secure-store": "~12.3.1",
    "expo-splash-screen": "~0.20.5",
    "expo-status-bar": "~1.6.0",
    "expo-system-ui": "~2.4.0",
    "expo-web-browser": "~12.3.2",
    "formik": "^2.4.5",
    "jwt-decode": "^4.0.0",
    "lodash": "^4.17.21",
    "react": "18.2.0",
    "react-native": "0.72.10",
    "react-native-device-info": "^11.1.0",
    "react-native-element-dropdown": "^2.10.1",
    "react-native-gesture-handler": "~2.12.0",
    "react-native-get-random-values": "~1.9.0",
    "react-native-safe-area-context": "4.6.3",
    "react-native-screens": "~3.22.0",
    "react-native-toast-message": "^2.1.9",
    "react-query": "^3.39.3",
    "scandit-react-native-datacapture-barcode": "^6.21.3",
    "scandit-react-native-datacapture-core": "^6.21.3",
    "uri-scheme": "^1.1.0",
    "uuid": "^9.0.1",
    "yup": "^1.3.2",
    "zustand": "^4.4.7"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@types/lodash": "^4.14.202",
    "@types/react": "~18.2.14",
    "@types/uuid": "^9.0.7",
    "cross-env": "^7.0.3",
    "react-native-dotenv": "^3.4.10",
    "typescript": "^5.1.3"
  },
  "private": true
}

Конв.ц

declare module '@env' {
  export const RANDOM_ENV_DEV: string;
  export const RANDOM_ENV_QA: string;
}
declare var process: {
  env: {
    NODE_ENV: string;
  };
};

Полученные результаты

Это работает в среде разработки, где process.env.NODE_ENV читается как development.

Вопрос

Теперь, как нам сделать так, чтобы при использовании команды expo prebuild для упаковки сборки, которая включала бы process.env.NODE_ENV, она будет читаться как uat или qa?

Можете ли вы уточнить свой вопрос? Я в замешательстве, особенно в контексте вашего раздела результатов, который, похоже, дает правильный результат.

Slbox 25.06.2024 23:13

@Slbox Мы используем команду expo prebuild в наших Azure-конвейерах, и нам нужен способ разделения среды type с помощью команды prebuild. см. мой ответ ниже.

Fiddle Freak 09.07.2024 17:03
Умерло ли Create-React-App?
Умерло ли Create-React-App?
В этом документальном фильме React.dev мы исследуем, мертв ли Create React App (CRA) и какое будущее ждет этот популярный фреймворк React.
Освоение React Native: Пошаговое руководство для начинающих
Освоение React Native: Пошаговое руководство для начинающих
React Native - это популярный фреймворк с открытым исходным кодом, используемый для разработки мобильных приложений. Он был разработан компанией...
В чем разница между react native и react ?
В чем разница между react native и react ?
React и React Native - два популярных фреймворка для создания пользовательских интерфейсов, но они предназначены для разных платформ. React - это...
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
Если вы уже умеете работать с React, создание мобильных приложений для iOS и Android - это новое приключение, в котором вы сможете применить свои...
Хуки React: что это такое и как их использовать
Хуки React: что это такое и как их использовать
Хуки React - это мощная функция библиотеки React, которая позволяет разработчикам использовать состояние и другие возможности React без написания...
1
2
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Поскольку у вас уже есть response-native-dotenv, вы можете создать несколько файлов .env для удовлетворения ваших потребностей в UAT или QA.

.env.dev
.env.uat
.env.qa

В вашем файле package.json

"scripts": {
     "dev-android": "cross-env NODE_ENV=development npx expo run:android --port 8082",
     "dev-ios": "cross-env NODE_ENV=development npx expo run:ios --port 8082",
     "uat-android": "cross-env NODE_ENV=uat npx expo run:android --port 8082",
     "uat-ios": "cross-env NODE_ENV=uat npx expo run:ios --port 8082",
     "qa-android": "cross-env NODE_ENV=qa npx expo run:android --port 8082",
     "qa-ios": "cross-env NODE_ENV=qa npx expo run:ios --port 8082",
  },

Мы используем Azure для использования команды expo prebuild... npx expo prebuild --platform ios --clean --npm. После того как конвейеры Azure запускают это, сборка компилируется в статическую сборку для отправки в хранилище. У нас нет конвейеров, пытающихся запустить приложение.

Fiddle Freak 09.07.2024 16:57
Ответ принят как подходящий

Единственное решение, которое я смог найти, все еще было немного хакерским, но, по крайней мере, оно есть в одном месте.

Babel.config.js

изменить на...

module.exports = function (api) {
  api.cache(false);
  return {
    ...,
    plugins: [
      ...
      [
        ...
        {
          ...
          path: '.env.dev', // .env.qa | .env.uat | ect...
          ...
        }
      ]
    ]
  };
};

Просто избегайте перебазирования между ветвями, и когда вы загружаете изменения для каждой ветки в правильном порядке, будущие слияния не будут перезаписывать это значение.

Это все еще не идеальное решение, но, по крайней мере, значение меняется только в одном месте.

Другие вопросы по теме