Разделить методы рендеринга React в отдельный пакет npm

У нас есть интерфейсное приложение, разработанное на React. Теперь мы также хотели бы создать приложение, ориентированное на реакцию, но с максимально возможным повторным использованием из текущего приложения.

Я видел, что в этих случаях часто используется response-native-web, однако мы уже разработали наше приложение, просто реагируя, и замена всех наших текущих компонентов на компоненты react-native-web займет слишком много времени (также потому, что мы используя библиотеку компонентов antd).

Моя идея состояла в том, чтобы переместить все методы рендеринга в другой пакет npm (и некоторые другие части, которые потребуют переписывания для использования response-native) и импортировать их из основного пакета.

Я представляю себе структуру папок примерно так:

  • корень
    • core - будет содержать весь повторно используемый код
    • web - будет содержать все методы рендеринга с компонентами antd
    • native - будет содержать все методы рендеринга с собственными компонентами

Таким образом, веб-пакеты и собственные пакеты будут иметь свои сценарии запуска и сборки npm. Как я могу в основном пакете и в зависимости от платформы (в данном случае веб или нативной) импортировать часть рендеринга из правильного пакета?

Я думал, что могу использовать библиотеку lerna для разделения пакетов и что-то вроде commonjs или requirejs, чтобы затем динамически импортировать правильный элемент рендеринга.

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

Другими словами, как мы можем добиться внедрения зависимостей из веб-пакета в основной пакет?

Представьте, у нас есть компонент Home в базовом пакете:

class Home extends Component {
..
    render() {
        // somehow import required 'view'
        // example: import('path_to_web_package_from_some_global_variable' + '/HomeRender.js');
        // There would be a HomeRender.js in 'web' package and another one in 'native' package
    }
..
}
Как я могу в основном пакете и в зависимости от платформы (в данном случае веб или нативной) импортировать часть рендеринга из правильного пакета? - желательно этого не делать, потому что это не позволит встряхнуть неиспользуемую платформу. Это пакеты для конкретной платформы, которые должны зависеть от core, а не наоборот. Рассмотрите возможность предоставления краткого примера, что это за пакеты и как они работают вместе.
Estus Flask 10.01.2019 14:24

@estus Что вы имеете в виду, говоря о неиспользуемой платформе? Я хочу импортировать только код, специфичный для «Интернета» или «нативного». Я добавил небольшой пример того, как это может выглядеть

Aurimas Dainius 10.01.2019 14:52

Почему бы просто не переместить компоненты в папку, доступную для обоих web/native, и импортировать их из них?

bamtheboozle 10.01.2019 14:55
Я хочу импортировать только код, специфичный для "веб" или "нативный" - у вас не получится. Кроме того, динамический import() является асинхронным, и он заставляет компонент быть асинхронным, что не очень хорошо. Постараюсь дать ответ, исходя из моего понимания того, как выглядят ваши пакеты.
Estus Flask 10.01.2019 15:10
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
4
296
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предполагается, что опубликованный пакет будет построен для ES5 традиционным способом, опционально с использованием экспорта и импорта ES6 (сборка ESM) для более эффективного использования в модульных средах.

Импорт и экспорт ES6 статичны. Их нельзя поменять местами, по крайней мере, без изменения модуля в инструменте сборки. В то время как динамический import() - это предложение, а не часть ES6. Это предотвратило бы эффективное встряхивание дерева, это привело бы к включению как web, так и native в комплект, даже если один из них не используется.

Чтобы сделать core независимым от рендерера, следует использовать некоторые вариации DI.

Один из способов - разрешить какую-то систему плагинов в core:

import { configureRenderer } from '@foo/core';
import * as renderers from '@foo/web';

configureRenderer(renderers);

Это может работать в некоторых случаях, но это не очень хорошо работает с компонентами, потому что это предотвращает раскачку дерева renderers и ограничивает использование core. В этом случае может работать native или web. This results inwebpackage bundled entirely, even if only small portion is used. The restriction tonativeor web, поскольку платформы являются взаимоисключающими, но это не так. В целом не удачное дизайнерское решение.

Лучше всего реализовать это наоборот. core не имеет зависимостей и содержит общие абстракции, в то время как web и native являются конкретными реализациями. Это может быть решено с помощью наследования ООП с компонентами класса, и есть много возможностей реализовать DI с функциональным подходом, тот, который подходит для этого случая, - визуализировать опору (отсюда и название):

// @foo/core
export class Home extends Component {
    ...
    render() {
        const {render, ...props} = this.props;
        return render(props);
    }
}

// @foo/web
import { Home as HomeWithoutRenderer } from '@foo/core';

const rendererHOC = (Comp, renderer) => props => <Comp render = {renderer} ...props />;

export const Home = rendererHOC(HomeWithoutRenderer, props => {
  // platform-specific view
});

Спасибо! Это действительно очень помогает :) Теперь он работает, единственное, что нужно было изменить, это новый экспорт Home: вместо 'export const Home = rendererHoc (..)' должен быть 'export const Home = () => rendererHoc ( ..) '

Aurimas Dainius 11.01.2019 16:24

Рад, что это сработало. Произошла опечатка, rendererHOC был задуман как HOC, поэтому ему можно было передать другие реквизиты. Я его обновил.

Estus Flask 11.01.2019 19:07

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