フリーランス 技術調査ブログ

フリーランス/エンジニア Ruby Python Nodejs Vuejs React Dockerなどの調査技術調査の備忘録

nuxtjsでtypescriptを利用できるように設定してみる

参考ページ

  • 下記のサイトを参考に設定する

typescript.nuxtjs.org

typescriptの設定

  • インストール
# npm i @nuxt/typescript-build @nuxt/types @nuxt/typescript-runtime
  • nuxt.config.jsファイルのbuildModulesを下記のように修正する
  buildModules: [
    ['@nuxt/typescript-build', {
      typeCheck: true,
      ignoreNotFoundWarnings: true
    }]
  ],
  • tsconfig.jsonファイルを作成して下記のように記述する
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "ESNext",
    "moduleResolution": "Node",
    "lib": [
      "ESNext",
      "ESNext.AsyncIterable",
      "DOM"
    ],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "baseUrl": ".",
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@types/node",
      "@nuxt/types"
    ]
  },
  "exclude": [
    "node_modules"
  ]
}
  • vue-shim.d.tsファイルを作成して下記のように記述する
declare module "*.vue" {
  import Vue from 'vue'
  export default Vue
}
  • package.jsonを下記のように変更する
"scripts": {
  "dev": "nuxt-ts",
  "build": "nuxt-ts build",
  "generate": "nuxt-ts generate",
  "start": "nuxt-ts start"
},

eslintの設定

  • インストール
# npm i -D @nuxtjs/eslint-config-typescript
  • .eslintrc.jsファイルを作成して下記の記述をする
module.exports = {
  extends: [
    '@nuxtjs/eslint-config-typescript'
  ]
}
  • package.jsonファイルのsciprtの箇所に下記の記述を追加する
  "scripts": {
    "lint": "eslint --ext .ts,.js,.vue ."
  },

vercelでnuxtjs環境を作ってみる

手順

  1. vercelの設定をする前に自分のgithubアカウントでvercel用のリポジトリを作成する。privateでもpublicでも大丈夫そう。

  2. vercelでアカウントを作成する。※githubアカウント連携 vercel.com

  3. vercelでアカウント作成後、ログインする。clone templateをnuxtjsを選択する f:id:PX-WING:20210313233811p:plain

  4. アカウント連携したgithubアカウントを選択する f:id:PX-WING:20210313233824p:plain

  5. githubを選択する f:id:PX-WING:20210313233832p:plain

  6. git scopeのプルダウンでAdd GitHub Org or Accountを選択する f:id:PX-WING:20210313233851p:plain

  7. 最初に作成したvercel用のリポジトリを選択し、installボタンをクリックする f:id:PX-WING:20210313233914p:plain

  8. プロジェクト名とフレームワークを指定してdeployボタンをクリックする。プロジェクト名がサブドメイン名になります。 f:id:PX-WING:20210313233927p:plain

  9. 下記の画面が表示されたら設定が完了 f:id:PX-WING:20210313233944p:plain

動作確認

  • ブラウザで指定のURLにアクセスするとデフォルトのページが表示される f:id:PX-WING:20210313234111p:plain

djangoを使用した英文スペルチェックと文法チェック

参考ページ

gingerit.readthedocs.io

インストール

python -m pip install gingerit

実装

  • templateファイルはテキストエリアとボタンのみを用意する
 {{message}}
    <form action="/" method="post">
        {% csrf_token %}
        <textarea name="txt"></textarea>
        <input type="submit" value="送信">
    </form>
  • views.pyファイルの中身は
from django.shortcuts import render
from django.http import HttpResponse
from gingerit.gingerit import GingerIt

def index(request):

    if request.method == "POST":
        text = request.POST.get('txt')
        parser = GingerIt()
        result_dict = parser.parse(text)
        params = {
            'message': result_dict["result"],
        }
    else:
        params = {'message': '英文を入力してください'}
    return render(request, 'index.html', params)

実行結果

  • 間違った下記の文章を
The smelt of fliwers bring back memories.

下記に変更してくれた

The smell of flowers brings back memories.

でも何パターンか試してみると、あまりにもスペルミスしていると違う単語に解釈されて微妙な感じでした。

 その他

  • スペルチェックや文法チェックのライブラリは他にもあった github.com

www.guru99.com

djangoのtemplateを設定してみる

フォルダ構成

  • 下記の構成でプロジェクト全体で利用するテンプレートとアプリケーションで利用するテンプレートを使い分ける
├── application
│   ├── templates (アプリケーションのテンプレート)
│   │   └── index.html
│   └── views.py
├── templates (プロジェクト全体のテンプレート)
│   └── app
│       ├── base.html
│       ├── footer.html
│       └── header.html
└── project
    ├── settings.py

settings.py

  • DIRSパラメータの箇所にプロジェクト全体で利用するテンプレートフォルダのパスを指定する
import os

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'templates'),
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
( 〜 省略 〜)

プロジェクト全体のテンプレート

  • templates/app/base.html
<!doctype html>
<html lang="ja">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
    <title>{{ title }}</title>
  </head>
  <body>
        {% include "app/header.html" %}
        {% block content %}
        {% endblock %}
        {% include "app/footer.html" %}
  </body>
</html>
  • templates/app/header.html
<div class="w-full">
    <nav class="bg-white shadow-lg">
        <div class="md:flex items-center justify-between py-2 px-8 md:px-12">
            <div class="flex justify-between items-center">
               <div class="text-2xl font-bold text-gray-800 md:text-3xl">
                    <a href="#">Brand</a>
               </div>
                <div class="md:hidden">
                    <button type="button" class="block text-gray-800 hover:text-gray-700 focus:text-gray-700 focus:outline-none">
                        <svg class="h-6 w-6 fill-current" viewBox="0 0 24 24">
                            <path class="hidden" d="M16.24 14.83a1 1 0 0 1-1.41 1.41L12 13.41l-2.83 2.83a1 1 0 0 1-1.41-1.41L10.59 12 7.76 9.17a1 1 0 0 1 1.41-1.41L12 10.59l2.83-2.83a1 1 0 0 1 1.41 1.41L13.41 12l2.83 2.83z"/>
                            <path d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"/>
                        </svg>
                    </button>
                </div>
            </div>
            <div class="flex flex-col md:flex-row hidden md:block -mx-2">
                <a href="#" class="text-gray-800 rounded hover:bg-gray-900 hover:text-gray-100 hover:font-medium py-2 px-2 md:mx-2">Home</a>
                <a href="#" class="text-gray-800 rounded hover:bg-gray-900 hover:text-gray-100 hover:font-medium py-2 px-2 md:mx-2">About</a>
                <a href="#" class="text-gray-800 rounded hover:bg-gray-900 hover:text-gray-100 hover:font-medium py-2 px-2 md:mx-2">Contact</a>
            </div>
        </div>
    </nav>
    <div class="flex bg-white" style="height:600px;">
        <div class="flex items-center text-center lg:text-left px-8 md:px-12 lg:w-1/2">
            <div>
                <h2 class="text-3xl font-semibold text-gray-800 md:text-4xl">Build Your New <span class="text-indigo-600">Idea</span></h2>
                <p class="mt-2 text-sm text-gray-500 md:text-base">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis commodi cum cupiditate ducimus, fugit harum id necessitatibus odio quam quasi, quibusdam rem tempora voluptates. Cumque debitis dignissimos id quam vel!</p>
                <div class="flex justify-center lg:justify-start mt-6">
                    <a class="px-4 py-3 bg-gray-900 text-gray-200 text-xs font-semibold rounded hover:bg-gray-800" href="#">Get Started</a>
                    <a class="mx-4 px-4 py-3 bg-gray-300 text-gray-900 text-xs font-semibold rounded hover:bg-gray-400" href="#">Learn More</a>
                </div>
            </div>
        </div>
        <div class="hidden lg:block lg:w-1/2" style="clip-path:polygon(10% 0, 100% 0%, 100% 100%, 0 100%)">
            <div class="h-full object-cover" style="background-image: url(https://images.unsplash.com/photo-1498050108023-c5249f4df085?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1352&q=80)">
                <div class="h-full bg-black opacity-25"></div>
            </div>
        </div>
    </div>
</div>
  • templates/app/footer.html
<footer class="mt-16">
    <div class="max-w-screen-lg mx-auto border-none px-4">
      <section
        class="flex flex-col md:flex-row md:justify-between md:border-solid md:border-t text-gray-700 font-light text-sm pt-4 pb-6 md:pt-5 md:pb-6 w-full"
      >
        <div>
          <p class="leading-8 tracking-wide">
            &copy; hogehoge
          </p>
        </div>
        <div>
          <p class="leading-8 tracking-wide">Privacy Policy</p>
        </div>
      </section>
    </div>
  </footer>

アプリケーションのテンプレート

{% extends 'app/base.html' %}
{% block content %}
    <div>
        <section class="py-40 bg-gray-100  bg-opacity-50 h-screen">
            <div class="mx-auto container max-w-2xl md:w-3/4 shadow-md">
              <div class="bg-gray-100 p-4 border-t-2 bg-opacity-5 border-indigo-400 rounded-t">
                <div class="max-w-sm mx-auto md:w-full md:mx-0">
                  <div class="inline-flex items-center space-x-4">
                    <img
                      class="w-10 h-10 object-cover rounded-full"
                      alt="User avatar"
                      src="https://avatars3.githubusercontent.com/u/72724639?s=400&u=964a4803693899ad66a9229db55953a3dbaad5c6&v=4"
                    />
      
                    <h1 class="text-gray-600">Charly Olivas</h1>
                  </div>
                </div>
              </div>
              <div class="bg-white space-y-6">
                <div class="md:inline-flex space-y-4 md:space-y-0 w-full p-4 text-gray-500 items-center">
                  <h2 class="md:w-1/3 max-w-sm mx-auto">Account</h2>
                  <div class="md:w-2/3 max-w-sm mx-auto">
                    <label class="text-sm text-gray-400">Email</label>
                    <div class="w-full inline-flex border">
                      <div class="pt-2 w-1/12 bg-gray-100 bg-opacity-50">
                        <svg
                          fill="none"
                          class="w-6 text-gray-400 mx-auto"
                          viewBox="0 0 24 24"
                          stroke="currentColor"
                        >
                          <path
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            stroke-width="2"
                            d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
                          />
                        </svg>
                      </div>
                      <input
                        type="email"
                        class="w-11/12 focus:outline-none focus:text-gray-600 p-2"
                        placeholder="email@example.com"
                        disabled
                      />
                    </div>
                  </div>
                </div>
      
                <hr />
                <div class="md:inline-flex  space-y-4 md:space-y-0  w-full p-4 text-gray-500 items-center">
                  <h2 class="md:w-1/3 mx-auto max-w-sm">Personal info</h2>
                  <div class="md:w-2/3 mx-auto max-w-sm space-y-5">
                    <div>
                      <label class="text-sm text-gray-400">Full name</label>
                      <div class="w-full inline-flex border">
                        <div class="w-1/12 pt-2 bg-gray-100">
                          <svg
                            fill="none"
                            class="w-6 text-gray-400 mx-auto"
                            viewBox="0 0 24 24"
                            stroke="currentColor"
                          >
                            <path
                              stroke-linecap="round"
                              stroke-linejoin="round"
                              stroke-width="2"
                              d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
                            />
                          </svg>
                        </div>
                        <input
                          type="text"
                          class="w-11/12 focus:outline-none focus:text-gray-600 p-2"
                          placeholder="Charly Olivas"
                        />
                      </div>
                    </div>
                    <div>
                      <label class="text-sm text-gray-400">Phone number</label>
                      <div class="w-full inline-flex border">
                        <div class="pt-2 w-1/12 bg-gray-100">
                          <svg
                            fill="none"
                            class="w-6 text-gray-400 mx-auto"
                            viewBox="0 0 24 24"
                            stroke="currentColor"
                          >
                            <path
                              stroke-linecap="round"
                              stroke-linejoin="round"
                              stroke-width="2"
                              d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"
                            />
                          </svg>
                        </div>
                        <input
                          type="text"
                          class="w-11/12 focus:outline-none focus:text-gray-600 p-2"
                          placeholder="12341234"
                        />
                      </div>
                    </div>
                  </div>
                </div>
      
                <hr />
                <div class="md:inline-flex w-full space-y-4 md:space-y-0 p-8 text-gray-500 items-center">
                  <h2 class="md:w-4/12 max-w-sm mx-auto">Change password</h2>
      
                  <div class="md:w-5/12 w-full md:pl-9 max-w-sm mx-auto space-y-5 md:inline-flex pl-2">
                    <div class="w-full inline-flex border-b">
                      <div class="w-1/12 pt-2">
                        <svg
                          fill="none"
                          class="w-6 text-gray-400 mx-auto"
                          viewBox="0 0 24 24"
                          stroke="currentColor"
                        >
                          <path
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            stroke-width="2"
                            d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
                          />
                        </svg>
                      </div>
                      <input
                        type="password"
                        class="w-11/12 focus:outline-none focus:text-gray-600 p-2 ml-4"
                        placeholder="New"
                      />
                    </div>
                  </div>
      
                  <div class="md:w-3/12 text-center md:pl-6">
                    <button class="text-white w-full mx-auto max-w-sm rounded-md text-center bg-indigo-400 py-2 px-4 inline-flex items-center focus:outline-none md:float-right">
                      <svg
                        fill="none"
                        class="w-4 text-white mr-2"
                        viewBox="0 0 24 24"
                        stroke="currentColor"
                      >
                        <path
                          stroke-linecap="round"
                          stroke-linejoin="round"
                          stroke-width="2"
                          d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
                        />
                      </svg>
                      Update
                    </button>
                  </div>
                </div>
      
                <hr />
                <div class="w-full p-4 text-right text-gray-500">
                  <button class="inline-flex items-center focus:outline-none mr-4">
                    <svg
                      fill="none"
                      class="w-4 mr-2"
                      viewBox="0 0 24 24"
                      stroke="currentColor"
                    >
                      <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
                      />
                    </svg>
                    Delete account
                  </button>
                </div>
              </div>
            </div>
          </section>        
    </div>    
{% endblock %}
  • アプリケーションのview.pyからテンプレートを呼び出す
from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    params = {
        'message': "aaaa",
    }
    return render(request, 'index.html', params)

参考

コーディング時に便利なChrome拡張機能

Pesticide for Chrome (without hover bar)

  • 要素に枠線が付くのでコーディングしている時にレイアウト崩れの原因や、わざわざ要素にborderを指定しなくても良いので便利 chrome.google.com

実行結果

f:id:PX-WING:20210310224933p:plain

DevTools z-index

  • 開発者ツールのElementsタブ内にz-indexが追加される  追加されているz-indexタブをクリックすると、z-indexの値と要素の一覧が、値の大きい順に並んでいます。

chrome.google.com

実行結果

f:id:PX-WING:20210310225639p:plain

Lighthouse

  • サイトの表示速度やセキュリティチェックを行ってくれるライブラリ

chrome.google.com

実行結果

f:id:PX-WING:20210310230125p:plain

Djangoの設定ファイルをenvファイルで管理する

利用用途

  • settings.pyにデータベースやセキュリティトークンの情報が記載されているのはあまり良くないため、envファイルで管理できるようにする

settings.pyファイルの設定(デフォルト)

  • djangoのデフォルトの設定ファイルは下記のようにsettings.pyファイルにベタ書きされているので、gitにアップするとそのままパスワードの情報などアップされてしまう。
 # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '<シークレットキー>'
 
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': '<DB>',
    'USER': '<ユーザー名>',
    'PASSWORD': '<パスワード>',
    'HOST': '<ホスト名>',
    'PORT': '3306',
  }
}

 インストール

  • 必要なパッケージ
python3.9 -m pip install python-decouple
python3.9 -m pip install dj_database_url

envファイルで管理する

  • .envファイルを作成する
SECRET_KEY=<シークレットキー>
DEBUG=False
DATABASE_URL=mysql://<ユーザー名>:<パスワード>@<ホスト名>:3306/<DB>

settings.pyファイルの設定(envを参照した場合)

  • 下記のように記述を変更することで.envファイルで管理することができる。
from decouple import config
import dj_database_url

SECRET_KEY = config('SECRET_KEY')

DEBUG = config('DEBUG')

DATABASES = {
  'default': dj_database_url.config(
    default=config('DATABASE_URL')
  )
}

django-tailwindを試してみる/djangoのコマンドを調べる

django-tailwind

  • 下記のパッケージをインストールして試してみる。 github.com

インストール

python3.9 -m pip install django-tailwind

設定

ー 下記のコマンドを実行する

# python3.9 manage.py tailwind init theme
Tailwind application 'theme' has been successfully created. Please add 'theme' to INSTALLED_APPS in settings.py.
  • settings.pyファイルにtailwindthemeを追加する
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tailwind',
    'theme'
]

TAILWIND_APP_NAME = 'theme'
  • 下記のコマンドを実行した時にnodeをインストールしてくださいというメッセージが出力されたので、このパッケージを利用する意味がないので、
# python3.9 manage.py tailwind install

CommandError: 
It looks like node.js and/or npm is not installed or cannot be found.

Visit https://nodejs.org to download and install node.js for your system.

If you have npm installed and still getting this error message, set NPM_BIN_PATH variable in settings.py to match path of NPM executable in your system.

Example:
NPM_BIN_PATH = "/usr/local/bin/npm"
                      
  • CDN指定するか、
<head>
  ...
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
  ...
</head>

nodeをインストールして下記のページを参考に設定した方が良さそです。 stackoverflow.com

djangoコマンド

startproject

  • プロジェクトを作成する
$ python3.9 manage.py startproject myproj

dbshell

  • データベースの接続確認と実際にDBに接続できる
$ python3.9 manage.py dbshell

migrage

$ python3.9 manage.py migrate

createsuperuser

  • 管理者サイトのためのスーパーユーザーを作成します。
$ python3.9 manage.py createsuperuser

startapp

  • アプリケーション作成
$ python3.9 manage.py startapp accounts

makemigrations

  • アプリケーションのmodels.py を探索してデータベースのマイグレーションファイルを作成します。
$ python3.9 manage.py startapp accounts

runserver

  • サーバー起動
# python3.9 manage.py runserver 0:8000