7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. CMS

Xây dựng một CMS: goPress

Scroll to top
Read Time: 37 mins
This post is part of a series called Building a CMS.
Building a CMS: Structure and Styling

Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)

Go là một ngôn ngữ lập trình tập trung vào kết nối mạng được phát triển bởi Google nhằm giúp viết các chương trình liên quan đến mạng được dễ dàng. Với rất nhiều thư viện tuyệt vời để lựa chọn, chạy một ứng dụng web là một việc rất dễ dàng.

Trong bài hướng dẫn này, tôi sẽ tạo một Hệ thống Quản lý Nội dung (CMS) sử dụng Go và một số thư viện trợ giúp. CMS này sẽ sử dụng cấu trúc dữ liệu trang web được hình thành trong hướng dẫn đầu tiên, Xây dựng CMS: Cấu trúc và Giao diện.

Thiết lập Môi trường Phát triển Với Go

Cách dễ nhất để cài đặt ngôn ngữ lập trình Go trên máy Mac là với Homebrew. Nếu bạn vẫn chưa cài đặt Homebrew, thì hướng dẫn Tìm hiểu Homebrew: Trình quản lý Gói Cơ bản của OS X sẽ chỉ cho bạn thấy cách cài đặt. Đối với các nền tảng khác, chỉ cần thực hiện theo các hướng dẫn trên trang Tải về của Go.

Trong terminal, gõ:

Trong thư mục home của bạn, tạo thư mục go. Ngôn ngữ Go sẽ lưu trữ tất cả các thư viện đã tải xuống ở đó. Thêm dòng này vào tập tin .bashrc và/hoặc .zshrc của bạn:

Nếu bạn đang sử dụng fish, thì hãy thêm điều này vào tập tin config.fish của bạn:

Tiếp theo, bạn cần cài đặt các thư viện. Thư viện goWeb cung cấp framework máy chủ web, thư viện amber cung cấp preprocessor (tiền xử lý) Jade tương đương cho HTML và BlackFriday biên dịch Markdown thành HTML thích hợp. Ngoài ra, tôi còn sử dụng thư viện Handlebars để tạo template. Để cài đặt các thư viện này, bạn cần gõ các lệnh sau trong thư mục của dự án:

Bây giờ thì Go và các thư viện cần thiết đã có trên hệ thống của bạn, bước tiếp theo là bắt đầu viết code. Thư viện goPress có năm tập tin, trong khi chương trình chính là một tập tin để gọi các hàm của thư viện.

Tập tin Thư viện goPress.go

Tôi muốn máy chủ càng nhanh càng tốt. Để đạt được điều này, bất cứ thứ gì có thể dùng lại được đều nằm trong bộ nhớ. Do đó, một biến toàn cục lưu giữ tất cả asset và trang chủ. Bạn có thể thiết kế máy chủ với tất cả asset nằm trong bộ nhớ, nhưng điều này sẽ làm cho bộ nhớ trở nên cồng kềnh trên các trang web lớn. Vì trang chủ sẽ là trang được tải thường xuyên nhất, nên nó cũng được lưu giữ trong bộ nhớ.

Bằng cấu trúc tập tin đã được thiết lập trong hướng dẫn trước, hãy tạo một thư mục mới trong thư mục src đặt tên là goPress. Đây sẽ là nơi mà tất cả các tập tin của thư viện goPress được đặt. Tập tin đầu tiên là goPress.go. Hãy tạo tập tin đó và bắt đầu dán các code sau vào.

Câu lệnh package ở phía trên nói cho trình biên dịch biết rằng tập tin này là một phần của một gói thư viện và nêu ra tên của thư viện. Mỗi tập tin trong thư mục này đều phải có câu lệnh này ở phía trên như là một phần của tập tin.

Tiếp theo, bạn import tất cả các thư viện được tham chiếu trong tập tin này. Nếu bạn liệt kê một thư viện mà không sử dụng nó, thì trình biên dịch sẽ nhắc nhở. Điều này giúp giữ cho code của bạn được sạch sẽ và gọn gàng.

Sau khi nạp các thư viện, tôi định nghĩa các cấu trúc dữ liệu và các biến toàn cục khác nhau mà CMS sẽ sử dụng. Những biến toàn cục này là thư viện toàn cục. Bên ngoài thư viện, các biến bắt đầu bằng chữ hoa có thể được tham chiếu đến nếu tên thư viện nằm trong phạm vi của nó.

Tiếp theo, thêm hàm này vào cùng một tập tin:

Hàm GetGlobals nạp toàn bộ thông tin được lưu trữ toàn cục cho trang web. Một hash map dựa trên tên tập tin (không có đuôi mở rộng) lưu trữ dữ liệu từ tập tin máy chủ, thư mục layouts và styling. Sau đó, mọi thứ ở trong thư mục site/parts đều được bỏ vào cùng một cấu trúc. Bằng cách này, nếu trang web chỉ muốn những gì mặc định được cung cấp trong theme, thì người dùng không cần phải đặt một tập tin cho nó trong thư mục site/parts.

Trong cùng một tập tin, hãy thêm các hàm sau đây:

Đây là những hàm trợ giúp SaveServerParameters()LoadServerParameters(). Các hàm này lưu và nạp các thiết lập máy chủ khác nhau vào tập tin server.json.

Các hàm tiếp theo là tạo các route (tuyến) và các route mặc định của chúng ta. Thêm các hàm này vào cùng một tập tin:

Hàm DefaultRoutes() tạo ra các route mặc định để sử dụng trong CMS của chúng ta. Các hàm cho các route này nằm ở trong các tập tin của thư viện khác. SetGetRoute() tạo ra từng route. Đây chỉ đơn giản là một wrapper ở trên hàm của thư viện goWeb mà nhận một biểu thức chính quy để xác định định dạng của route và một hàm để thực thi khi biểu thức đó là đúng. Nếu bạn đã từng sử dụng framework Sinatra cho Ruby hoặc framework Express cho Node.js, thì bạn sẽ quen với thiết lập này.

Thứ tự tạo ra các route là rất quan trọng. Nếu route đầu tiên chứa một biểu thức chính quy để khớp tất cả mọi thứ, thì các route còn lại không thể truy cập được. Route đầu tiên sẽ bắt lấy tất cả. Vì vậy, tôi đã định nghĩa các route cụ thể nhất trước, và các route chung chung sau.

Hàm StartServer() khởi động máy chủ web. Nó gọi hàm Run() của goWeb lấy địa chỉ cho máy chủ.

Xuyên suốt code, tôi tận dụng tối đa hàm log.PrintLn(). Điều này in ra trong console thông báo cùng với ngày tháng và mốc thời gian. Điều này rất tốt cho việc gỡ lỗi, nhưng cũng được sử dụng để phân tích lưu lượng truy cập.

Tập tin Thư viện PagesPosts.go

Tiếp theo, tạo tập tin PagesPosts.go trong cùng một thư mục. Tập tin này sẽ chứa tất cả code để làm việc với các loại trang và các loại bài viết. Một page chỉ đơn giản là một trang web. Một post là bất cứ điều gì được tạo ra theo thời gian: bài viết tin tức, bài đăng trên blog, bài hướng dẫn, v.v... Trong tập tin này, hãy thêm code sau:

Như trong tập tin goPress.go, nó bắt đầu với khai báo package và danh sách các thư viện cần import. Tập tin này sẽ sử dụng mọi thư viện mà chúng ta đã tải xuống cho go.

Hàm Mainpage() hiển thị front-page của trang web. Nó chỉ đơn giản là một wrapper cho hàm RenderPageContents() xác định trang index chính sẽ được kết xuất. RenderPageContents() thực hiện tất cả công việc thực tế.

Hàm SiteMap() cung cấp sơ đồ trang theo yêu cầu. Nó kéo thông tin từ sitemap.xml ở bên trên thư mục site.

Hàm PostPages() hiển thị đúng bài viết được yêu cầu. Một lần nữa, điều này chỉ là thiết lập cuộc gọi đến hàm RenderPageContents(), hàm thực hiện tất cả các công việc chính.

Hàm PostIndex() gom lại các thông tin cho một chỉ mục bài viết và đưa nó đến hàm RenderPageContents().

Hàm topPages() thiết lập hàm RenderPageContents() để kết xuất một trang chuẩn. Tất cả các trang nằm trong thư mục pages/.

Hàm GetPageContents() nạp nội dung của tất cả các trang hoặc bài viết. Đầu tiên, tải nội dung của trang lỗi không tìm thấy 404 từ cấu trúc dữ liệu toàn cục. Hàm này sau đó sẽ tìm kiếm tập tin Markdown trước, sau đó là tập tin HTML, và sau đó là tập tin Amber. Tiếp theo, chuyển đổi tất cả các nội dung Markdown và Amber sang HTML. Tập tin Amber có thể có dữ liệu được liên kết trong một tập tin JSON. Tập tin dữ liệu đó cũng được nạp cho việc xử lý tập tin Amber.

Việc xử lý Markdown trong Blackfriday có một kết quả cho bộ xử lý Handlebars. Bộ chuyển đổi markdown sang HTML Blackfriday sẽ thay đổi tất cả các dấu nháy kép sang code HTML tương ứng của nó (“”). Vì điều đó không hoàn toàn cần thiết cho việc kết xuất, nên tôi đã đảo ngược sự thay đổi sau đó. Điều này giữ cho tất cả các macro Handlebars sử dụng dấu nháy kép.

Nếu bạn muốn có thêm nhiều kiểu định dạng tập tin, chỉ cần thêm chúng vào đây. Cách thiết lập này nạp từng loại nội dung.

RenderPageContents() là hàm chính được sử dụng để tạo một trang web. Sau khi nó thiết lập header tiêu chuẩn cho trả lời, thủ tục này sẽ tạo ra một cấu trúc dữ liệu và điền nó với nội dung mặc định, nội dung trang và một tập tin JSON liên kết cho trang. Handlebars sử dụng cấu trúc dữ liệu để kết xuất toàn bộ trang.

Tiếp theo, thủ tục định nghĩa tất cả các hàm trợ giúp của Handlebars. Hiện tại, có hai hàm: savedate. Nếu bạn muốn có thêm hàm trợ giúp, thì đây là nơi bạn sẽ thêm chúng vào dự án của bạn.

Hàm trợ giúp save có hai tham số: một cái tên được phân chia ra từ nội dung bởi một dấu |. Vì các tham số của hàm trợ giúp trong Handlebars không thể chứa dấu cách, nên các tham số sử dụng một dấu - thay vì một dấu cách. Điều này cho phép bạn tạo các biến template cho mỗi trang bên trong ngữ cảnh của trang. Ví dụ, macro {{save site| Custom-Computer-Tools}} sẽ đặt Custom Computer Tools tại nơi định nghĩa và bất cứ nơi nào khác trên trang có {{site}}.

Hàm trợ giúp date nhận một chuỗi định dạng và tạo ra ngày thích hợp theo chuỗi định dạng đó. Ví dụ, macro {{date January-2,-2006}} tạo ra October 13, 2015 vào ngày đó.

Handlebars xử lý trang hai lần: trước khi shortcode được kết xuất trong trường hợp bất kỳ shortcode nào trong khai triển template và sau khi chạy các shortcode trong trường hợp một shortcode bổ sung bất kỳ hành động template nào của Handlebars. Cuối cùng, hàm trả về toàn bộ nội dung HTML cho trang được yêu cầu.

Hàm SetStandardHeader() thiết lập bất kỳ phần tử header tùy biến nào vào phản hồi. Đây là nơi bạn thiết lập thông tin máy chủ và kiểm soát bộ nhớ đệm.

Tập tin Thư viện Images.go

Tập tin tiếp theo để xử lý là Images.go và tất cả các hàm cần thiết để gửi hình ảnh tới trình duyệt. Vì đây sẽ là một máy chủ web đầy đủ, nên nó phải làm việc với các dữ liệu nhị phân của một hình ảnh đang gửi. Hãy tạo tập tin Images.go và đặt code sau đây vào:

Tập tin thư viện này cũng giống như các tập tin khác: một khai báo gói và các khai báo thư viện. Hàm ImagesLoad() và hàm LoadThemeImage() thiết lập một cuộc gọi đến hàm LoadImage() để thực hiện công việc thật sự. Các hàm này cho phép tải các hình ảnh từ thư mục site hoặc từ thư mục theme hiện tại.

Hàm LoadImage() kiểm tra loại hình ảnh. Nếu đó là một tập tin svg, thì nó nạp như là văn bản thuần tuý. Giả sử tất cả các loại tập tin khác là tập tin nhị phân, thì phương thức này tải chúng cẩn thận hơn. Nó sẽ tải lên các tập tin nhị phân trong các khối 1K.

Tập tin Thư Viện StyleSheetScripts.go

Tập tin tiếp theo là để nạp CSS và JavaScript. Vì build script của chúng ta biên dịch tất cả các CSS và JavaScript thành một tập tin, nên những hàm này thật sự đơn giản. Tạo tập tin StyleSheetScripts.go và thêm các dòng sau:

Tập tin này có ba hàm. Hàm GetStylesheets() nạp tập tin CSS đã được biên dịch. Hàm GetScripts() nạp tập tin JavaScript đã được biên dịch. Với cờ Cache được thiết lập, cả hai hàm này sẽ lưu nội dung vào bộ nhớ đệm. Tôi tắt cờ Cache trong khi kiểm thử. Hàm LoadFile() là một hàm nạp tập tin đơn giản để lấy nội dung của tập tin.

Tập tin Thư viện Shortcodes.go

Mặc dù tôi muốn một máy chủ nhanh, nhưng tôi cũng muốn có nhiều tính linh hoạt. Để đạt được tính linh hoạt, có hai kiểu khai triển macro khác nhau: khai triển bằng Handlebar và khai triển bằng shortcode.

Sự khác biệt là khai triển bằng Handlebars là một cách khai triển đơn giản, ít logic, trong khi việc khai triển bằng shortcode là bất cứ điều gì mà bạn có thể lập trình vào hệ thống: tải thông tin từ một trang bên ngoài, xử lý thông tin với một chương trình bên ngoài, hoặc bất cứ điều gì.

Tạo tập tin Shortcodes.go và dán code sau đây vào nó:

Tập tin này bắt đầu giống như tất cả các tập tin còn lại với một định nghĩa gói và thư viện được sử dụng. Nhưng nó nhanh chóng khác với việc định nghĩa một kiểu biến ShortcodeFunction đặc biệt, một biến thư viện và một hàm init(). Các biến thư viện chỉ được nhìn thấy bởi một hàm của thư viện. Biến thư viện này, shortcodeStack, là một ánh xạ các chuỗi đến một hàm.

Các hàm init() của thư viện cho phép bạn chạy code trước bất kỳ cuộc gọi nào khác vào thư viện. Ở đây, tôi khởi tạo cấu trúc dữ liệu shortcodeStack để nắm giữ danh sách các shortcode.

Hàm AddShortCode() cho phép bạn tải một hàm để xử lý một shortcode thành biến thư viện cho tất cả các shortcode.

Hàm ProcessShortCodes() lấy một chuỗi là nội dung của trang web và tìm kiếm tất cả các shortcode nằm trong đó. Vì vậy, nếu bạn có một shortcode gọi là box, bạn sẽ chèn nó vào trang web của bạn với định dạng sau:

Mọi thứ đằng sau dấu cách trong mở đầu shortcode là các đối số để cho shortcode xử lý. Định dạng của các đối số phụ thuộc vào hàm shortcode xử lý.

Tất cả shortcode phải có một shortcode đóng. Những gì bên trong shortcode mở và đóng cũng là cách thức cho các shortcode trước khi gửi đến hàm xử lý shortcode. Tôi sử dụng -[]- để xác định một shortcode để cho chỉ mục JavaScript nội tuyến không bị nhầm lẫn với một shortcode.

Phần cuối cùng của code định nghĩa bảy shortcode đơn giản và thêm chúng vào mảng shortcode bằng hàm LoadDefaultShortcodes(). Nếu bạn muốn có một chức năng khác, bạn chỉ cần thay đổi code này và nó sẽ cập nhật nó ở khắp mọi nơi trong trang web của bạn.

Tập tin Chương trình Chính goPressServer.go

Tập tin cuối cùng cần tạo ra là tập tin chương trình chính. Ở cấp cao nhất của thư mục phát triển, tạo tập tin goPressServer.go và dán vào đó các thông tin sau đây:

Hàm main() là phương thức được gọi khi chương trình chạy. Đầu tiên nó sẽ thiết lập các shortcode, nạp vào các biến toàn cục, thiết lập các route mặc định, và sau đó khởi động máy chủ.

Biên dịch và Chạy

Để biên dịch toàn bộ chương trình, di chuyển đến thư mục cấp cao nhất nơi chứa tập tin goPressServer.go và gõ:

Nếu tất cả các tập tin đều đúng, nó sẽ biên dịch thành goPressServer trên các hệ thống Mac và Linux và goPressServer.exe trên Windows.

Running goPressServer in the TerminalRunning goPressServer in the TerminalRunning goPressServer in the Terminal

Khi bạn thực thi chương trình trên terminal, bạn sẽ thấy các câu lệnh log của nó cùng với ngày và giờ như trên.

The Front Page From the ServerThe Front Page From the ServerThe Front Page From the Server

Nếu bạn mở trình duyệt và truy cập địa chỉ của máy chủ, bạn sẽ thấy front-page. Bạn sẽ thấy shortcode mẫu và hai hàm trợ giúp khác nhau của Handlebars được sử dụng. Bây giờ bạn đã có máy chủ web của riêng mình!

Như bạn có thể thấy, tôi đã thay đổi trang front-page và thêm ba trang nữa vào thiết kế trang web ban đầu được đưa ra trong hướng dẫn Xây dựng CMS: Cấu trúc và Giao diện. Tôi cũng đã thêm Thư viện JavaScript Syntax Highlighter trong thư mục site/js/ để hiển thị code trên trang web bằng shortcode.

Tất cả những thay đổi này là nhằm minh hoạ Handlebars và xử lý shortcode. Tuy nhiên, do Syntax Highlighter không hoạt động tốt với tính năng nén, nên tôi đã loại bỏ việc nén JavaScript khỏi tập tin Gulp. Tất cả các thay đổi nằm trong tập tin tải về của hướng dẫn này.

Có một khóa học mới, Go Cơ bản cho việc Xây dựng các Máy chủ Web, đưa ra một giới thiệu tuyệt vời về ngôn ngữ Go và cách lập trình với nó.

Tóm tắt

Bây giờ thì bạn đã biết cách làm thế nào để xây dựng một máy chủ web đơn giản nhưng mạnh mẽ bằng ngôn ngữ Go, đã đến lúc để bạn thực hành rồi. Hãy tạo các trang, bài viết, các bộ phận nhúng và các shortcode mới. Nền tảng đơn giản này còn chậm hơn nhiều so với sử dụng WordPress, và nó hoàn toàn nằm trong tầm kiểm soát của bạn. Hãy cho tôi biết về máy chủ của bạn trong phần bình luận ​​dưới đây nhé.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.