Повторное использование кода в Node, Web и Mobile

В этом руководстве я покажу вам, как настроить монорепозиторий JavaScript с api (Express), веб-приложением (React), мобильным приложением (React Native) и общей папкой для повторно используемого кода. Но сначала…

Краткое введение

Я разработчик программного обеспечения и большую часть времени трачу на создание REST API и приложений React. Мое путешествие с монорепозиториями началось сначала как любопытство. А потом все стало еще серьезнее, когда несколько месяцев назад я начал создавать собственное приложение. Когда я начал создавать это приложение, у меня были некоторые основные принципы, которым я хотел следовать как можно больше:

  1. Используйте JavaScript для всего стека
  2. Избегайте дублирования бизнес-логики между серверной частью и интерфейсом
  3. Простая установка и обслуживание

Основными частями стека были: сервер API (GraphQL / Node), веб-приложение (React) и мобильное приложение (React Native).

Основное внимание в этой статье уделяется второму пункту выше. Наличие всего стека как монорепозитория позволило мне обмениваться кодом между моим сервером api, веб-приложением и собственным приложением. Далее следует несколько открытий, которые я сделал на этом пути, и то, как я создал свой проект. Я надеюсь, тебе это нравится.

Метод проб и ошибок

В своем стремлении к настройке монорепозитория я попробовал несколько методов и инструментов, в том числе:

  • Лерна
  • Webpack (с использованием псевдонима и параметров разрешения)
  • Алльный метод.
  • Рабочие места пряжи

У всех есть свои плюсы и минусы. Такие инструменты, как Lerna, создают символические ссылки для соединения папок в монорепозитории, и это было одной из проблем при запуске собственного приложения. В конце концов, я решил проблему символических ссылок с помощью Haul. Но опять же, было так больно склеивать все вместе. Симулятор часто выдавал мне ошибки о рассинхронизации пакета JavaScript и других проблемах. И я был не в восторге от того, что тратил столько времени на настройку, а не на разработку.

Webpack также был вариантом. Я настроил конфигурацию, которая позволила мне импортировать модули из корневой папки монорепозитория. Но это заставило меня везде использовать webpack, и это казалось ненужным.

По поводу метода Алле. Я не мог заставить его работать с React Native.

Затем, в счастливый день, я услышал о рабочих пространствах Yarn, а затем я нашел этот отличный учебник от Дарио Хавьера Краверо о том, как использовать рабочие пространства Yarn с приложением React и приложением React Native. То, что он описывает в статье, было самым быстрым, простым и надежным методом, который я нашел до сих пор, чтобы получить монорепозиторий, который работает для React и React Native.

Обсуждение дешево. Покажи мне код.

Линус Торвальдс

Давай перейдем к делу. В этом руководстве мы создадим следующую структуру папок:

/jsrepo
  /api
  /native
  /shared
  /web

Общая папка будет содержать код, который можно повторно использовать в серверной части и во внешнем интерфейсе (веб / собственный). Эта папка может содержать такие вещи, как константы, вспомогательные функции и бизнес-логику.

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

Предварительные условия

Я предполагаю, что у вас есть:

Фундамент

Создадим основной проект. Я назову его jsrepo и положу в свою домашнюю папку ~/jsrepo. Измените имя и местоположение по своему желанию.

mkdir jsrepo
cd jsrepo
npm init

Все следующие команды cli взяты из ~/jsrepo

Общий пакет

1. Создайте общую папку.

mkdir shared
cd shared
npm init

2. Давайте добавим контент в общую папку.

touch index.js
mkdir packages
cd packages
touch colors.js

3. Добавить в ~/jsrepo/shared/packages/colors.js

const GREEN = '#24ad34';
module.exports = {
    GREEN
};

4. И в ~/jsrepo/shared/index.js

const Colors = require('./packages/colors');
module.exports = {
    Colors
};

Убедитесь, что основное поле package.json файла общей папки указывает на ~/jsrepo/shared/index.js. Это очень важно для правильной работы.

API

Теперь давайте создадим простой экспресс-сервер для использования нашего общего пакета.

1. Создайте папку api

cd ~/jsrepo
mkdir api
cd api
npm init

2. Добавьте общую папку и выразите как зависимость

npm install ../shared express --save

Зависимости в файле package.json для api будут следующими:

"dependencies": {
    "express": "^4.16.3",
    "shared": "file:../shared"
}

3. Давайте создадим простой экспресс-сервер и воспользуемся общим пакетом.

touch server.js

4. Вставьте это в файл ~/jsrepo/api/server.js:

const express = require('express');
const { Colors } = require('shared');
const app = express();
app.get(
    '/', 
    (req, res) => res.send(`Colors: ${JSON.stringify(Colors)}`)
);
app.listen(3001, () => console.log('App listening on port 3001!'));

5. Запустите сервер api npm run start и перейдите по адресу http: // localhost: 3001. Вы увидите это:

Интернет

  1. Давайте воспользуемся приложением create-react-app, чтобы создать простое веб-приложение.
cd ~/jsrepo
create-react-app web
cd web
rm -r node_modules

2. Добавьте общую папку.

npm install ../shared --save

3. Импортируйте общий код в App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// 1. add this line
import { Colors } from 'shared';
class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
</p>
        {/* 2. add the following line */}
        <p>Colors are {JSON.stringify(Colors)}</p>
      </div>
    );
  }
}
export default App;

4. Установите зависимости с npm install

5. Запустите приложение с npm run start и перейдите по адресу http: // localhost: 3000. Вы должны увидеть это:

Родной

  1. Давайте использоватьcreate-react-native-app для создания нового проекта
cd ~/jsrepo
create-react-native-app native

2. Установите общий пакет.

npm install ../shared --save

3. Измените App.js, чтобы использовать общий пакет.

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
// 1. add this
import { Colors } from 'shared';
export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Open up App.js to start working on your app!</Text>
        <Text>Changes you make will automatically reload.</Text>
        <Text>Shake your phone to open the developer menu.</Text>
        {/* 2. Add this line */}
        <Text>{JSON.stringify(Colors)}</Text>
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

4. Установите зависимости:

npm install

5. Запустите приложение с помощью Expo или другого понравившегося вам инструмента. Если вы используете Expo, перейдите в Expo IDE и откройте проект. Убедитесь, что ваш компьютер и мобильный телефон находятся в одной сети Wi-Fi.

6. Вы должны это увидеть

И это все. У нас есть монорепозиторий с API, веб-проект и собственный проект, которые могут повторно использовать код из общей папки.

Что, скорее всего, произойдет, если вы пойдете по этому пути:

  1. Одна из проблем, которые я обнаружил до сих пор, и я не могу это подчеркнуть, - это проблема смешивания модулей ES6 и модулей Commons JS. Как вы заметили, общая папка использует только Commons JS, и это потому, что мы хотим повторно использовать общие пакеты в api, который работает на Node. А Node по умолчанию не поддерживает модули ES6. Итак, если вы попытаетесь использовать модули ES6 в общей папке, вам придется проделать дополнительную работу. Вероятно, вы могли бы транспилировать общий код и экспортировать его в разные системы модулей, тогда Node и веб-приложение смогут его использовать.
  2. Несколько раз, работая с общей папкой, мне приходилось использовать стороннюю библиотеку, и, как всегда, я сделал: const lib = require('some-lib'). Но ничего не вышло. Пока не пойму, что в некоторых случаях приходилось делать const lib = require('some-lib').default. Просто хорошо иметь в виду.
  3. Работа с модулями Commons JS и ES6 в монорепозитории была настоящим кошмаром. В какой-то момент я решил везде использовать только Commons JS. Я имею в виду везде. Это была большая работа, но она разрешила множество конфликтов, когда модули не разрешались и не импортировались должным образом. Если вы хотите прервать описанную выше настройку, просто замените любой экспорт в общей папке с Commons JS на модули ES6.

Следующая часть

  • Повторное использование компонентов React между веб-платформами и нативными платформами

Подпишитесь на мою рассылку!

Если вам понравился этот контент, подпишитесь на мою ежемесячную новостную рассылку. Я пишу о
Developer Experience (DX), Frontend-разработке и архитектуре программного обеспечения. Обещаю, без спама. И вы можете отказаться от подписки в любой момент. Зарегистрируйтесь на rafaelrozon.com.

Ресурсы

Спасибо и удачного взлома!