2048 создан на основе лучших практик реакции и редукции.

JavaScript игра React.js Webpack Redux

Некоторое время назад вокруг проблемы с лицензией React было много шума, что вызвало панику в сообществе React.К счастью, команда React наконец прислушалась к мнению сообщества и сменила лицензию на MIT. Независимо от лицензии React, React — отличная библиотека представлений для изучения.

Этот проект не является масштабным проектом, но он по-прежнему использует лучшие практики интерфейса в соответствии со стандартами крупномасштабных проектов для создания приложения с хорошим качеством кода, высокой производительностью, высокой ремонтопригодностью и модульностью. Этот проект основан наreact, reduxBuild 2048, в дополнение к использованию отличных инструментов с открытым исходным кодом в течение последних двух лет для улучшения качества кода, в том числеeslint,stylelint,prettierи так далее, иtravis,codecovИ другие услуги, такие как непрерывная интеграция и непрерывное развертывание, для обеспечения качества кода и повышения эффективности разработки.

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

предварительный просмотр

рабочий стол


screenshot

мобильный


screenshot

характеристика

Отзывчивый

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


screenshot

сохранение данных

Веб-приложения больше всего боятся сбоев питания и оффлайна, первая проблема пройденаstore.subscribeПодпишитесь на обновления состояния редукции и сериализуйте состояние вlocalStorageХранилище, обновление в реальном времени, точки останова, сбои программы и повторное открытие по-прежнему являются последним состоянием, вторая проблема связана с помощью хрома.PWAтехнологии кэшированные файлы ресурсов по-прежнему доступны, даже если сеть отключена.


screenshot

Редуксное состояние

reduxпредсказуемый контейнер для управления государством JS, который сочетает в себеRedux DevTools extensionЕго можно легко расширить, чтобы помочь в разработке и отладке с большим преимуществом. Мало того, что можно увидеть сохраненное состояние редукции, вы всегда можете вернуться к прошлому состоянию в какой-то момент времени, как космический шаттл, а также увидеть редукцию каждого действия триггера и состояние каждого триггера, вызванное изменениями.


screenshot

Система комментариев

С помощью github issue api войдите в систему с учетной записью github и оставьте сообщение, чтобы ответить на вопрос. Сообщение поддерживает формат уценки, который аналогичен проблеме с github.


screenshot

PWA

в поддержкуPWAПри открытии страницы в техническом браузере (например, в более новом Chrome) вам автоматически будет предложено добавить на экран, и процесс добавления аналогичен установке собственного приложения. После добавления приложения его можно использовать в автономном режиме, как собственное приложение, или приложение можно удалить. На следующем рисунке показан процесс добавления PWA в Chrome.После завершения добавления добавленное приложение появится на рабочем столе.Даже если все сети отключены, оно все равно может нормально работать как родное приложение.


screenshot

i18n

Приложение поддерживает несколько языков и автоматически адаптируется к языковым настройкам браузера. В настоящее время обнаружено, что браузер поддерживает китайский язык, чтобы сначала использовать китайский язык, в противном случае по умолчанию используется английский язык. Нужна дополнительная языковая поддержка, отредактируйтеsrc/utils/i18n.jsизdataОбъект, добавить соответствующий язык текста.


screenshot

реагировать на лучшие практики

  • Один файл на компонент.
  • Максимально используйте компоненты без состояния, то есть, если вы просто пишете простой компонент отображения, вам не нужны компоненты для сохранения собственного состояния, а компоненты, которым не требуются методы жизненного цикла или ссылки для работы с DOM, предпочтительнее использовать без состояния компоненты форма. В качестве примера возьмем компонент проекта «Советы»:

      import React from "react";
      import PropTypes from "prop-types";
      import styles from "./tips.scss";
    
      export default function Tips({ title, content }) {
        return (
          <div className={styles.tips}>
            <p className={styles.title}>{title}</p>
            <p className={styles.content}>{content}</p>
          </div>
        );
      }
    
      Tips.propTypes = {
        title: PropTypes.string.isRequired,
        content: PropTypes.string.isRequired
      };
  • В отличие от вышеизложенного, если вам нужны методы жизненного цикла компонента для оптимизации производительности компонента (обычное использование, переопределениеshouldComponentUpdateметод), вам нужен компонент для сохранения собственного состояния или использования ссылок для управления DOM, вам нужен компонент с состоянием, использующий класс es6 для наследования React.Component Метод записи. Пример компонента:

      import React from "react";
      import PropTypes from "prop-types";
      import classnames from "classnames";
      import styles from "./cell.scss";
      import { isObjEqual } from "../../utils/helpers";
    
      export default class Cell extends React.Component {
        static propTypes = {
          value: PropTypes.number.isRequired
        };
    
        shouldComponentUpdate(nextProps, nextState) {
          return (
            !isObjEqual(nextProps, this.props) || !isObjEqual(nextState, this.state)
          );
        }
    
        render() {
          const { props: { value } } = this;
    
          const color = `color-${value}`;
          return (
            <td>
              <div
                className={classnames([styles.cell, { [styles[color]]: !!value }])}
              >
                <div className={styles.number}>{value || null}</div>
              </div>
            </td>
          );
        }
      }
  • Событие привязано к этому методу. После связывания этого один раз в конструкторе его можно использовать позже. кControlPanelПример кода детали компонента:

    constructor(...args) {
      super(...args);
    
      this.handleMoveUp = this.handleMoveUp.bind(this);
      this.handleMoveDown = this.handleMoveDown.bind(this);
      this.handleMoveLeft = this.handleMoveLeft.bind(this);
      this.handleMoveRight = this.handleMoveRight.bind(this);
      this.handleKeyUp = this.handleKeyUp.bind(this);
      this.handleSpeakerClick = this.handleSpeakerClick.bind(this);
      this.handleUndo = this.handleUndo.bind(this);
    }
  • использоватьpropTypesАтрибуты проверяются для входящих реквизитов. Вы можете проверить тип реквизита и требуется ли он, а значение по умолчанию defaultProps также должно быть заполнено для необязательных реквизитов. компоненты без сохранения состоянияButtonЧасть примера кода:

      Button.propTypes = {
        children: PropTypes.oneOfType([PropTypes.node]),
        onClick: PropTypes.func,
        size: PropTypes.oneOf(["lg", "md", "sm", "xs"]),
        type: PropTypes.oneOf([
          "default",
          "primary",
          "warn",
          "danger",
          "success",
          "royal"
        ]).isRequired
      };
    
      Button.defaultProps = {
        children: "",
        onClick() {},
        size: "md",
      };
  • использоватьHOC(Higher-Order Components)вместо миксинов. Использование примесей официально не рекомендуется, а методом подключения редукции является применение HOC.
  • Чтобы повысить производительность приложения и избежать ненужных перерисовок представления, используйтеshouldComponentUpdateметод; компонентRowПример:
    // 如果该行没有格子需要刷新也没有组件自己的状态刷新,
    // 则该组件不执行 render 方法,
    // 避免每次别的行数据刷新也跟着重新渲染。
    shouldComponentUpdate(nextProps, nextState) {
      return (
        !isObjEqual(nextProps, this.props) || !isObjEqual(nextState, this.state)
      );
    }

Структура проекта

Этот проект основан на официальном продукте Facebook.create-react-appОн был построен на строительных лесах, и после отказа были внесены соответствующие изменения в соответствии с требованиями проекта.

Отрегулируйте следующим образом

  • webpackДобавить кscssслужба поддержки. почему это не работаетCssInJSРешение состоит в том, что эти решения, как правило, не идеальны, и, учитывая принцип разделения стиля и структуры, scss в настоящее время является относительно зрелым препроцессором CSS, и существует множество кругов сообщества, что очень удобно для разработки. Рекомендуется изучить scss/sassруководство. Добавить кsass-loaderПерейдите к нижней части правил scss.код конфигурации
  • включиcss moduleслужба поддержки. В больших проектах компоненты должны быть максимально разделены, но глобальный характер имен классов CSS может легко привести к непредвиденным ошибкам. После того, как модуль css будет включен, все имена классов в конечном итоге будут заполнены небольшим хеш-значением, поэтому имя класса будет иметь определенную уникальность, и загрязнить глобальный код будет непросто.код конфигурации
  • Добавить кstylelintслужба поддержки. js-код уже естьeslint(но с более популярной и строгой проверкойairbnbправила) для проверки кода, но код стиля также должен поддерживать единообразие стиля кода, а правила проверки обычно основаны на лучших практиках сообщества.код конфигурации
  • Добавьте поддержку cdn статических ресурсов. Поскольку проект развернут вgithub pageСкорость доступа в Китае не очень идеальна, поэтому очень важно максимально уменьшить размер js-пакета для скорости загрузки страницы. Большие пакеты npm, такие как ReactDOM, удаляются из пакета и загружаются с использованием CDN, что может значительно уменьшить размер пакета. (PS: Причина, по которой CDN загружается быстрее, заключается в том, что провайдеры CDN установили кеш-серверы по всей стране, а получение ресурсов поблизости намного быстрее, чем их получение с github, а пропускная способность CDN, как правило, более широкая) Разделите React и ReactDOM на выходите, нужно только добавить CDN в html файлтег скрипта, при добавлении в webpackexternalsатрибут, который указывает кодimportПакет получается непосредственно из глобальной переменной. Размер связанного файла js после зачистки был уменьшен с 278 КБ до 164 КБ.
  • добавить веб-пакетсжатие кодаплагин. Конфигурация webpack по умолчанию напрямую выводит исходный код js и css, но после добавления сжатия размер файла значительно уменьшается (js файл со 164кб до 49кб), а скорость открытия для мобильных браузеров значительно повышается.код конфигурации
  • Добавить кwebpack-bundle-analyzerПлагин анализирует код проекта в соответствии с долей каждого пакета модуля в упакованном файле, тем самым оптимизируя код. Например, удаление React и ReactDOM связано с тем, что после анализа обнаруживается, что на эти два пакета приходится большая доля.

файловая структура

  • src, большая часть исходного кода проекта находится здесь, в основном код реактивного компонента js и код стиля scss. подкаталоги содержатjestКод модульного теста, тестовый код и исходный код максимально приближены для облегчения написания.
    • активы, которые в основном хранят некоторые глобальные коды стилей, файлы svg значков, файлы mp3 со звуком игры, изображения и т. д .;
    • комплектующие, хранениереагировать немой компонент, каждый компонент, содержащийся в каталоге, начинается с заглавной буквы.index.jsВ то же время этот каталог содержит файлы scss, используемые компонентом, старайтесь содержать весь код, требуемый компонентом, в одном каталоге, чтобы не загрязнять другие коды и улучшить возможность повторного использования компонента.
    • контейнеры, хранениереагировать умные компонентыСтруктура каталогов иcomponentsАналогично, но поскольку это интеллектуальный компонент, компоненты здесь могут манипулировать данными избыточности, не слишком задумываясь о возможности повторного использования.
    • Редьюсеры, которые представляют собой функции, содержащиеся в редуксе, являются чисто функциональными вычислительными операциями состояния без побочных эффектов.
    • утилиты, в том числе инициализация компонента комментариев, многоязычные файлы i18n, обнаружение и регистрация в мобильном браузереServiceWorkerи т.п.
    • index.js, файл входа в проект, в основном отображает корневой компонент реакции на указанный узел DOM и регистрирует его.ServiceWorker.
    • store.js, инициализация избыточного хранилища, в то же времяstore.subscribeПодписываясь на обновления статуса приложения, сериализованный статус сохраняется вlocalStorage.
  • общедоступный, включая файлы html проекта, иконку веб-сайта favicon иPWA manifestдокумент.
  • config, в основном включающий различные конфигурационные файлы webpack.
  • сценарии, сценарии запуска npm, запуск режима разработки, пакетные проекты, запуск модульных тестов jest и многое другое.
  • build, выходной каталог после упаковки проекта.
  • скриншоты, оригинальные изображения различных изображений README, для удобства внутренних пользователей, изображения README на самом деле взяты из картинной кровати Sina Weibo.
  • .editorconfig, общая конфигурация редактора, унифицирующая формат кода различных редакторов/IDE.
  • .eslintignore, файлы или каталоги, которые eslint должен игнорировать, правила аналогичны .gitignore
  • .travis.yml, скрипт непрерывной интеграции, каждый раз, когда код отправляется на github, тестовый сервер автоматически запускает скрипт для выполнения тестового примера, выводит покрытие кода и, наконец, автоматически развертывает наgithub page. Весь статус виден в значке README в проекте.
  • package.json, основная информация о проекте и некоторые настройки. Общий контент включает в себя различные зависимости проекта, различные сценарии запуска, домашнюю страницу проекта и т. д., для уменьшения количества файлов в корневом проекте здесь также написана конфигурация jest, babel, eslint и stylelint. Стоит отметить, что проект представилhusky, который будет выполняться перед каждой фиксацией кодаlint-stagedАвтоматизироватьprettierчтобы украсить формат кода. Каждый раз, когда код отправляется на github, будут выполняться все случаи модульных тестов, и отправка может быть продолжена после того, как все они пройдены.
  • пряжа.замок,yarnФайл блокировки, сгенерированный после первой установки зависимостей. При установке пакета зависимостей через yarn, yarn автоматически исправляет пакет зависимостей проекта (включая родительский пакет, от которого зависит пакет зависимостей) в указанной версии (включая URL-адрес и хеш-значение установки пакета зависимостей), чтобы все среды разработки использовать пряжу для управления проектом, пакеты, установленные на разных машинах и в разных системах, одинаковы, что позволяет избежать дефектов предыдущего npm (требования к версии слишком свободны или версия родительского пакета обновлена ​​и т. д., что приводит к различным версии зависимостей, устанавливаемых каждый раз).

стек технологий

  • react, интерфейс построения на основе компонентов
  • redux, Управление состоянием приложения
  • babelСинтаксисный синтаксисный синтаксис ES2017 + включается в ES5
  • webpack, горячая загрузка кода, обработка файлов в стиле scss, компиляция и упаковка компонентов и т. д.
  • scss, зрелый препроцессор css (причина, по которой решения CssInJS не используются, заключается в том, что эти решения в целом несовершенны, а также учитывают принцип разделения стилей и структур)
  • eslint, используя популярную спецификацию кода airbnb, чтобы строго ограничить стиль кода
  • stylelint, проверка стиля кода scss
  • jest, среда тестирования кода, созданная fb, функция моментального снимка очень удобна для тестирования пользовательского интерфейса реагирующих компонентов.
  • Prettier, JS и инструменты для улучшения формата кода SCSS
  • PWA(Progressive Web Apps), с помощью возможностей сервисного работника браузера веб-приложения имеют возможность быть близкими к нативным приложениям на мобильных платформах, могут использоваться в автономном режиме, получать уведомления и т. д.

Запустить, протестировать и упаковать

Поскольку файл конфигурации использует синтаксис es6+, требуется, чтобы версия узла была выше 6.10, и рекомендуется использоватьyarnдля управления зависимостями. После разветвления проекта вы можете действовать следующим образом.

  npm i -g yarn # 安装 yarn
  git clone git@github.com:<你的名字>/React-2048-game.git
  cd React-2048-game
  yarn # 安装依赖包
  yarn start # 开启调试模式,启动后自动打开浏览器 http://localhost:3000 
  yarn test # 自动测试
  yarn build # 打包代码

Побить пит-рекорд

  • Когда я настроил анимацию фейерверка, я обнаружил, что это не имеет никакого эффекта.После тщательного сравнения файлов css, скомпилированных webpack, я обнаружил, что все имена @keyframes имеют добавленное хеш-значение (то есть как обычное имя локального класса CSS ).Решение состоит в том, чтобы использовать @keyframes Добавить псевдокласс: глобальный перед именем файла scss и всего файла scss, вы можете обратиться к файлу scss фейерверка, это не идеальное решение (класс css название уже не имеет местных особенностей), а потом копнуть глубже.
  • :global, используемый модулем css, не является стандартным псевдоклассом, поэтому stylelint необходимо добавить конфигурацию, чтобы игнорировать эту ошибку. видетьpackage.jsonизstylelint.rules.

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