2019年6月29日土曜日

firebase-tools v6.11.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v6.11.0

  • Fixed bug in Firestore emulator where some FieldTransforms were sending back incorrect results.
  • Fixed bug where read-only transactions would cause errors in the Firestore emulator.
  • Fixed bug where collection group query listeners would cause errors in the Firestore emulator.
  • Fixed bug where query parameters were not sent to HTTP functions.
  • Fixed bug where some HTTP methods (like DELETE) were not allowed.
  • Fixed bug where CORS headers were too restrictive.
  • Fixed bug where CSV exporting users with commas in displayName causes columns to no longer align.
  • Fixed bug where environment variables are unset for script in emulators:exec.
  • emulators:exec script now inherits stdout and stderr.
  • Improved reliability and performance of project listing for firebase use command.
  • Fixed bug where firestore:delete skips legacy documents with numeric IDs.
  • Fixed bug in Firestore emulator where it ignored x-forwarded-host header.
  • Improved Scheduled Functions deployment to keep and not recreate schedules that are already correct.

  • いくつかの FieldTransforms が誤った結果を送り返していたFirestoreエミュレータのバグを修正しました。
  • 読み取り専用トランザクションがFirestoreエミュレータでエラーを引き起こすというバグを修正しました。
  • Collection Group Query リスナーがFirestoreエミュレータでエラーを引き起こすというバグを修正しました。
  • クエリパラメータがHTTP関数に送信されなかったバグを修正しました。
  • いくつかのHTTPメソッド(DELETEなど)が許可されていなかったバグを修正しました。
  • CORSヘッダの制限が厳しすぎるというバグを修正。
  • displayName にカンマを使用してCSVをエクスポートすると、列が整列されなくなるというバグが修正されました。
  • 環境変数が emulators:exec のスクリプトに設定されていないバグを修正しました。
  • emulators:exec スクリプトは現在 stdoutstderr を継承しています。
  • firebase use コマンドのプロジェクト一覧の信頼性とパフォーマンスが向上しました。
  • firestore:delete が数値IDを持つレガシードキュメントをスキップするバグを修正しました。
  • Firestoreエミュレータが x-forwarded-host ヘッダを無視していたバグを修正しました。
  • Scheduled Functions のデプロイを改善し、すでに正しいスケジュールを保持し、再作成しないようにしました。

Written with StackEdit.

Nuxt.js v2.7.1 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/nuxt/nuxt.js/releases/tag/v2.7.1

Fixes

修正

  • builder: use warn only for mismatched dependencies (#5723)
  • webpack: correctly resolve consola for the client bundle (#5729)

  • builder: 依存関係が一致しない場合にのみ警告を使用する (#5723)
  • webpack: クライアントバンドル時にconsolaを正しく解決する (#5729)

Dependency Upgrades

依存関係のアップグレード



Written with StackEdit.

2019年6月20日木曜日

Nuxt.js v2.7.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/nuxt/nuxt.js/releases/tag/v2.7.0

DX Improvements 💅

SSR logs in your browser 🖥️

SSRのログをブラウザへ出力


We all know the console.log debugging method, but when working with universal applications, you have to remember that sometimes, your logs are in your terminal and not in your browser console.

console.logというデバッグ方法がありますが、ユニバーサルアプリケーションを作成している場合、ログはブラウザコンソールではなくターミナルに出力されることがあるのを覚えておかなければなりません。


This can be really annoying when developing a Nuxt.js application, starting with this version and running nuxt dev, the ssr logs are now reported to your browser console:

このバージョンから始めて nuxt devを実行して、Nuxt.jsアプリケーションを開発するとき、これは本当に厄介なことになるかもしれません、SSRのログはブラウザのコンソールに表示されるようになりました。


Detecting store/ creation 👀

store/ ディレクトリの作成を検出


Nuxt.js now detects when you created a store/ directory and will reload himself auto-magically so you don’t have to restart it anymore.

Nuxt.jsは、あなたが store/ディレクトリを作成したことを検出し、自動的に自分自身を再ロードするので、もう再起動する必要はありません。


PS: We also improved the serverMiddleware watch to restart Nuxt.js and clean their cache

PS:Nuxt.jsを再起動してキャッシュを消去するために serverMiddlewareの監視を改良しました。

Fixes ✔️

修正

  • builder: corretly detect mode of hashed plugins (#5695)
  • builder: call watch:restart after watch:fileChanged hook (#5620)
  • utils: node v8 not support dotAll in regex (#5608)
  • vue-app: properly catch component loading error (#5687) (#5688) (#5690)
  • vue-app: consider watchQuery option in routerViewKey (#5516)
  • vue-renderer: await on spa:templateParams hook (#5619)
  • webpack: set log level to warn for HardSourcePlugin (#5653)
  • vue-app: properly catch loading error in component prefetching (#5688) (#5690)
  • vue-app: avoid using aliases in templates (#5656)
  • builder: watch store dir and serverMiddleware paths (#5681)

  • builder: ハッシュプラグインのモードを正しく検出する (#5695)
  • builder: watch:fileChangedフックの後にwatch:restartを呼び出す (#5620)
  • utils: ノードv8は正規表現でdotAllをサポートしていません (#5608)
  • vue-app: コンポーネントの読み込みエラーを正しく検出 (#5687) (#5688) (#5690)
  • vue-app: routerViewKeywatchQueryオプションを検討してください(#5516)
  • vue-renderer: spa:templateParamsフックを待ってください (#5619)
  • webpack: ログレベルを HardSourcePluginに警告するように設定します (#5653)
  • vue-app: コンポーネントのプリフェッチでロードエラーを適切に検出する (#5688) (#5690)
  • vue-app: テンプレートでエイリアスを使用しない (#5656)
  • builder: storeディレクトリと serverMiddlewareパスを監視する (#5681)

Features 🚀

特徴

  • vue-app: rename transition to pageTransition and deprecate it (#5558)
  • vue-renderer/vue-app: report SSR console logs to the browser with consola (#5673)
  • webpack: suppress not found typescript warnings (#5635)
  • webpack: extendable babel.presets and babel envName (#5637)
  • configurable aliases (#5655)

  • vue-app: transitionpageTransitionに改名して非推奨になりました (#5558)
  • vue-renderer/vue-app: SSRコンソールログをconsolaでブラウザに報告する (#5673)
  • webpack: 見つからないタイプスクリプトの警告を抑制 (#5635)
  • webpack: 拡張可能なbabel.presetsとバベルenvName(#5637)
  • 設定可能なエイリアス (#5655)

Refactors 🧹

リファクタリング

  • server: exclude dist files request from browser detection (#5571)
  • vue-renderer: remove chalk in renderer (#5609)
  • vue-renderer: split renderer into ssr, spa and modern (#5559)
  • move modern detection from server to utils (#5584)

  • server: ブラウザ検出からdistファイル要求を除外する(#5571)
  • vue-renderer: レンダラーのchalkの警告を削除 (#5609)
  • vue-renderer: レンダラーをssr、spa、modernに分割 (#5559)
  • 最新ブラウザの検出をサーバーからutilsに移動 (#5584)

Examples 📚

  • auth-routes: fix typo (#5651)
  • babel-preset-app: add core-js@3 example in the readme (#5633)
  • docker: fix Dockerfile casing (#5705)

  • auth-routes: typoを修正 (#5651)
  • babel-preset-app: readmeにcore-js@3の例を追加 (#5633)
  • docker: Dockerfileのスペルを修正 (#5705)

Typescript 👷

Only for typescript users, Nuxt.js v2.7 dropped support for node < 8.6 relate to ts-loader v6

TypeScriptユーザのみ、Nuxt.js v2.7ではts-loader v6に関連してNode v8.6未満のサポートを終了しました

  • add babel config types (#5666)
  • upgrade ts-loader to v6 (#5691)
  • fix context.app type (#5701)
  • fix extendRoutes method type (#5700)
  • prevent ts-node to register twice (#5699)

  • config typesbabelを追加 (#5666)
  • ts-loaderをv6にアップグレード (#5691)
  • context.appタイプを修正 (#5701)
  • extendRoutesメソッドの型を修正 (#5700)
  • ts-nodeが2回登録されるのを防ぎます (#5699)

Written with StackEdit.

2019年6月13日木曜日

JestでVuex.Storeのテストを行う

NuxtでTypeScriptを使うときのVeux.storeの設定方法で作成したプロジェクトに Jest でのユニットテストをつけていきます。

できあがったものは以下のリポジトリになります。
https://github.com/TAC/nuxt-vuex-typescript-jest-example

Jestの追加

Nuxt を新規作成時のオプションでテストフレームワークに Jest を選択すると自動で追加されますが、それらを手動で追加してみます。

yarn add -D jest vue-jest babel-jest ts-jest eslint-plugin-jest @vue/test-utils babel-core@^7.0.0-bridge.0

Babelのバージョンが7になっているのでbabel-core@^7.0.0-bridge.0 が必要になります。
Vuex.StoreTypeScriptなのでts-jestも追加します。

Jestの設定

jest.config.js.babelrc を以下の内容で追加します。

app/jest.config.ts

module.exports = {
  moduleNameMapper: {
    '^vue$': 'vue/dist/vue.common.js',
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1'
  },
  moduleFileExtensions: ['js', 'ts', 'vue'],
  transform: {
    '^.+\\.js$': 'babel-jest',
    '^.+\\.ts$': 'ts-jest',
    '^.+\\.vue$': 'vue-jest'
  },
  collectCoverage: false,
  collectCoverageFrom: [
    '<rootDir>/components/**/*.vue',
    '<rootDir>/pages/**/*.vue',
    '<rootDir>/store/**/*.ts'
  ]
}

.babelrc

{
  "env": {
    "test": {
      "presets": [
        [
          "@babel/preset-env",
          {
            "targets": {
              "node": "current"
            }
          }
        ]
      ]
    }
  }
}

テストの作成

コンポーネントのテスト

まずはコンポーネントのテストから。

import Vuex from 'vuex'
import { cloneDeep } from 'lodash'
import { createLocalVue, mount } from '@vue/test-utils'
import Counter from '@/components/Counter.vue'
import counter from '@/store/modules/counter.ts'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('components/Counter.vue', () => {
  let wrapper
  const initValue = 10
  beforeEach(() => {
    // create store
    const store = new Vuex.Store({
      'modules': {
        'modules/counter': cloneDeep(counter)
      }
    })

    // initialize store
    store.commit('modules/counter/SET_VALUE', initValue)

    // mount Vue Component
    wrapper = mount(Counter, {
      store: store,
      localVue
    })
  })

  describe('template', () => {
    test('snapshot correctly', () => {
      expect(wrapper.element).toMatchSnapshot()
    })
  })

  describe('script', () => {
    test('get counter value correctly', () => {
      expect(wrapper.vm.counter).toBe(initValue)
    })
    test('increment button correctly', () => {
      wrapper.find('[name="increment"]').trigger('click')
      expect(wrapper.vm.counter).toBe(initValue + 1)
    })
    test('decrement button correctly', () => {
      wrapper.find('[name="decrement"]').trigger('click')
      expect(wrapper.vm.counter).toBe(initValue - 1)
    })
  })
})

@vue/test-utilscreateLocalVueを使ってローカルコピーを作成しておきます。
Vuex.Storeには使用するstoreの定義をmodulesの該当パスにcloneDeepでコピーしてあげます。
そうすることで他のテスト時に値が汚染されなくなります。
あとは好きなテストを記述していきます。
wrapper.find()にはCSSセレクターを指定できるので、テスト対象のエレメントなどが一意になるようにnameclassを設定しておくと探しやすくなります。

Veux.Storeのテスト

次はstoreのテストです。

import Vuex from 'vuex'
import { cloneDeep } from 'lodash'
import { createLocalVue } from '@vue/test-utils'
import counter from '@/store/modules/counter.ts'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('store/modules/counter.ts', () => {
  let store
  const initValue = 10
  beforeEach(() => {
    // create store
    store = new Vuex.Store({
      'modules': {
        'modules/counter': cloneDeep(counter)
      }
    })

    // initialize store
    store.commit('modules/counter/SET_VALUE', initValue)
  })

  describe('getters', () => {
    test('get value correctly', () => {
      expect(store.getters['modules/counter/value']).toBe(initValue)
    })
  })

  describe('actions', () => {
    test('increment correctly', () => {
      const addValue = 1
      store.dispatch('modules/counter/increment', addValue)
      expect(store.getters['modules/counter/value']).toBe(initValue + addValue)
    })
    test('decrement correctly', () => {
      const subValue = 1
      store.dispatch('modules/counter/decrement', subValue)
      expect(store.getters['modules/counter/value']).toBe(initValue - subValue)
    })
  })
})

ほぼコンポーネントと同じですが、作成したstoreを使用してテストしたいactionsなどを実行していく形になります。

package.jsonに以下のスクリプトを追加します。

    "test": "jest",
    "test:coverage": "jest --coverage",

これで準備が整ったので、yarn testを実行すると以下のような結果が得られると思います。

PS C:\work\repos\nuxt\jest\app> yarn test
yarn run v1.15.2
$ jest
$ C:\work\repos\nuxt\jest\app\node_modules\.bin\jest
 PASS  tests/store/modules/counter.test.js
 PASS  tests/components/Counter.test.js

Test Suites: 2 passed, 2 total
Tests:       7 passed, 7 total
Snapshots:   1 passed, 1 total
Time:        3.831s
Ran all test suites.
Done in 5.54s.

テストカバレッジも見たい時はtest:coverageを実行します。

PS C:\work\repos\nuxt\jest\app> yarn test:coverage
yarn run v1.15.2
$ jest --coverage
$ C:\work\repos\nuxt\jest\app\node_modules\.bin\jest --coverage
 PASS  tests/store/modules/counter.test.js
 PASS  tests/components/Counter.test.js
---------------|----------|----------|----------|----------|-------------------|
File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files      |    65.38 |      100 |     87.5 |    65.22 |                   |
 components    |    71.43 |      100 |      100 |    71.43 |                   |
  Counter.vue  |      100 |      100 |      100 |      100 |                   |
  Logo.vue     |        0 |      100 |      100 |        0 |             10,13 |
 pages         |        0 |      100 |      100 |        0 |                   |
  index.vue    |        0 |      100 |      100 |        0 |         8,9,10,18 |
 store         |        0 |      100 |        0 |        0 |                   |
  index.ts     |        0 |      100 |        0 |        0 |               1,3 |
 store/modules |      100 |      100 |      100 |      100 |                   |
  counter.ts   |      100 |      100 |      100 |      100 |                   |
---------------|----------|----------|----------|----------|-------------------|

Test Suites: 2 passed, 2 total
Tests:       7 passed, 7 total
Snapshots:   1 passed, 1 total
Time:        10.346s
Ran all test suites.
Done in 11.68s.

Written with StackEdit.

2019年6月4日火曜日

NuxtでTypeScriptを使うときのVeux.storeの設定方法

NuxtTypeScript で構築した時に Vuex.store の構成をどうしたらいいかを考えてみました。

結論としては vuex-class-component を使用してモジュールモードで構成する、という感じになりました。

完成したプロジェクトは以下のリポジトリになります。
https://github.com/TAC/nuxt-vuex-typescript-example

簡単なカウンターを作成しました。

環境

- version
OS Windows10
Node.js v8.15.0
Nuxt.js v2.7.1

どのモジュールがいいのか?

Vuex.store を簡潔にかけるようにするモジュールはいくつかあって、以下の2つが主に使われてるようでした。

vuex-class-component
https://github.com/michaelolof/vuex-class-component

vuex-module-decorators
https://github.com/championswimmer/vuex-module-decorators

Nuxt では store ディレクトリ以下にファイルを配置すれば自動で Vuex のモジュールモードで構築してくれます。

ただし、 store/index.ts が関数を返すとクラシックモードになり、その恩恵を受けることができません。
また、各モジュールのファイルも関数ではなくオブジェクトを返す必要があり、それができるのが vuex-class-component でした。
また、Nuxt.jsv3.0.0 ではクラシックモードが非対応になるようなので、それを考慮に入れての選択になります。

ディレクトリ構成

以下のような構成を考えてみました。

src/store/index.ts
  +- modules/
      +- counter.ts

modules に機能毎に分けたモジュールを作成していく感じです。
models とか作ってDBのテーブル毎などに分けたモジュールを作成してもいいかもしれない。

counter.ts

デコレータを使って以下のように記述します。

import {
  VuexModule,
  Module,
  action,
  getter,
  mutation
} from 'vuex-class-component'

interface Counter {
  value: number
}

@Module({ namespacedPath: 'modules/counter/', target: 'nuxt' })
export class CounterStore extends VuexModule implements Counter {
  @getter value = 0

  @mutation
  public SET_VALUE(value: number) {
    this.value = value
  }

  @action()
  public increment(value: number) {
    this.SET_VALUE(this.value + value)
  }

  @action()
  public decrement(value: number) {
    this.SET_VALUE(this.value - value)
  }
}

export default CounterStore.ExtractVuexModule(CounterStore)

ポイントは2つあって、1つは @Module のオプションに namespacedPathtarget:'nuxt' を指定するところです。
もう1つは、最後の行で ExtractVuexModule を使ってオブジェクト形式で export してあげるところです。
これで Vuex.store のモジュールモードに対応できました。

index.ts

index.ts もデコレータを使って記述しようとしたのですが、 nuxtServerInit の定義がどうしてもできなかったので、デコレータを使わずに記述します。

export const actions = {
  nuxtServerInit: ({ commit }) => {
    commit('modules/counter/SET_VALUE', 20)
  }
}

ここでは modules/counter の初期化を行ってみました。

呼び出すComponent

components/Counter.vue を作成します。

<template lang="pug">
  div [counter]
    div {{ counter }}
    div
      button(@click="increment") +
      button(@click="decrement") -
</template>

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'

@Component
export default class Counter extends Vue {
  get counter() {
    return this.$store.getters['modules/counter/value']
  }

  public increment() {
    this.$store.dispatch('modules/counter/increment', 1)
  }
  public decrement() {
    this.$store.dispatch('modules/counter/decrement', 1)
  }
}
</script>

呼び出す箇所は通常の使い方と同じです。

これでごちゃごちゃしがちな store 周りをスッキリとかけるようになったかと思います。

Written with StackEdit.

2019年5月23日木曜日

NuxtでTypeScriptを使えるようにする

https://ja.nuxtjs.org/guide/typescript/
基本的に上記の手順で設定していけばOK

  1. モジュールの追加
  2. nuxt.config.jsのTypeScript化
  3. nuxt-property-decoratorの導入
  4. ESLintの設定

完成したプロジェクトは以下になります。
ご査収ください。
https://github.com/TAC/nuxt-typescript-example

環境

- version
OS Windows10
Node.js v8.15.0
Nuxt.js v2.7.1

1. モジュールの追加

yarn add -D @nuxt/typescript
yarn add ts-node

上記のモジュール追加後、空のtsconfig.jsonファイルを作成して、nuxtコマンドを実行するとデフォルト値で更新されます。

2. nuxt.config.jsのTypeScript化

nuxt.config.jsnuxt.config.tsにリネームします。
そしてドキュメントの手順通り以下を追記して、コンフィグの export 方法を変更します。

import NuxtConfiguration from  '@nuxt/config'
import pkg from './package'

const nuxtConfig: NuxtConfiguration = {
...
}

export default nuxtConfig

ただ、上記の変更だけだと下記のようなエラーが出るはずです。

 ERROR  ⨯ Unable to compile TypeScript:                                                                                                                                                                 23:58:04
nuxt.config.ts:2:17 - error TS2307: Cannot find module './package'.

2 import pkg from './package'
                  ~~~~~~~~~~~
nuxt.config.ts:51:9 - error TS2532: Object is possibly 'undefined'.

51         config.module.rules.push({
           ~~~~~~~~~~~~~


  nuxt.config.ts:2:17 - error TS2307: Cannot find module './package'.

  2 import pkg from './package'
                    ~~~~~~~~~~~
  nuxt.config.ts:51:9 - error TS2532: Object is possibly 'undefined'.

  51         config.module.rules.push({
             ~~~~~~~~~~~~~

  at createTSError (node_modules\ts-node\src\index.ts:240:12)
  at reportTSError (node_modules\ts-node\src\index.ts:244:19)
  at getOutput (node_modules\ts-node\src\index.ts:360:34)
  at Object.compile (node_modules\ts-node\src\index.ts:393:11)
  at Module.m._compile (node_modules\ts-node\src\index.ts:439:43)
  at Module._extensions..js (module.js:664:10)
  at Object.require.extensions.(anonymous function) [as .ts] (node_modules\ts-node\src\index.ts:442:12)
  at Module.load (module.js:566:32)
  at tryModuleLoad (module.js:506:12)
  at Function.Module._load (module.js:498:3)

Done in 3.26s.

まずはこちらのエラー

Cannot find module './package'.

TypeScriptはデフォルトではJSONファイルのImportを許可していないのでコンフィグで設定を変更する必要があるようです。
https://www.typescriptlang.org/docs/handbook/compiler-options.html
"resolveJsonModule": truetscofig.jsonに追記します。

{
  "compilerOptions": {
    "resolveJsonModule": true
  }
}

そしてImport時には拡張子まで指定するようにすればOK

import pkg from './package.json'

続いてはこちらのエラー

Object is possibly 'undefined'.

config.moduleundefined になってしまうことがあるのが原因なので、undefined の場合の処理を追記します。
(参考サイト) https://qiita.com/dora1998/items/932506fa995962d4dc63#nuxtconfigjs–nuxtconfigts

  /*
   ** Build configuration
   */
  build: {
    publicPath: '/assets/',
    
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {
      // Run ESLint on save
      if (ctx.isDev && ctx.isClient) {
+       if (!config.module) return
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue|ts)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
    }
  }

これでひとまず起動できるようになっているはずです。

3. nuxt-property-decoratorの導入

コンポーネントの記述を楽にするためにデコレータモジュールを導入します。
ドキュメントの手順ではvue-property-decoratorとなっているが、nuxt-property-decoratorを追加します。

yarn add nuxt-property-decorator

各コンポーネントのスクリプト部分をTypeScriptにします。

page/index.vue

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import Logo from '@/components/Logo.vue'

@Component({
  components: {
    Logo
  }
})
export default class extends Vue {}
</script>

components/Logo.vue

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'

@Component
export default class Logo extends Vue {}
</script>

クラスの定義が必要になるので少し冗長になります。
なおnuxt.config.tssrcDirを設定している場合は、tsconfig.jsonbaseUrlをそれに合わせないとコンポーネントの読み込みに失敗します。

4. ESLintの設定

以下のモジュールを追加する。

yarn add -D @typescript-eslint/eslint-plugin

そして、デフォルトで作成されている.eslintrc.jsを以下のように修正します。

module.exports = {
  root: true,
  env: {
    browser: true,
    node: true
  },
  parserOptions: {
    parser: '@typescript-eslint/parser'
  },
  extends: [
    '@nuxtjs',
    'plugin:nuxt/recommended',
    'plugin:prettier/recommended',
    'prettier',
    'prettier/vue'
  ],
  plugins: [
    'prettier',
    '@typescript-eslint'
  ],
  // add your custom rules here
  rules: {
    '@typescript-eslint/no-unused-vars': 'error'
  }
}

package.jsonlintスクリプトにts拡張子を追加しておきます。

"lint": "eslint --ext .js,.vue,.ts --ignore-path .gitignore .",

以上でNuxtでTypeScriptを使用できるようになりました。

Cloud FunctionsもTypeScriptにする

https://firebase.google.com/docs/functions/typescript?hl=ja
こちらの手順に従って進めればOKですが、いくつか追加で行う作業が必要でした。

まずはディレクトリ構成ですが、カレントディレクトリにアプリのビルド環境がある場合、予期せぬ動作が起こるようでした。

myproject
 +- src            # Nuxt src dir
 +- package.json   # Nuxt build script
 +- tsconfig.json  # Nuxt tsconfig
 +- nuxt.config.ts
 +- functions/
      +- package.json   # functions build script
      +- tsconfig.json  # functions tsconfig

上記の構成だと Nuxt を ビルドした際に functions 以下もビルドされてしまいコンフィグ設定の違いによりエラーが出てしまいます。
なので以下のような構成で Nuxtfunctions を配置します。

myproject
 +- app
 |    +- src            # Nuxt src dir
 |    +- package.json   # Nuxt build script
 |    +- tsconfig.json  # Nuxt tsconfig
 |    +- nuxt.config.ts
 +- functions/
      +- package.json   # functions build script
      +- tsconfig.json  # functions tsconfig

それぞれのディレクトリでビルドすることで干渉しなくなります。

次に app で追加したモジュールとExpressの型定義も追加しておきます。
また、lint が通らなくなるので、@nuxt/config を追加しておきます。

yarn add -D @nuxt/typescript @types/express
yarn add ts-node @nuxt/config

そして、公式の手順にあった firebase init functions で作成された functions/src/index.ts に色々と修正をいれて最終的に以下のようになりました。

import * as functions from 'firebase-functions'
import * as express from 'express'
import NuxtConfiguration from '@nuxt/config'
const { Nuxt } = require('nuxt')

const nuxtConfig: NuxtConfiguration = {
  dev: false,
  buildDir: 'nuxt',
  build: {
    publicPath: '/assets/'
  }
}
const nuxt = new Nuxt(nuxtConfig)

async function handleRequest(req: express.Request, res: express.Response) {
  res.set('Cache-Control', 'public, max-age=600, s-maxage=1200')
  await nuxt.ready()
  return nuxt.render(req, res)
}

const app = express()
app.use(handleRequest)

exports.ssr = functions.https.onRequest(app)

functions へ移動してビルドをすると functions/lib/index.js が出力されます。

cd functions/
yarn build

あとはアプリのビルドの成果物と合わせてローカルエミュレータを起動して動作確認ができると思います。

Written with StackEdit.

2019年5月21日火曜日

firebase-tools v6.10.0 でNuxtのSSRアプリを動かすことができた!

下記の記事で動かないといってたものが動くようになりました!
https://blog.28go.jp/2019/05/firebase-tools_19.html

きっかけはこちらの記事です。
https://www.memory-lovers.blog/entry/2019/03/31/003456

https://nuxtjs.org/guide/release-notes#-strong-important-strong-migration-guide

どうやら Cloud Functions での Nuxt の呼び出し方が変わっていたようです。
上記の修正をすることで firebase-toolsv6.10.0 の ローカルエミュレータでも動作するようになりました。

ただ、functions のパッケージにいくつか追加するモジュールがあったので記載しておきます。

yarn add firebase-admin
yarn add -D firebase-functions-test

firebase-admin は使用していなくても必要になったようです。

以前検証に使ったリポジトリも修正しました。
https://github.com/TAC/nuxt-ssr-firebase-example

動かなくてもやもやしていたのでスッキリしました!

Written with StackEdit.

2019年5月19日日曜日

firebase-toolsをバージョンアップすると動かない

firebase-toolsをバージョンアップするとNuxtで作成したSSRアプリがfirebase serveで動かなくなったので、その対処法を記録しておきます。
結論としては「最新バージョンでは動かない」ということになります。

環境

Windows10
Node.js v8.15.0
Nuxt.js v2.7.1

検証にはcreate-nuxt-appでなにもモジュールを追加しないプロジェクトを作成して、Firebase Functionsで動作するようにちょっと修正した以下のプロジェクトを使用しました。
https://github.com/TAC/nuxt-ssr-firebase-example

6.9.0

そもそもhostingが起動しません。
6.9.1で修正された模様です。

6.9.1

functions実行時に以下のメッセージが表示されて動きません。

!  The Cloud Functions emulator requires the module "firebase-admin" to be installed as a dependency. To fix this, run "npm install --save firebase-admin" in your functions directory.
i  functions: Your functions could not be parsed due to an issue with your node_modules (see above)

使ってないのにfirebase-adminを要求されます。
とりあえずdevDependenciesに追加して、再度実行すると以下のエラーに変わります。

!  The Cloud Functions emulator requires the module "firebase-admin" to be installed. This package is in your package.json, but it's not available. You probably need to run "npm install" in your functions directory.
i  functions: Your functions could not be parsed due to an issue with your node_modules (see above)

これは6.9.2で修正されたようです。

6.9.2

今度はfirebase-functions-testを要求されるようになります。

!  The Cloud Functions emulator requires the module "firebase-functions-test" to be installed as a development dependency. To fix this, run "npm install --save-dev firebase-functions-test" in your functions directory.
i  functions: Your functions could not be parsed due to an issue with your node_modules (see above)

メッセージ通りdevDependenciesに追加して再実行すると、以下のエラーメッセージが表示される。

!  The Firebase Admin module has not been initialized early enough. Make sure you run "admin.initializeApp()" outside of any function and at the top of your code

使ってないのだが初期化が必要になっています。
これは6.10.0で修正されたようです。

6.10.0

6.10.0でいろいろ修正されていたので、起動できるようになっているかと期待したが、以下のエラーが解消できませんでした。
以前は、モジュールの読み込み等でNuxtが起動できていなくて同様のエラーが出ていたが、そうではないようです。

>  C:\work\repos\nuxt\example\functions\index.js:19
>        promise.then(resolve).catch(reject)
>                ^
>
>  TypeError: Cannot read property 'then' of undefined
>      at Immediate.nuxt.render.promise [as _onImmediate] (C:\work\repos\nuxt\example\functions\index.js:19:15)
>      at runCallback (timers.js:812:20)
>      at tryOnImmediate (timers.js:768:5)
>      at processImmediate [as _immediateCallback] (timers.js:745:5)

6.9.0以降はまともに動かなくなってしまった。

6.8.0

今のところちゃんと動く最新バージョンは6.8.0です。
このバージョンあたりからNode.js v6が非推奨になったので、--ignore-enginesのオプションをつけないと@google-cloud/functions-emulatorのインストールに失敗します。

https://github.com/googlearchive/cloud-functions-emulator/issues/267

yarn global add firebase-tools@6.8.0 @google-cloud/functions-emulator --ignore-engines

まだ、しばらくは6.8.0を使っていくしかないようです。

追記(2019-05-21)

解決しました!
詳細は下記の記事に記載してあります。
https://blog.28go.jp/2019/05/firebase-tools-v6100-nuxtssr.html

Written with StackEdit.

firebase-tools v6.10.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v6.10.0

  • database:instances:{create,list} now allow viewing and creating Realtime Database instances
  • Fixed issue with CORS rejecting some callable functions
  • Functions emulator no longer watches node_modules files
  • Functions emulator fails to route HTTPS functions to user-provided Express app
  • Functions emulator fails to provide correct req.path
  • Functions emulator fails on various malformed body requests
  • Functions emulator fails on Windows with EACCESS error
  • Functions emulator can now automatically initialize firebase-admin for simple use-cases
  • Fixed race condition where downloading emulators would sometimes resolve too early and fail
  • Fixed a number of issues that broke functions:shell
  • Fixed an issue where Firestore emulator would not start if rules file can’t be found

  • database:instances:{create,list} コマンドで Realtime Database インスタンスの表示と作成が可能になりました
  • 一部の呼び出し可能関数を拒否したCORSに関する問題を修正しました
  • 関数エミュレータは node_modules ファイルを監視しなくなりました
  • 機能エミュレータがHTTPS機能をユーザー提供のExpressアプリにルーティングできない
  • 関数エミュレータが正しい req.path を提供できない
  • 関数エミュレータがさまざまな不正な形式の本体要求で失敗する
  • Windows上でEACCESSエラーで関数エミュレータが失敗する
  • 関数エミュレータは単純なユースケースのためにfirebase-adminを自動的に初期化するようになりました
  • エミュレータをダウンロードすると早く解決しすぎて失敗することがあるという競合状態を修正しました
  • functions:shellを壊したいくつかの問題を修正しました
  • ルールファイルが見つからないとFirestoreエミュレータが起動しない問題を修正しました

Written with StackEdit.

2010年5月13日木曜日

jQueryである要素のイベントをすべて表示する方法

とりあえずどんなイベントが起こってるのかを見たい時に。

var arr = ["blur", "focus", "focusin", "focusout", "load",
           "resize", "scroll", "unload", "click", "dblclick",
           "mousedown", "mouseup", "mousemove", "mouseover",
           "mouseout", "mouseenter", "mouseleave", "change",
           "select", "submit", "keydown", "keypress", "keyup",
           "error"];
$.each(arr, function() {
  var type = this+"";
  $("option").bind(type, function(event) {
    $("pre[id='debug']").append(event.type + ":"
                                + event.target.nodeName
                                + "<br>");
  });
  $("select").bind(type, function(event) {
    $("pre[id='debug']").append(event.type + ":"
                                + event.target.nodeName
                                + "<br>");
 });
});