クロコめも2。

ただのめもー

Nuxt.js v2.6 と TypeScript 3.4.2でプロジェクトを作ってみたときのメモ

準備

  1. nodebrewでnodeのv10.15.3にあげる
  2. npm i -g npmでnpmを最新にしておく
  3. yarn global add typescriptをして3.4.2にあげる

参考にした情報一覧

https://nuxtjs.org/guide/typescript/

プロジェクト生成

  • npx create-nuxt-app myproject
    Generating Nuxt.js project in /Users/自分のパス/workspaces/myproject
    ? Project name myproject
    ? Project description My fantabulous Nuxt.js project
    ? Use a custom server framework express
    ? Choose features to install Linter / Formatter, Prettier, Axios
    ? Use a custom UI framework buefy
    ? Use a custom test framework jest
    ? Choose rendering mode Single Page App
    ? Author name kurokokoruru
    ? Choose a package manager yarn
  • cd myproject
  • yarn run dev プロジェクトを起動してみる
  • http://localhost:3000/で表示できることを確認

    設定を追加していく

  • yarn add -D @nuxt/typescript
  • yarn add ts-node
  • touch tsconfig.json
  • nuxt.config.jsをnuxt.config.tsにリネームして中身をバックアップしたのちまずまっさらにする。
    import NuxtConfiguration from '@nuxt/config'

    const config: NuxtConfiguration = {
    // Type or Press `Ctrl + Space` for autocompletion
    }

    export default config
  • まずはnuxt.config.jsにあったものをそのまま移植
  • buildの設定がそのままだとコンパイルエラーになる。undefinedの可能性があるよ的なやつのため修正
      /* && config.moduleを書き足す */
      if (ctx.isDev && ctx.isClient && config.module) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
  • nuxt.config.tsのheadでmetaに'http-equiv': 'X-UA-Compatible'が設定できない
    /* node_modules内 vue-meta/types/index.d.ts抜粋 */
    meta?: {
        vmid?: string,
        charset?: string,
        content?: string,
        'http-equiv'?: 'content-security-policy' | 'refresh',
        name?: string,
        [key: string]: any
    }[]

これはバグなのか?content-security-policyとrefreshのどちらかで良いのか。手元にIEがないので不明

  • yarn run devでは起動できない。ts-nodeに書き換えればいけるのかとpackage.jsonを見たがnodemonというあまり知らないものだったので断念
  • yarn nuxt dev -oなら起動できた
  • tsconfig.jsonの中身は生成されず空のままだったので別プロジェクトからコピーして流用
  • ここでプロジェクトを開き直さないとtsconfig.jsonのpathsの設定がeditorに反映されなかったりする
  • 公式のガイドにあるComponentを作ってみる
    /* models/Post.ts */
    export default interface Post {
        id: number
        title: string
        description: string
    }

export default Post {と公式では書いてあったがコンパイルエラーになるためinterfaceを足した

    /* components/PostPreview.vue */
    <template>
    <div>
        <h2>{{ post.title }}</h2>
        <p>{{ post.description }}</p>
    </div>
    </template>

    <script lang="ts">
    import axios from 'axios'
    import { Component, Vue, Prop } from 'vue-property-decorator'
    import Post from '~/models/Post'

    @Component
    export default class PostPreview extends Vue {
        @Prop({ type: Object, required: true }) post!: Post
        }
    </script>

exportのあたりで下記のエラーが出るがどうすればいいのか?@decとは何者か

    Parsing error: Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.
  • .eslintrc.jsのparserOptionsに以下の内容を追記したらエラーが取れた
    ,
    ecmaFeatures: {
      legacyDecorators: true
    }

今度は@Propの行の最後の!マークでParsing error: Unexpected token yarn add -D @typescript-eslint/parserをやってなかったので実行してエディタリロード。変わらず。。 !マークをとるとコンパイルエラーが外れるので外して次行ってみる。多分ダメだろうけど

  • 公式に書いてあったyarn add -D @typescript-eslint/eslint-plugin実行
  • 公式にある.eslintrc.js書き換えをやる
    module.exports = {
    plugins: ['@typescript-eslint'],
    parserOptions: {
        parser: '@typescript-eslint/parser'
    },
    extends: [
        '@nuxtjs'
    ]
    }

上記のコンパイルエラーの右往左往はこれやればよかったらしい。(先に書いておいてよ。。。)

  • feed.vueのAPI取得のところを書き換えて画面に表示させてみる
    <template>
    <div>
        <PostPreview v-for="post in posts" :key="post.id" :post="post" />
    </div>
    </template>

    <script lang="ts">
    import { Component, Vue } from 'vue-property-decorator'
    import Post from '~/models/Post'

    @Component({
    components: {
        PostPreview: () => import('~/components/PostPreview.vue')
    }
    })
    export default class FeedPage extends Vue {
    posts: Post[] = [
        {
        id: 10,
        title: 'タイトル',
        description: '説明です'
        }
    ]
    }
    </script>
  • localhost:3000/feedで表示される
  • PostPreview.vueの!マークを元に戻すとやっぱりコンパイルエラーになる。謎はまだ多い。

IEでおきるバグの小さいサンプル

どんなバグか

input type="text"のplaceholderに日本語を設定しておいて

v-ifで画面表示直後(mounted中)に

  • インプットテキストを消えるようにしておく
  • v-modelに設定されている変数に値を設定する

こうしておくと、IE以外のブラウザでは変数に値が設定されているが、 IEだけ値がリセットされ、空白で上書きされてしまう。

サンプルコード

Nuxtのプロジェクトを作ったときにpagesの中に入っているサンプルの.vueファイルをバグが起きるように書き換える

<template>
  <section class="section">
    <h2 class="title is-3 has-text-grey">
      バグ再現コンポーネント
      <b-icon
        icon="rocket"
        size="is-large"
      />
    </h2>
    <div v-if="isView">これはラベルです。画面表示するとこっちが見えるようになります。{{inputText}}</div>
    <div v-else>これはテキストインプットです。mounted中にv-elseに来ないようになります
      <input type="text" v-model="inputText" placeholder="プレースホルダー文言です。ここをaaとかに書き換えると再現しない"/>
    </div>
    <button @click="change">ラベルとテキストの表示を切り替える確認用ボタン</button>
  </section>
</template>

<script>
export default {
  data() {
    return {
      inputText: '',
      beVisible: false
    }
  },
  mounted() {
    this.inputText = 'IEだけこの変数がリセットされ空白になる'
    this.beVisible = true
  },
  methods: {
    change(e) {
      this.beVisible = !this.beVisible
    }
  },
  computed: {
    isView() {
      return this.beVisible
    }
  }
}
</script>

どうなおすのか

  • placeholderを消す

  • placeholderに日本語を使わない?

  • テキストインプットがmounted前から表示されないようにする(サンプルでいうとbeVisibleの初期値をtrueにする)

    他にもググるといくつか出てくる

    vueのissuesのやりとりに似たようなものも出てくるがvue2.6.10でも再現するのは確認済み

Nuxt2.5.1とTypeScript3.4.1でプロジェクト作ってみるメモ

注意

ただのメモです。これが正解かどうかはまだわかってません。

環境

  • node v10.12.0
  • yarn 1.15.2

スタート

  • yarn global add typescript
  • yarn global add tslint
  • npx create-nuxt-app myproject 好きなものを選ぶ(buefy使いたいから選ぶ)
  • cd myproject
  • yarn.lockを削除
  • node_modulesを削除
  • package.jsonでnuxtのバージョンを2.5.1に書き換えてみる
  • yarn add -D @nuxt/typescript vue-property-decorator
  • echo "{}" > tsconfig.json ファイル作る
  • yarn add -D @typescript-eslint/parser
  • yarn add -D sass-loader node-sass
  • assets/css/main.scssを作って公式ドキュメントにある内容をペースト(https://buefy.org/documentation/customization
  • nuxt.config.jsのcss:[]にassets/css/main.scssを追記。色を変えたりなどして確認
  • yarn nuxt dev -o で起動するとなんかかっこいい。`
  • サンプルを参考に.vueファイルのscript部分をlang="ts"にしてTypescriptに書き換え
  • Propで警告がでるがts-config.json "strictPropertyInitialization": false,を追加してvscode再起動して回避
  • ipでアクセスできるようにnuxt.config.jsに追記 server: { port: 3014, // デフォルト: 3000 host: '0.0.0.0' // デフォルト: localhost, },
  • IE11でも表示できるようにnuxt.config.jsのhead.metaに追記 { hid: 'http-equiv', 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' }

Vue.js入門を読んでて

基本的にはすごく良い本じゃないかなと思うんですが

読むのが苦手な人を突き放すような書かれ方があってイラっとする箇所があります。

例えば

5.4.3 の createElement関数のあたり

第二引数の呼び方が毎回違う

  • オプションを含むデータオブジェクト
  • 属性オブジェクト
  • オプション
  • データオブジェクト

第二引数について書いてあるのかどうかを判断できない

同じ文脈の中に「省略可能」って意味(だと思う)のオプションというワードも出てきて

これはすでに知っている人じゃないとすごく伝わりにくいと感じました。

それとは別に第一引数の説明も「非同期にそれらを解決する関数」について書かれているのか書かれてないのか

実際に「非同期にそれらを解決する関数」がどういうものなのか知らない人からするとわからない。

書かれてない気がするんだけど・・・別の呼び名で実は説明されているのかもしれない。わからない。。。

読むのが下手な私には難しい

好きなボーカリストさん

なんとなく好きor尊敬or神な人を忘れないように書き出しておこうと思った

  • skin(スカンク・アナンシーの元ボーカル) 歌声が全てをねじ伏せる。なんだか大好き

  • angraの初代ボーカル アンドレ・マトス

  • マイクベゼーラ

  • メタリカのジェイムス。声が好きすぎる。シャウトばっかり目立ってるみたいだけど単純に歌が上手い

  • 稲葉浩志

  • kokia 調和という曲のライブ映像がやばすぎる。神なんぞ信じてないけどこの人に神のお告げとか言われたら信じない自信がない。

  • 玉置浩二

  • 宇多田ヒカル デビュー当時はブレスが日本人っぽくなくて好きだなと。休業前のライブ音源はやばかった。歌がキレキレ。

  • 槇原敬之 ザ・ミックスボイス!

  • 平井堅 ザ・ミックスボイス2!

  • 秦基博(TVの生歌は疲れが出てる事あるけど)

  • いきものがかりの人

  • ドリカムの吉田さん

  • ニッケルバックの人

映像なし。声がかっこよすぎて曲が頭に入ってこない

Vue2系とTypescript2系

本格的にTypescriptを勉強したいし、何か作りたいんだけど、何をどう初めていいのかよくわからない今日この頃。

  • vue2系
  • typescript2系
  • webpack 2系
  • nodeは確か7系で検証
  • .vueファイルを使っとこう
  • sassを使っとこう
  • vuexはあとにしとこう
  • vue-routerはいらないかな
  • SSRっていまいち何がしたいのかわかってない

ってな感じで雛形ってみた。 参考にさせてもらったのは

Vue.jsとTypeScript - Qiita

GitHub - Microsoft/TypeScript-Vue-Starter: A starter template for TypeScript and Vue with a detailed README describing how to use the two together.

自分で色々触りながら理解を深めるための雛形としてメモを残そうと思います。

はい、完全に自分用。WEBに漂うゴミっす。

setup step

1. yarn init

2. add lib to dev

    yarn add -D css-loader extract-text-webpack-plugin html-webpack-plugin node-sass sass-loader ts-loader typescript
    vue-template-compiler vue-template-loader webpack tslint-language-service vue-ts-plugin vue-loader file-loader url-loader

3. add lib

    yarn add tslib vue vue-class-component vue-property-decorator vuex vuex-class

4. create template.html

        <html lang="ja">
            <head>
                <meta charset="UTF-8">
                <title>Vue Type 君</title>
            </head>
            <body>
                <div id="app"></div>
            </body>
        </html>

5. create tsconfig.json

    {
        "compilerOptions": {
            "module": "es2015",
            "moduleResolution": "node",
            "target": "es5",
            "noImplicitAny": true,
            "sourceMap": true,
            "strictNullChecks": true,
            "typeRoots": [
                "./node_modules/@types"
            ],
            "lib": [
                "dom",
                "es5",
                "es2015"
            ],
            "noEmitHelpers": true,
            "experimentalDecorators": true,
            "importHelpers": true,
            "allowSyntheticDefaultImports": true,
            "emitDecoratorMetadata": true,
            "plugins": [
                {
                    "name": "tslint-language-service"
                },
                {
                    "name": "vue-ts-plugin"
                }
            ]
        },
        "include": [
            "./src/**/*"
        ]
    }

6. create tslint.json

    {
        "defaultSeverity": "error",
        "extends": [
            "tslint:recommended"
        ],
        "jsRules": {},
        "rules": {
            "quotemark": [
                true,
                "single"
            ],
            "indent": [
                true
            ],
            "interface-name": [
                false
            ],
            "arrow-parens": false,
            // Pending fix for shorthand property names.
            "object-literal-sort-keys": false
        },
        "rulesDirectory": []
    }

7. create webpack.config.js

    var path = require("path");
    var webpack = require("webpack");
    const HTMLWebpackPlugin = require('html-webpack-plugin')
    const ExtractTextPlugin = require('extract-text-webpack-plugin')

    module.exports = {
    entry: "./src/index.ts",
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "build.js"
    },
    module: {
        rules: [
        {
            test: /\.tsx?$/,
            loader: "ts-loader",
            exclude: /node_modules/,
            options: {
            appendTsSuffixTo: [/\.vue$/]
            }
        },
        {
            test: /\.vue$/,
            loader: "vue-loader",
            options: {
            loaders: {
                scss: ExtractTextPlugin.extract({
                use: ['css-loader', 'sass-loader'],
                fallback: 'vue-style-loader' // <- this is a dep of vue-loader, so no need to explicitly install if using npm3
                })
            }
            // other vue-loader options go here
            }
        },
        {
            test: /\.(png|jpg|gif|svg)$/,
            loader: "file-loader?name=assets/[name].[ext]"
        }
        ]
    },
    resolve: {
        extensions: [".ts", ".js", ".vue", ".json"],
        alias: {
        vue$: "vue/dist/vue.esm.js"
        }
    },
    devServer: {
        historyApiFallback: true,
        noInfo: true
    },
    performance: {
        hints: false
    },
    devtool: "#eval-source-map",
    plugins: [
        new HTMLWebpackPlugin({ template: './template.html' }),
        new ExtractTextPlugin('styles.css')
    ]  
    };

    if (process.env.NODE_ENV === "production") {
    module.exports.devtool = "#source-map";
    // http://vue-loader.vuejs.org/en/workflow/production.html
    module.exports.plugins = (module.exports.plugins || []).concat([
        new webpack.DefinePlugin({
        "process.env": {
            NODE_ENV: '"production"'
        }
        }),
        new webpack.optimize.UglifyJsPlugin({
        sourceMap: true,
        compress: {
            warnings: false
        }
        }),
        new webpack.LoaderOptionsPlugin({
        minimize: true
        })
    ]);
    }

    

8. create ./src and ./dist directory

9. create index.ts

    import Vue from "vue";
    import App from "./components/App.vue";

    let v = new Vue({
        el: "#app",
        render: h => h(App)
    });

10. create components/App.vue

    <template>
        <div>
            Name:
            <input v-model="name" type="text">
            <hello-component :name="name" :initialEnthusiasm="5" />
        </div>
    </template>
    <script lang="ts">
    import Vue from "vue";
    import Component from 'vue-class-component'
    import { Prop } from 'vue-property-decorator'

    import HelloComponent from "./Hello.vue";

    @Component<App>({
        components: {
            HelloComponent
        }
    })
    export default class App extends Vue {
        name = 'わたしだ'
    }

    </script>
    <style lang="scss">
    @import '../assets/style/main.scss';
    </style>

11. create components/Hello.vue

    <!-- src/components/Hello.vue -->
    <template>
        <div>
            <div class="greeting">Hello {{name}}{{exclamationMarks}}</div>
            <button @click="decrement">-</button>
            <button @click="increment">+</button>
        </div>
    </template>

    <script lang="ts">
    import Vue from "vue";
    import Component from 'vue-class-component'
    import { Prop } from 'vue-property-decorator'

    @Component<Hello>({
    })
    export default class Hello extends Vue {
        @Prop() readonly name: string;    
        @Prop() readonly initialEnthusiasm: number;

        enthusiasm = this.initialEnthusiasm;

        increment() { this.enthusiasm++; };

        decrement() {
            if (this.enthusiasm > 1) {
                this.enthusiasm--;
            }
        };

        get exclamationMarks(): string {
            return Array(this.enthusiasm + 1).join('!');
        }
    }

    </script>

    <style lang="scss">
    .greeting {
        font-size: 20px;
    }
    </style>    

12. create assets/style/main.scss

    body {
        margin: 0;
        padding: 0;
        font-family: Arial, Helvetica, sans-serif;
        background-image: url("../assets/images/logo.png");
    }

13. create assets/images/logo.png

exec webpack command. check dist directory.

Vueのコンポーネントをテストするのにmockを使いたい時

sinonの使い方を一生懸命調べようとしてたんだけどinject-loaderを使えばいいのね。

へー!!

Testing with Mocks · GitBook