20201126のvue.jsに関する記事は8件です。

Vue + axios + Spring BootでCORSでクマった時の対処法

CORSエラーで絶対に躓かないために

CORSとは何か

正式名称は"Cross Origin Resource Sharing"
セキュリティの観点から、リソースを制限するものだと思います。
詳しくは、こちらの記事がより丁寧に説明してくれています。?
https://qiita.com/att55/items/2154a8aad8bf1409db2b

実際の実装

axios側の設定?

originには、postのparamsが含まれています。

import service from '../utils/service'

export const api = {
  async getRoute(origin) {
    return await service
      .post('http://localhost:8080/getRoute', origin, {
        withCredentials: true,
      })
      .then(result => {
        return result.data
      })
      .catch(result => {})
  },
}

serviceでは、axiosの設定そしています。

import axios from 'axios'
import { api } from '../config/api'

const service = axios.create({
  timeout: 30000,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8',
  },
  emulateJSON: true,
  withCredentials: true,
})

Vue側の設定?

  methods: {
    async searchRoute() {
      const params = {
        origin: this.markers.marker[0].position,
        direction: this.direction,
      }
      const result = await api.getRoute(params)
    },

Vueのmethodsのところで呼び出します。

Spring Boot側での設定

私は、Springfilterを使ってnetworkのconfigを設定しました。
Vueはlocalhost:9000で動かしているので、9000を許可します。

CorsConfig.java

@Configuration
public class corsConfig {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(new ArrayList<>(Arrays.asList("http://localhost:9000")));
        config.setAllowCredentials(true);
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.addExposedHeader("Set-Cookie");

        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        return new  CorsFilter(configSource);
    }
}

Controller.java

@CrossOrigin(origins = {"http://localhost:9000"})
@RestController
public class RouteController {

    @Autowired
    RouteManager routeManager;

    @PostMapping("/getRoute")
    public DirectionsResult sendGetRouteReq (@RequestBody GetRouteReq req) throws InterruptedException, ApiException, IOException {
        DirectionsResult result = routeManager.getRoute(req.getOrigin(), req.getDirection());
        return result;
    }
}

こんな感じで実装しました。
参考になりましたら幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10のPCにVueCLIを使用してVue.jsの環境を構築

〈下準備〉
Node.js、IDE環境(今回はVSCode)のインストールを行います。

①Node.jsのインストール

下記のURLよりNode.jsのインストールを行います。
https://nodejs.org/ja/

※VueCLSを使用するにはNode.jsのバージョンは8.9以上がインストールされている必要があります。
すでにNode.jsはインストールされているがバージョンが8.9未満の場合はインストールを行いましょう。

【確認方法】
コマンドプロンプトで「node --version」のコマンドを実行

Nodejsバージョン確認コマンド.png

実行すると画像のようにバージョンが表示される

②VSCodeのインストール

下記のURLよりインストールを行います。
https://azure.microsoft.com/ja-jp/products/visual-studio-code/

/-----------------------------------------------------------------------------------------------------/

ここからが実際のインストールです。
ここからのコマンドはVSCode上のターミナルからすべて実行します。

【ターミナルの表示方法】
VSCodeメニューの「View」→「Terminal」と選択してください。

①Vue CLIのnpmパッケージをインストール

次のコマンドを実行します。
npm install -g @vue/cli

処理が走るので、一通り終わったところで下記のコマンドを実行します。
vue -V

コマンド実行後にバージョン情報が表示されたらインストールは成功です。

次はプロジェクトの作成方法について書きます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue-CLI + Vuexでポケモンのパーティを構築するSPAをつくる。

概要

ポケモンのパーティを構築して遊べるSPAです。
VueでSPAを作りたいなーと思って作り始めた。
加えて、listの高速なフィルター機能も使いたい。
実装はGitHubPagesを使ってフロントエンドのみ。

GitHub pokemon-zukan

readme.jpg

技術・ライブラリ

  • Vue-CLI
  • Vuex
  • lodash
  • moji
  • axios
  • ityped
  • babel-polyfill
  • reset-css
  • progressbar.js

つくったもの

パーティをつくる

ポケモンずかんからポケモンをピックアップし、パーティを構築する。

ずかん

パーティはVuexのstoreで管理し、てもち画面で確認できる。

てもち

ポケモンの詳細をみる

vue-routerを利用して詳細画面を生成。
ポケモンのステータスを確認できる。

しょうさい

詳細設計

ポケモンのステータス、画像

axiosで外部APIから取得。

フォント

pokemon-font

検索機能

computed()でフィルター、ソートを実現。
早くてかっこいい。(全データを取得してるだけだから数が大きくなると問題だけど。)

ソート

  • なまえ
  • ばんごう
フィルター
  • なまえ検索
  • タイプ

どれもjsで操作しているだけなのでレスポンスが早い。
さらになまえ検索は日本語入力未決定前でも検索できるようにしている。早い。

vue
<input @input="handleInput"></input>
js
    handleInput(event) {
      this.wd = event.target.value //未決定の値を取得
    },

タイプフィルターはチェックボックスから選ぶ。

フィルター

おわり

細かい実装やその方針などは省略していますが、素人ながらかなり手こずりました。
良い勉強になりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Nuxt.js】Vuex基礎編②stateを複数使ってみよう

? この記事はWP専用です
https://wp.me/pc9NHC-en

前置き

今回は前回の基礎編に続き、
stateが複数ある場合の書き方です✍️
基礎編でVuexの基本的な解説はしています!
また基礎編のコードに追記するので
そちらを確認しながらやってみてください?

Vuex基礎編はこちら
https://note.com/aliz/n/n497914c981c8

やりたいこと

picture_pc_f55edca4f826019fede322e05e15c0ba.gif

基礎編のカウンターを2つに増やします!
これだけ!!!

NGパターン

picture_pc_18c865e53858c3abb3d3d4560c782d23.gif

まずはNGパターンから。
まずはstateにsubCounterを追加。
mutationsなどにも同様に
subCounterについて追記します✍️

が!
これだと後述したsubCounterに
全てがまとまってしまいます。。。

? 続きはWPでご覧ください?
https://wp.me/pc9NHC-en

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue-CLIを使ってVue.js開発環境をお手軽に実装する

はじめに

Vue-CLIをつかって最速でVueアプリケーションの雛形を作成します。今回はnpmを使用するので、あらかじめnode.jsがインストールされている前提で進めていきます。

参考環境

  • apple MacBook (Retina, 12-inch, Early 2016)
  • macOS Catalina 10.15.4

Vue-CLIとは

Vue-CLIは、Vue.jsでアプリケーションを構築する際に、開発環境をセットアップしてくれたりする公式のコマンドラインツールです。今回解説するプロジェクトの作成以外にもいろいろできるみたいです。

Vue-CLIのインストール

早速Vue-CLIをインストールしていきます。Macの場合はターミナルを、Windowsの場合はコマンドプロンプトを開いて下記のコマンドを実行すると最新バージョンがインストールされます。(記事作成時の最新は4.5.9)

npm install -g @vue/cli
vue --version #バージョンの確認

プロジェクトの作成

次にプロジェクトを作成したいディレクトリに移動して

vue create myproject #プロジェクト名

実行すると

Vue CLI v4.5.9
❯ Default ([Vue 2] babel, eslint)  
  Manually select features 

と表示されます。特定のライブラリを使用する予定がない場合はDefault ([Vue 2] babel, eslint)Default (Vue 3 Preview) ([Vue 3] babel, eslint)を選択してエンターするだけでプロジェクトが作成されます。これらを選択した場合も後からライブラリの追加ができるようです。

プロジェクトをマニュアルで作成する

Manually select featuresを選択すると下記のように表示されます。

? Check the features needed for your project: 
❯◉ Choose Vue version
 ◯ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◉ Vuex
 ◯ CSS Pre-processors
 ◯ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

カーソルキーで移動、スペースキーで選択ができます。今回はRouterとVuexを選択しました。選択した状態でエンターするとVueのバージョンと各ライブラリの設定を行うことができます。

プロジェクトの動作確認

cdコマンドでプロジェクトのディレクトリに移動し、npmでサーバー(http-server)を起動して動作を確認します。

npm run serve
  App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://192.168.10.30:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

サーバーの起動に成功すると上のように表示されるので、ブラウザでhttp://localhost:8080/にアクセスします。
スクリーンショット 2020-11-26 13.46.21.png
このように表示されていればプロジェクトの作成は完了です!

追記

Vue-CLIを使用して作ったプロジェクトで認証機能を作成しました!よかったらこちらもご覧ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[vue.js] クリックすると編集可能に切り替え、入力した後、input value を取得する(v-if/v-show $refs)

参考先「1」でinput実装したけど、更新されたinput値はどうやって取得するかは苦戦した!

v-ifを使う時に、$refsでinput valueなどを取得したいのに、undefined になっていることがよくあります!($refs.inputまで値出ているけど、$refs.input.XXXにすると、undefinedになった)

色々調べて、原因はわかった、参考先「2」より

ref の登録タイミングに関する重要な注意事項として、参照自体は、render 関数の結果として作成されているため、最初の描画においてそれらにアクセスすることができません。それらはまだ存在しておらず、$refs はリアクティブではなく、従ってデータバインディングのためにテンプレートでそれを使用すべきではありません。

のためです!
下記の方法で一応、編集モードからテキストモードに切り替えると、更新されたinput値を取得できた!

*** IDを付与して、document.getElementById('post_wgt').innerTextでvalueをgetします ***

<template>
 <div id="app">
  <div class="text" id="post_wgt" v-if="!edit" v-text="value" v-on:click="edit = true"></div>
  <b-inform-input v-if="edit" type="text" ref="input"
          v-model="value" v-on:blur="edit = false"  v-focus></div>
  <b-button @click="onSave()" variant="outline-info" >保存</b-button>
</template>
<script>

export default {
  data () {
    return {
      edit: false
    }
  },
  directives: {
    focus: {
      inserted: function (el) {
        el.focus()
      }
    }
  },
  methods: {
    onSave () {
      this.$nextTick(() => {
       console.log(document.getElementById('post_wgt').innerText)
      )}
    }
  }
}

</script>

参考先:
1、[vue]クリックすると編集可能に切り替わるテキスト
2、vue.js(ref)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsで上手く初期表示が出来なかったときの謎を再レンダリングで無理やり解決した

Vue.jsとFirebaseを利用して、Cloud Firestore からデータを読み込んで初期表示させたかったが、上手く初期表示できず苦しんだのでメモ。

事象

データベース(Firebase)から取得したデータを、Vue.jsの"Test[0]"と"Test[1]"に入れて表示させたかったが、何故か表示がされなかった。コンソールで見るとちゃんとデータは取得出来ているのに、、謎。
image.png

取り敢えずv-ifのレンダリングで無理やり解決させた。データベースに保存した内容が表示される。
image.png

v-ifの再レンダリングで無理やり解決したコード

無理やり解決させた時の全体コードを書いておく。(あまり良くない解決の仕方ではあると思う。)

.html
<!DOCTYPE html>
<html lang="jp" >
<head>
  <meta charset="UTF-8">
  <title>Vuejs Rerender</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <!-- 全体をVue.js有効にする -->
  <div id="app" v-if="Show === 1">
    <input v-model="Test[0]">
    <input v-model="Test[1]">
  </div>

  <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/firebase/8.0.1/firebase.js'></script>
  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authDomain: "xxxx.firebaseapp.com",
      databaseURL: "https://xxxx.firebaseio.com",
      projectId: "xxxx",
      storageBucket: "xxxx.appspot.com",
      messagingSenderId: "999999999999",
      appId: "1:999999999999:web:xxxxxxxxxxxxxxxxxxxxxx"
    };

    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
    const db = firebase.firestore();

    const app = new Vue({
      el: '#app', // Vueが管理する一番外側のDOM要素
      data: {
        // Vue内部で利用する変数定義
        Test: ["0000","1111"],
        Show: 0,  // 再レンダリング用
      },

      created: async function (){
        // Firebaseから初期値を読み込み
        await this.FirebaseSet();
        console.log(`Test[0]:${this.Test[0]},Test[1]:${this.Test[1]}`);
        // 上手いこと初期表示できないから無理やりレンダリング
        this.Show = 1;
      },

      methods: {
        // 関数はココに記述
        FirebaseSet: async function() {
          // CloudFirestoreからデータ取得
          let docRef = db.collection("hpcaccede").doc("User01");
          let me = this;  // thisを関数内で使えないので変数に代入

          await docRef.get().then(function(doc) {
            if (doc.exists) {
              me.Test[0] = doc.data().test1;
              me.Test[1] = doc.data().test2;
            } else {
              console.log("No such Cloud Firestore document!");
            }
          });
        },
      },
    });
  </script>
</body>
</html>

ポイント

全体に対して、v-ifで再レンダリングさせる。

.html
<div id="app" v-if="Show === 1">

"Show"変数の初期値は"0"として非表示。

.js
const app = new Vue({
  el: '#app',
  data: {
   Test: ["0000","1111"],
   Show: 0,  // 再レンダリング用
  },});

"created"の最後に"this.Show"を"1"に更新して、再レンダリングさせる。

.js
created: async function (){
  await this.FirebaseSet();
  console.log(`Test[0]:${this.Test[0]},Test[1]:${this.Test[1]}`);
  // 上手いこと初期表示できないから無理やりレンダリング
  this.Show = 1;
},

原因と思われる個所を特定した

色々切り分けていくと、配列が悪さをしているっぽいことが判明。
vue.jsのルールなのか、私の書き方が悪いのかは知らんけど、Test配列を止めたら再レンダリングせずに上手く表示できた。(body要素内だけ記述しておく。)

.html
<body>
  <!-- 全体をVue.js有効にする -->
  <div id="app">
    <input v-model="Test0">
    <input v-model="Test1">
  </div>

  <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/firebase/8.0.1/firebase.js'></script>
  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authDomain: "xxxx.firebaseapp.com",
      databaseURL: "https://xxxx.firebaseio.com",
      projectId: "xxxx",
      storageBucket: "xxxx.appspot.com",
      messagingSenderId: "999999999999",
      appId: "1:999999999999:web:xxxxxxxxxxxxxxxxxxxxxx"
    };

    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
    const db = firebase.firestore();

    const app = new Vue({
      el: '#app', // Vueが管理する一番外側のDOM要素
      data: {
        // Vue内部で利用する変数定義
        Test0: "0000",
        Test1: "1111",
        //Show: 0,  // 再レンダリング用
      },

      created: async function (){
        // Firebaseから初期値を読み込み
        await this.FirebaseSet();
        //console.log(`Test[0]:${this.Test[0]},Test[1]:${this.Test[1]}`);
        console.log(`Test0:${this.Test0},Test1:${this.Test1}`);
        // 上手いこと初期表示できないから無理やりレンダリング
        // this.Show = 1;
      },

      methods: {
        // 関数はココに記述
        FirebaseSet: async function() {
          // CloudFirestoreからデータ取得
          let docRef = db.collection("hpcaccede").doc("User01");
          let me = this;  // thisを関数内で使えないので変数に代入

          await docRef.get().then(function(doc) {
            if (doc.exists) {
              // me.Test[0] = doc.data().test1;
              // me.Test[1] = doc.data().test2;
              me.Test0 = doc.data().test1;
              me.Test1 = doc.data().test2;
            } else {
              console.log("No such Cloud Firestore document!");
            }
          });
        },
      },
    });
  </script>

</body>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js、emitで動かすかcallbackで動かすか

はじめに

Vue.jsでコンポーネント間のやり取りを記述する場合、親はプロパティ(props)を利用してデータを受け渡し、イベント(event)を利用して子コンポーネントの動作を購読する形式が一般的かと思います。

こうした中、TypeScript x Vue.jsでの実装をプロダクト開発で行っていく際に、propsにコールバック関数を渡したほうが型安全に記述でき、ランタイムエラーを減らせるのではないか?という意見が開発チーム内で挙がったため、従来のevent駆動形式とpropsにコールバック関数を渡す形式をそれぞれで比較し、どちらが型安全に開発ができそうか比較してみます。

前提

こうしたemit vs props-callback論争?はすでにいくつか意見があるようでした

Events vs callback props

vue, emitting vs passing function as props

「propで子に渡してeventで親に伝える」が基本理念というのは正しいようですが、callbackでも同じことは実現できるというようですね。

検証

ボタンをクリックするとconsoleにmessageを渡すような部品を作ってみて検証してみます。
実装したサンプルはこちらのGithubリポジトリに公開していますので、ご自由に参照ください。

まずはevent駆動のボタン部品ですが、以下のように
発火するイベントで渡す値をEmitButtonClickEventValueという型で指定する形です。
このボタンだけで見れば、クリックしたことを親に伝えることだけを意識すれば良く、その先を意識することはありません。

EmitButton.vue
<template>
  <button @click="emitClick">イベント駆動ボタン</button>
</template>

<script lang="ts">
import Vue from "vue";
import { Component, Emit } from "vue-property-decorator";

export type EmitButtonClickEventValue = {
  message: string;
};

@Component
export default class EmitButton extends Vue {
  @Emit("click")
  emitClick(): EmitButtonClickEventValue {
    return {
      message: "myEmitMessage"
    };
  }
}
</script>

一方で、callback駆動のボタン部品です。
こちらはevent駆動のものとは違い、CallbackButtonOnClickCallbackという名前でコールバック関数の型を定義しています。
また、executeClickCallback関数内に記述している通り、親から渡されたコールバック関数が存在するかを意識する必要が出てきます。

CallbackButton.vue
<template>
  <button @click="executeClickCallback">コールバック駆動ボタン</button>
</template>

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

export type CallbackButtonOnClickCallback = (value: {
  message: string;
}) => void;

@Component
export default class CallbackButton extends Vue {
  @Prop({ type: Function, required: false })
  onClick?: CallbackButtonOnClickCallback;

  executeClickCallback() {
    if (!this.onClick) return;
    this.onClick({ message: "myCallbackMessage" });
  }
}
</script>

続いて、上記2つのボタンを利用する親のコンポーネントを見ていきましょう。
ここで、イベント駆動型ボタン部品と連動しているonEmitButtonClickでは、EmitButton.vueclickイベントで渡される引数の型EmitButtonClickEventValueをimportして利用する必要があります。
一方で、コールバック駆動型ボタン部品と連動しているonCallbackButtonClickでは、CallbackButton.vueのpropに定義したコールバック関数の型CallbackButtonOnClickCallbackをimportして利用する必要があります。

App.vue
<template>
  <div id="app">
    <emit-button @click="onEmitButtonClick" />
    <callback-button :on-click="onCallbackButtonClick" />
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import EmitButton, {
  EmitButtonClickEventValue
} from "./components/EmitButton.vue";
import CallbackButton, {
  CallbackButtonOnClickCallback
} from "./components/CallbackButton.vue";

@Component({
  components: {
    EmitButton,
    CallbackButton
  }
})
export default class App extends Vue {
  // イベント駆動の場合、イベントから渡される値の型を知っている必要がある
  onEmitButtonClick(value: EmitButtonClickEventValue) {
    console.log(value.message);
    // -> 'myEmitMessage'
  }

  // コールバック駆動の場合、コールバック関数のインターフェースを知っている必要がある
  onCallbackButtonClick: CallbackButtonOnClickCallback = value => {
    console.log(value.message);
    // -> 'myCallbackMessage'
  };
}
</script>

どちらで実装すべきか

では、上記の2つの実装方式どちらを選択すべきでしょうか?
いくつかの観点から見てみます。

型安全の観点

先ほど実装したコンポーネントの型が変化した際、壊れやすいのはどちらでしょうか?
改めてそれぞれの実装形式で定義した型をまとめると、それぞれ

export type EmitButtonClickEventValue = {
  message: string;
};

export type CallbackButtonOnClickCallback = (value: {
  message: string;
}) => void;

ですが、messageを配列で渡すような修正を行い、

export type EmitButtonClickEventValue = {
  messages: string[];
};

export type CallbackButtonOnClickCallback = (value: {
  messages: string[];
}) => void;

に変更したとしましょう。
この場合、利用元のApp.vueではtype errorが発生し、変更を静的に検知することが出来ます。
そのため、既存の定義済の型を変更する分にはどちらの実装形式も特に変わりないといえます。

一方、今回のevent vs callbackそのものには関係ないのですが、現在Vue.jsの制約として型テンプレート内と、eventで渡される型そのもの静的型推論は効かない(はず)なので、以下のようにそもそもの型を変更するような修正をした場合は親側でimportしている型を変更する必要があります。

EmitButton.vue
<template>
  <button @click="emitClick">イベント駆動ボタン</button>
</template>

<script lang="ts">
import Vue from "vue";
import { Component, Emit } from "vue-property-decorator";

// 元の型を残したまま
export type EmitButtonClickEventValue = {
  message: string;
};

// 新しい型を作って 
export type NewEmitButtonClickEventValue = {
  message: number[];
};

@Component
export default class EmitButton extends Vue {
  @Emit("click")
  emitClick(): NewEmitButtonClickEventValue {
    return {
      message: 12345
    };
  }
}
</script>

Vue.jsの基本理念

冒頭にも記述した通り、Vue.jsのコンポーネントの基本理念はpropsとeventで親子のやり取りを行うことだと思います。
そのため、prop-eventパターンで記述できるのであればそちらを選択するのが安牌だと考えています。
いべn
またcallback形式を選択した場合、例えば以下のようにネイティブのHTMLElementと組み合わせた際にイベント駆動とコールバック駆動の記述が混在してしまう恐れや、

sample.vue
<template>
  <div>
    <input type="text" :value="myTextValue" @input="onMyTextValueChange"/>
    <callback-button :on-click="onClickCallback"/>
  </div>
</template>

コールバック関数用のpropの命名規則を固めないと、親から見た際にコールバック関数を渡しているのかプリミティブな値を渡しているのか判別しにくいという問題もあるとは思います。 

sample.vue
<template>
  <my-sample-component
    :name="myName"
    :my-value="myValue"
    :on-click="onClickCallback"
    :context-menu="contextMenuFunction"
  />
</template>

結論

結論ですが、プロジェクトのメンバーと意見を擦り合わせつつ、好きなほうを選択すればいいと思います(最後に投げやりですみません)。
上記で見た通り、型推論の観点でもどちらも大差ないと思えますし、アプリケーションの要件はどちらの実装方式でも満たすことが出来ると思います。

私はprop-eventに長く触れてきており、これからもこの形式を推していきますが、プロジェクトの状況・メンバーや、Vue.jsが進化していく中で常に考え、検証を行い、堅牢なアプリケーションを開発していくことが大事かなーと思いました。

最後まで読んでくれた方がいれば、駄文にお付き合いいただきありがとうございました。
うちはこうやってるよー、とか、もっとこうした方が良いのでは?等意見がありましたら頂けると嬉しいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む