Skip to content

17. [nuxt-20] örneği: [vuejs-22] örneğinin uyarlanması

17.1. Présentation

Burada, SPA türündeki [vue.js] uygulamasını oluşturan [vuejs-22] örneğini, [nuxt] SSR bağlamına taşımayı öneriyoruz. [vuejs-22], vergi hesaplama sunucusunun bir istemci uygulamasıydı ve aşağıdaki görünümleri içeriyordu:

İlk görünüm, kimlik doğrulama görünümüdür:

Image

İkinci ekran, vergi hesaplama ekranıdır:

Image

Üçüncü ekran, kullanıcı tarafından yapılan simülasyonların listesini gösteren ekrandır:

Image

Yukarıdaki ekran, 1 numaralı simülasyonun silinebileceğini göstermektedir. Bunun üzerine aşağıdaki görünüm elde edilir:

Image

Şimdi son simülasyonu silersek, aşağıdaki yeni ekran karşımıza çıkar:

Image

[vuejs-22] uygulamasını kademeli olarak [nuxt-20] uygulamasına taşıyacağız. [vuejs-22] kodlarını tekrar açıklamayacağız. Okuyucunun |Introduction au framework VUE.JS par l’exemple| belgesini tekrar gözden geçirmesi önerilir. Farklı adımlar, bir [vuejs] uygulaması ile bir [nuxt] uygulaması arasındaki farkları göstermelidir.

17.2. 1. adım

[nuxt-20] projesi, başlangıçta [nuxt-12] projesinin kopyalanmasıyla elde edilir. Bu proje, aslında iyi bir başlangıç noktasıdır:

  • vergi hesaplama sunucusuyla iletişim kurabiliyor;
  • sunucunun gönderdiği hataları doğru bir şekilde yönetir;
  • [nuxt] istemcisi ve sunucusu, bir [nuxt] oturumu aracılığıyla iletişim kurabiliyor;

Dolayısıyla iyi bir başlangıç altyapısına sahibiz. Asıl işimiz şu değişiklikleri yapmak olmalı:

  • sayfaları değiştirmek. [vuejs-22] projesindeki sayfaları alıp yeni ortama uyarlayacağız;
  • mağaza yönetimi. Ek bilgiler eklenmeli (simülasyon listesi) ve bazı bilgiler ise gereksiz hale gelebilir;
  • [nuxt] istemci ve sunucu yönlendirme yönetimi;

Bu nedenle öncelikle, [nuxt-12] projesini kopyalayarak [nuxt-20] projesini oluşturacağız:

Image

Ardından, artık gereksiz hale gelen sayfaları ve bileşenleri siliyoruz [2]:

  • [components/navigation] bileşeni kaybolur;
  • [layout/default] düzeni kaybolur;
  • [index, authentification, get-admindata, fin-session] sayfaları silinir;

Ardından, [nuxt-20]'e [vuejs-22] ve [3]'ten öğeler eklenir:

  • [vuejs-22] uygulamasındaki üç [Authentification, CalculImpot, ListeSimulations] sayfası, [pages] klasörüne taşınır;
  • [vuejs-22] uygulamasının [FormCalculImpot, Menu, Layout] bileşenleri, [components] klasörüne taşınır;
  • [vuejs-22] uygulamasında [layout] olarak kullanılan [vuejs-22] sayfasının [Main] sayfası, [layouts] klasörüne taşınır;

[4] adlı entegre öğelerin adları şu şekilde değiştirilir:

Image

  • [layouts]'te, [Main], [nuxt] uygulamasının düzeninin varsayılan adı olduğu için [default] haline geldi;
  • [pages] dosyasında, [Authentification] sayfası [index] olarak değiştirilmiştir; çünkü [Authentification], [vuejs-22] uygulamasında bu rolü üstleniyordu;

Bu noktada, ilk hataları görmek için projeyi derleyebiliriz. [nuxt-12] örneğindeki [nuxt.config] dosyasını, artık [nuxt-20]'i çalıştıracak şekilde değiştiriyoruz:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    title: 'Introduction à [nuxt.js]',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: 'ssr routing loading asyncdata middleware plugins store'
      }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  /*
   ** Customize the progress-bar color
   */
  loading: false,

  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [
    { src: '@/plugins/client/plgSession', mode: 'client' },
    { src: '@/plugins/server/plgSession', mode: 'server' },
    { src: '@/plugins/client/plgDao', mode: 'client' },
    { src: '@/plugins/server/plgDao', mode: 'server' },
    { src: '@/plugins/client/plgEventBus', mode: 'client' }
  ],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Belge: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Belge: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Belge: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    // https://www.npmjs.com/package/cookie-universal-nuxt
    'cookie-universal-nuxt'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  },
  // kaynak kod dizini
  srcDir: 'nuxt-20',
  // yönlendirici
  router: {
    // uygulamanın URL kökü
    base: '/nuxt-20/',
    // yönlendirme ara yazılımı
    middleware: ['routing']
  },
  // sunucu
  server: {
    // hizmet bağlantı noktası, varsayılan olarak 3000
    port: 81,
    // dinlenen ağ adresleri, varsayılan olarak localhost: 127.0.0.1
    // 0.0.0.0 = makinenin tüm ağ adresleri
    host: 'localhost'
  },
  // ortam
  env: {
    // axios yapılandırması
    timeout: 2000,
    withCredentials: true,
    baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
    // oturum çerezi yapılandırması [nuxt]
    maxAge: 60 * 5
  }
}

Ardından projenin [build] derlemesini yapıyoruz:

Image

Bildirilen hatalar şunlardır:

1
2
3
4
5
6
7
Module not found: Error: Can't resolve '../assets/logo.jpg' @ ./nuxt-20/layouts/default.vue?...
Module not found: Error: Can't resolve './FormCalculImpot' @ ./nuxt-20/pages/calcul-impot.vue?...
Module not found: Error: Can't resolve './Layout' @ ./nuxt-20/pages/_.vue?...
Module not found: Error: Can't resolve './Layout' @ ./nuxt-20/pages/liste-des-simulations...
Module not found: Error: Can't resolve './Layout' @ ./nuxt-20/pages/calcul-impot.vue?...
Module not found: Error: Can't resolve './Menu' @ ./nuxt-20/pages/_.vue?...
Module not found: Error: Can't resolve './Menu' @ ./nuxt-20/pages/calcul-impot.vue
  • 1. satırdaki hata, var olmayan bir resme atıfta bulunulduğunu gösterir. Bu resim, [vuejs-22] komutunda alınacaktır;
  • 2. satırdaki hata, [./FormCalculImpot] bileşeninin mevcut olmadığını göstermektedir. Nitekim bu bileşen artık [@/components/form-calcul-impot]'te yer almaktadır;
  • [3-5] satırlarındaki hatalar, [./Layout] bileşeninin mevcut olmadığını göstermektedir. Nitekim bu bileşen artık [@/components/layout] içinde yer almaktadır;
  • [6-7] satırlarındaki hatalar, [./Menu] bileşeninin mevcut olmadığını göstermektedir. Nitekim, bu bileşen artık [@/components/menu] olarak adlandırılmaktadır;

[assets/logo.jpg] adlı resim, [nuxt-20] projesine eklenir:

Image

Ayrıca, tüm sayfalarda bileşenlerin yollarını düzelteceğiz. [calcul-impot] sayfasını örnek olarak alalım:


<!-- HTML görünüm tanımı -->
<template>
  <div>
    <Layout :left="true" :right="true">
      <!-- sağdaki vergi hesaplama formu -->
      <FormCalculImpot slot="right" @resultatObtenu="handleResultatObtenu" />
      <!-- sol taraftaki gezinme menüsü -->
      <Menu slot="left" :options="options" />
    </Layout>
    <!-- formun altındaki vergi hesaplama sonuçlarının görüntülenme alanı -->
    <b-row v-if="résultatObtenu" class="mt-3">
      <!-- boş üç sütunlu alan -->
      <b-col sm="3" />
      <!-- dokuz sütunlu alan -->
      <b-col sm="9">
        <b-alert show variant="success">
          <span v-html="résultat"></span>
        </b-alert>
      </b-col>
    </b-row>
  </div>
</template>

<script>
// ithalatlar
import FormCalculImpot from './FormCalculImpot'
import Menu from './Menu'
import Layout from './Layout'

export default {
  // kullanılan bileşenler
  components: {
    Layout,
    FormCalculImpot,
    Menu
  },
  

26-28. satırlardaki üç [import] şu şekilde değiştirilecek:


// ithalatlar
import FormCalculImpot from '@/components/form-calcul-impot'
import Menu from '@/components/menu'
import Layout from '@/components/layout'

Böylece tüm bileşenler, düzenler ve sayfalardaki [import] değerlerini kontrol eder ve gerekirse düzeltiriz. Bu düzeltmeler yapıldıktan sonra, yeni bir [build] denemesi yapabiliriz. Normalde artık hata kalmaz.

Ardından şu komutu çalıştırmayı deneyebiliriz:

Image

Hatalar ortaya çıkıyor:

1
2
3
4
5
6
Module Error (from ./node_modules/eslint-loader/dist/cjs.js):

c:\Data\st-2019\dev\nuxtjs\dvp\nuxt-20\pages\index.vue
   92:29  error  Expected '!==' and instead saw '!='  eqeqeq
  129:27  error  Expected '!==' and instead saw '!='  eqeqeq
150:28  error  Expected '!==' and instead saw '!='  eqeqeq

Görüldüğü üzere, [dev] komutu, [eslint] modülüyle birleştiğinde, sözdizimi açısından [build] komutundan daha katıdır. Burada, [!=] karşılaştırma operatörünün, daha katı bir operatör olan (aynı zamanda işlenenlerin türünü de kontrol eden) [!==] olarak yazılması istenmektedir. Bu hatalar [index.vue] sayfasında ortaya çıkmaktadır.

Yukarıdaki hataları düzelttikten sonra projenin yürütülmesini yeniden başlatıyoruz. Ardından, [eslint] modülünden bir uyarı alıyoruz:

c:\Data\st-2019\dev\nuxtjs\dvp\nuxt-20\components\menu.vue
14:5  warning  Prop 'options' requires default value to be set  vue/require-default-prop

Image

Bu hatayı, [eslint] ve [2] modüllerinden [Quick fix] ile düzeltin.

Projenin yürütülmesini yeniden başlatıyoruz. Artık derleme hatası yok. Ardından bir tarayıcıyla URL ve [http://localhost:81/nuxt-20/] dosyalarını çağırıyoruz. Bir yürütme hatası alıyoruz:

Image

Hata, [index.vue] ve [2] dosyalarında bulunuyor. [1] hatası, [vuejs-22] dosyasında [dao] katmanı [this.$dao]'te mevcutken, altyapısını benimsediğimiz [nuxt-12]'te ise bu katman [this.$dao()] işlevinde mevcut olması nedeniyle ortaya çıkmıştır.

Hata, [index] sayfasının yaşam döngüsündeki [created] işlevinde yer almaktadır:

Image

Şimdilik, yaşam döngüsü fonksiyonu [created]'in çalıştırılmaması için [created]'i [created2] olarak yeniden adlandırıyoruz.

Değişikliği kaydedip [index] sayfasını tarayıcıda yeniden yüklüyoruz. Bu sefer doğru:

Image

17.3. 2. adım

[vuejs-22] projesinin sayfaları aşağıdaki enjekte edilmiş öğeleri kullanıyordu:

  • $dao: [vue.js] istemcisinin [dao] katmanı için;
  • $session: tarayıcının [localStorage]'inde depolanan bir oturum için;

Kopyaladığımız [nuxt-12] proje altyapısında bu öğeler artık mevcut değildir:

  • artık iki [dao] katmanı bulunmaktadır; biri [nuxt] istemcisi, diğeri ise [nuxt] sunucusu içindir. Her ikisi de [$dao] adlı bir enjeksiyon fonksiyonu aracılığıyla kullanılabilir. Bu, uygulama sayfalarında [this.$dao]'in [this.$dao()] ile değiştirilmesi gerektiği anlamına gelir;
  • [nuxt-20] uygulaması tarafından yönetilen [nuxt] oturumu, oturum çerezi kavramının bulunmadığı[vuejs-22] uygulamasındaki [$session] nesnesiyle artık hiçbir ilgisi yoktur; bu uygulamada oturum çerezi kavramı mevcut değildi. Bununla birlikte, her ikisi de benzer bir işlevselliğe sahiptir: kullanıcının eylemleri boyunca kalıcı bilgileri depolamak. [nuxt] oturumu, bilgileri doğrudan oturumda değil, depoda saklar. Uygulamanın sayfalarında, oturumda bilgi depolamak söz konusu olduğunda [this.$session], oturumun kendisiyle işlem yapmak söz konusu olduğunda ise [this.$session()] ile değiştirilmelidir;
  • depolamadaki bir P özelliğinin durumunu öğrenmek için [this.$store.state.P] yazılmalıdır;
  • deposunun P özelliğini değiştirmek için [this.$store.commit(‘replace’, {P:value}] yazılmalıdır;

Bu değişiklikleri [index] sayfasında yapıyoruz:


<!-- HTML görünüm tanımı -->
<template>
  <Layout :left="false" :right="true">
    <template slot="right">
      <!-- HTML formu - değerler [authentifier-utilisateur] eylemi ile gönderilir -->
      <b-form @submit.prevent="login">
        <!-- başlık -->
        <b-alert show variant="primary">
          <h4>Bienvenue. Veuillez vous authentifier pour vous connecter</h4>
        </b-alert>
        <!-- 1. satır -->
        <b-form-group label="Nom d'utilisateur" label-for="user" label-cols="3">
          <!-- kullanıcı giriş alanı -->
          <b-col cols="6">
            <b-form-input id="user" v-model="user" type="text" placeholder="Nom d'utilisateur" />
          </b-col>
        </b-form-group>
        <!-- 2. satır -->
        <b-form-group label="Mot de passe" label-for="password" label-cols="3">
          <!-- şifre giriş alanı -->
          <b-col cols="6">
            <b-input id="password" v-model="password" type="password" placeholder="Mot de passe" />
          </b-col>
        </b-form-group>
        <!-- 3. satır -->
        <b-alert v-if="showError" show variant="danger" class="mt-3">L'erreur suivante s'est produite : {{ message }}</b-alert>
        <!-- 3. satırda [submit] tipi düğme -->
        <b-row>
          <b-col cols="2">
            <b-button :disabled="!valid" variant="primary" type="submit">Valider</b-button>
          </b-col>
        </b-row>
      </b-form>
    </template>
  </Layout>
</template>

<!-- görünüm dinamikleri -->
<script>
/* eslint-disable no-console */
import Layout from '@/components/layout'
export default {
  // kullanılan bileşenler
  components: {
    Layout
  },
  // bileşen durumu
  data() {
    return {
      // kullanıcı
      user: '',
      // şifresi
      password: '',
      // hata mesajının görüntülenmesini kontrol eder
      showError: false,
      // hata mesajı
      message: ''
    }
  },

  // hesaplanan özellikler
  computed: {
    // geçerli girdiler
    valid() {
      return this.user && this.password && this.$store.state.started
    }
  },
  // yaşam döngüsü: bileşen yeni oluşturuldu
  mounted() {
    // eslint-disable-next-line
    console.log("Authentification mounted");
    // kullanıcı simülasyon yapabilir mi?
    if (this.$store.state.started && this.$store.state.authenticated && this.$métier.taxAdminData) {
      // o halde kullanıcı simülasyon yapabilir
      this.$router.push({ name: 'calculImpot' })
      // olay döngüsüne geri dön
      return
    }
    // jSON oturumu daha önce başlatılmışsa, yeniden başlatılmaz
    if (!this.$store.state.started) {
      // bekleme başlıyor
      this.$emit('loading', true)
      // sunucu ile oturum başlatılıyor - asenkron istek
      // [dao] katmanındaki yöntemler tarafından döndürülen söz kullanılır
      this.$dao()
        // bir oturum başlatılıyor jSON
        .initSession()
        // yanıt alındı
        .then((response) => {
          // bekleme sona erdi
          this.$emit('loading', false)
          // yanıtın analizi
          if (response.état !== 700) {
            // hata görüntüleniyor
            this.message = response.réponse
            this.showError = true
            // olay döngüsüne geri dönülüyor
            return
          }
          // oturum başlatıldı
          this.$store.commit('replace', { started: true })
          console.log('[authentification], session=', this.$session())
        })
        // hata durumunda
        .catch((error) => {
          // hata, [Main] görünümüne iletilir
          this.$emit('error', error)
        })
        // her durumda
        .finally(() => {
          // oturum kaydedilir
          this.$session().save()
        })
    }
  },

  // olay yöneticileri
  methods: {
    // ----------- kimlik doğrulama
    async login() {
      try {
        // bekleme başlangıcı
        this.$emit('loading', true)
        // henüz kimlik doğrulaması yapılmadı
        this.$store.commit('replace', { authenticated: false })
        // sunucuda engelleyici kimlik doğrulama
        const response = await this.$dao().authentifierUtilisateur(this.user, this.password)
        // yükleme bitti
        this.$emit('loading', false)
        // sunucu yanıtı analiz ediliyor
        if (response.état !== 200) {
          // hata görüntüleniyor
          this.message = response.réponse
          this.showError = true
          // olay döngüsüne geri dönüş
          return
        }
        // hata yok
        this.showError = false
        // kimlik doğrulaması yapıldı
        this.$store.commit('replace', { authenticated: true })
        // --------- şimdi vergi idaresinden veriler isteniyor
        // başlangıçta veri yok
        this.$métier.setTaxAdminData(null)
        // bekleme başladı
        this.$emit('loading', true)
        // sunucuya yapılan istek bloke edildi
        const response2 = await this.$dao().getAdminData()
        // yükleme tamamlandı
        this.$emit('loading', false)
        // yanıtın analizi
        if (response2.état !== 1000) {
          // hata görüntüleniyor
          this.message = response2.réponse
          this.showError = true
          // olay döngüsüne geri dönüş
          return
        }
        // hata yok
        this.showError = false
        // alınan veri [métier] katmanında saklanıyor
        this.$métier.setTaxAdminData(response2.réponse)
        // vergi hesaplamasına geçilebilir
        this.$router.push({ name: 'calculImpot' })
      } catch (error) {
        // hata ana bileşene iletilir
        this.$emit('error', error)
      } finally {
        // değişiklik kaydedilir
        this.$store.commit('replace', { métier: this.$métier })
        // oturum kaydediliyor
        this.$session().save()
      }
    }
  }
}
</script>

Aşağıdaki noktalara dikkat edelim:

  • 69. satır: [created2] işlevi, [mounted] olarak yeniden adlandırılmıştır; bunun amacı, [nuxt] sunucusunun bu işlevi çalıştırmamasıdır (bu sunucu ne [beforeMount] ne de [mounted] işlevlerini çalıştırır). Sadece [nuxt] istemcisi bunu çalıştıracaktır, tıpkı [vuejs-22] örneğinde olduğu gibi;
  • 73. satır: Şu anda mevcut olmayan [this.$métier]'e atıfta bulunuluyor;
  • 75. satır: Bu yöntemi [nuxt] uygulamasında hiç kullanmadık. [nuxt] bağlamında çalışıp çalışmadığını kontrol etmek gerekecek;
  • satır 112, 172: [vuejs-22]'te proje oturumu bu şekilde kaydedilmişti. [nuxt-20] projesinde ise [save] yöntemine geçerli bağlamın aktarılması gerekir. Bilindiği üzere, [nuxt] sayfasında, [context] nesnesi [this.$nuxt.context]'te mevcuttur;

Bu nedenle 112. ve 172. satırlar şu şekilde yeniden yazılır:


this.$session().save(this.$nuxt.context)

Bu kodun optimize edilmediğine dikkat edilmelidir. [this.$session()] işlevini birkaç kez kullanmak yerine, şu şekilde yazmak daha uygun olur:


const session=this.$session()

ve ardından [session] değişkenini kullanmak daha uygun olur. Aynı mantık, [this.$dao()] işlevi için de geçerlidir.

Bu düzeltmeleri yaptıktan sonra, URL ve [http://localhost:81/nuxt-20/]'i bir tarayıcıyla yeniden yükleyebiliriz. Hala daha önce gördüğümüzle aynı sayfayı elde ediyoruz:

Image

Tarayıcının günlüklerine bir göz atalım:

Image

[1] günlüğü, [nuxt] istemcisi tarafından oluşturulan son günlüktür. [2]'te, [started] özelliğinin [vrai]'e ait olduğunu görüyoruz; bu, [mounted] işlevinin vergi hesaplama sunucusuyla jSON oturumunu başlatmayı başardığı anlamına gelir. Ayrıca, deponun ya silinmesi ya da yeniden adlandırılması gereken özellikleri olduğu da görülüyor. Hatırlayalım ki, [nuxt-12] örneğindeki depoyu kullanıyoruz.

Şimdi, vergi hesaplama sunucusu çalışmıyorken URL ve [http://localhost:81/nuxt-20/] oturumlarını yeniden talep edelim. Öncelikle, [nuxt] oturum çerezini silmeye özen gösterelim:

Image

Yukarıdaki ekran görüntüsü Chrome'dan alınmıştır. Bu işlem tamamlandıktan sonra, URL ve [http://localhost:81/nuxt-20/] çerezleri şu sonucu verir:

Image

Hata, [vuejs-22] projesi tarafından doğru şekilde yönetildi. Hata, [nuxt-20] projesi tarafından da doğru şekilde yönetilmeye devam ediyor.

17.4. 3. adım

Artık kimlik doğrulama sayfasına sahip olduğumuza göre, kullanıcı [Valider] düğmesine tıkladığında yürütülen koda bakmamız gerekiyor:


// olay yöneticileri
  methods: {
    // ----------- kimlik doğrulama
    async login() {
      try {
        // bekleme başlıyor
        this.$emit('loading', true)
        // henüz kimlik doğrulaması yapılmadı
        this.$store.commit('replace', { authenticated: false })
        // sunucuda engelleyici kimlik doğrulama
        const response = await this.$dao().authentifierUtilisateur(this.user, this.password)
        // yükleme bitti
        this.$emit('loading', false)
        // sunucu yanıtı analiz ediliyor
        if (response.état !== 200) {
          // hata görüntüleniyor
          this.message = response.réponse
          this.showError = true
          // olay döngüsüne geri dönüş
          return
        }
        // hata yok
        this.showError = false
        // kimlik doğrulaması yapıldı
        this.$store.commit('replace', { authenticated: true })
        // --------- şimdi vergi idaresinden veriler isteniyor
        // başlangıçta veri yok
        this.$métier.setTaxAdminData(null)
        // bekleme başladı
        this.$emit('loading', true)
        // sunucuya yapılan istek bloke edildi
        const response2 = await this.$dao().getAdminData()
        // yükleme tamamlandı
        this.$emit('loading', false)
        // yanıtın analizi
        if (response2.état !== 1000) {
          // hata görüntüleniyor
          this.message = response2.réponse
          this.showError = true
          // olay döngüsüne geri dönüş
          return
        }
        // hata yok
        this.showError = false
        // alınan veri [métier] katmanında saklanıyor
        this.$métier.setTaxAdminData(response2.réponse)
        // vergi hesaplamasına geçilebilir
        this.$router.push({ name: 'calculImpot' })
      } catch (error) {
        // hata ana bileşene iletilir
        this.$emit('error', error)
      } finally {
        // değişiklik kaydedilir
        this.$store.commit('replace', { métier: this.$métier })
        // oturum kaydediliyor
        this.$session().save(this.$nuxt.context)
      }
    }
  }

Buradaki temel sorun, [this.$métier] verisinin eksikliği gibi görünüyor. Bunu gidermek için şunları yapacağız:

  • [vuejs-22] örneğindeki [Métier] sınıfını ekleyeceğiz. Bunu [api] klasörüne yerleştireceğiz;
  • [nuxt] istemcisinin bağlamına, bu sınıfa erişim sağlayacak bir [$métier] işlevi ekleyeceğiz;

Öncelikle, [Métier] sınıfını [api] klasörüne kopyalayalım:

Image

[Métier] sınıfı projeye eklendikten sonra, [nuxt] istemcisi için yeni bir eklenti oluşturulur. [pluginMétier] adlı bu eklenti, [$métier] işlevini ekleyecek ve bu işlev [Métier] sınıfına erişim sağlayacaktır:


/* eslint-disable no-console */
// [métier] katmanına erişim noktası oluşturuluyor
import Métier from '@/api/client/Métier'
export default (context, inject) => {
  // [métier] katmanının örneklenmesi
  const métier = new Métier()
  // [$métier] işlevinin bağlama enjeksiyonu
  inject('métier', () => métier)
  // günlük
  console.log('[fonction client $métier créée]')
}

Bu işlem tamamlandıktan sonra, [index] sayfasını düzeltebiliriz:


// yaşam döngüsü: bileşen az önce oluşturuldu
  mounted() {
    // eslint-disable-next-line
    console.log("Authentification mounted");
    // kullanıcı simülasyon yapabilir mi?
    if (this.$store.state.started && this.$store.state.authenticated && this.$métier().taxAdminData) {
      // o halde kullanıcı simülasyon yapabilir
      this.$router.push({ name: 'calcul-impot' })
      // olay döngüsüne geri dön
      return
    }
    // jSON oturumu daha önce başlatılmışsa, yeniden başlatılmaz
    ...
  },

  // olay işleyicileri
  methods: {
    // ----------- kimlik doğrulama
    async login() {
      try {
        // bekleme başlangıcı
        this.$emit('loading', true)
        // henüz kimlik doğrulaması yapılmadı
        this.$store.commit('replace', { authenticated: false })
        // sunucuda engelleyici kimlik doğrulama
        const response = await this.$dao().authentifierUtilisateur(this.user, this.password)
        // yükleme bitti
        this.$emit('loading', false)
        // sunucu yanıtı analizi
        if (response.état !== 200) {
          // hatanın görüntülenmesi
          this.message = response.réponse
          this.showError = true
          // olay döngüsüne geri dönüş
          return
        }
        // hata yok
        this.showError = false
        // kimlik doğrulaması yapıldı
        this.$store.commit('replace', { authenticated: true })
        // --------- şimdi vergi idaresinden veriler isteniyor
        // başlangıçta veri yok
        this.$métier().setTaxAdminData(null)
        // bekleme başladı
        this.$emit('loading', true)
        // sunucuya yapılan istek bloke edildi
        const response2 = await this.$dao().getAdminData()
        // yükleme tamamlandı
        this.$emit('loading', false)
        // yanıtın analizi
        if (response2.état !== 1000) {
          // hata görüntüleniyor
          this.message = response2.réponse
          this.showError = true
          // olay döngüsüne geri dönüş
          return
        }
        // hata yok
        this.showError = false
        // alınan veri [métier] katmanında saklanır
        this.$métier().setTaxAdminData(response2.réponse)
        // vergi hesaplamasına geçilebilir
        this.$router.push({ name: 'calcul-impot' })
      } catch (error) {
        // hata ana bileşene iletilir
        this.$emit('error', error)
      } finally {
        // değişiklik kaydedilir
        this.$store.commit('replace', { métier: this.$métier() })
        // oturum kaydediliyor
        this.$session().save(this.$nuxt.context)
      }
    }
  }
  • 43., 61. ve 69. satırlarda, [this.$métier], [this.$métier()] ile değiştirilmiştir;
  • 8. ve 63. satırlar: [vuejs-22] projesindeki [CalculImpot] sayfası, [nuxt-20] projesinde [calcul-impot] sayfası haline getirildi;

Bu düzeltmeler yapıldıktan sonra, kimlik doğrulama sayfasını onaylamayı deneyebiliriz:

Image

Elde edilen sayfa şöyledir:

Image

Vergi hesaplama sayfasını başarıyla elde ettik. Şimdi loglara bakalım:

Image

[2]'te, oturum açma bilgilerinin doğru şekilde kaydedildiğini görüyoruz. [3-4]'te, [Métier] sınıfı aracılığıyla vergi hesaplamasına olanak tanıyan [taxAdminData] verisinin alındığını görüyoruz.

17.5. 4. adım

Elde ettiğimiz [calcul-impot] sayfasını inceleyelim:


<!-- HTML görünümünün tanımı -->
<template>
  <div>
    <Layout :left="true" :right="true">
      <!-- sağdaki vergi hesaplama formu -->
      <FormCalculImpot slot="right" @resultatObtenu="handleResultatObtenu" />
      <!-- sol taraftaki gezinme menüsü -->
      <Menu slot="left" :options="options" />
    </Layout>
    <!-- formun altında vergi hesaplama sonuçlarının görüntülendiği alan -->
    <b-row v-if="résultatObtenu" class="mt-3">
      <!-- boş üç sütunlu alan -->
      <b-col sm="3" />
      <!-- dokuz sütunlu alan -->
      <b-col sm="9">
        <b-alert show variant="success">
          <span v-html="résultat"></span>
        </b-alert>
      </b-col>
    </b-row>
  </div>
</template>

<script>
// ithalatlar
import FormCalculImpot from '@/components/form-calcul-impot'
import Menu from '@/components/menu'
import Layout from '@/components/layout'

export default {
  // kullanılan bileşenler
  components: {
    Layout,
    FormCalculImpot,
    Menu
  },
  // dahili durum
  data() {
    return {
      // menü seçenekleri
      options: [
        {
          text: 'Liste des simulations',
          path: '/liste-des-simulations'
        },
        {
          text: 'Fin de session',
          path: '/fin-session'
        }
      ],
      // vergi hesaplama sonucu
      résultat: '',
      résultatObtenu: false
    }
  },
  // yaşam döngüsü
  created() {
    // eslint-disable-next-line
    console.log("CalculImpot created");
  },
  // olay yönetimi yöntemleri
  methods: {
    // vergi hesaplama sonucu
    handleResultatObtenu(résultat) {
      // sonuç bir dize olarak oluşturulur HTML
      const impôt = "Montant de l'impôt : " + résultat.impôt + ' euro(s)'
      const décôte = 'Décôte : ' + résultat.décôte + ' euro(s)'
      const réduction = 'Réduction : ' + résultat.réduction + ' euro(s)'
      const surcôte = 'Surcôte : ' + résultat.surcôte + ' euro(s)'
      const taux = "Taux d'imposition : " + résultat.taux
      this.résultat = impôt + '<br/>' + décôte + '<br/>' + réduction + '<br/>' + surcôte + '<br/>' + taux
      // sonucun görüntülenmesi
      this.résultatObtenu = true
      // ---- deponun güncellenmesi [Vuex]
      // bir simülasyon daha
      this.$store.commit('addSimulation', résultat)
      // oturum kaydediliyor
      this.$session.save()
    }
  }
}
</script>
  • 44. ve 48. satırlar: gezinme menüsündeki bağlantılar doğrudur. [/fin-session] sayfası mevcut değildir. [vuejs-22] projesi bu sorunu yönlendirme ile çözmüştü. [nuxt-20] projesinde de aynısını yapacağız;
  • 76. satır: Şu anda mevcut olmayan [addSimulation] numaralı bir mutasyona atıfta bulunuluyor. Bunu oluşturacağız;
  • 78. satır: [index] sayfasında olduğu gibi, [this.$session().save(this.$nuxt.context)] yazılmalıdır;

[store/index] depolama alanını değiştirelim. [nuxt-12] projesinden devralınan bu depolama alanı, şu anda şu şekildedir:


/* eslint-disable no-console */

// mağazanın durumu
export const state = () => ({
  // jSON oturumu başlatıldı
  jsonSessionStarted: false,
  // kullanıcı kimliği doğrulandı
  userAuthenticated: false,
  // oturum çerezi PHP
  phpSessionCookie: '',
  // adminData
  adminData: ''
})

// depo değişiklikleri
export const mutations = {
  // durumun değiştirilmesi
  replace(state, newState) {
    for (const attr in newState) {
      state[attr] = newState[attr]
    }
  },
  // depolama alanının sıfırlanması
  reset() {
    this.commit('replace', { jsonSessionStarted: false, userAuthenticated: false, phpSessionCookie: '', adminData: '' })
  }
}

// depolama işlemleri
export const actions = {
  nuxtServerInit(store, context) {
    // bu kodu kim çalıştırıyor?
    console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server, 'env=', context.env)
    // oturum başlatma
    initStore(store, context)
  }
}

function initStore(store, context) {
  // başlatılacak depo
  // oturum alınır
  const session = context.app.$session()
  // oturum daha önce başlatılmış mı?
  if (!session.value.initStoreDone) {
    // yeni bir depo başlatılıyor
    console.log("nuxtServerInit, initialisation d'un nouveau store")
    // depolama alanı oturuma ekleniyor
    session.value.store = store.state
    // depolama alanı artık başlatıldı
    session.value.initStoreDone = true
  } else {
    console.log("nuxtServerInit, reprise d'un store existant")
    // depolama alanı, oturumdaki depolama alanıyla güncelleniyor
    store.commit('replace', session.value.store)
  }
  // oturum kaydediliyor
  session.save(context)
  // günlük
  console.log('initStore terminé, store=', store.state)
}
  • 3-27. satırlar: [vuejs-22] uygulamasının durumunu ve değişikliklerini alacağız (bkz. [3] belgesi):

// depolama alanı durumu
export const state = () => ({
  // jSON oturumu başlatıldı
  started: false,
  // kullanıcı kimliği doğrulandı
  authenticated: false,
  // oturum çerezi PHP
  phpSessionCookie: '',
  // simülasyon listesi
  simulations: [],
  // son simülasyon numarası
  idSimulation: 0,
  // katman [métier]
  métier: null
})

// perde değişiklikleri
export const mutations = {
  // durumun değiştirilmesi
  replace(state, newState) {
    for (const attr in newState) {
      state[attr] = newState[attr]
    }
  },
  // depolamanın sıfırlanması
  reset() {
        this.commit('replace', { started: false, authenticated: false, phpSessionCookie: '', idSimulation: 0, simulations: [], métier: null })
  },
  // indeks numaralı satırın silinmesi
  deleteSimulation(state, index) {
    // eslint-disable-next-line no-console
    console.log('mutation deleteSimulation')
    // [index] numaralı satır siliniyor
    state.simulations.splice(index, 1)
    console.log('store simulations', state.simulations)
  },
  // bir simülasyon ekleniyor
  addSimulation(state, simulation) {
    // eslint-disable-next-line no-console
    console.log('mutation addSimulation')
    // simülasyon numarası
    state.idSimulation++
    simulation.id = state.idSimulation
    // simülasyon simülasyon tablosuna ekleniyor
    state.simulations.push(simulation)
  }
}
  • 4. ve 6. satırlar: Daha önce kullanılmış olan özellikleri ekliyoruz;
  • 8. satır: PHP oturum çerezini koruyoruz. Bu, istemci ile [nuxt] sunucusunun, vergi hesaplama sunucusuyla aynı PHP oturumuna sahip olması için hayati önem taşır;
  • 10. satır: Kullanıcı tarafından yapılan simülasyonların listesi;
  • 12. satır: kullanıcı tarafından yapılan son simülasyonun numarası;
  • 14. satır: [métier] katmanı;
  • satır 30-47: [vuejs-22] projesinin depolama alanında bulunan ve uygulama sayfaları tarafından referans verilen değişiklikler. [vuejs-22] projesinde, simülasyon listesini boşaltan [clear] adlı bir değişiklik vardı. Bu mutasyon eklenmez çünkü halihazırda mevcut olan [reset] mutasyonu bu işi halletmelidir;
  • 26-28. satırlar: [reset] mutasyonu, state'in yeni içeriğini dikkate alacak şekilde değiştirilmiştir;

[calcul-impot] sayfası, aşağıdaki [form-calcul-impot] bileşenini kullanır:


<!-- HTML görünümünün tanımlanması -->
<template>
  <!-- HTML formu -->
  <b-form @submit.prevent="calculerImpot" class="mb-3">
    <!-- mavi arka planlı 12 sütunlu mesaj -->
    <b-row>
      <b-col sm="12">
        <b-alert show variant="primary">
          <h4>Remplissez le formulaire ci-dessous puis validez-le</h4>
        </b-alert>
      </b-col>
    </b-row>
    <!-- form öğeleri -->
    <!-- ilk satır -->
    <b-form-group label="Etes-vous marié(e) ou pacsé(e) ?">
      <!-- 5 sütunlu radyo düğmeleri-->
      <b-col sm="5">
        <b-form-radio v-model="marié" value="oui">Oui</b-form-radio>
        <b-form-radio v-model="marié" value="non">Non</b-form-radio>
      </b-col>
    </b-form-group>
    <!-- ikinci satır -->
    <b-form-group label="Nombre d'enfants à charge" label-for="enfants">
      <b-form-input id="enfants" v-model="enfants" :state="enfantsValide" type="text" placeholder="Indiquez votre nombre d'enfants"></b-form-input>
      <!-- olası hata mesajı -->
      <b-form-invalid-feedback :state="enfantsValide">Vous devez saisir un nombre positif ou nul</b-form-invalid-feedback>
    </b-form-group>
    <!-- üçüncü satır -->
    <b-form-group label="Salaire annuel net imposable" label-for="salaire" description="Arrondissez à l'euro inférieur">
      <b-form-input id="salaire" v-model="salaire" :state="salaireValide" type="text" placeholder="Salaire annuel"></b-form-input>
      <!-- olası hata mesajı -->
      <b-form-invalid-feedback :state="salaireValide">Vous devez saisir un nombre positif ou nul</b-form-invalid-feedback>
    </b-form-group>
    <!-- dördüncü satır, düğme [submit] -->
    <b-col sm="3">
      <b-button :disabled="formInvalide" type="submit" variant="primary">Valider</b-button>
    </b-col>
  </b-form>
</template>

<!-- komut dosyası -->
<script>
export default {
  // iç durum
  data() {
    return {
      // evli mi değil mi
      marié: 'non',
      // çocuk sayısı
      enfants: '',
      // yıllık maaş
      salaire: ''
    }
  },
  // hesaplanan iç durum
  computed: {
    // formun onaylanması
    formInvalide() {
      return (
        // maaş geçersiz
        !this.salaire.match(/^\s*\d+\s*$/) ||
        // veya geçersiz çocuk sayısı
        !this.enfants.match(/^\s*\d+\s*$/) ||
        // veya vergi verileri alınamadı
        !this.$métier.taxAdminData
      )
    },
    // maaş doğrulaması
    salaireValide() {
      // sayısal olmalı ve 0'dan büyük olmalı
      return Boolean(this.salaire.match(/^\s*\d+\s*$/) || this.salaire.match(/^\s*$/))
    },
    // çocuk bilgilerinin doğrulanması
    enfantsValide() {
      // sayısal olmalı ve 0'dan büyük olmalı
      return Boolean(this.enfants.match(/^\s*\d+\s*$/) || this.enfants.match(/^\s*$/))
    }
  },
  // yaşam döngüsü
  created() {
    // günlük
    // eslint-disable-next-line
    console.log("FormCalculImpot created");
  },
  // olay yöneticisi
  methods: {
    calculerImpot() {
      // vergi, [métier] katmanı kullanılarak hesaplanır
      const résultat = this.$métier.calculerImpot(this.marié, Number(this.enfants), Number(this.salaire))
      // eslint-disable-next-line
      console.log("résultat=", résultat);
      // sonuç tamamlanır
      résultat.marié = this.marié
      résultat.enfants = this.enfants
      résultat.salaire = this.salaire
      // [resultatObtenu] olayını tetiklenir
      this.$emit('resultatObtenu', résultat)
    }
  }
}
</script>
  • 65. ve 89. satırlar: [this.$métier] referansı, [this.$métier()] olarak değiştirilmelidir;

Bu düzeltmeler yapıldıktan sonra bir simülasyon denemesi yapılabilir:

Image

Aşağıdaki yanıt alınır:

Image

Günlük dosyalarına bakıldığında:

Image

  • [9-10]'te, ilk simülasyonun [store]'te yer aldığı görülüyor;
  • [5]'te ise son simülasyon numarasının artırıldığını görüyoruz;

17.6. 5. adım

Simülasyonu gerçekleştirdiğimize göre, [Liste des simulations] bağlantısına tıklayalım. Aşağıdaki sayfa karşımıza çıkar:

Image

[nuxt] istemcisinin yönlendirmesi doğru şekilde gerçekleştirildi. [liste-des-simulations] sayfasının koduna bakalım:


<!-- HTML görünümünün tanımı -->
<template>
  <div>
    <!-- sayfa düzeni -->
    <Layout :left="true" :right="true">
      <!-- sağ sütundaki simülasyonlar -->
      <template slot="right">
        <template v-if="simulations.length == 0">
          <!-- simülasyon yok -->
          <b-alert show variant="primary">
            <h4>Votre liste de simulations est vide</h4>
          </b-alert>
        </template>
        <template v-if="simulations.length != 0">
          <!-- simülasyonlar var -->
          <b-alert show variant="primary">
            <h4>Liste de vos simulations</h4>
          </b-alert>
          <!-- simülasyon tablosu -->
          <b-table :items="simulations" :fields="fields" striped hover responsive>
            <template v-slot:cell(action)="data">
              <b-button @click="supprimerSimulation(data.index)" variant="link">Supprimer</b-button>
            </template>
          </b-table>
        </template>
      </template>
      <!-- sol sütundaki gezinme menüsü -->
      <Menu slot="left" :options="options" />
    </Layout>
  </div>
</template>

<script>
// içe aktarmalar
import Layout from '@/components/layout'
import Menu from '@/components/menu'
export default {
  // bileşenler
  components: {
    Layout,
    Menu
  },
  // iç durum
  data() {
    return {
      // gezinti menüsü seçenekleri
      options: [
        {
          text: "Calcul de l'impôt",
          path: '/calcul-impot'
        },
        {
          text: 'Fin de session',
          path: '/fin-session'
        }
      ],
      // HTML tablosunun parametreleri
      fields: [
        { label: '#', anahtar: 'id' },
        { label: 'Marié', key: 'marié' },
        { label: "Nombre d'enfants", key: 'enfants' },
        { label: 'Salaire', key: 'salaire' },
        { label: 'Impôt', key: 'impôt' },
        { label: 'Décôte', key: 'décôte' },
        { label: 'Réduction', key: 'réduction' },
        { label: 'Surcôte', key: 'surcôte' },
        { label: '', key: 'action' }
      ]
    }
  },
  // hesaplanan dahili durum
  computed: {
    // Vuex deposundan alınan simülasyon listesi
    simulations() {
      return this.$store.state.simulations
    }
  },
  // yaşam döngüsü
  created() {
    // eslint-disable-next-line
    console.log("ListeSimulations created");
  },
  // yöntemler
  methods: {
    supprimerSimulation(index) {
      // eslint-disable-next-line
      console.log("supprimerSimulation", index);
      // simülasyonun kaldırılması n° [index]
      this.$store.commit('deleteSimulation', index)
      // oturum kaydediliyor
      this.$session.save()
    }
  }
}
</script>
  • 47-56. satırlar: gezinme menüsündeki hedefler doğru;
  • 75. satır: mağaza doğru şekilde referanslandırılmıştır;
  • 89. satır: bir önceki adımda entegre ettiğimiz [deleteSimulation] mutasyonu kullanılıyor;
  • 91. satır: Bu satır, [this.$session().save(this.$nuxt.context)] olarak yeniden yazılmalıdır;

Gerekli değişiklikleri yaptıktan sonra, görüntülenen simülasyonu silmeye çalışıyoruz:

Image

Böylece şu sayfa karşımıza çıkar:

Image

Günlük dosyalarına bakalım:

Image

  • [6]'te, simülasyon tablosunun boş olduğu görülüyor;

Şimdi vergi hesaplama formuna geri dönelim:

Image

Şu sayfa karşımıza çıkıyor:

Image

Yani yönlendirme işlemi başarılı oldu.

17.7. 6. adım

Şimdi gezinme menüsündeki [Fin de session] gezinme seçeneğini yönetmemiz gerekiyor:


// menü seçenekleri
      options: [
        {
          text: 'Liste des simulations',
          path: '/liste-des-simulations'
        },
        {
          text: 'Fin de session',
          path: '/fin-session'
        }
]
  • 9. satırda, [/fin-session] sayfası mevcut değil. [vuejs-22] projesi, bu durumu [router.js] dosyasındaki yönlendirme kurallarıyla yönetiyordu:

// ithalatlar
import Vue from 'vue'
import VueRouter from 'vue-router'
// görünümler
import Authentification from './views/Authentification'
import CalculImpot from './views/CalculImpot'
import ListeSimulations from './views/ListeSimulations'
import NotFound from './views/NotFound'
// oturum
import session from './session'

// yönlendirme eklentisi
Vue.use(VueRouter)

// uygulama yolları
const routes = [
  // kimlik doğrulama
  { path: '/', name: 'authentification', component: Authentification },
  { path: '/authentification', name: 'authentification2', component: Authentification },
  // vergi hesaplaması
  {
    path: '/calcul-impot', name: 'calculImpot', component: CalculImpot,
    meta: { authenticated: true }
  },
  // simülasyon listesi
  {
    path: '/liste-des-simulations', name: 'listeSimulations', component: ListeSimulations,
    meta: { authenticated: true }
  },
  // oturum sonlandırma
  {
    path: '/fin-session', name: 'finSession'
  },
  // bilinmeyen sayfa
  {
    path: '*', name: 'notFound', component: NotFound,
  },
]

// yönlendirici
const router = new VueRouter({
  // yollar
  routes,
  // URL görüntüleme modu
  mode: 'history',
  // uygulamanın temel URL'i
  base: '/client-vuejs-impot/'
})

// yolların doğrulanması
router.beforeEach((to, from, next) => {
  // eslint-disable-next-line no-console
  console.log("router to=", to, "from=", from);
  // kimliği doğrulanmış kullanıcılara özel rota mı?
  if (to.meta.authenticated && !session.authenticated) {
    next({
      // kimlik doğrulamaya geçiliyor
      name: 'authentification',
    })
    // olay döngüsüne geri dönülüyor
    return;
  }
  // oturum sonu özel durumu
  if (to.name === "finSession") {
    // oturum temizleniyor
    session.clear();
    // [authentification] görünümüne geçiliyor
    next({
      name: 'authentification',
    })
    // olay döngüsüne geri dönülür
    return;
  }
  // diğer durumlar - normal yönlendirme görünümüne geç
  next();
})

// yönlendiricinin dışa aktarımı
export default router
  • 64-76. satırlar, [/fin-session] yoluna giden özel durumu yönetiyordu;
  • 66. satır: geçerli oturum boşaltılır;
  • 68-70. satırlar: [authentification] görünümü görüntülenir;

[nuxt] istemcisinin yönlendirme dosyasında da benzer bir işlem yapmaya çalışacağız:

Image

[client/routing.js] komut dosyası şu şekilde olur:


/* eslint-disable no-console */
export default function(context) {
  // bu kodu kim çalıştırıyor?
  console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
  // tarayıcıdaki PHP oturum çerezinin yönetimi
  // Tarayıcıdaki PHP oturum çerezi, Nuxt oturumunda bulunanla aynı olmalıdır
  // [fin-session] eylemi, yeni bir PHP çerezi alır (hem sunucu hem de Nuxt istemcisi)
  // Eğer çerezi alan sunucuysa, istemci bunu tarayıcıya iletmelidir
  // sunucuyla kendi iletişimi için PHP
  // burada bir istemci yönlendirmesi söz konusudur

  // oturum çerezini alıyoruz PHP
  const phpSessionCookie = context.store.state.phpSessionCookie
  if (phpSessionCookie) {
    // varsa, PHP oturum çerezini tarayıcıya atanır
    document.cookie = phpSessionCookie
  }

  // Nereye gidiyoruz?
  const to = context.route.path
  if (to === '/fin-session') {
    // oturumu temizliyoruz
    const session = context.app.$session()
    session.reset(context)
    // ana sayfaya yönlendiriliyor
    context.redirect({ name: 'index' })
  }
}
  • Mevcut koda [19-27] satırlarını ekledik;
  • 20. satır: mevcut yolun hedefinden [path] alınır;
  • 21. satır: [/fin-session] olup olmadığına bakılır. Eğer öyleyse:
    • 23-24. satırlar: oturum sıfırlanır;
    • satır 26: [nuxt] istemcisi ana sayfaya yönlendirilir;

Oturumun [session.reset(context)] yöntemi (satır 24) şöyledir:


// oturumu sıfırla
  reset(context) {
    console.log('nuxt-session reset')
    // depolama alanını sıfırla
    context.store.commit('reset')
    // yeni depoyu oturuma kaydediyoruz ve oturumu kaydediyoruz
    this.save(context)
}

[context.store.commit('reset')] yöntemi (satır 5) şöyledir:


// depolama alanını sıfırla
  reset() {
        this.commit('replace', { started: false, authenticated: false, phpSessionCookie: '', idSimulation: 0, simulations: [], métier: null })
}

Şimdi [Fin de session] bağlantısı kullanıldığında, ana sayfa aşağıdaki günlük kayıtlarıyla görüntülenir:

Image

  • [3]'te, artık oturum açılmamış olduğu görülüyor;
  • [4]'te, jSON oturumunun başlatıldığı görülüyor;
  • [6]'te, [métier] katmanı artık depoda mevcut değildir ([this.$métier()]'in bulunduğu sayfalarda hâlâ mevcuttur);
  • [5, 7]'te artık simülasyon kalmamıştır;

Bir oturumun sona ermesi sırasında neler olduğunu iyi anlamak gerekir:

  • [nuxt] oturumu sıfırlanır: mağazanın [started] özelliği [false] olarak değişir;
  • [index] sayfasına yönlendirme yapılır;
  • [index] sayfasındaki [mounted] yöntemi yürütülür. Bu yöntem, vergi hesaplama sunucusuyla yeni bir jSON oturumu başlatır. İşlem başarılı olursa, deponun [started] özelliği [true] olarak güncellenir;

17.8. 7. adım

Bu aşamada, [nuxt-20] uygulaması, [vuejs-22] uygulamasının tüm işlevlerine sahiptir. Taşıma işlemi tamamlanmış gibi görünüyor.

[nuxt] yaklaşımıyla biraz daha ileri gideceğiz. [index] sayfasındaki [mounted] yöntemi sorun yaratıyor. Bu yöntem, bir arama motorunun sonunu beklemeyeceği bir asenkron işlem başlatıyor. Bu durumda, asenkron işlemi bir [asyncData] işlevine yerleştirmek gerektiği bilinmektedir; çünkü o zaman, işlemi yürüten [nuxt] sunucusu, sayfayı arama motoruna teslim etmeden önce işlemin tamamlanmasını bekler.

Burada, [index] sayfası için [nuxt-12] uygulamasında yazılmış olan [asyncData] işlevinden yararlanıyoruz:


export default {
  name: 'InitSession',
  // kullanılan bileşenler
  components: {
    Layout,
    Navigation
  },
  // asenkron veriler
  async asyncData(context) {
    // günlük
    console.log('[index asyncData started]')
    // sayfa daha önce istenmişse işlem iki kez yapılmaz
    if (process.server && context.store.state.jsonSessionStarted) {
      console.log('[index asyncData canceled]')
      return { result: '[succès]' }
    }
    try {
      // bir oturum başlatılır jSON
      const dao = context.app.$dao()
      const response = await dao.initSession()
      // günlük
      console.log('[index asyncData response=]', response)
      // sonraki istekler için PHP oturum çerezini alınır
      const phpSessionCookie = dao.getPhpSessionCookie()
      // PHP oturum çerezini [nuxt] oturumunda saklanıyor
      context.store.commit('replace', { phpSessionCookie })
      // Bir hata mı oluştu?
      if (response.état !== 700) {
        // hata response.réponse'te bulunuyor
        throw new Error(response.réponse)
      }
      // jSON oturumunun başladığı belirtiliyor
      context.store.commit('replace', { jsonSessionStarted: true })
      // sonuç veriliyor
      return { result: '[succès]' }
    } catch (e) {
      // günlüğe kaydediliyor
      console.log('[index asyncData error=]', e)
      // jSON oturumunun başlamadığı kaydedilir
      context.store.commit('replace', { jsonSessionStarted: false })
      // hata bildiriliyor
      return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // depolama alanı kaydedilir
      const session = context.app.$session()
      session.save(context)
      // günlük
      console.log('[index asyncData finished]')
    }
  },
  // yaşam döngüsü
  beforeCreate() {
    console.log('[index beforeCreate]')
  },
  created() {
    console.log('[index created]')
  },
  beforeMount() {
    console.log('[index beforeMount]')
  },
  mounted() {
    console.log('[index mounted]')
    // sadece istemci
    if (this.showErrorLoading) {
      console.log('[index mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
}
  • 13., 33. ve 40. satırlar: [jsonSessionStarted] özelliğini [started] olarak değiştirmeliyiz;
  • 13. satır: [nuxt-12] uygulamasında, yalnızca [nuxt] sunucusu [index] sayfasını ve [asyncData] işlevini çalıştırıyordu. [nuxt] istemcisi, [index] sayfasını ancak [nuxt] sunucusundan aldıktan sonra çalıştırıyordu ve bu durumda [asyncData] işlevini çalıştırmıyordu. [nuxt-20]'te durum farklıdır: [Fin de session] bağlantısı, [index] sayfasını [nuxt] istemcisi ortamında görüntüler. Bunun üzerine [asyncData] işlevi çalıştırılacaktır. Ancak, bu şekilde [index] sayfasına ulaşıldığında, bu arada [nuxt] oturumu sıfırlanmış olacaktır ve deponun [started] özelliği [false] değerine sahip olacaktır; dolayısıyla 13. satırdaki koşul mutlaka yanlış olacaktır. Dolayısıyla [process.server]'i olduğu gibi bırakabiliriz; böylece [nuxt] istemcisi bu testi yapmayacaktır;
  • 15., 35. ve 42. satırlar: [result] özelliği, [index] sayfasının [data] özelliklerine eklenir. [nuxt-20]'te bu özellik kullanılmayacaktır ve işlevin döndürdüğü sonuçtan bunu kaldıracağız;
  • 61-67. satırlar: [mounted] yöntemi, [nuxt] istemcisinin hata mesajını görüntülemesini sağlayan yöntem olduğu için korunmalıdır. Ancak hatanın işlenme şekli değiştirilecektir;

Mevcut [index] sayfasında, eski [mounted] fonksiyonunun yerine yukarıdaki [asyncData] fonksiyonunu entegre ediyoruz ve yeni bir [mounted] fonksiyonu ekliyoruz. [nuxt-20] örneğindeki [index] sayfasının kodu şu şekilde olur:


...

<!-- görünüm dinamiği -->
<script>
/* eslint-disable no-console */
import Layout from '@/components/layout'
export default {
  // kullanılan bileşenler
  components: {
    Layout
  },
  // bileşen durumu
  data() {
    return {
      // kullanıcı
      user: '',
      // şifresi
      password: '',
      // hata gösterimi
      showError: false
    }
  },

  // hesaplanan özellikler
  computed: {
    // geçerli girdiler
    valid() {
      return this.user && this.password && this.$store.state.started
    }
  },
  // asenkron veriler
  async asyncData(context) {
    // günlük
    console.log('[index asyncData started]')
    // sayfa daha önce istenmişse işlem iki kez yapılmaz
    if (process.server && context.store.state.started) {
      console.log('[index asyncData canceled]')
      return
    }
    try {
      // bir oturum başlatılıyor jSON
      const dao = context.app.$dao()
      const response = await dao.initSession()
      // günlük
      console.log('[index asyncData response=]', response)
      // sonraki istekler için PHP oturum çerezini alınır
      const phpSessionCookie = dao.getPhpSessionCookie()
      // PHP oturum çerezini [nuxt] oturumunda saklanıyor
      context.store.commit('replace', { phpSessionCookie })
      // Bir hata mı oluştu?
      if (response.état !== 700) {
        // hata response.réponse'te bulunuyor
        throw new Error(response.réponse)
      }
      // jSON oturumunun başladığı belirtilmiştir
      context.store.commit('replace', { started: true })
      // sonuç yok
      return
    } catch (e) {
      // günlük
      console.log('[index asyncData error=]', e.message)
      // jSON oturumunun başlamadığı kaydedilir
      context.store.commit('replace', { started: false })
      // hata bildiriliyor
      return { showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // depolama alanı kaydediliyor
      const session = context.app.$session()
      session.save(context)
      // günlük
      console.log('[index asyncData finished]')
    }
  },
  // yaşam döngüsü
  beforeCreate() {
    console.log('[index beforeCreate]')
  },
  created() {
    console.log('[index created]')
  },
  beforeMount() {
    // sadece istemci
    console.log('[index beforeMount]')
    // olası hatanın yönetimi
    if (this.showErrorLoading) {
      // günlük
      console.log('[index beforeMount, showErrorLoading=true]')
      // hata ana bileşene iletilir [default]
      this.$emit('error', new Error(this.errorLoadingMessage))
    }
  },
  mounted() {
    console.log('[index mounted]')
  },

  // olay yöneticileri
  methods: {
    // ----------- kimlik doğrulama
    async login() {
      ...
}
</script>
  • 58. ve 65. satırlar: [asyncData] işlevi artık burada [result] özelliğini kullanılmayan hale getirmiyor;
  • 81. satır: [nuxt] istemcisinin [beforeMount] yöntemi. Bu yöntem, [asyncData]'in olası hatasını yönetmek için [mounted] yöntemine tercih edilmiştir;
  • satır 85: [errorLoading] özelliğinin ayarlanıp ayarlanmadığı kontrol edilir. Bu özellik yalnızca [asyncData] işlevi tarafından ayarlanabilir;
  • 85-90. satırlar: [asyncData] işlevi bir hata bildirmişse, bu hata [error] olayı aracılığıyla [default] sayfasına aktarılır. Az önce değiştirdiğimiz eski [created] işlevi, olası hataları bu şekilde yönetiyordu;

Birkaç test yapalım.

Öncelikle, varsa [nuxt] oturum çerezini ve PHP oturum çerezini siliyoruz. Ardından, vergi hesaplama sunucusu çalışır durumda değilken [http://localhost:81/nuxt-20/] sayfasını çağırıyoruz. Aşağıdaki sayfayı görüyoruz:

Image

Vergi hesaplama sunucusunu başlattıktan sonra aynı sayfayı yeniden yüklüyoruz:

Image

Günlük dosyalarına bakalım:

Image

  • [2-3]'te, jSON oturumunun başlatıldığını görüyoruz;
  • [4]'te, [nuxt] sunucusunun vergi hesaplama sunucusuyla yaptığı iletişim sırasında aldığı PHP oturum çerezi görülüyor. [nuxt] istemcisi bundan sonra bu çerezi kullanacaktır;

Şimdi kimliğimizi doğrulayalım:

Image

Aşağıdaki sayfayı görüyoruz:

Image

[1]'te bir hata mesajı aldık. Bu, tarayıcının bir önceki adımda [nuxt] sunucusu tarafından başlatılan PHP oturumu için doğru çerezi göndermediği anlamına gelir. [nuxt-12]'te, PHP oturum çerezinin [nuxt] sunucusundan [nuxt] istemcisine aktarımı, [middleware/client/routing] betiğinin [nuxt] istemcisi yönlendirmesinde gerçekleştiriliyordu :


/* eslint-disable no-console */
export default function(context) {  // bu kodu kim çalıştırıyor?
  console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
  // tarayıcıdaki PHP oturum çerezinin yönetimi
  // tarayıcıdaki PHP oturum çerezi, nuxt oturumunda bulunanla aynı olmalıdır
  // [fin-session] eylemi, yeni bir PHP çerezi alır (hem sunucu hem de Nuxt istemcisi)
  // Eğer çerezi alan sunucuysa, istemci bunu tarayıcıya iletmelidir
  // sunucuyla kendi iletişimi için PHP
  // burada bir istemci yönlendirmesi söz konusudur

  // oturum çerezini alıyoruz PHP
  const phpSessionCookie = context.store.state.phpSessionCookie
  if (phpSessionCookie) {
    // varsa, PHP oturum çerezini tarayıcıya atanır
    document.cookie = phpSessionCookie
  }

  // Nereye gidiyoruz?
  const to = context.route.path
  if (to === '/fin-session') {
    // oturumu temizlenir
    const session = context.app.$session()
    session.reset(context)
    // ana sayfaya yönlendirilir
    context.redirect({ name: 'index' })
  }
}

[nuxt] istemcisinin, [nuxt] sunucusundaki PHP oturum çerezini almasını sağlayan satırlar 13-17'dir.

Buradaki sorun, [Valider] düğmesine tıklandığında [nuxt] istemcisine yönlendirme yapılmamasıdır. Dolayısıyla, bu istemcinin yönlendirme işlevi çağrılmamaktadır. Bu sorunu, [index] sayfasının kimlik doğrulama yönteminin başına 12-17. satırları kopyalayarak çözebiliriz:


// olay yöneticileri
  methods: {
    // ----------- kimlik doğrulama
    async login() {
      // depolama alanında PHP oturum çerezini alıyoruz
      const phpSessionCookie = this.$store.state.phpSessionCookie
      if (phpSessionCookie) {
        // varsa, PHP oturum çerezi tarayıcıya atanır
        document.cookie = phpSessionCookie
      }
      try {
        // bekleme başlıyor
        this.$emit('loading', true)
        // henüz kimlik doğrulaması yapılmamıştır

5-10. satırlarda, [nuxt] sunucusu tarafından başlatılan PHP oturum çerezini çerez tablosundan alıyoruz. Bu değişiklik yapıldıktan sonra, vergi hesaplama sayfasını başarıyla alıyoruz; bu da kimlik doğrulamanın başarılı olduğu anlamına geliyor.

17.9. 8. adım

[nuxt] felsefesine uygun olarak çalışan işlevsel bir uygulamamız var. [nuxt-13] uygulamasında yaptığımız gibi, şimdi de [nuxt] sunucusundaki gezinme yapısına odaklanacağız. Daha önce de belirtildiği gibi, kullanıcının uygulamanın URL adreslerini elle yazması gerekmez. Kullanıcıya sunulan ve o sırada SPA modunda çalışan [nuxt] istemcisi tarafından yürütülen bağlantıları kullanması beklenir. Bununla birlikte, [nuxt] sunucusundaki gezinme işleminin uygulamayı her zaman kararlı bir durumda bırakmasını sağlayacağız.

[nuxt-13] için yapılan çalışmadan (bkz. bağlantı paragrafı), şunları yapmamız gerektiğini biliyoruz:

  • [midleware/routing] komut dosyasını değiştirmek;
  • bir [middleware/server/routing] komut dosyası eklemek;

Image

[middleware/routing] komut dosyası şu şekilde değiştirilir:


/* eslint-disable no-console */

// sunucu ve istemci middleware'lerini içe aktarıyoruz
import serverRouting from './server/routing'
import clientRouting from './client/routing'

export default function(context) {
  // Bu kodu kim çalıştırıyor?
  console.log('[middleware], process.server', process.server, ', process.client=', process.client)
  if (process.server) {
    // sunucu yönlendirmesi
    serverRouting(context)
  } else {
    // müşteri yönlendirmesi
    clientRouting(context)
  }
}
  • 4. satır: [nuxt] sunucusunun yönlendirme komut dosyası içe aktarılır;
  • 10-12. satırlar: kodu çalıştıran sunucu [nuxt] ise, bu sunucunun yönlendirme işlevi kullanılır;

[middleware/server/routing] komut dosyası şöyledir:


/* eslint-disable no-console */
export default function(context) {
  // bu kodu kim çalıştırıyor?
  console.log('[middleware server], process.server', process.server, ', process.client=', process.client)

  // buradan ve oradan bazı bilgiler topluyoruz
  const store = context.store
  // nereden geliyoruz?
  const from = store.state.from || 'nowhere'
  // Nereye gidiyoruz?
  let to = context.route.name
  
  // [name] özniteliği olmayan /fin-session özel durumu
  if (context.route.path === '/fin-session') {
    to = 'fin-session'
  }
  
  // olası yönlendirme
  let redirection = ''
  // yönlendirme yönetimi tamamlandı
  let done = false
  
  // [nuxt] sunucusundan bir yönlendirmenin içinde miyiz?
  if (store.state.serverRedirection) {
    // yapılacak bir şey yok
    done = true
  }
  
  // Bu bir sayfa yenileme mi?
  if (!done && from === to) {
    // yapılacak bir şey yok
    done = true
  }
  
  // [nuxt] sunucusunun gezinme kontrolü
  // müşterinin gezinme menüsüne uyarlanıyor

  // önce oturum sonu durumunu işliyoruz
  if (!done && store.state.started && store.state.authenticated && to === 'fin-session') {
    // oturumu temizlenir
    const session = context.app.$session()
    session.reset(context)
    // ana sayfaya yönlendirme yapılır
    redirection = 'index'
    // işlem tamamlandı
    done = true
  }

  // PHP oturumu başlatılmamışsa
  if (!done && !store.state.started && to !== 'index') {
    // [index] sayfasına yönlendirme
    redirection = 'index'
    // iş tamamlandı
    done = true
  }

  // kullanıcının kimliği doğrulanmamışsa
  if (!done && store.state.started && !store.state.authenticated && to !== 'index') {
    redirection = 'index'
    // işlem tamamlandı
    done = true
  }

  // [adminData] alınamadığı durum
  if (!done && store.state.started && store.state.authenticated && !store.state.métier.taxAdminData && to !== 'index') {
    // [index]'e yönlendirme
    redirection = 'index'
    // iş tamamlandı
    done = true
  }

  // [adminData] elde edildiğinde
  if (
    !done &&
    store.state.started &&
    store.state.authenticated &&
    store.state.métier.taxAdminData &&
    to !== 'calcul-impot' &&
    to !== 'liste-des-simulations'
  ) {
    // aynı sayfada kalınıyor
    redirection = from
    // iş tamamlandı
    done = true
  }

  // normalde tüm kontroller yapıldı ---------------------
  // yönlendirme mi?
  if (redirection) {
    // yönlendirme mağazada kaydedildi
    store.commit('replace', { serverRedirection: true })
  } else {
    // yönlendirme yok
    store.commit('replace', { serverRedirection: false, from: to })
  }
  // depolama alanı oturuma kaydediliyor [nuxt]
  const session = context.app.$session()
  session.value.store = store.state
  session.save(context)
  // sunucudan olası yönlendirme yapılır [nuxt]
  if (redirection) {
    context.redirect({ name: redirection })
  }
}
  • Bu komut dosyasında, [nuxt-13] uygulamasının [nuxt] sunucusunun yönlendirmesinde daha önce geliştirilen ve kullanılan fikirleri tekrar kullanıyoruz;
  • uygulamanın depolama alanına iki özellik ekliyoruz:
    • [from]: en son görüntülenen sayfanın adı. [nuxt] istemcisinin bu bilgiye sahip olduğu biliniyor, ancak [nuxt] sunucusu bu bilgiye sahip değil. [nuxt] sunucusundaki her yönlendirmede, görüntülenecek sayfanın adını depoya kaydederek bu bilgiyi sunucuya ekleyeceğiz. Aynı işlemi, [nuxt] istemcisinin her yönlendirmesinde de yapacağız. Böylece, [nuxt] sunucusunun bir sonraki yönlendirmesinde, bu sunucu depoda uygulama tarafından en son görüntülenen sayfanın adını bulacaktır;
    • [serverRedirection]: Bir yönlendirme hedefi [nuxt] sunucusu tarafından reddedildiğinde, bu sunucu bir yönlendirme işlemi gerçekleştirecektir. Ardından depoda, [nuxt] sunucusunun bir sonraki hedefinin bir yönlendirme sayfası olduğunu belirtecektir. Bu yönlendirme, [nuxt] sunucusunun yönlendiricisinin yeniden çalıştırılmasına neden olacaktır. Bu sunucu, mevcut hedefin bir yönlendirmeden geldiğini tespit ederse, işlemi devam ettirecektir;
  • 6-11. satırlar: yönlendirme için gerekli bilgiler alınır;
  • 13-16. satırlar: [/fin-session] hedefi, [fin-session] adlı bir sayfayla ilişkilendirilmemiştir. Dolayısıyla bir adı yoktur. Ona bir ad verilir;
  • 19. satır: Olası bir yönlendirmenin hedefi;
  • 21. satır: Yönlendirme testleri tamamlandığında [done=true];
  • 23-27. satırlar: daha önce de belirtildiği gibi, devam eden yönlendirme bir yönlendirmeden kaynaklanıyorsa, yapılacak bir şey yoktur. Nitekim, önceki yönlendirme sırasında yönlendirici, istemci tarayıcısını yönlendirmek gerektiğine karar vermiştir. Bu kararı yeniden gözden geçirmeye gerek yoktur;
  • satır 29-33: Sayfanın yeniden yüklenmesi söz konusuysa, işlem devam etmesine izin verilir. Bu, tüm uygulamalar için geçerli bir kural değildir: Her sayfa için yeniden yüklemenin etkilerini ayrı ayrı incelemek gerekir. Bu durumda, [index, calcul-impot, liste-des-simulations] sayfalarının yeniden yüklenmesinin istenmeyen sonuçlara yol açmadığı görülmektedir;
  • 35-85. satırlar: [nuxt] sunucusunun yönlendirmesi, [nuxt] istemcisinin yönlendirmesini devralır. Bir sayfadayken, [nuxt] sunucusunun yönlendirmesi, o sayfadayken [nuxt] istemcisi tarafından sunulan gezinme menüsünü yansıtmalıdır;
  • 38-47. satırlar: Öncelikle, mevcut bir sayfaya karşılık gelmeyen [fin-session] hedef durumu ele alınır. Koşullar sağlanmışsa (oturum başlatılmış, kullanıcı kimliği doğrulanmış), oturum temizlenir ve kullanıcı [index] sayfasına yönlendirilir;
  • 49-55. satırlar: Vergi hesaplama sunucusuyla jSON oturumu başlatılmamışsa, tek olası hedef [index] sayfasıdır;
  • satır 57-62: jSON oturumu başlatılmışsa ve kullanıcı kimliği doğrulanmamışsa ve kimlik doğrulama sayfasını talep etmemişse, kullanıcı kimlik doğrulama sayfasına, yani [index] sayfasına yönlendirilir;
  • 64-70. satırlar: Kullanıcı kimliği doğrulanmışsa ancak [adminData] verisi alınmamışsa, kimlik doğrulama sayfasına yönlendirilir. Kimlik doğrulama iki şey yapar: kullanıcıyı doğrular ve kimlik doğrulama başarılı olursa [adminData] verisini de ister. Bu veri alınmamışsa kimlik doğrulama işlemi yeniden başlatılmalıdır;
  • 72-85. satırlar: [adminData] verisi elde edildiğinde, olası tek hedefler [calcul-impot] ve [liste-des-simulations]'tir. Aksi takdirde yönlendirme reddedilir;
  • satır 88-95: yönlendirme olup olmayacağına göre depo güncellenir;
  • 94. satır: Yönlendirme yoktur. Dolayısıyla mevcut [to], bir sonraki yönlendirmede [from] olacaktır;
  • satır 96-99: depodaki bilgiler, [nuxt] oturum çerezine kaydedilir;
  • satır 100-103: Yönlendirme yapılması gerekiyorsa, bu işlem gerçekleştirilir;

Testleri yapmak için, vergi hesaplama sunucusundaki [nuxt] oturum çerezini ve PHP oturum çerezini silerek temiz bir durumdan başlamaya özen gösterilmelidir:

Image

[nuxt] sunucusunun yönlendirme işlevini test etmek için, her sayfada olası tüm URL ve [/, /calcul-impot, /liste-des-simulations] değerlerini deneyin. Her seferinde uygulama tutarlı bir durumda kalmalıdır.

17.10. 9. adım

  1. adım, [nuxt-20] uygulamasının dağıtımını içerir. Bu adım, [nuxt] sunucusunu çalıştırmak için [node.js] ortamı sunan bir barındırma hizmeti gerektirir. Bende böyle bir barındırma hizmeti yok. Okuyucu, bağlantı paragrafında açıklanan prosedürleri izleyerek [nuxt-20] uygulamasını geliştirme makinesine dağıtabilir ve HTTPS protokolüyle güvenliğini sağlayabilir.

17.11. Conclusion

[vuejs-22] uygulamasının [nuxt-20] uygulamasına taşınması artık tamamlanmıştır. Bu taşıma işlemiyle ilgili birkaç noktayı hatırlayalım:

  • [vuejs-22] sayfaları korunmuştur;
  • [vuejs-22] sayfalarında bulunan asenkron işlemler, [asyncData] işlevine taşınmıştır;
  • [nuxt-20]'te iki varlık yönetilmesi gerekti: [nuxt] istemcisi ve [nuxt] sunucusu. Bu son varlık, [vuejs-22]'te mevcut değildi. İki varlık arasında tutarlılığı sağlamak için [nuxt] oturumuna ihtiyacımız oldu;
  • [nuxt] sunucusunun yönlendirmesini yönetmemiz gerekti;

Uygulamada, [vue.js] mimarisini oluşturup daha sonra bunu [nuxt] ortamına taşımaktansa, doğrudan [nuxt] mimarisiyle başlamak şüphesiz daha tercih edilebilir bir seçenektir.