Desempenho adicional de SSR com o servidor Nuxt fullstack (parte 2)

Desempenho adicional de SSR com o servidor Nuxt fullstack


Na Parte 1, falei sobre como é fácil organizar um servidor de API no Nuxt . Na Parte 2, quero lhe dizer quais benefícios adicionais você pode obter do servidor Nuxt fullstack .

Parte 2: acelerando a renderização do servidor!


Vamos pensar agora como nosso servidor funciona a partir do exemplo codesandbox.io/s/codesandbox-nuxt-3gzhl

  1. O cliente solicita a página principal 3gzhl.sse.codesandbox.io
  2. O Nuxt começa a renderizar no servidor a página /pages/index.vue
  3. Chega a

      async fetch() {
        this.users = await this.$api("users", "index");
      },
    
  4. Por axios, ele faz uma solicitação http em 3gzhl.sse.codesandbox.io/api/users/index, ou seja, em mim mesmo
  5. Uma conexão é estabelecida, uma nova sessão é criada no servidor e a memória é alocada para processar a solicitação http
  6. Uma solicitação de entrada é aceita via protocolo http , a URL é analisada, os parâmetros são processados
  7. Executa o middleware do servidor
  8. Nuxt lança nosso servidor de API
  9. JSON
  10. users.index(), JSON
  11. JSON http
  12. axios JSON
  13. API

Agora imagine que temos 20 componentes na página que solicitam dados por meio da API ; portanto, em uma solicitação para a página com o servidor Nuxt, 20 conexões http internas adicionais serão estabelecidas e as etapas 4-13 serão executadas 20 vezes. O servidor HTTP Nuxt pode processar mais de 55 mil solicitações por segundo; no entanto, ao criar solicitações HTTP internas, reduzimos os recursos potenciais do servidor em dezenas de vezes.

Mas quando renderizamos a página no servidor, temos acesso direto a todos os controladores na pasta / api /

Vamos mudar a lógica para que, ao renderizar no servidor, o código do controlador seja chamado diretamente e, quando chamado pelo navegador, a solicitação foi enviada via http

  1. Renomeie o arquivo /plugins/api-context.js para /plugins/api-context.client.js
  2. altere o nome do arquivo nas configurações /nuxt.config.js

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

    Agora, este contexto . $ Api está disponível apenas para o código do cliente
  3. crie esse contexto . $ api para chamar diretamente os controladores no servidor

    /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. conecte o plugin do servidor

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

Agora, a função this. $ Api no servidor chama diretamente o método do controlador, e no cliente isso. $ Api envia uma solicitação http via axios .

O código

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

ao renderizar no servidor, ele não executará uma solicitação http por si só, mas simplesmente conectará o arquivo /api/users.js através de require e chame o método index () , ou seja, itens de 4 a 13 não serão executados, mas apenas 10. Serão executados 10. No entanto, quando o cliente clicar no botão Atualizar no navegador , os mesmos dados serão solicitados via http . Aqui está o código completo: codesandbox.io/s/codesandbox-nuxt-pbriw





Teste de performance


codesandbox.io/s/codesandbox-nuxt-rzdyw

  1. Para eliminar a influência da velocidade das conexões externas, substituí o recebimento de dados por dados estáticos:

    /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. Agora compare o tempo de execução do tempo de busca de renderização de chamada da API interna do servidor rzdyw.sse.codesandbox.io

    : tempo de 1ms
    de 0ms a um máximo de 2ms

    Tempo de
    busca de renderização de chamada da API http do servidor:
    tempo de 71ms de 46ms a um máximo de 1059ms
    e várias vezes o servidor geralmente travava com um erro

    RangeError
    Maximum call stack size exceeded

Aqui está um exemplo completo - codesandbox.io/s/codesandbox-nuxt-rzdyw

Total Parte 2


  • Com alterações mínimas, você pode acelerar a renderização do servidor em mais de 50 vezes. Em um exemplo ao vivo, a renderização da minha página foi acelerada em ~ 1,7 vezes
  • Recursos do servidor HTTP do nó reduzidos significativamente
  • De maneira otimizada, a única instância do Nuxt deve suportar a carga de projetos pequenos e médios

All Articles