Разработка с Flask, ReactJS, gulp.js, bower, Browserify. Часть 1.

main-logo
image-4292

Давайте посмотрим на небольшую, но мощную JavaScript UI библиотеку ReactJS в действии. Это приложение работает на Python 3 и фремворке Flask, на back-end. Так же мы будем использовать на front-end: gulp.js (для выполнения задач), bower(front-end менеджер пакетов), и Browserify(пакетирование зависимостей JavaScript).

ReactJS

Реагировать библиотека, а не фреймворк. В отличие от клиентских MVC фреймворков таких как: Backbone, Ember, и AngularJS, React не делает никаких предположений о вашей технологии стека, так что вы можете легко интегрировать его в новый или унаследованного кода. Это часто используется, чтобы управлять конкретных областей UI приложение, а не всем пользовательским интерфейсом.

React заботится только о пользовательском интерфейсе, который определяется иерархией модульных views компонентов. Если вы знакомы с Anmgular эти компоненты аналогичны директивам. Компоненты используют синтаксис XML, именуемый JSX, который собирает в JavaScript.

Так компоненты определяются в иерархическом порядке, вам не придется повторно рендерить весь DOM при изменении состояния. Вместо этого, он использует виртуальную DOM, что только повторное оказывает индивидуальные компоненты после изменения состояния, в невероятно быстрых скоростях!

Настройка проекта

Давайте начнем с того, что мы знаем: Flask.

Скачать шаблонный кода из репозитория, извлеките файлы, создавайте и активируйте virtualenv, и установите необходимые модули: pip install -r requirements.txt

Теперь давайте запустим приложение:

 $ sh run.sh 

React — первый раунд

Давайте посмотрим на простой компонент.

Компонент: переход от статичного к React

Мы добавим этот скрипт JSX в наш hello.html. Остановитесь на минутку, чтобы проверить его.

<script type="text/jsx">
  /*** @jsx React.DOM */
  var realPython = React.createClass({
    render: function() {
      return (
<h2>Greetings, from Real Python!</h2>
)
    }
  });
  React.render(
    React.createElement(realPython, null),
    document.getElementById('content')
  );
</script>

Что происходит?

  1. Мы создаем компонент с помощью вызова createClass(), и дали ему имя realPython. React.createClass() принимает один аргумент, объект.
  2. Внутри этого объекта мы добавили функцию render, которая декларативно обновляет DOM во время вызова.
  3. Затем идет возвращение значения Greetings, from Real Python!, в JSX, который представляет актуальный HTML элемент, который будет добавлен к DOM.
  4. В конце, React.render() создает экземпляр компонента realPython и вводит элемент в DOM с ID селектором content.

Трансформация

Что дальше? Мы должны «трансформировать», или скомпилировать, JSX в JavaScript. Это делается очень просто. Обновляем hello.html:

<!DOCTYPE html>
<html>
  <head lang="en">
    <meta charset="UTF-8">
    <title>Flask React</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- styles -->
  </head>
  <body>
<div class="container">
<h1>Flask React</h1>
<div id="content"></div>
    </div>
    <!-- scripts -->
    <script src="http://cdnjs.cloudflare.com/ajax/libs/react/0.12.0/react.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/react/0.12.0/JSXTransformer.js"></script>
    <script type="text/jsx">
      /*** @jsx React.DOM */
      var helloWorld = React.createClass({
        render: function() {
          return (
<h2>Greetings, from Real Python!</h2>
)
        }
      });
      React.render(
        React.createElement(helloWorld, null),
        document.getElementById('content')
      );
    </script>
  </body>
</html>

Здесь мы добавили скрипты react.js и JSXTransformer.js. Последний из них используется для «преобразования» синтаксис JSX в обычный JavaScript в браузере.

Обратите внимание, мы не добавили JQuery, так как это не требуется для React.

Вот и все. Запустите сервер Flask и проверьте результат в браузере по адресу: http://localhost:5000/hello

flask-react-hello-world
image-4293

Bower

Вместо того чтобы вручную скачивать JavaScript файлы или подключать их с CDN, давайте использовать Bower для лучшего управлениями этими зависимостями. Bower это мощный менеджер пакетов для фронтальных зависимостей, таких как: JQuery, Bootstrap, React, Angular, Backbone.

Убедитесь, что у вас уже установлен Node и npm. Если его нет то установите его.

Инициализация

Установим Bower с помощью npm:

$ npm install -g bower

npm это менеджер пакетов используется для управления модулями Node. В отличие от PyPi/pip, npm по умолчанию устанавливает зависимости локально. Флаг -g используется для переопределения, чтобы установить Bower глобально.

bower.json

Bower использует файл bower.json для определения зависимостей проекта, который похож на файл requirements.txt. Выполните следующую команду, чтобы в интерактивном режиме создать этот файл:

$ bower init

Просто нажимайте enter что бы установить значения по умолчанию. После этого файл bower.json должен выглядеть примерно так:

{
"name": "ultimate-flask-front-end",
"version": "0.0.1",
"authors": [
"Michael Herman <michael@realpython.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

npm

npm использует аналогичный bower.json файл, называется package.json, он определяет зависимости проекта. Вы также можете создать его в интерактивном режиме:

$ npm init

Так же установите значения по умолчанию:

{
"name": "ultimate-flask-front-end",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

Теперь, давайте добавим файл bower в npm зависимости:

$ npm install --save-dev bower

Конфигурация

Наряду с файлом bower.json, мы можем определить параметры конфигурации Bower в файле .bowerrc. Создадим такой файл в корне проекта. Структура проекта должна теперь выглядеть следующим образом:

├── .bowerrc
├── .gitignore
├── bower.json
├── package.json
├── project
│   ├── app.py
│   ├── static
│   │   ├── css
│   │   │   └── style.css
│   │   └── scripts
│   └── templates
│       ├── hello.html
│       └── index.html
├── requirements.txt
└── run.sh

По умолчанию Bower установит пакеты в каталоге «bower_components» в корне проекта. Мы должны изменить это, так как Flask необходимо что бы файлы лежали в static. Таким образом, добавьте следующий JSON код в файл .bowerrc, так что бы Bower автоматически устанавливал файл в нужную директорию:

{
"directory": "./project/static/bower_components"
}

Инициализация

Мы должны установить следующие пакеты для этого проекта:

  • Bootstrap
  • jQuery
  • React

Это можно сделать двумя способами:

  1. Запустите bower install --save для каждого из пакетов (флаг —save добавляет зависимость (название и версию) в файле bower.json.).
  2. Обновите файл bower.json добавив названию и версию пакета, а затем запустить bower install, чтобы установить все зависимости от файла.

Давайте воспользуемся вторым способом.

{
"name": "ultimate-flask-front-end",
"version": "0.0.1",
"authors": [
"Michael Herman <michael@realpython.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"./project/static/bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "~3.3.2",
"jquery": "~2.1.3",
"react": "~0.12.2"
}
}

И запустим bower install

$ bower install
bower cached git://github.com/twbs/bootstrap.git#3.3.2
bower validate 3.3.2 against git://github.com/twbs/bootstrap.git#~3.3.2
bower cached git://github.com/jquery/jquery.git#2.1.3
bower validate 2.1.3 against git://github.com/jquery/jquery.git#~2.1.3
bower cached git://github.com/facebook/react-bower.git#0.12.2
bower validate 0.12.2 against git://github.com/facebook/react-bower.git#~0.12.2
bower install react#0.12.2
bower install jquery#2.1.3
bower install bootstrap#3.3.2

react#0.12.2 project/static/bower_components/react

jquery#2.1.3 project/static/bower_components/jquery

bootstrap#3.3.2 project/static/bower_components/bootstrap
└── jquery#2.1.3

Теперь вы можете проверить файлы в каталоге «project/static/bower_components».

Тест

Обновите hello.html:

<script src="{{ url_for('static', filename='bower_components/react/react.min.js') }}"></script>
<script src="{{ url_for('static', filename='bower_components/react/JSXTransformer.js') }}"></script>

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

Продвинутые концепции Flask

flask
image-888

Введение — приложение, которое можно масштабировать.

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

Существует два тесно связанных понятий связанных с масштабированием — как влияет на приложение увеличение числа пользователей и как влияет на разработку приложения увеличение числа программистов. Эти проблемы являются центральными в разработке программного обеспечения. Центральные вопросы: Как мы эффективно будем работать в командах 20 разработчиков, 40 разработчиков, или даже тысячи? И как нам справиться с максимальной нагрузки на нашей системе?

Эти вопросы могут показаться простыми, но всегда есть подводные камни. В плохо разработанное приложение, миллионы строк в итоге могут быть выброшены. С другой стороны, есть некоторые системы, которые были разработаны еще в 70-х годах и до сих пор используется.

Масштабирование кодовой базы

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

Есть некоторые идеи которые можно использовать при проектировании  кода:

  1. Модульность
  2. Слабосвязанный код лучше, чем тесно связанный (обычно)
  3. Используйте комментарии
  4. Повторно используйте код, как можно чаще
  5. Пишете код, который является как можно более общим
  6. Тестируйте так часто, как это возможно, и на уровне модуля и на уровень системы
  7. Дайте себе достаточно времени, чтобы добиться своей цели, и затем останьтесь в рамках бюджета
  8. Сотрудничество является крайне важным

Следует отметить, что все из перечисленных выше пунктов, не будут рассмотрены в этой статье; Пункты 6 — 8 будет в значительной степени игнорироваться.

Давайте поговорим о модульности. При разработке программы, как правило, вы будете сначала думать над всем приложением. Например: если создать сайт, который позволяет повысить уровень информированности о рабстве, какие функции нужны?

  1. Сервер для обслуживания страниц. — конкретно
  2. База данных для хранения данных пользователей. — конкретно
  3. Способ входа активных пользователей, и взаимодействия с ними. — расплывчато
  4. Система управления контентом для администратора сайта, для обновления сайта. — конкретно
  5. Способ взаимодействовать с сообществом которое мы разрабатываем. — расплывчато
  6. RSS фиды — конкретно
  7. Способ централизованного управления нашей социальной наличием. — конкретно
  8. Поддержка видео контента. — конкретно

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

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

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

  1. Таблица базы данных регистрации пользователей в нашей системе.
  2. Функция или набор функций, которые необходимо работы с пользователями.

Способ взаимодействовать с сообществом которое мы разрабатываем. Можно разделить на:

  1. Форум для обсуждения тем
  2. Раздел комментарий после каждого поста в блоге.
  3. Обратная связь и контакты для связи с администрацией сайта

Теперь, когда у нас есть план для нашего приложения, давайте посмотрим, что уже есть у Flask и что мы должны написать сами.

Что мы получаем с Flask

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

База данных — Flask поставляется с SQLite, но есть и много других вариантов.

Вход пользователей? Мы должны создать эту функциональность в нашем приложении.

То, что мы должны написать:

Систему управления контентом — это основная часть приложения. Обратите внимание, что мы должны управлять комментариями и видео, поэтому мы не должны создать отдельный функциональность для них.

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

RSS — мы создадим это в его собственном разделе приложения.

Почтовый клиент — мы должны создать тоже с нуля.

Имея свой дизайн настроен, как правило, сэкономить время. В этом примере, зная доска объявлений и CMS потребуется некоторое повторное использование кода, необходимо сохранить какое-то время.

Blue prints (эскизы)

Так что мы идем вперед и создаем пять раздельных приложений, и код будет повторятся в каких то местах? Конечно нет! Эскизы позволяют создать одно большое приложение, работающее с несколькими приложениями одновременно. Благодаря этому увеличивается модульность приложения и в целом облегчит разработку. Это также делают ваш код более отказоустойчивым. Это означает, что когда часть вашего кода не работает, будет легче найти причину, и у вас будете меньше ошибок (потому что у вас есть куча небольших приложений вместо одного очень большого).

Настройка нашего проекта

Если вы уже работали с Flask, создание  настройка эскизов будет вам знакома.

Настройка эскизов имеет почти тот же синтаксис, как создание приложений Flask. Разница лишь в том, что вы регистрируете эскизы в приложение после того как вы создали их.

Структура каталога:

run.py
/slavery_website/
    __init__.py
    blog/
        __init__.py
        static/
        templates/
        views.py
        models.py
    cms/
        __init__.py
        static/
        templates/
        views.py
        models.py
    email_client/
        __init__.py
        static/
        templates/
        views.py
        models.py
    feeder/
        __init__.py
        static/
        templates/
        views.py
        models.py
    logger/
        __init__.py
        static/
        templates/
        views.py
        models.py
    message_board/
        __init__.py
        static/
        templates/
        views.py
        models.py

Некоторые из views.py файлов

cms/views.py

from flask import Blueprint, render_template
from models import *
cms = Blueprint("cms",__name__,template_folder='templates')
@cms.route("/add",methods=["GET","POST"])
def add():
    return render_template("admin.html")
@cms.route("/remove",methods=["GET","POST"])
def remove():
    return render_template("admin.html")
@cms.route("/view_entries",methods=["GET","POST"])
def view_entries():
    entries = get_entries()
    return render_template("entries.html",entries=entries)

logger/views.py

from flask import Blueprint, render_template
from models import *
logger = Blueprint('logger',__name__,template_folder="templates")
@logger.route("/analytics/page_views",methods=["GET","POST"])
def page_views():
    pages = get_page_views()
    return render_template("viewer.html",pages=pages)
@logger.route("/analytics/button_press", methods=["GET","POST"])
def button_press():
    buttons = get_button_press()
    return render_template("viewer.html",buttons=buttons)
**Some functions snipped**

slavery_website/init.py:

from flask import Flask
from cms.views import cms
from logger.views import logger
app = Flask(__name__)
app.register_blueprint(cms, url_prefix='/admin')
app.register_blueprint(logger,url_prefix='/analytics')