Cách tạo trình đọc RSS đơn giản bằng SvelteKit

Viết trình đọc RSS là một nhiệm vụ đơn giản, thậm chí còn dễ hơn với SvelteKit, một framework meta được xây dựng dựa trên Svelte.

Lập trình với Svelte

RSS là tiêu chuẩn thông dụng trong phân phối nội dung web theo định dạng có cấu trúc. Nhiều người, từ đam mê công nghệ tới giáo viên, dùng RSS để cập nhật những bản tin mới nhất và đăng bài viết trên blog yêu thích của họ.

Thiết lập dự án SvelteKit

Trước khi tiếp tục, bạn cần cài runtime Node.js trên máy và Node Package Manager (NPM). Mở terminal và chạy lệnh sau:

npm create svelte
# hoặc
yarn create svelte

Nó sẽ khởi động Command Line Interface (CLI) do Svelte tạo và được chạy bởi Vite. Đặt tên cho dự án và thiết lập mẫu ứng dụng là "Skeleton project". Tắt tính năng kiểm tra nhập liệu bằng TypeScript, và click bất kỳ lựa chọn bổ sung mà bạn muốn. Sau đó, chuyển sang thư mục dự án và chạy:

npm install
# or
Yarn

Sau khi cài đặt các phần phụ thuộc mặc định, bạn cần cài 2 gói tên: rss-parser moment. Gói đầu tiên sẽ khiến việc phân tích dữ liệu XML dễ dàng hơn, còn gói thứ hai giúp bạn định dạng ngày tháng chính xác. Trong terminal, chạy lệnh sau:

npm install rss-parser
npm install moment
# hoặc
yarn add rss-parser
yarn add moment

Giờ, bạn có thể khởi động server lập trình bằng cách chạy lệnh sau:

npm run dev
# hoặc
yarn dev

Xóa nội dung của file App.css và chỉnh sửa cấu trúc dự án như ảnh minh họa bên dưới. Tạo bất kỳ thư mục hiện chưa có và tạo file trống để khớp với những mục được đặt tên bên dưới:

Tạo bảng thư mục

Bạn sẽ chỉ cần thay đổi thư mục src, chứa mục lib và file lib/addToLocalStorage.js. Nó cũng chứa một thư mục routes, bao gồm thư mục con feed và 4 file: +layout.js, +layout.svelte, +page.svelte, +server.js. Bên trong feed, tạo một thư mục tên [title] với hai file bên trong: +page.server.js+page.svelte.

Tạo lộ trình API để kiểm tra bảng tin RSS hợp lệ

Mở file routes/+server.js và nhập tiện ích json. Ngoài ra, nhập Parser từ gói rss-parser.

import { json } from "@sveltejs/kit";
import Parser from "rss-parser";

Giờ, xuất hàm không đồng bộ, GET, và chuyển URL làm tham số. Trong hàm này, tạo hai hằng số: rssLink parser.

Hằng số đầu tiên sẽ chứa tham số tìm kiếm từ url đã chuyển, còn thứ hai là parser, sẽ chứa phiên bản đối tượng Parser mới. Tiếp theo, gọi phương thức parseURL trên parser và chuyển rssLink làm tham số. Cuối cùng, tuần tự hóa phản hồi bằng hàm json và trả về nó.

export async function GET({url}) {
    const rssLink = url.searchParams.get('url');
    const parser = new Parser();
    let feed = await parser.parseURL(rssLink);
    return json(feed);
}

Thiết kế trang chủ

SvelteKit dùng hệ thống định tuyến dựa trên filesystem. Mặc định, file routes/+page.svelte hoặc động dưới dạng trang chủ cho web của bạn.

Mở file +page.svelte. Trong tag script, nhập hàm addToLocalStorage từ thư mục lib. Bạn chưa tạo cái này nhưng bạn sẽ làm việc đó sau này. Sau khi nhập hàm này, tạo hai biến, url ready, đặt biến ready sang false.

<script>
   import addToLocalStorage from '$lib/addToLocalStorage';
   let url;
   let ready = false;
</script>

Trong phần markup, thêm:

<main>
    <h1>RSS Reader</h1>
    <h3>Add a new feed:</h3>
    <input
        type="url"
        placeholder="Enter a valid RSS link..."
        bind:value={url}
        on:input={() => {
            if (url.length > 0) {
                setTimeout(() => {
                    ready = true;
                }, 250);
            } else {
                ready = false;
            }
        }}
    />
</main>

Khối code trên xác định một phần tử input đặt biến ready sang true nếu độ dài của đầu vào người dùng lớn hơn 0. Tiếp theo, thêm code hiện một số phần tử nếu ready truthy.

{#if ready}
    {#await fetch(`/?url=${url}`).then((res) => res.json())}
        <p>Gathering information... Please wait</p>
    {:then data}
        {#if data.message === 'Internal Error'}
            <p>Something went wrong...Check your URL and try again</p>
        {:else}
            <div>
                {#if data.image}
                    <img
                        src={data.image.url}
                        alt={data.title}
                    />
                {/if}
                <p>{data.title}</p>
                <p>{data.description || ''}</p>
                {console.log(data) || ''}
            </div>
            <button on:click={()=>{
                addToLocalStorage(data.title, url);
                location.reload();
                }}>Add to My Feeds</button>
        {/if}
    {/await}
{/if}

Khối code này kiểm tra xem liệu ready có đúng, sau đó thực hiện cuộc gọi tới route API bạn đã tạo từ đầu. Code này chịu trách nhiệm kiểm tra xem liệu URL người dùng đã nhập có trỏ tới bảng RSS hợp lệ hay không.

Cuối cùng, thêm một số kiểu cơ bản cho trang như sau:

<style>
img {
width: 40px;
height: 40px;
}

input {
padding: 15px;
font-size: 20px;
width: 50%;
}
</style>

Thiết lập bố cục

Thêm code sau vào file layout.js. Code này sẽ yêu cầu Svelte chạy file +layout.svelte chỉ trên client:

export const prerender = false;
export const ssr = false;

Tiếp theo, trong file +layout.svelte, trả về danh sách bảng tin từ lưu trữ cục bộ:

<script>
let feeds = JSON.parse(window.localStorage.getItem('feeds')) || [];
feeds = feeds.reverse();
</script>

Tiếp theo, thêm đánh dấu cho thanh điều hướng như thế này:

<nav>
    <a href="/">Home</a>
    <span>My Feeds:</span>
    <div class="my-feeds">
        {#each feeds as feed}
            {@const number = feeds.indexOf(feed)}
            <div>
                {number + 1}. <a href={`/feed/${feed.title}?url=${feed.url}`}>{feed.title}</a>
            </div>
        {/each}
    </div>
</nav>

Thêm thành phần slot và kiểu cho bố cục:

<slot />

<style>
nav {
    display: flex;
    font-size: 18px;
    background-color: white;
    padding: 10px;
    width: 98vw;
}

.my-feeds {
    display: flex;
    white-space: nowrap;
    overflow-x: scroll;
    margin-left: 30px;
    gap: 10px;
}

span {
    white-space: nowrap;
    font-weight: 900;
    margin-left: 20px;
    margin-right: -5px;
}
</style>

Thêm URL hợp lệ cho lưu trữ cục bộ

Sau khi ứng dụng xác nhận rằng bảng tin RSS tồn tại, bạn nên có cơ chế lưu URL trong ổ lưu trữ cục bộ, để người dùng sẽ không phải nhập lại nó. Mở file addToLocalStorage.js và thêm:

export default function addToLocalStorage (title, url) {
    let feedInLocalStorage = JSON.parse(localStorage.getItem("feeds")) || [];

    localStorage.setItem(
        "feeds",
        JSON.stringify([...feedInLocalStorage, {title:title, url:url}])
    );
}

Code này dùng phương thức setItem trên localStorage để lưu bộ nhớ đệm một mảng chứa dữ liệu về bảng tin của người dùng.

Hiện danh sách các mục cho bảng tin RSS cụ thể

Thêm code sau vào file [title]/+page.server.js:

import Parser from "rss-parser";

export async function load({url}){
    const rssLink = url.searchParams.get('url');
    const parser = new Parser();
    let feed = await parser.parseURL(rssLink);
    return {...feed};
}

Đây là code chạy cùng file +page.svelte. Nó tìm nạp các mục mới nhất từ một bảng cụ thể. Giờ trong file +page.svelte, nhập gói moment, và thêm thuộc tính data:

<script>
import moment from 'moment';
export let data; 
</script>

Tiếp theo, hiện một ảnh nếu nó có sẵn và di chuyển qua từng mục trong mảng data.items, hiện nội dung phù hợp:

{#if data.items}
    {#each data.items as item}
        {@const number = data.items.indexOf(item)}

        <div class="item">
            {number + 1}. 
            <a href={item.link}> {@html item.title}</a>

            <div class="metadata">
                <span>{item.author || item.creator || ""}</span>
                <span>{moment(item.isoDate).fromNow()}</span>
            </div>

            <div class="snippet">{item.contentSnippet || ""}</div>
        </div>
    {/each}
{:else}
    <p>Something went wrong...</p>
{/if}

Cuối cùng, tạo kiểu trang như ý bạn muốn:

<style>
.snippet {
    font-size: 18px;
}

a {
    font-size: 25px;
    text-decoration: underline;
    color: black;

    &:visited {
        color: gray;
    }

    &:hover {
        text-decoration: none;
    }
}

.item {
    display: flex;
    flex-direction: column;
    padding: 10px 10px;
}

.metadata {
    display: flex;
    gap: 10px;
    margin: 10px 0px 10px 0px;
}

img {
    width: 40px;
    height: 40px;
}
</style>

Giờ bạn đã tạo thành công một trình đọc RSS bằng SvelteKit rồi đấy.

Hi vọng bài viết hữu ích với các bạn.

Thứ Năm, 21/09/2023 16:52
31 👨 128
0 Bình luận
Sắp xếp theo