Post Excerpt: Slice Content in Laravel or in Vue?

Imagine you have a Laravel + Vue project with Posts in the DB but need to show only the first 300 characters of content in the Posts list. Where should you perform that slicing - in Vue or Laravel? Let's compare.

The main point is that if we slice text in Vue, it means we download too much data from the server, which is not needed.

For this demo project, we chose Laravel Breeze Vue+Inertia preset for the JavaScript part.

Post List

We have a Post model with two fields: title and content. And imagine that content is quite long: around 5000 words.

database/factories/PostFactory.php

public function definition(): array
{
return [
'title' => fake()->sentence(),
'content' => fake()->paragraphs(250, true),
];
}

Setup: API and Vue Component

The Laravel API endpoint:

routes/api.php:

use App\Models\Post;
 
// ...
 
Route::get('/v1/posts', function () {
return Post::get(['id', 'title', 'content']);
});

In Vue, here's how we get the data from the API:

resources/js/Pages/Dashboard.vue

<script setup>
// ...
 
onMounted(() => {
axios.get('/api/v1/posts').then(response => {
posts.value = response.data
})
})
</script>

And here's how we present it:

resources/js/Pages/Dashboard.vue

// ...
<div class="p-6 text-gray-900">
<div v-for="post in posts" :key="post.id" class="mb-8">
<Post :post="post" />
</div>
</div>

Slice Excerpt on the Vue Side: Computed Property

To display posts, create a Post Component.

resources/js/Components/Post.vue

<script setup>
import { computed } from 'vue';
 
const props = defineProps({
post: {
type: Object,
required: true
}
})
 
const excerpt = (value, length) => {
return value.length > length ? value.substring(0, length) : value
}
 
const post_excerpt = computed(() => {
return excerpt(props.post.content, 300)
})
</script>
 
<template>
<article>
<h2 class="font-semibold text-xl mb-4">{{ post.title }}</h2>
<div class="">{{ post_excerpt }}</div>
</article>
</template>

Here we define the excerpt function and a computed property post_excerpt.

Vue Excerpt

We download all the posts from the API and slice them on the Vue level.

Result: fetching posts with full content consumes 226.12 kB of traffic data.


Slice Excerpt on the Laravel Side: Observer

Now let's take another approach and generate excerpts on the back end.

Create a new migration with a dedicated field called excerpt:

Schema::table('posts', function (Blueprint $table) {
$table->longText('excerpt');
});

Create an Observer with the method creating():

php artisan make:observer PostObserver

app/Observers/PostObserver.php

use App\Models\Post;
 
class PostObserver
{
public function creating(Post $post)
{
$post->excerpt = str($post->content)->substr(0, 300);
}
}

When you create a post, Observer will fill in the excerpt attribute before saving it into the database.

You can also use the words() method to generate an excerpt based on word count. It can also append a string like ... to the end of the text.

$post->excerpt = str($post->content)->words(65, '...');

For more methods, see Available String Helper Methods.

Now let's register our PostObserver in EventServiceProvider.

app/Providers/EventServiceProvider.php

use App\Models\Post;
use App\Observers\PostObserver;
 
// ...
 
public function boot(): void
{
// ...
 
Post::observe(PostObserver::class);
}

Now, update our API endpoint to return the excerpt instead of content.

routes/api.php:

Route::get('/v1/posts', function () {
return Post::get(['id', 'title', 'content']);
return Post::get(['id', 'title', 'excerpt']);
});

And finally, we remove the computed property and excerpt function from the component. It should look as follows:

resources/js/Components/Post.vue

<template>
<article>
<h2 class="font-semibold text-xl mb-4">{{ post.title }}</h2>
<div class="">{{ post.excerpt }}</div>
</article>
</template>

Laravel Excerpt

Result: response size has been reduced drastically from 226.12 kB to 2.99 kB. It is 75 times.


Conclusion: response size may seem like a small amount of data, but it may compound for multiple simultaneous system users. Also, in the long run, this might result in higher costs for your traffic.

You can also watch a video from my course "Better Eloquent Performance" where I illustrate a similar concept: API Return: Kilobytes Optimization

No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials