ひさびさに新規でNuxtアプリを作ろうと思ったら、
いろいろ変わっていたので、備忘用のまとめ。
(時間がなかったので割と雑め...いつかきれいに加筆する予定...)
ソースコード
自分用のスタータになるようにGitHubで公開してみた。 (この記事の執筆時よりも変わっていくと思います...)
プロジェクト作成
# 雛形の作成 $ npx create-nuxt-app <project_name> # GitとGitFlowの初期化 $ cd <project_name> $ git init $ git flow init # giboでgitignoreを生成 $ gibo dump Vim macOS VisualStudioCode Node > .gitignore # remoteの設定 $ git remote add origin git@github.com:memory-lovers/<project_name>.git $ git push -u origin --all
参考: ・インストール - NuxtJS ・simonwhitaker/gibo: Easy access to gitignore boilerplates
TypeScriptの設定(ビルド)
パッケージのインストール
$ npm install --save-dev @nuxt/typescript-build
nuxt.config.jsの設定
// nuxt.config.js export default { buildModules: ['@nuxt/typescript-build'] }
tsconfig.jsonの作成
// tsconfig.json { "compilerOptions": { "target": "esnext", "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"] }
TypeScriptの設定(ランタイム)
パッケージのインストール
$ npm install @nuxt/typescript-runtime
package.jsonでnuxt-tsを使うように変更
"scripts": { - "dev": "nuxt", - "build": "nuxt build", - "start": "nuxt start", - "generate": "nuxt generate" + "dev": "nuxt-ts", + "build": "nuxt-ts build", + "start": "nuxt-ts start", + "generate": "nuxt-ts generate" },
nuxt.configをts化
ファイル名を.jsから.tsに変えつつ、中身も変える。
昔はNuxtConfiguration
だったけど、Configuration
に変わってた。。
+import { Configuration } from "@nuxt/types"; +require("dotenv").config(); -export default { +const config: Configuration = { mode: "universal", }; +export default config;
nuxt-property-decoratorを入れる
Nuxt TypeScriptのCookbookにあるコンポーネントより。
Class APIがすきなので、nuxt-property-decoratorを入れる
# See: https://typescript.nuxtjs.org/ja/cookbook/components/#script $ npm install nuxt-property-decorator
デコレータを使う場合は、experimentalDecorators
を有効にする必要があるので、
tsconfig.jsonを変更する。
// tsconfig.json
{
"compilerOptions": {
+ "experimentalDecorators": true,
},
}
Vuexで型を使えるようにvuex-module-decoratorsを入れる
公式ガイドのストアのページにこんな一文が。
最も人気のあるアプローチの1つはvuex-module-decoratorsです。- ガイドを参照してください。
この記事がわかりやすかった。 ・Nuxt.js + Typescript + Vuexする現時点のベストと思う方法 - Qiita
ストアのモジュールを作成する
まずは、モジュールを作成。
// ~/store/user.ts import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators"; // Stateの型を定義する export interface UserState { uid: string | null; } // デコレータを設定。nameにモジュール名を指定する。UserStateを継承する @Module({ stateFactory: true, namespaced: true, name: "user" }) export default class UserModule extends VuexModule implements UserState { uid: string | null = null; // getterはデコレータなしのgetアクセサで書く get isLogin(): boolean { return this.uid != null; } // mutationはデコレータで指定 @Mutation setUser(uid: string | null) { this.uid = uid; } // actionもデコレータで指定 @Action async login(uid: string | null) { // thisでmutationが呼べる this.setUser(uid); } }
ストアを取りまとめるUtilクラスを作成する
ストアの初期化と取得するUtilクラスを用意。
モジュールが増えるとこのクラスも増やしていく。
// ~/utils/store-accessor.ts import { Store } from "vuex"; import { getModule } from "vuex-module-decorators"; import UserModule from "~/store/user"; let userStore: UserModule; // ストアを初期化する関数。rootのstoreを受け取って、モジュールを初期化する function initialiseStores(store: Store<any>): void { // userStoreはここで初期化。 userStore = getModule(UserModule, store); } export { initialiseStores, userStore };
store/index.tsを作成
最後に、store/index.ts
に、store-accessor.tsのinitialiseStores()を呼び出すようにする。
一度書いたら、基本変更することはなさそう。
// ~/store/index.ts import { Store } from 'vuex' import { initialiseStores } from '~/utils/store-accessor' // Vuexのプラグインを利用して初期化する const initializer = (store: Store<any>) => initialiseStores(store) export const plugins = [initializer] export * from '~/utils/store-accessor'
コンポーネントから使ってみる
準備は上の3つで完了。使い方はモジュールをimportして使うっぽい。
import { Component, Vue, Prop } from "nuxt-property-decorator"; import { userStore } from "~/store"; @Component export default class LoginPage extends Vue { private async onClickLogin(uid:string) { await userStore.setUser(uid); } }
モジュールをそのまま呼ぶので、型がそのまま使える!!
もちろん、$store
でも使える(´ω`)
SASSとBuefyの設定
BuefyのテーマをSASSでカスタマイズしたいので設定していく。
とりあえず、SASS loarderをインストール
$ npm install --save-dev node-sass sass-loader
buefy用のscssを用意(assets/css/buefy.scss
)
// Import Bulma's core @import "~bulma/sass/utilities/_all"; // Set your colors $primary: #ff99a3; $primary-invert: findColorInvert($primary); $twitter: #4099ff; $twitter-invert: findColorInvert($twitter); // Setup $colors to use as bulma classes (e.g. 'is-twitter') $colors: ( "white": ( $white, $black ), "black": ( $black, $white ), "light": ( $light, $light-invert ), "dark": ( $dark, $dark-invert ), "primary": ( $primary, $primary-invert ), "info": ( $info, $info-invert ), "success": ( $success, $success-invert ), "warning": ( $warning, $warning-invert ), "danger": ( $danger, $danger-invert ), "twitter": ( $twitter, $twitter-invert ) ); // Links $link: $primary; $link-invert: $primary-invert; $link-focus-border: $primary; // Fottoer $footer-background-color: $primary; // Import Bulma and Buefy styles @import "~bulma"; @import "~buefy/src/scss/buefy";
ついでに、page-transition用のscssも用意(assets/css/transition.scss
)
// page transiton: slide-fade .page-enter-active, .layout-enter-active { transition: all 0.3s ease; } .page-leave-active, .layout-leave-active { transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1); } .page-enter, .page-leave-to, .layout-enter, .layout-leave-to { transform: translateX(30px); opacity: 0; }
最後に、nuxt.config.tsに設定。
const config: Configuration = { /* ** Global CSS */ - css: [], + css: ["~/assets/css/buefy.scss", "~/assets/css/transition.scss"], ... + + /** + * nuxt-buefy + * Doc: https://github.com/buefy/nuxt-buefy + * Doc: https://buefy.org/documentation/constructor-options + */ + buefy: { + css: false + }, +
Firebaseを利用できるようにする
Firebase AuthとFirebase Cloudstoreを使うので、その設定をしていく。
まずは、パッケージのインストール.
$ npm install --save firebase
次に、.dotenv
ファイルを用意
BASE_URL=http://localhost:3000 API_KEY='AIXXXXXXXXXXXXXXXXXXXXXXXX' AUTH_DOMAIN='hogefuga.firebaseapp.com' DATABASE_URL='https://hogefuga.firebaseio.com' PROJECT_ID='hogefugao' STORAGE_BUCKET='hogefuga.appspot.com' MESSAGING_SENDER_ID='123456789' APP_ID='1:123456789:web:abcde1234' MEASUREMENT_ID='G-AAAAAA'
参考: - [Nuxt.js] Firebaseの設定で環境変数dotenvを扱う - Qiita
firebaseを初期化するpluginを作成(plugins/firebase.ts
)
//firebase.ts import * as firebase from "firebase/app"; import "firebase/auth"; import "firebase/firestore"; if (!firebase.apps.length) { firebase.initializeApp({ apiKey: process.env.API_KEY, authDomain: process.env.AUTH_DOMAIN, databaseURL: process.env.DATABASE_URL, projectId: process.env.PROJECT_ID, storageBucket: process.env.STORAGE_BUCKET, messagingSenderId: process.env.MESSAGING_SENDER_ID, appId: process.env.APP_ID, measurementId: process.env.MEASUREMENT_ID }); firebase.auth().useDeviceLanguage(); } export default firebase;
それをnuxt.config.tsに設定
const config: Configuration = { /* ** Plugins to load before mounting the App */ - plugins: [], + plugins: ["~/plugins/firebase.ts"],
Firebase Authの便利クラスを用意
認証をチェックする便利クラスをよく使うので、用意しておく。
認証状態の変更チェック関数
// plugins/authState.ts import firebase from "~/plugins/firebase"; export default function(): Promise<firebase.User | null> { return new Promise(function(resolve, reject) { firebase.auth().onAuthStateChanged(function(user) { resolve(user || null); }); }); }
未認証の場合、ログイン画面にリダイレクトするmiddleware
// middleware/checkAuthed.ts import authState from "~/plugins/authState"; export default async function({ store, redirect }) { try { // こんな感じのことを書く。そのままだと無限ループする... // if (!!store.getters["user/isLogin"]) return; // redirect({ name: "login" }); } catch (e) { console.error(`error=${e}`, e); return; } }
nuxt.config.tsにも追加
import { Configuration } from "@nuxt/types";
require("dotenv").config();
const config: Configuration = {
router: {
+ middleware: ["checkAuthed"]
},
}
おわりに
だいたいいつもこんな感じのことをしている。
ひさびさに公式ドキュメントをみると、新しいやり方が増えているので、
定期的に振り返ってまとめるの大事...
また、タイミング見て、更新・追記していく予定...
以上!!