In Part 1, I described how easy it is to organize an API Server in Nuxt . In Part 2, I want to tell you what additional benefits you can get from the Nuxt fullstack server .Part 2: speeding up server rendering!
Let's think now how our server works from the example codesandbox.io/s/codesandbox-nuxt-3gzhl- The client requests the main page 3gzhl.sse.codesandbox.io
- Nuxt starts rendering on the server the page /pages/index.vue
- Comes to
async fetch() {
this.users = await this.$api("users", "index");
},
- Via axios, he makes an http request , at 3gzhl.sse.codesandbox.io/api/users/index i.e. on myself
- A connection is established, a new session is created on the server, and memory is allocated for processing the http request
- An incoming request is accepted via http protocol , url is parsed, parameters are processed
- Executes server middleware
- Nuxt Launches Our API Server
- JSON
- users.index(), JSON
- JSON http
- axios JSON
- API
Now imagine that we have 20 components on the page that request data via the API , so in one request for the page with the Nuxt server, 20 additional internal http connections will be established and steps 4-13 will be performed 20 times. Nuxt HTTP server can process more than 55 thousand requests per second, however, creating internal HTTP requests, we reduce the potential server resources by tens of times.But when we render the page on the server, we have direct access to all the controllers in the / api folder /Let's change the logic so that when rendering on the server, the controller code is called directly, and when called from the browser, the request was sent via http- Rename the file /plugins/api-context.js to /plugins/api-context.client.js
- change the file name in the settings /nuxt.config.js
plugins: ["~/plugins/api-context.client.js"]
Now this. $ Api context is available only for client code
- create this. $ api context to directly call controllers on the
/plugins/api-context.server.js server
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;
}
});
};
- connect the server plugin
/nuxt.config.js
plugins: [
"~/plugins/api-context.client.js",
"~/plugins/api-context.server.js"
]
Now the function this. $ Api on the server will directly call the controller method, and on the client this. $ Api send an http request through axios .The code async fetch() {
this.users = await this.$api("users", "index");
},
when rendering on the server, it will not perform an http request to itself, but simply connect the /api/users.js file via require and call the index () method , i.e. items from 4-13 will not be executed, but only 10 will be executed. However, when the client clicks the Refresh button in the browser , the same data will be requested via http . Here is the full code: codesandbox.io/s/codesandbox-nuxt-pbriwPerformance testing
codesandbox.io/s/codesandbox-nuxt-rzdyw- To eliminate the influence of the speed of external connections, I replaced receiving data with static data:
/api/users.js
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."
}
};
}
....
- 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;
}
});
};
- 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;
},
- 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";
...
- Now compare the execution time of rzdyw.sse.codesandbox.io
Server internal API call rendering fetch time: 1ms
time from 0ms to a maximum of 2ms
rzdyw.sse.codesandbox.io/httpcall
Server http API call rendering fetch time: 71ms
time from 46ms to a maximum of 1059ms
and several times the server generally crashed with an error
RangeError
Maximum call stack size exceeded
Here is a complete example - codesandbox.io/s/codesandbox-nuxt-rzdywTotal Part 2
- With minimal changes, you can speed up server rendering by more than 50 times, on a live example, rendering my page was accelerated by ~ 1.7 times
- Node HTTP server resources significantly reduced
- In an optimized way, Nuxt's only instance should withstand the load of small and medium-sized projects