Day35
Expressでの画像出力を試した。ついでにルーティング周り改めて調べてみたけど色々面白いメソッドがある。formatとか。
res.format({
text: function(){
res.send('hey');
},
html: function(){
res.send('<p>hey</p>');
},
json: function(){
res.send({ message: 'hey' });
}
});
Day34
記事ページをCDN通すようにした。来週まで様子見る。もしかしたら一体何をやってるのかほとんど誰にも通じてないかもしれないが、まあとりあえず記事書いていく。
まあこんな感じでテンプレート直書きで認証チェックはやめて全部Storeからのチェックにしてある。
- @if ($post->user_id && Auth::id() == $post->user_id)
- <div class="text-muted">
- {{ number_format($post->access_count) }} views
- </div>
- @endif
+ <access-count></access-count>
Day33
ログイン後に認証情報をStoreにわたすようにした。リダイレクトすると渡せないので画面を表示して渡したらjs側でリダイレクト。その間ローディングを出すのでBootstrapで中央に表示。(メンテすることもないので雑に直接書いた…)
<div style="position: relative; height:100%;">
<div style="position:absolute; top:50%; transform: translateX(-50%)
translateY(-50%); left:50%;">
<div
class="spinner-border"
style="width: 3rem; height: 3rem;"
role="status"
>
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
Day32
Laravelのテンプレートに直でログインによる分岐を入れているところをひたすらコンポーネント化してStoreの情報で分岐するようにしている。大変…。
例えばなんかこんな感じでVueテンプレート内でisLoginが使えるようになる。
import { Vue, Component, Prop } from 'vue-property-decorator'
import { mapGetters } from 'vuex'
@Component({
computed: {
...mapGetters('auth', ['isLogin'])
}
})
export default class MuComponent extends Vue {
Day31
こんな感じの関数でNuxt.jsにわたすhead用のオブジェクトを作成している。
export interface CreateHeadOptions {
title?: string
description?: string
image?: string
}
export function createHead(options: CreateHeadOptions) {
const head: any = { meta: [] }
if (options.title) {
const title = `${options.title} - 質問サービスタイトル未定`
head.title = title
head.meta.push({ hid: 'og:title', property: 'og:title', content: title })
}
Day30
質問サービスの画像アップロードを作った。Cloud Storageへ。
async upload(filePath: string) {
const storage = new Storage({ projectId: process.env.GCP_PROJECT_ID })
await storage
.bucket(<string>process.env.STORAGE_BUCKET)
.upload(filePath, {
destination: this.path,
gzip: true,
metadata: {
cacheControl: 'public, max-age=31536000'
}
})
}
Day29
質問サービスの残っているページ対応を進めて大まかにはできてきた。
TypeORMでの回答数集計のコードとか。
async updateAnswerCount() {
this.answerCount = await Answer.count({ question: this })
await this.save()
}
Day28
質問サービスの質問登録や詳細画面を作った。登録処理とか。(実際には認証チェック必要)
const question = Question.create(req.body.question)
question.uniqueId = uuidv1()
question.user = await User.findOne(req.session.passport.user.id)
await question.save()
res.json({ question: question.toJson() })
Day27
Day26
auto increment付きのprimary keyはこんな感じになってる。マニュアルにもないけどとにかくsyncして生SQLでやれって方針?
{
name: 'id',
type: 'int',
isPrimary: true,
isGenerated: true,
generationStrategy: 'increment'
},
Day25
とりあえずormconfigのentitiesのパスは下記のようにして決めてる。なぜビルドフォルダ内のormconfigを見てくれないのか…。
let path = 'src';
if (process.env.NODE_ENV == 'production') {
path = 'build/' + path
}
module.exports = {
entities: [
`${path}/entity/**/*{.ts,.js}`
],
migrations: [
`${path}/migration/**/*{.ts,.js}`
],
subscribers: [
`${path}/subscriber/**/*{.ts,.js}`
],
Day24
コードは書いていないが、Angularの周辺環境について復習がてらいろいろ調べた。Component LibraryやSSRやPWAなど。
Day23
記事に画像がない場合にOGPを自動生成するようにした。
UbuntuのOGPサーバー内でダウンロードしてきたフォントを/usr/share/fonts/opentype
にコピーし、fc-cache -f -v
で有効化。fc-list
でフォント一覧を見ることができるのでそこに書かれているフォント名をCSSのfont-familyに指定。
Day22
puppeteerサーバーに不正アクセスが大量に来てクラッシュするので特定のURLでしか動作しないように調整した。
function isValidPath(path) {
if (!process.env.URL_FILTER || process.env.URL_FILTER == '') {
return true
}
const validUrls = process.env.URL_FILTER.split(/,/)
return (
validUrls.find(validUrl => path.substr(0, validUrl.length) === validUrl) !==
undefined
)
}
Day21
ボード詳細ページにブログみたいな月毎の集計を追加した。全然知らなかったけどLaravelのCacheには(モデルにもついてるみたい)remember的なメソッドがあってキャッシュがなければクロージャを実行して値取得、みたいな便利なことができた。
$monthSummary = Cache::remember($key, $minutes, function () use ($board) {
return $board->getMonthSummary();
});
分を指定しないrememberForeverもある。