Ứng dụng CLI quản lý bài viết

Ứng dụng CLI quản lý bài viết

Threads
  • Có bạn nào trong lúc code mà bị "ngẫn tò te" hoặc "lú lẫn" trong mớ hỗn độn của mình viết ra chưa. Những lúc như thế tôi thường hay ngừng lại, thư giãn đầu óc, hoặc để mai tính tiếp. Ấy vậy mà rất hiệu quả nhé! Lúc sau xem lại cái tự nhiên thấy vấn đề ở đâu ngay.

    Hoặc cũng có thể thử áp dụng phương pháp "chú vịt vàng" - thử giải thích vấn đề đang gặp phải với vịt xem, nó sẽ cho thấy mâu thuẫn trong lời nói ra.

    Còn không có tiền mua vịt to thì xe túi mù ra vịt bé giống mình nè 😅

    » Xem thêm
  • Ơ buồn cười thật. Ai cũng biết GIF là định dạng ảnh động thường được dùng thay cho video clip để hiển thị các nội dung ngắn trên nền tảng web. GIF tiện hơn các nội dung dạng video là vì nó được hiển thị như một bức ảnh và được hỗ trợ rộng rãi. Cơ mà GIF có dung lượng nặng quá.

    Nói thật nhiều lúc mình có vài cái hành động muốn hiển thị lên web cho mọi người xem, cơ mà định dạng GIF nó nặng với cả cũng không biết cách tối ưu cho nhẹ xuống. Hôm nay lên mạng tìm hiểu xem định dạng nào có khả năng thay thế GIF trong tương lai thì mọi người biết đó là gì không? Là WEBP (webp)!!! Đúng vậy, là định dạng ảnh mà mình đang dùng trên blog lâu nay luôn á, mà giờ mới biết là nó hiển thị được cả ảnh động nữa, hơi quê 😆

    Kết hợp với ffmpeg nữa là chuyển được tất tần tật video clip thành webp được ngay. Để vài nửa ngồi chế lại cái cli một tí là dùng ngon luôn mọi người ạ 🤪

    » Xem thêm
  • Cảm giác như Github Copilot đang cố gắng mở rộng thị trường cho anh em developer á. Mới trước họ ra mắt Github Open Copilot Chat thì mới đây lại thêm cái Using GitHub Copilot in the command line dùng để giải thích hoặc gợi ý lệnh trong terminal.

    Đây, cách dùng rất đơn giản thôi, ví dụ muốn nó giải thích câu lệnh sudo apt-get để làm gì, thì:

    $ gh copilot explain "sudo apt-get"

    Hoặc nhờ nó gợi ý lệnh mong muốn, sử dụng tiếng Việt được luôn nhé (kể cả tiếng Việt không dấu vẫn hiểu 😳)

    $ gh copilot suggest "xoá commit chưa push"

    Mình đã kiểm tra và thấy lệnh ra rất đúng, xịn thật 🤓

    » Xem thêm

Vấn đề

Xin chào các độc giả của 2coffee.dev. Một tuần nữa lại trôi qua, nhanh đến nỗi mà khi nhìn lại trang chủ, không ngờ rằng mình lại ngừng viết trong một khoảng thời gian dài như thế. Thành thật mà nói tuần vừa rồi khá là bận rộn, tôi vừa tập trung phát hành một bản cập nhật quan trọng cho sản phẩm tại nơi đang làm việc. Có lẽ vì thế mà khái niệm thời gian đã tạm thời bị vùi lấp. Hmm... Phải nghĩ ra xem có gì để kể không chứ!

Song song với việc đó, tôi đang cố gắng tối ưu hoá lại trải nghiệm người dùng cho trang blog. Bằng cách sửa một số lỗi tồn đọng từ trước, làm cho đường dẫn đến liên kết hiển thị rõ ràng hơn, thêm một vài hiệu ứng vui mắt và bổ sung thêm một số tinh chỉnh giao diện. Chỉ nhiêu đấy thôi mà cũng ngốn thời gian ra mặt. Sáng đi làm, tối về quay cuồng với guồng tối ưu không hồi kết.

Một vấn đề mới phát sinh trong lúc tối ưu hoá là quá trình render markdown lại gặp vấn đề. Cụ thể là khi sử dụng một số thẻ mới thì trang web bị vỡ giao diện. Chà! Kiếp nạn này bao giờ mới hết. Nếu nhớ không nhầm, phải có 2-3 bài viết nói về những vấn đề đã gặp phải với markdown. Cũng có khả năng là lúc trước đã quá xem nhẹ nên bây giờ phải đối mặt với những vấn đề như thế này.

Đằng nào cũng phải đụng đến nên quyết tâm sửa lại luôn một thể. Không sử dụng showdown nữa mà chuyển sang một thư viện khác có tên là marked.js. Chọn luôn tiêu chuẩn gfm của Github để định dạng. Làm như vậy sẽ hạn chế được những thay đổi sau này.

Trong rất nhiều bài viết trước đây, tôi có sử dụng một thẻ markdown để hiển thị hình ảnh thumbnail cho bài viết. Nhưng từ sau khi đập đi xây lại, phần hiển thị hình ảnh thumbnail đã được viết trực tiếp vào trong code. Còn phần hình ảnh đầu bài viết dùng code để tạm ẩn đi. Bây giờ chuyển sang tính năng mới, cần phải loại bỏ hết thẻ markdown bị thừa.

Nên công việc tiếp theo là cần sửa lại hàng loạt bài viết. Trang web có cách vận hành khá thú vị, đó là trang quản lý hết sức sơ sài. Không như những phiên bản trước có một trang quản lý "xịn sò", phiên bản này chỉ có một vài tính năng vừa đủ như tạo/cập nhật bài viết. Để truy cập vào trang chỉnh sửa, chỉ cần thêm một postfix /edit vào sau đường dẫn đến bài viết thì nó sẽ dẫn đến trang chỉnh sửa. Tất nhiên là trước đó phải đăng nhập bằng tài khoản có quyền admin, còn không thì bạn sẽ thấy một thông báo lỗi rằng trang không khả dụng.

Như vậy đếm sơ sơ có hơn 300 bài viết cần phải sửa lại, tương đương phải thực hiện lại các thao tác chỉnh sửa hơn 300 lần 🤮. Chưa kể mạng không phải lúc nào cũng tải được trang web trong vòng 3s. Vì thế lại một lần nữa, tôi tìm đến giải pháp CLI.

Ứng dụng CLI

Ý tưởng về một ứng dụng CLI giúp quản lý bài viết không mới. Thực tế từ lúc xây dựng phiên bản mới cho trang blog tôi đã nghĩ đến việc quản lý bài viết bằng những dòng lệnh. Mỗi bài viết là một file markdown, lưu trữ ở dưới máy, chỉnh sửa xong thì dùng một lệnh để xuất bản các bài viết lên là được. Vừa nhanh mà vừa tiện. Nhưng đến khi nghiêm túc ngồi "break" ra những thứ cần làm thì chao ôi... có lẽ mình nên làm cách đơn giản hơn. Hãy nhớ lại sứ mệnh của 2coffee.dev, mang đến những bài viết chất lượng chứ không phải là cặm cụi nửa tháng mà vẫn chưa ra ngô ra khoai.

Giờ đây thời cơ đã đến, đã có những thứ xây dựng từ trước và tận dụng lại được. Ứng dụng CLI xuất phát từ nhu cầu: quản lý được bài viết và chỉnh sửa phải nhanh gọn. Vì thế chức năng cơ bản chỉ cần kéo (pull) được danh sách bài viết về, chỉnh sửa hàng loạt rồi đẩy (push) bài viết lên, lấy cảm hứng tương tự như cách dùng git.

Nếu bạn còn nhớ về bài viết ứng dụng cli để tối ưu hoá hình ảnh, tôi đã tạo ra một cli xử lý hình ảnh từ trước đó. Ban đầu định viết tiếp phần code mới vào đây nhưng thực tế phải viết thêm nhiều code nên cách nhanh nhất là viết vào chung với dự án page-fresh - vốn là trang blog này. Nó có chứa nhiều mã giúp lấy dữ liệu từ máy chủ, mình có thể tận dụng để không cần phải viết lại nữa.

Để đơn giản hết mức có thể, các tệp pull.ts, push.ts... để đại diện cho lệnh pullpush. pull để kéo bài viết về còn push để xuất bản bài viết. Mỗi lúc cần chạy thì cú pháp sử dụng sẽ là:

$ deno run -A pull.ts
$ deno run -A push.ts

Để hỗ trợ thêm cờ (flag), kiểu như là --change, --force giống như các ứng dụng CLI chính thống thì cứ gõ thêm vào deno run rồi dùng Deno.args để phân tích dữ liệu và xử lý.

const args = Deno.args;

const flags: { [key: string]: string | boolean } = {};
for (let i = 0; i < args.length; i++) {
  if (args[i].startsWith("--")) {
    const flag = args[i].substring(2); // loại bỏ '--'
    if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
      flags[flag] = args[i + 1]; // lấy giá trị của flag
      i++;
    } else {
      flags[flag] = true;
    }
  }
}

pull.ts chứa mã lấy dữ liệu về. Khi chạy lệnh pull nó sẽ kéo tất cả nội dung bài viết về và lưu lại dưới dạng tệp *.md, với * là url của bài viết.

$ deno run -A cli/commands/pull.ts 
ℹ Kéo về 212 bài viết, bỏ qua 0 bài viết, thay đổi 0 bài viết (VI)
ℹ Kéo về 202 bài viết, bỏ qua 0 bài viết, thay đổi 0 bài viết (EN)
✔ Đã xong

Sau đó tôi tạo thêm một tệp article.ts để kiểm tra các bài viết đã thay đổi ở dưới máy. Đó là các bài viết được chỉnh sửa và chuẩn bị để xuất bản. Ví dụ:

$ deno run -A cli/commands/article.ts --change
ℹ Các thay đổi của bài viết tiếng Việt:
- 1-thang-hoc-rust-nhung-dieu-co-ban-cua-ngon-ngu-lap-trinh-rust.md
ℹ Các thay đổi của bài viết tiếng Anh:
- a-compilation-of-free-and-high-quality-serverless-databases.md
✔ Đã xong

Sau khi sửa xong, dùng lệnh push để xuất bản một bài chỉ định trước. Ví dụ:

$ deno run -A cli/commands/push.ts --file data/1-thang-hoc-rust-nhung-dieu-co-ban-cua-ngon-ngu-lap-trinh-rust.md

Hoặc push toàn bộ những bài đã sửa. Ví dụ:

$ deno run -A cli/commands/push.ts --change
ℹ Tìm thấy 1 bài viết tiếng Việt, 1 bài viết tiếng Anh
- 1-thang-hoc-rust-nhung-dieu-co-ban-cua-ngon-ngu-lap-trinh-rust.md
- a-compilation-of-free-and-high-quality-serverless-databases.md
✔ Đã cập nhật 1-thang-hoc-rust-nhung-dieu-co-ban-cua-ngon-ngu-lap-trinh-rust.md
✔ Đã cập nhật a-compilation-of-free-and-high-quality-serverless-databases.md
✔ Đã xong

Ngay lập tức các bài viết tìm thấy được đẩy lên. Trong push.ts có một hàm gọi API để xuất bản bài viết với quyền admin. Nên buộc phải có cookie của tài khoản quản trị. Cookie có thể lấy bằng cách vào trang web sao chép rồi dán thẳng vào trong code. Nhưng cookie có thời hạn khá ngắn cho nên viết thêm một tệp login.ts xử lý việc lấy cookie sẽ tiện hơn cho quá trình sử dụng sau này.

Cơ chế login cũng đơn giản. Bên trong login.ts khởi tạo một server cục bộ lắng nghe ở cổng 3069, bên trong có 1 endpoint tên là /callback. Khi gọi vào 2coffee.dev, ví dụ như là https://2coffee.dev/auth?redirect_url=http://localhost:3069/callback?token=<cookie> thì nó sẽ gọi lại vào endpoint /callback kèm theo token chính là cookie của admin, với điều kiện là admin đã đăng nhập từ trước. Lưu lại token vào certificate.txt để sử dụng cho các lần tiếp theo.

Kết hợp tất cả lại, tôi đã có 4 tệp login.ts, pull.ts, push.ts, articles.ts. Nếu cứ gõ đi gõ lại deno run sẽ rất dài, vì thế hãy nghĩ cách tối giản lại. Một lệnh gì đó giống như như là 2cf, khi đó chỉ cần gõ 2cf login, 2cf pull, 2cf push... tiện hơn biết bao.

Tạo một tệp cli.sh ngay trong thư mục của dự án page-fresh:

#!/bin/bash

case $1 in
  login)
    cd /Users/hoaitx/src/hoaitx/page-fresh && deno run -A cli/commands/login.ts $2
    ;;
  pull)
    cd /Users/hoaitx/src/hoaitx/page-fresh && deno run -A cli/commands/pull.ts $2
    ;;
  push)
    cd /Users/hoaitx/src/hoaitx/page-fresh && deno run -A cli/commands/push.ts $2
    ;;
  article)
    cd /Users/hoaitx/src/hoaitx/page-fresh && deno run -A cli/commands/article.ts $2
    ;;
  *)
    echo "Usage: $0 {login|pull|push|article}"
    ;;
esac

Như vậy lúc này chỉ cần ./cli.sh login, ./cli.sh pull...

Ở đây tôi dùng Mac và cài Oh My Zsh nên có thể đặt alias cho dòng lệnh. Tiếp tục mở tệp .zshrc và thêm vào function 2cf().

function 2cf() {
    /Users/hoaitx/src/hoaitx/page-fresh/cli.sh "$@"
}

Reload lại .zshrc:

$ source ~/.zshrc

Thế là đã xong, từ giờ đã có thể dùng lệnh 2cf:

$ 2cf login
$ 2cf pull
$ 2cf push
...

Cuối cùng để cho CLI trở nên sinh động hơn, tôi sử dụng thêm 2 package là orachalk. ora dùng để tạo hiệu ứng xử lý còn chalk để thay đổi màu sắc của văn bản trong terminal.

Trong tương lai, tôi sẽ tiếp tục phát triển ứng dụng CLI này với mục đích thay thế hoàn toàn trang quản trị và tiến tới một vài tính năng tự động khác.

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.
Author

Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.

Bạn thấy bài viết này có ích?
Không

Bình luận (4)

Nội dung bình luận...
Avatar
Xuân Hoài Tống2 ngày trước
Thôi nào các bác, đăng nhập vào có khi vui hơn ấy 😅
Trả lời
Avatar
Ẩn danh2 ngày trước
Gòi toàn ẩn danh thật thật giả giả 👈🫵👉
Trả lời
Avatar
Ẩn danh3 ngày trước
bài viết hữu ích
Trả lời
Avatar
Ẩn danh3 ngày trước
tuyệt's vời
Trả lời