空飛ぶ気まぐれ雑記帳

主に趣味とかプログラミングについて扱います。

はじめてWebアプリケーションを作った話

はじめに

プログラミングを初めて早6年と3ヶ月。
これまでに、C++でアプリケーションを作ったことは数多くあれど、Webアプリケーションは作ったことがありませんでした。
ただ、某FEの試験を受けたり、QtからGoogleAPIをJavascript経由でバインディグしたりと色々やっていた影響でHTMLやJavascriptはそこそこ書けたのでぶっつけ本番でもなんとかなるかと思って実際に作ってみました。
が…思ってた異常に大変で躓いたところも多かったので、herokuを使ってPythonでWebアプリを作るまでに躓いたところを紹介したいと思います。
下記は実際に作ったアプリケーションへのリンクです

http://ppt-scripter.herokuapp.com/ppt-scripter.herokuapp.com

何つくったの

ざっくりと説明するとMicrosoftのPower Pointで作ったスライドからノートのみを抽出するアプリケーションです。
実は前回記事のGUIアプリケーションをやめて、Webアプリケーションにしてみました。

elda27.hatenablog.com

Webアプリの構成について

今回はherokuの公式が紹介しているdjangoで作るのではなく、もう少しlightにアプリを作れるらしいflaskを使って作ってみました。
また、pythonは2系ではなく、3系を使っています。

躓いたところ

以下は実際に躓いたところについて紹介していきます。
flaskの絡みはググれば出てくるので、多くのことで悩むことが無かったのですが、herokuの仕様が?すぎて辛かったです。
なお、私は初心者なので、もしその解決方法は不味いよってところがあったら教えてくれると嬉しいです。

Javascriptで躓いたところ。

Postでファイルをアップロードする時、input type="file"とDrag&DropAPIの両方を使う場合

Google Chromeの場合input type="file"にDrag&Dropしてやるとそのままアップロードできるのだけど、Edgeだとそんなことが無かったりする。
そのため、Drag&Dropでファイルを受け取る場合、JavascriptのDrag&DropAPIを使えば良いらしいのだけど、Formによる送信と共存させる方法が最初わからなかった。
ただ、まあ良くよく調べてみると簡単な話で、input type="file"の時とDrag&Drop APIで取得したファイルそれぞれを自前でnewしたFormDataに設定してやればいいそうです。

  function uploadFiles(files)
  {
    filelist_dom.children().remove()
    var fd = new FormData()
    for(file of files)
    {
      fd.append('fileinputs', file, file.name)
    }

    $.ajax({
      type:'POST',
      contentType: false,
      processData: false,
      url: '/convert',
      data: fd,
      dataType: 'json'
    })
  }

  $('#file-upload').on('click', function(event) {
    event.preventDefault()
    $('#hidden-file-upload').click()
  })

  $('#hidden-file-upload').change(function(event) {
    console.log('File upload via hidden input')
    event.preventDefault()
    uploadFiles(this.files)
  })

herokuで躓いた所

必要なファイルについて

前述の通り公式で紹介されているPythonによるWebアプリケーションはdjangoを用いたアプリケーションで、flaskを用いたアプリケーションではありません。
そのため、必要なファイルに若干の違いがあります。

github.com

結局Webアプリケーションを実行するまでに必要な最低限のファイルは下記の3つです。

  • requirements.txt:必要なパッケージをリストするファイル
  • runtime.txt:Pythonのバージョンを指定するファイル
  • Procfile:Webアプリ実行のためのコマンドを書くファイル
requirements.txt

サーバサイドでPythonのパッケージをインストールする際に使われるファイル。
pipを使って出力すればいいらしい。

pip freeze > requirements.txt 

Anacondaを使っているなら新しく環境を作成して必要なパッケージだけをインストールして実行すれば良いと思う。

runtime.txt

herokuではPython2系がデフォルトになっているので、Pythonのバージョンを指定してやる必要があります。下記リンクを見ると使用できるPythonのバージョンが書かれているので、今回はPython3.6.0を設定しました。

devcenter.heroku.com

実際に設定ファイルに書いた内容は下記のとおりです。

python-3.6.0
Procfile

そもそもProcfileってなんぞや。という所から始まったのですが、どうやらProcfileというのは、foremanという1アプリケーションを複数プロセス管理するツールのためのファイルだそうです。
それで、ファイルフォーマットとしては、Webアプリケーションを実行する際のコマンドを列挙するファイルだそうで、下記のようなフォーマットで書くそうです。

<Process type>: <Command>

herokuでこのファイルを書く場合、Http通信のやりとりをするコマンドのに「web」を使えば良いそうです。実際にgunicornを使ってwsgi対応のWebアプリケーションとして実行する場合、下記のように書けば良いそうです。

web: gunicorn <mainにあたるスクリプトファイル(拡張子なし)>:app --preload --log-file=-

ここで、ポイントなのが--preloadオプション。herokuのtutorialでは無くても動くようなことが書いてあったのですが、私の環境だと動かなかったので、追加しました。

おわりに

今回は、herokuでWebアプリケーションを作るまでに躓いたところをまとめました。
デザインとかはお察しですが、そのうちもう少しマシにしようと思っています。