Vue Composition APIを試す

Composition APIを使用すれば、同じ論理的な関心事に関連するコードを並べることが出来る?可読性が良くなる?良くわからないけど、前にVue 2で書いたコードを書き換えてみる。

このドキュメントでは実際にどのように変更したかをメインに記載する。

ログイン画面(Login.vue)の例

・Vue 2
一見シンプルに見えるけれども、thisで参照するものが多すぎて、何が使えて、何が使えないのか、後から見るとわかりづらい。

<script>
import {AUTH_REQUEST} from '@/store/actions/auth'

export default {
  data () {
    return {
      username: '',
      password: '',
    }
  },
  methods: {
    login: function () {
      const { username, password } = this
      this.$store.dispatch(AUTH_REQUEST, { username, password }).then(() => {
        this.$router.push(this.$route.query.redirect || '/')
      }).catch(error => {
        this.$message({
          showClose: true,
          message: error,
          type: 'error'
        })
      })
    }
  }
}
</script>

・Vue 3.2
Vue 2で必要だった独特な書き方がなくなって、一般的なJavaScriptの書き方になっている。インポート、宣言部、関数とわかれていて、わかりやすくなっているように感じる。

<script setup>
import { reactive } from 'vue'
import { useStore } from 'vuex'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { AUTH_REQUEST } from '@/store/actions/auth'

const store = useStore()
const router = useRouter()
const route = useRoute()

const state = reactive({
  username: '',
  password: ''
})

function login() {
  const { username, password } = state
  store.dispatch(AUTH_REQUEST, { username, password }).then(() => {
    router.push(route.query.redirect || '/')
  }).catch(error => {
    ElMessage({
      message: error,
      grouping: true,
      type: 'error'
    })
  })
}
</script>

Raspberry Pi 4 Model Bを設定する

やりたいこと

Raspberry Pi OS動かして、デスクトップ画面を表示する。

Raspberry Pi 4を購入する

今は品薄で、なかなか手が入らない。仕方がないので必要なものが揃っている下記を購入した。

Raspberry Pi OSをインストールする

下記からRaspberry Pi Imagerをダウンロードしてインストールする。
https://www.raspberrypi.com/software/

SDカードを挿入し、Raspberry Pi Imagerを起動して、OS選択し下記の通り実行する。

OSをインストールしたSDカードをRaspberry Piに挿入し電源を入れる。

※4/21追記
コンパクトなキーボードとマウスが欲しかったので下記を購入した。USBレシーバーも付属しているので、互換性を気にしなくて良く、すぐ使用できる点が気に入った。

Unreal Engine 5をインストールしてCity Sampleを見てみたい

Unreal Engine 5のCity Sampleとは何か

The Matrix Awakens: An Unreal Engine 5 Experienceの技術デモはPlayStation 5 と Xbox Series X/Sでしか公開されていなかったが、Unreal Engine 5が先日リリースされ、この都市シーンをPC上で動かしてみることが出来るようになった。(ただし、Matrix関係のコンテンツは含まれない)

City Sample をインストールする

Epic Gamesから、Unreal Engine 5をダウンロードし、インストールする。(Epic Games Launcherが必要になる)

Unreal EngineのマーケットプレイスからCityサンプルを探して入手する。

ライブラリのマイダウンロードにあるCityサンプルから、プロジェクトを作成する。

Cityサンプルの容量は約93GB程あるので、ダウンロードに時間がかかる。

Unreal Engineは全く触ったことがないので、サンプル起動後Small Cityをロードしてみた。

プレビューで動かすことは出来たけど、この後パッケージするにはどうしたら良いのだろう。

※追記:パッケージ化出来るようになった。
1.勝手に日本語化されていたタイトルの2バイト文字を1バイト文字に変更(Cityサンプル→CitySample)。
2.下記から.NET Core 3.1 ランタイムをダウンロードしてインストール。
https://aka.ms/dotnet-core-applaunch?framework=Microsoft.WindowsDesktop.App&framework_version=3.1.0&arch=x64&rid=win10-x64

Spring Boot 2.6でHibernate Search 6を動かす

依存関係

implementation 'org.hibernate.search:hibernate-search-mapper-orm:6.1.4.Final'
implementation 'org.hibernate.search:hibernate-search-backend-lucene:6.1.4.Final'

実装

Entityクラスに@Indexed、メソッドに@FullTextFieldを追加する。

@Entity
@Table(name = "novel")
@Indexed
public class Novel implements Serializable {

...

    @FullTextField
    private String title;

Serviceクラスに検索処理のロジックを追加する。

@Service
public class NovelService {

...

    @Transactional
    public Stream<Novel> searchIndex(final String searchParameters) {
        SearchSession searchSession = Search.session(entityManager);

        SearchResult<Novel> result = searchSession.search(Novel.class)
                .where(f -> f.bool()
                        .must(f.match()
                                .field("title")
                                .matching("異世界")))
                .fetchAll();
        return result.hits().stream();
    }

実際に動くコードはGitHubに公開予定。公開完了したら、下記に追記する。

※4/22追記
NovelService.java – github

public Stream<Novel> searchIndex(final String searchParameters) {
    SearchSession searchSession = Search.session(entityManager);
    String operationSetExper = String.join("|", SearchOperation.SIMPLE_OPERATION_SET);
    Pattern pattern = Pattern.compile(
            "(\\p{Punct}?)(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),",
            Pattern.UNICODE_CHARACTER_CLASS);
    Matcher matcher = pattern.matcher(searchParameters + ",");

    SearchResult<Novel> result = searchSession.search(Novel.class)
            .where(f -> f.bool(b -> {
                b.must(f.matchAll());
                while (matcher.find()) {
                    b.must(f.match().field(matcher.group(KEY))
                            .matching(matcher.group(VALUE)));
                }
            }))
            .fetchAll();

    return result.hits().stream();
}

Spring BootでLuceneAnalysisConfigurerがうまく動かなかった件

Spring Boot 2.6はHibernate Search 6に対応している。そこで、日本語の検索も出来るようにするため、lucene-analyzers-kuromojiのAnalyzerをLuceneAnalysisConfigurerで設定しようとした。しかし、公式のガイド通りやってもうまくいかなかったため、メモを残しておく。

依存関係

implementation 'org.apache.lucene:lucene-analyzers-kuromoji:8.11.1'
implementation 'org.hibernate.search:hibernate-search-mapper-orm:6.1.4.Final'
implementation 'org.hibernate.search:hibernate-search-backend-lucene:6.1.4.Final'

LuceneAnalysisConfigurerの実装

@Component("customLuceneAnalysisConfigurer")
public class CustomLuceneAnalysisConfigurer implements LuceneAnalysisConfigurer {

    /**
     * {@inheritDoc}
     */
    @Override
    public void configure(LuceneAnalysisConfigurationContext context) {
        context.analyzer("japanese").instance(new JapaneseAnalyzer());
    }
}

CustomLuceneAnalysisConfigurerの設定

公式の例では、実装したクラスを直接crawlerapi.config.CustomLuceneAnalysisConfigurerのように指定していたのだが、上記のようにComponentとして登録してから、下記のように参照するようにしないとSpring Bootの起動でハングアップした。

spring:
  jpa:
    properties:
      hibernate:
        search.backend:
          analysis.configurer: customLuceneAnalysisConfigurer

設定したAnalyzerの使用方法

先ほど定義した名前で参照できる。

@FullTextField(analyzer = "japanese")

element-ui 2からelement-plus 2にアップグレードする

今まではelement-ui 2を使用していたが、今後はVue 3に対応しているelement-plus 2を使用する。変更点のメモを残しておく。

element-ui 2の依存関係

"element-ui": "^2.15.6",

element-plus 2の依存関係

"@element-plus/icons-vue": "^1.1.4",
"element-plus": "^2.1.8",

element-ui 2の初期設定

import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import locale from 'element-ui/lib/locale/lang/ja'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI, {locale})

new Vue({
  render: h => h(App)
}).$mount('#app')

element-plus 2の初期設定

import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import locale from 'element-plus/lib/locale/lang/ja'
import 'element-plus/dist/index.css'

const app = createApp(App)

app.use(ElementPlus, {locale})

app.mount('#app')

vee-validate 3から4にアップグレードする

APIが完全に変わったため、マイグレーションガイドは存在しないらしい。変更点のメモを残しておく。

vee-validate 3の依存関係

"vee-validate": "^3.4.13",

vee-validate 4の依存関係

"@vee-validate/i18n": "^4.5.10",
"@vee-validate/rules": "^4.5.10",
"vee-validate": "^4.5.10",

vee-validate 3の初期設定

import Vue from "vue"
import { extend, localize } from "vee-validate"
import { required, max, email } from "vee-validate/dist/rules"
import en from "vee-validate/dist/locale/en.json"
import ja from "vee-validate/dist/locale/ja.json"
import enNames from '../locale/enNames.json'
import jaNames from '../locale/jaNames.json'

extend("required", required)
extend("max", max)
extend("email", email)

localize({
  en: {
    messages: en.messages,
    names: enNames
  },
  ja: {
    messages: ja.messages,
    names: jaNames
  }
})

let LOCALE = "ja"

Object.defineProperty(Vue.prototype, "locale", {
  get() {
    return LOCALE
  },
  set(val) {
    LOCALE = val
    localize(val)
  }
})

vee-validate 4の初期設定

import { defineRule, configure } from 'vee-validate';
import { required, max, email } from '@vee-validate/rules';
import { localize, setLocale } from '@vee-validate/i18n';
import en from '@vee-validate/i18n/dist/locale/en.json';
import ja from '@vee-validate/i18n/dist/locale/ja.json';
import enNames from '../locales/enNames.json'
import jaNames from '../locales/jaNames.json'

defineRule('required', required)
defineRule('max', max)
defineRule('email', email)

const customLocalize = localize({
  en: {
    messages: en.messages,
    names: enNames
  },
  ja: {
    messages: ja.messages,
    names: jaNames
  }
})

setLocale('ja')

configure({
  generateMessage: customLocalize
})

vee-validate 3の使用方法

<template>
  <ValidationObserver
    ref="observer"
    v-slot="{ passes }"
  >
    <el-form
      ref="form"
      class="login"
    >
      <h2>Sign up</h2>
      <ValidationProvider
        name="username"
        rules="required|max:16"
        v-slot="{ errors }"
      >
        <el-form-item
          :error="errors[0]"
          class="input-form-wrapper"
        >
          <el-input
            type="text"
            placeholder="Username"
            v-model="username"
          />
        </el-form-item>
      </ValidationProvider>
      <el-button
        type="primary"
        @click="passes(signup)"
      >Signup</el-button>
<script>
import { ValidationProvider, ValidationObserver } from "vee-validate"

export default {
  components: {
    ValidationProvider,
    ValidationObserver
  },
  methods: {
    signup: function () {
      const { username, password, email } = this

vee-validate 4の使用方法

※vee-validate以外にも、element-uiからelement-plusに変更している。element-plusの変更点については、こちらを参照のこと。

<template>
  <Form
    as="el-form"
    :validation-schema="schema"
    @submit="onSubmit"
  >
    <h2>Sign up</h2>
    <Field
      name="username"
      v-slot="{ value, field, errorMessage }"
    >
      <el-form-item
        :error="errorMessage"
        class="input-form-wrapper"
      >
        <el-input
          type="text"
          placeholder="Username"
          v-bind="field"
          :model-value="value"
        />
      </el-form-item>
    </Field>
<script setup>
import { Field, Form } from "vee-validate";

const schema = {
  username: 'required|max:16'
}

function onSubmit(values) {
  const { username, password, email } = values

記述量が減って良いと思う。

WordPressのパーマリンクに日付や投稿名を指定すると404になる場合の対処法

新規に環境を構築したとき、いつものようにパーマリンクを日付と投稿名にすると、リンクが404エラーになってしまうことがある。リンクに日付や投稿名を設定する機能はmod_rewriteによって実行されているため、以下の通り有効にする必要がある。

mod_rewriteの有効化

sudo a2enmod rewrite

.htaccessを使った設定の上書きを許可

httpd.conf内の該当Directory設定のAllowOverrideをallに変更する。

<Directory /var/www/>
	Options Indexes FollowSymLinks
	AllowOverride all
	Require all granted
</Directory>

さらに、Wordpressをインストールしたフォルダの書き込み権限があることを確認する。Wordpressによってフォルダ下の.htaccessにrewriteの設定が自動的に作成されることになるため、書き込み権限が必要になる。

例えばパーマリンクを日付と投稿名に変更すると、下記のように.htaccessが自動生成される。

# BEGIN WordPress
# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は
# 動的に生成され、WordPress フィルターによってのみ修正が可能です。
# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /wordpress/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wordpress/index.php [L]
</IfModule>

# END WordPress

Amazon Web Services(AWS)でWordPressを動かす

1.やりたいこと

AWSの無料利用枠を利用して、Wordpress環境を構築し、インターネットに公開する。

2.AWSのアカウント作成

メールアドレスと、クレジットカードが必要になるため、事前に用意しておく。メールアドレスはフリーのアドレスで大丈夫だった。

下記の「無料アカウントを作成」をクリックし、指示通り入力を進める。
https://aws.amazon.com/jp/free/

3.Wordpressの実行に必要なもの

  • Linuxサーバー
    • apache(Wordpressをインストールする)
    • mysql(Wordpressの記事を保存する)

Linuxサーバーの構築

Amazon Elastic Compute Cloud (Amazon EC2) はアカウント登録から12か月無料でサーバーを借りることが出来る。「無料利用枠の対象」と表記のあるLinuxサーバーであればどれでもよい。

最初の設定は全てデフォルトで良いが、セキュリティグループの設定でSSHによるアクセスを許可する場合は、警告文にある通りアクセスを制限することを検討したほうが良い。

最後に画面の指示通りにSSHでアクセスするためのキーペアを作成する。これはSSHで接続するとき必要になるため、作成後必ずダウンロードしておく。

apache、phpのインストールと設定

sudo apt install apache2
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2ensite default-ssl
sudo apt install php libapache2-mod-php
sudo apt install php-fpm php-common php-mbstring php-xmlrpc php-gd php-xml php-mysql php-cli php-zip php-curl php-imagick

WordPressのパーマリンクに日付と投稿名を使用するため、.htaccessによる設定の上書きを有効にする。下記の通り、httpd.confのAllowOverrideをallに変更する。

<Directory /var/www/>
	Options Indexes FollowSymLinks
	AllowOverride all
	Require all granted
</Directory>

設定を有効にするため、apacheを再起動する。

sudo service apache2 restart

DBサーバーの追加

Amazon RDSを使用する。こちらも無料利用枠があるのでMariaDBを選択した。

DBインスタンス識別子はわかりやすいように変更しておく。

追加設定を開き最初のデータベース名を入力する。これを設定しておくと環境構築時にデータベースの作成まで行ってくれる。

データベースの作成には少々時間がかかるので、気長に待つ。その間にデータベース用のセキュリティグループを作成する。

セキュリティグループの作成

セキュリティグループのインバウンドルールにMysqlの許可を追加する。外部からアクセスさせる必要はないので、ソースに先ほど作成したEC2のセキュリティグループを指定して、EC2サーバーからのみアクセス出来るように制限する。

データベースの作成とセキュリティグループの設定が終わったら、両者を忘れずに紐付る。

4.Wordpressのインストール

作成したEc2サーバーからAmazon RDSにアクセスし、Wordpressデータベースアクセス用のユーザを作成する。

export MYSQL_HOST=wordpress.作成したAmazon RDSのエンドポイント参照.rds.amazonaws.com
mysql -u ユーザー名 -p wordpress
 CREATE USER 'wordpress' IDENTIFIED BY 'パスワード';
 GRANT SELECT, UPDATE, DELETE, INSERT, CREATE, DROP, INDEX, ALTER, LOCK TABLES, EXECUTE, CREATE TEMPORARY TABLES, TRIGGER, CREATE VIEW, SHOW VIEW, EVENT ON wordpress.* TO wordpress;
 FLUSH PRIVILEGES;

WordPressはダウンロードして、解凍するだけで良い。

5.動作確認

一時的にEC2にアクセス出来るようにする。先ほど作成したEC2サーバーのセキュリティグループを選択し、インバウンドルールの編集から80ポートのアクセス許可を追加する。

アクセスに必要なパブリックIPやDNSはインスタンス概要に記載がある。

今回はここまで。Wordpressを動かすだけであれば、これだけで良いが、本番運用するには、まだいくつか設定が必要になる。

Pythonの開発環境をWSLで構築するまで

Windows の機能の有効化または無効化を開き、仮想マシンプラットフォームを有効にする。

Power Shellを管理者権限で起動する。WSL2にUbuntuの構成で良ければ以下のコマンドを実行するだけで良い。

wsl --install

Windowsの再起動後、インストールしたUbuntuを更新する。

sudo apt update
sudo apt upgrade

Pythonをインストール。

sudo apt install -y python3 python3-pip

Download Visual Studio CodeからWindows用インストーラーをダウンロードし、インストールする。

Ubuntu上で以下を実行する。

code ./<作業フォルダ>

WSLにリンクした状態でVisual Studio Codeが起動する。