Как получить вариант React Native в метро? - PullRequest
2 голосов
/ 28 января 2020

Я разрабатываю приложение React Native, которое включает в себя различные конфигурации для разных возможных клиентов, в файле, таком как src/config/config.js. Эти конфигурации довольно сложны. Файл структурирован на основе имени клиента в качестве ключа и значений в качестве записей объекта, например:

export default {
  fooClient: {
    apiUrl: "https://foo.example.com/",
  barClient: {
    apiUrl: "https://bar.example.com/"
  }
}

Конечно, есть много других ключей параметров.

При построении приложение, я знаю, для какого клиента я хочу это сделать, указав Android вариант сборки, например:

ENVFILE=.env npx react-native run-android --variant fooDebug --appIdSuffix foo

Из соображений безопасности я не хочу, чтобы ключи других клиентов были включены в файл конфигурации, хотя. Какие у меня есть варианты удалить все другие клиентские конфигурации из этого файла, прежде чем я соберу приложение и отправлю его клиенту?

Я подумал о следующем: я изменяю упаковщик так, чтобы он удаляет ключи, которые не соответствуют текущему варианту сборки.

Теперь у меня есть плагин-трансформер для Metro, который делает следующее:

const upstreamTransformer = require('metro-react-native-babel-transformer');

module.exports.transform = function(src, filename, options) {
  if (typeof src === 'object') {
    // handle RN >= 0.46
    ({ src, filename, options } = src);
  }

  if (filename.endsWith('config.js')) {
    console.log('Transforming ' + filename);
    let srcStripped = src.replace(';', '').replace('export default ', '');
    let configObj = JSON.parse(srcStripped);
    // TODO: get the build variant and strip all keys that we do not need from configObj
    return upstreamTransformer.transform({
      src: 'export default ' + JSON.stringify(configObj) + ';',
      filename: filename,
      options
    });
  } else {
    return upstreamTransformer.transform({ src, filename, options });
  }
};

Но как узнать, какой вариант сборки используется?

Если это похоже на проблему XY, я рад изучить альтернативы динамическому построению конфигурации. Однако я не могу использовать переменные окружения, поскольку конфигурация будет слишком сложной, чтобы представлять собой просто список .env ключей.

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Вы не должны использовать Метро transform таким образом. Он не чистый и может рано или поздно привести к отсутствующей конфигурации и / или поврежденному синтаксису.

То, что я сделал и предлагаю вам, - это создание 3 различных файлов конфигурации в src/config/; один файл для fooClient.js, один файл для barClient.js и один последний файл с общей конфигурацией client.js. Все файлы будут экспортировать объекты конфигурации по умолчанию, но внутри каждого fooClient и barClient вы будете использовать модуль deepmerge для объединения client.js config:

client.js:

export default {
  commonSettingA: "...",
  commonSettings: {
    ...
  }
  ...
}

fooClient.js:

import merge from 'deepmerge';
import config from './config';

export default merge.all([
  config,
  {
    apiUrl: "https://foo.example.com/",
  }
]);

barClient.js:

import merge from 'deepmerge';
import config from './config';

export default merge.all([
  config,
  {
    apiUrl: "https://bar.example.com/",
  }
]);

Затем вы можете использовать переменную окружения для передачи необходимой конфигурации и создания собственное разрешение метро; @react-native-community/cli не передает аргументы командной строки в скрипт конфигурации Metro. Вы можете использовать process.argv для самостоятельного анализа, но это того не стоит.

Вот как вы можете создать разрешение внутри metro.config.js, используя переменную окружения:

const path = require("path");

module.exports = {
  projectRoot: path.resolve(__dirname),

  resolver: {
    sourceExts: ['js', 'jsx', 'ts', 'tsx'],
    extraNodeModules: {
      // Local aliases
      "@config": path.resolve(__dirname, "src/config", `${process.env.METRO_VARIANT}Client.js`)
    }
  }
};

Использование Для этого решения вам нужно будет импортировать конфигурацию следующим образом:

import config from '@config';

Затем вы добавляете 2 package.json сценария, один для fooClient и один для barClient:

{
   ...
  "scripts": {
    "run:android:foo": "METRO_VARIANT=foo ENVFILE=.env npx react-native run-android --variant fooDebug --appIdSuffix foo",
    "run:android:bar": "METRO_VARIANT=bar ENVFILE=.env npx react-native run-android --variant barDebug --appIdSuffix bar",
    ...
  }
  ...
}

Затем вы просто запускаете нужный скрипт:

yarn run:android:foo # will build with fooClient.js
yarn run:android:bar # will build with barClient.js
1 голос
/ 01 февраля 2020

Разве вы не можете просто добавить «дублированный» параметр в команду?

Примерно так: METRO_VARIANT=fooDebug ENVFILE=.env npx react-native run-android --variant fooDebug --appIdSuffix foo

И получить его с помощью process.env.METRO_VARIANT

Вы можете не хочу, чтобы сделать вашу настройку намного сложнее. В зависимости от количества различных клиентов, вы можете захотеть go с несколькими схемами / вариантами для каждого клиента, но это, вероятно, излишне.

...