個人サイトを作り直した

「個人サイト」ってなんか良い響きですよね。これまでは「ポートフォリオサイト」として作っていたんですが、就活が終わったのを機に作り直してみました。

はじめに

サイト自体はVue.js + Vuetify + VueRouterのSPA。サイト自体は静的サイトで、後述のスライド一覧ページのために Google Apps Scritpで建てたAPIを叩いています。ホスティングはさくらのVPSで、WebサーバーはCaddyです。GitHub Pagesで十分ではあるんだけども、自分でやった方が楽しい。

作ったサイトはこちら。w-haibara

GitHubはこちら。 github.com

全体構成

なるべくシンプルになるようにした。

  • 色:白背景に黒文字で、アイコンの色はblue-grey darken-5を指定した。aタグの色は指定せずにデフォルトの青にした。
  • フォント:Google FontsのSource Code Pro。 Google Fonts
  • ヘッダはサイトタイトルと各画面へのリンクのみ。
  • フッタはGitHubレポジトリへのリンクと権利表記のみ。
  • 画面は以下の6つ。
    • /profile:プロフィールページ
    • /logs:活動履歴ページ
    • /works:制作物ページ
    • /slides:スライド一覧ページ
    • /slides/:id:スライド閲覧ページ (idはGoogle SlidesのファイルID)
    • *:NotFound

色やフォントの設定、ヘッダとフッタの記述はApp.vueでしている。

w-haibara.com/App.vue at dev · w-haibara/w-haibara.com · GitHub

/profile:プロフィールページ

プロフィールのページ。router/index.jsで、/から/#/profileにリダイレクトするように設定している。

f:id:w_haibara:20210506141639p:plain
プロフィールページ (/profile)

リンクのホバーアクションを追加したりして、ちょっと遊んでいる。

w-haibara.com/Profile.vue at dev · w-haibara/w-haibara.com · GitHub

/logs:活動履歴ページ

活動履歴のページ。

f:id:w_haibara:20210506141728p:plain
活動履歴 (/logs)

w-haibara.com/Logs.vue at dev · w-haibara/w-haibara.com · GitHub

/works:制作物ページ

制作物のページ。

f:id:w_haibara:20210506141812p:plain
制作物 (/works)

w-haibara.com/Works.vue at dev · w-haibara/w-haibara.com · GitHub

/slides:スライド一覧ページ

スライド一覧のページ。

f:id:w_haibara:20210506141844p:plain
スライド一覧 (/slides)

GASからスライドの情報を取得する

このページでは、公開しているスライドを一覧表示します。このスライドの情報はAPIで取ってくることにしました。 僕はスライドをGoogle Slidesで作っているので、元々Google Drive上にスライドのデータがあります。そのため、Google Drive上にスライド公開用のフォルダを作り、GASでそのフォルダ内のファイル(スライド)の情報を返すAPIを作りました。

// HTTP GETリクエストで発火
function doGet() {
  // 公開用フォルダ内のファイル情報を取得
  let data = [];
  const files = DriveApp.getFolderById("<フォルダのID>").getFiles();
  while (files.hasNext()) {
    const file = files.next();
    data.push({
      "title": file.getName(), // ファイル名
      "url": file.getUrl(), // 共有URL
      "id": file.getId(), // ファイルID
      "created": formatDate(file.getDateCreated()), // ファイル作成日時
    });
  }

  // ファイルの作成日時が新しい順にソート
  data.sort(function (a, b) {
    if (a.created > b.created) return -1;
    if (a.created < b.created) return 1;
    return 0;
  });

  // dataをjsonとして返す
  const json = JSON.stringify(data);
  const output = ContentService.createTextOutput(json);
  output.setMimeType(ContentService.MimeType.JSON);
  return output;
}

// date --> yy-mm-dd
function formatDate(date) {
  var d = new Date(date),
    month = '' + (d.getMonth() + 1),
    day = '' + d.getDate(),
    year = d.getFullYear();

  if (month.length < 2)
    month = '0' + month;
  if (day.length < 2)
    day = '0' + day;

  return [year, month, day].join('-');
}

公開したいスライドを公開用フォルダに入れるだけで、スライド一覧ページの内容も更新されます。

lscacheでAPIで取得したデータをキャッシュする

スライド一覧をAPIで取得するようにしたのはいいんですが、このままでは/slidesを表示する度に通信が発生します。そのため、lscasheというライブラリを使ってキャッシュするようにしました。

github.com

lscasheはブラウザのローカルストレージを期限付きのキャッシュとして扱いやすくしてくれるライブラリです。lscacheを使って、APIで取得したデータを24時間キャッシュするようにしました。

w-haibara.com/Slides.vue at dev · w-haibara/w-haibara.com · GitHub

/slides/:id:スライド閲覧ページ

スライド一覧ページのスライドを閲覧するためのページ。URLの:idGoogle SlidesのファイルIDです。

f:id:w_haibara:20210506141941p:plain
スライド閲覧ページ (/slides/:id)

Google Slidesの編集画面で「Webに共有」を選ぶと、iframeでスライドを埋め込むコードスニペットが表示されます。このスニペットのURLをそれぞれのファイルIDに置き換えることで、サイトにスライドを埋め込んでいます (別途、高さの指定などをしています)。スライドがピッタリ収まっていて気持ちいいですね。

ファイルIDは、このページのURLの:idから取得しています。そのため、このままでは他人のGoogle SlidesのファイルIDを指定してURLを叩けば、そのスライドが表示されてしまいます。これは望ましくないので、こちらでも先ほどのGASのAPIからスライド一覧のデータを取得し、一覧にないIDは無効として表示しないようにしています。

w-haibara.com/SlideView.vue at dev · w-haibara/w-haibara.com · GitHub

NotFound

NotFoundページです。無効なURLを叩くと、このページにリダイレクトされます。

f:id:w_haibara:20210506142053p:plain
Not Found

このサイトではVueRouterの設定でhashモードを使っているので、w-haibara.com/hogeのように存在しないがフラグメントで指定されていないような場合には、Webサーバー側でハンドルされます。 そのため、Caddyfileに以下を追加しました。

handle_errors {
      @404 {
        expression {http.error.status_code} == 404
      }
      redir @404 https://w-haibara.com/#/NotFound
    }

これで404ページとしても、このNotFoundを表示することができます。

おわりに

次はデプロイの自動化をいい感じにする。