Flask + NPM + Heroku =?

Вступление

Допустим, вы создаете веб-сайт с бэкэндом Flask и внезапно обнаруживаете, что для вашего проекта необходимо использовать пакет / модуль JavaScript. Возможно, вы делаете это, чтобы дать вашему сайту немного больше взаимодействия, или вы работаете с модулем, который недоступен как CDN. Это оставляет вам возможность использовать Диспетчер пакетов узлов (NPM). Обычно вы добавляете npm init в корневой каталог вашего проекта веб-разработки и устанавливаете нужные модули с помощью npm install <package>, если бы не Flask (шучу - Flask прекрасен во многих отношениях).

Если вы попытаетесь это сделать, в конечном итоге вы получите неразрешимые ошибки JavaScript или неправильную связь HTML с вашим модулем NPM. Шутки в сторону, но остаётся актуальный вопрос: h как это можно сделать? Эта статья призвана ответить на этот вопрос.

Важное примечание:. В этом коротком руководстве предполагается, что вы знакомы с Flask, NPM и Heroku и у вас уже есть приложение Flask, развернутое на Heroku. .

Хитрость

Если вы знакомы с Flask, вы должны знать, что простая структура каталогов для (очень) простого веб-приложения должна выглядеть примерно так:

/<your_flask_proj_directory>/
├── app.py (or __init__.py)
├── requirements.txt
├── venv (python_environment)
│   └── ...
├── static
│   ├── css
│   │   └── styles.css
│   └── img
│       ├── img1.jpg
│       └── img2.png
└── templates
    ├── layout.html
    ├── index.html
    └── about.html

Ключ к этой дилемме - использовать вашу папку / static. Это просто: запустите npm init в своей static папке и установите модули NPM в этот каталог.

Почему? Помните, что папка static используется для хранения буквально статичных (неизменяемых) файлов, в отличие от HTML-шаблонов - отсюда и название «статические». Файлы CSS, изображения и, что более важно, код JavaScript соответствуют этим критериям для приложения Flask. С другой стороны, файлы из-за пределов папки static не будут работать должным образом, если вы попытаетесь связать их с помощью тега <script> в своих шаблонах HTML.

Ваш node_modules должен появиться внутри вашей static папки. На этом этапе вы можете связать модуль NPM со своими HTML-шаблонами с помощью тега <script>. Например, если я пытался использовать swup.js для добавления ярких переходов страниц на свой сайт, я свяжу этот модуль с HTML-кодом макета следующим образом:

<script src="{{ url_for('static', filename='node_modules/swup/dist/swup.js' }}"></script>

Мы используем функцию url_for() для создания пути, не беспокоясь о попытках получить правильный относительный путь. Теперь вы можете использовать свои модули NPM в своем приложении и увидеть, как они работают на вашем локальном сервере!

Важное примечание. Ваши файлы JavaScript в static не поддерживают import или require(), поскольку Flask рассматривает их как полностью клиентский JavaScript. Таким образом, вы должны относиться к своему модулю так, как будто он связан, как к CDN. Обратитесь к документации используемого модуля (поскольку каждый модуль отличается) и следуйте дорожке CDN.

О, Heroku!

Вы можете подумать: «Он работает в моей настройке, так что наверняка он будет работать, когда я разверну его на Heroku!» Это наивный ход мыслей, но я признаю, что недолго думал так же назад. В этом состоянии установленные вами модули NPM на static НЕ будут работать сразу после развертывания на Heroku.

Что еще хуже, Node.js или NPM не устанавливаются, если вы попытаетесь запустить свой Procfile. Это потому, что исходный Buildpack, который вы использовали на Heroku, подготавливает только минимум того, что вам нужно для развертывания вашего приложения; пакет сборки Python не будет тратить впустую место в хранилище, пытаясь установить Node.js, и наоборот. Нам нужны два пакета сборки для этого проекта Heroku: Node.js и Python (оба официально поддерживаются в указанном порядке).

Предполагая, что у вас уже есть пакет сборки Python, выполните команду в корневом каталоге вашего проекта ниже:

heroku buildpacks:add --index 1 heroku/nodejs

Это добавляет пакет сборки Node.js перед аналогом Python при создании приложения. Это необходимо для того, чтобы убедиться, что все наши ресурсы модуля NPM установлены и готовы к работе, прежде чем настраивать сервер Flask и запускать его. Если у вас нет интерфейса командной строки Heroku, вы можете настроить его на странице настроек Heroku для своего проекта / приложения.

Осталась одна небольшая проблема, о которой мы должны позаботиться: пакет сборки Node.js ищет package.json только на корневом уровне каталога проекта, то есть фактически не устанавливает модули в папку static. Простое исправление - создать еще один package.json файл в корне вашего проекта с записью postinstall, которая указывает на script и запускает npm install там. Вот что должно быть package.json на корневом уровне:

"scripts": {
  "postinstall": "cd static && npm install"
},

Теперь ваше развернутое на Heroku приложение Flask с модулями NPM готово и работает!

Заключение

Эта проблема меня беспокоила не так давно, когда мне приходилось поддерживать веб-сайт организации с помощью бэкэнда Flask. И я, и организация думали об использовании переходов между страницами с swup.js, чтобы улучшить взаимодействие с пользователем. Однако замена необходимых мне плагинов пришла только в виде модулей NPM (так что CDN не рассматриваются). Эта статья является кульминацией моих выводов о довольно узком сценарии использования, но я надеюсь, что это было полезно - или, по крайней мере, интересно - для тех из вас, кто читает эту статью.