Performa SSR tambahan dengan server fullstack Nuxt (Bagian 2)

Performa SSR tambahan dengan server Nuxt fullstack


Di Bagian 1, saya berbicara tentang betapa mudahnya mengatur Server API di Nuxt . Di Bagian 2, saya ingin memberi tahu Anda manfaat tambahan apa yang bisa Anda dapatkan dari server fullstack Nuxt .

Bagian 2: mempercepat rendering server!


Mari kita pikirkan sekarang bagaimana server kami bekerja dari contoh codesandbox.io/s/codesandbox-nuxt-3gzhl

  1. Klien meminta halaman utama 3gzhl.sse.codesandbox.io
  2. Nuxt mulai merender di server halaman / halaman /index.vue
  3. Datang ke

      async fetch() {
        this.users = await this.$api("users", "index");
      },
    
  4. Melalui axios, ia membuat permintaan http , di 3gzhl.sse.codesandbox.io/api/users/index i.e. pada diriku sendiri
  5. Koneksi dibuat, sesi baru dibuat di server, dan memori dialokasikan untuk memproses permintaan http
  6. Permintaan yang masuk diterima melalui protokol http , url diurai, parameter diproses
  7. Menjalankan middleware server
  8. Nuxt Meluncurkan Server API Kami
  9. JSON
  10. users.index(), JSON
  11. JSON http
  12. axios JSON
  13. API

Sekarang bayangkan bahwa kita memiliki 20 komponen pada halaman yang meminta data melalui API , jadi dalam satu permintaan untuk halaman dengan server Nuxt 20 koneksi http internal tambahan akan dibuat dan langkah 4-13 akan dilakukan 20 kali. Server HTTP nuxt dapat memproses lebih dari 55 ribu permintaan per detik, namun, dengan membuat permintaan HTTP internal, kami mengurangi sumber daya server potensial hingga puluhan kali.

Tetapi ketika kita me-render halaman di server, kita memiliki akses langsung ke semua pengontrol di folder / api /

Mari kita ubah logika sehingga ketika merender di server, kode pengontrol dipanggil secara langsung, dan ketika dipanggil dari browser, permintaan dikirim melalui http

  1. Ganti nama file /plugins/api-context.js menjadi /plugins/api-context.client.js
  2. ubah nama file di pengaturan /nuxt.config.js

      plugins: ["~/plugins/api-context.client.js"]
    

    Sekarang ini. Konteks $ Api hanya tersedia untuk kode klien
  3. buat ini. $ api konteks untuk langsung memanggil controller di server

    /plugins/api-context.server.js
    export default (context, inject) => {
      inject("api", async (controller, method, params) => {
        try {
          let api = require("../api/" + controller.replace(/^\/+|\/+$|\.+/g, ""));
          return await api[method](params);
        } catch (e) {
          console.error(e);
          throw e;
        }
      });
    };
    
  4. hubungkan plugin server /

    nuxt.config.js
      plugins: [
        "~/plugins/api-context.client.js",
        "~/plugins/api-context.server.js"
      ]
    

Sekarang fungsi ini. $ Api di server akan langsung memanggil metode controller, dan pada klien ini. $ Api mengirim permintaan http melalui axios .

Kode

  async fetch() {
    this.users = await this.$api("users", "index");
  },

saat rendering di server, tidak akan melakukan permintaan http untuk dirinya sendiri, tetapi hanya menghubungkan /api/users.js berkas via membutuhkan dan memanggil index () metode , yaitu item dari 4-13 tidak akan dieksekusi, tetapi hanya 10 yang akan dieksekusi. Namun, ketika klien mengklik tombol Refresh di browser , data yang sama akan diminta melalui http . Ini kode lengkapnya: codesandbox.io/s/codesandbox-nuxt-pbriw





Pengujian kinerja


codesandbox.io/s/codesandbox-nuxt-rzdyw

  1. Untuk menghilangkan pengaruh kecepatan koneksi eksternal, saya mengganti menerima data dengan data statis:

    /api/users.js
    // we can get data from any DB
    async function getDataFromDB() {
      return {
        page: 1,
        per_page: 6,
        total: 12,
        total_pages: 2,
        data: [
          {
            id: 1,
            email: "george.bluth@reqres.in",
            first_name: "George",
            last_name: "Bluth",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
          },
          {
            id: 2,
            email: "janet.weaver@reqres.in",
            first_name: "Janet",
            last_name: "Weaver",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
          },
          {
            id: 3,
            email: "emma.wong@reqres.in",
            first_name: "Emma",
            last_name: "Wong",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"
          },
          {
            id: 4,
            email: "eve.holt@reqres.in",
            first_name: "Eve",
            last_name: "Holt",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"
          },
          {
            id: 5,
            email: "charles.morris@reqres.in",
            first_name: "Charles",
            last_name: "Morris",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/stephenmoon/128.jpg"
          },
          {
            id: 6,
            email: "tracey.ramos@reqres.in",
            first_name: "Tracey",
            last_name: "Ramos",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/bigmancho/128.jpg"
          }
        ],
        ad: {
          company: "StatusCode Weekly",
          url: "http://statuscode.org/",
          text:
            "A weekly newsletter focusing on software development, infrastructure, the server, performance, and the stack end of things."
        }
      };
      /*
      return (await require("axios").get(`https://reqres.in/api/users?page=1`))
        .data;
      */
    }
    ....
    
  2. api , http

    /plugins/api-context.server.js
    export default (context, inject) => {
      inject("server", () => true);
      inject("api", async (controller, method, params) => {
        try {
          if (params && params.httpcall) {
            return await context.$axios["$" + (params ? "post" : "get")](
              "/api/" + controller + "/" + method,
              params
            );
          }
          let api = require("../api/" + controller.replace(/^\/+|\/+$|\.+/g, ""));
          return await api[method](params);
        } catch (e) {
          console.error(e);
          throw e;
        }
      });
    };
    
  3. index.vue fetch api 50

    /pages/index.vue
      async fetch() {
        let start = new Date();
        let promises = [];
        let callNum = 50;
        for (let i = 0; i < callNum; i++) {
          promises.push(this.$api("users", "index"));
        }
    
        let arr = await Promise.all(
          promises.map(async p => {
            return await p;
          })
        );
    
        let res = [];
        for (let r of arr) {
          res = res.concat(r);
        }
    
        this.users = res;
        this.fetchType =
          (this.$server && this.$server() ? "Server internal" : "Client http") +
          " API call";
        this.fetchTime = new Date() - start;
      },
    
  4. httpcall.vue fetch api 50 http

    /pages/httpcall.vue
    ...
          promises.push(this.$api("users", "index", { httpcall: true }));
    ...
        this.fetchType =
          (this.$server && this.$server() ? "Server http" : "Client http") +
          " API call";
    ...
    
  5. Sekarang bandingkan waktu pelaksanaan rzdyw.sse.codesandbox.io

    Server rendering panggilan API internal server mengambil waktu: 1
    ms waktu dari 0ms hingga maksimum 2ms

    rzdyw.sse.codesandbox.io/httpcall
    Server http API rendering panggilan mengambil waktu: 71ms
    waktu dari 46ms ke maksimum 1059ms
    dan beberapa kali server umumnya mengalami kesalahan

    RangeError
    Maximum call stack size exceeded

Berikut ini adalah contoh lengkap - codesandbox.io/s/codesandbox-nuxt-rzdyw

Total Bagian 2


  • Dengan perubahan minimal, Anda dapat mempercepat rendering server lebih dari 50 kali, dengan contoh langsung, rendering halaman saya dipercepat ~ 1,7 kali
  • Node sumber daya server HTTP berkurang secara signifikan
  • Dengan cara yang dioptimalkan, satu-satunya contoh Nuxt harus tahan terhadap beban proyek-proyek kecil dan menengah

All Articles