えぐろぐ

https://twitter.com/eggpogg

Vuex で変更通知が正常に動かなかったときのメモ

State の初期値を undefined で初期化するときに
以下は正常に変更通知を受け取れるが

export type StateType = { hoge?: Hoge}
export const state = (): StateType => ({
  hoge: undefined
})
export type ConfigState = ReturnType<typeof state>

以下は変更通知を受け取れない

export type StateType = { hoge?: Hoge}
export const state = (): StateType => ({})
export type ConfigState = ReturnType<typeof state>

色々とネットを見ていると以前は undefined の初期化でもだめだったぽい?

Intellij x husky x nodenv 時に pre-commit が失敗したときの対応

Intellij IDEA で日頃開発をしており、Project で npm の husky を使って、 pre-commit 時に lint チェックをしていたが、 Intellij 内の Git から commit をしたときだけ以下のエラーになりcommit が正常にできないことがあった。

※ terminal から git commit する場合は正常に動作する

12:42 Commit failed with error
  0 file committed, 8 files failed to commit: test
  error project-name@1.0.0: The engine "node" is incompatible with this module. Expected version ">=14.16.x". Got "14.8.x"
  error Commands cannot run with an incompatible environment.

node 14.8.x は mac の system node のバージョンだったので、 husky 実行時に nodenv による切り替えが正常に動作していないっぽい💦

調べると、 ~/.huskyrc に以下を記述すると nodenv で指定する node version で husky が実行されて解決した 👀

if command -v nodenv >/dev/null 2>&1; then
  eval "$(nodenv init -)"
fi

github.com

NestJS のMiddleware 内でModuleのServiceを使用する

たいした話ではないけど、実装中にハマったのでメモ 📝

MiddlewareはInjectableのデコレータをつけて、 NestMiddlewareをimplementsして、useメソッドを実装すれば使える Injectしたい値は他のControllerなどと同じで、constructorで設定をしてあげれば良い

// sample.middleware.ts

@Injectable
export class SampleMiddleware implements NestMiddleware {
  constructor(private readonly hogesService: HogseService) {}
  
  use(req: any, res: any, next: () => void) {
    this.hogesService.moge()
    next()
  }
}

Middleware | NestJS - A progressive Node.js framework

外部で使用されるクラスはModuleデコレータの
exportsに渡してあげれば外部で使用させることができる

@Module({
  exports: [HogseService],
})
export class HogesModule {}

Modules | NestJS - A progressive Node.js framework

TypeScript x Express x Session の実装

ちょくちょく express-session を使うのだけど実装方法を、
その都度調べながらやっているので、やり方をメモ... 📝

SessionOptionsを書き換えて使う

// session.ts

import * as express from 'express';
import * as ExpressSession from 'express-session';
import { createClient, RedisClient } from 'redis';
import * as connectRedis from 'connect-redis';

const redisClient: RedisClient = createClient({
  host: process.env.REDIS_HOST,
  port: parseInt(process.env.REDIS_PORT),
  prefix: process.env.REDIS_PREFIX,
});
const SessionRedisStore: connectRedis.RedisStore = connectRedis(ExpressSession);
const redisStore: connectRedis.RedisStore = new SessionRedisStore({
  client: redisClient,
});

const sessionOption: ExpressSession.SessionOptions = {
  secret: process.env.REDIS_SECRET,
  resave: true,
  saveUninitialized: false,
  store: redisStore,
};

const session: express.RequestHandler = ExpressSession(sessionOption);
export default session;

使い方

// index.ts

import session from './session'
const app = express()
app.use(session)

Nuxt x TypeScript で拡張関数の設定

TypeScriptで拡張関数を記述できることを知ったのでNuxtに組み込んでみた kakkoyakakko2.hatenablog.com

1度でも読み込まれれば良いので、  今回はPluginとして読み込ませるようにした

拡張ファイルを記述する 今回は1つだけだけど、複数増えるときはファイルを分けたほうがいいかも。

// ./plugins/extenstions.ts

export {}

declare global {
  interface Number {
    separatePrice: () => string
  }
}

Number.prototype.price = function(): string {
  return `¥${this}`
}

プラグインを読み込ませる

// ./nuxt.config.js

plugins: [ "~plugins/extenstions" ]

使うときは値を変数に代入後に使用できる

// ./page/index.vue

mounted() {
  const num = 100
  console.log(num.price()) // ¥100
},

自分で作ったカスタムクラスの場合は、それぞれのファイルで記述すればいいけど  プリミティブラッパーオブジェクト やDate , Array , Map とかのクラスはこっちで一元管理したほうが良さそう。

複数プロジェクトで使い回せるようにするにはnpm として管理だけど...それはのちのち...

久しぶりにOSS活動をした

DeepLAPIのAPIClientを作っているdeep-clientの日本語の値が
間違っていたのでPRを送ったら速攻でマージされた. github.com

送ったPR github.com

たいした修正ではないけど、
やはり承認欲求が得られて良い

ただ、久しぶりにOSS活動すると やり方を忘れるのでメモ

  1. CONTRIBUTE.md があれば読んで、対応する
  2. 無い場合はRepositoryをforkする
  3. ローカルでブランチを切って修正をする
  4. PushしてPRを作成すると、どのRepositoryのブランチにマージするか選べる
  5. master or main ブランチに修正内容を添えてPRを作って待つ。

Nuxt x TypeScript でVuetifyのComponentのメソッドの呼び出し方

VuetifyがまだTypeScriptに対応していない状態なので、
自分でVFormのinterfaceを作成をして、$refsの値をキャストすることで使用できる。

<template>
  <div>
    <v-form ref="form"></v-form>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

interface VForm extends Vue {
  reset(): void
  resetValidation(): void
  validate(): boolean
}

export default Vue.extend({
  mounted() {
    const form = this.$refs.form as VForm
    form.reset()
  },
})
</script>

使用できる関数は公式サイトを見るか vuetifyjs.com

実際にコードを見るか github.com

参考 github.com