Trong bài viết này, tôi sẽ giải thích cách tôi sử dụng Gatsby Functions và Stripe API để cho phép đóng góp "Trả những gì bạn muốn" an toàn giúp tài trợ cho dự án nguồn mở của tôi MDX Embed.
Lưu ý: MDX Embed cho phép bạn dễ dàng nhúng nội dung phương tiện truyền thông phổ biến của bên thứ ba như video YouTube, Tweet, bài đăng trên Instagram, bài học Egghead, Spotify, TikTok và nhiều nội dung khác trực tiếp vào
Các dịch vụ của bên thứ ba như những dịch vụ được đề cập ở trên sẽ chỉ chấp nhận các yêu cầu được gửi phía máy chủ. Có một số lý do cho điều này nhưng sử dụng khóa bảo mật hoặc khóa riêng tư thường là một trong số đó. Sử dụng các khóa này ở phía máy chủ có nghĩa là chúng không được hiển thị cho máy khách (trình duyệt) và không thể bị lạm dụng, và đây chính là lúc Serverless Functions của Gatsby có thể giúp ích.
Gatsby cung cấp cùng một cách tiếp cận hợp lý đối với Serverless Functions như cách họ làm với các trang. Ví dụ: các trang web nằm trong
Tất nhiên, còn nhiều hơn thế nữa nhưng trải nghiệm của nhà phát triển Gatsby vừa hợp lý vừa nhất quán, và cá nhân tôi hoàn toàn thích điều đó!
Dưới đây là sơ đồ giúp minh họa cho cách thức hoạt động này:

Lần đầu tiên tôi thử nghiệm phương pháp này là vào tháng 11 năm 2020 trước khi phát hành Gatsby Functions và sử dụng Netlify Functions để cung cấp giao tiếp giữa máy chủ với máy chủ bằng Twitter API và blog Gatsby cùng danh mục đầu tư thương mại của tôi. Bạn có thể đọc về cách tiếp cận này tại đây: Sử dụng Netlify Functions và Twitter API v2 làm CMS cho blog Gatsby của bạn.
Sau khi phát hành Gatsby Functions vào tháng 6 năm 2021, tôi đã tái cấu trúc phần trên để hoạt động với Gatsby Functions và sau đây là một số thông tin thêm về cách tôi thực hiện và lý do tại sao: Sử dụng Gatsby Functions làm API trừu tượng.
Sau đây là sơ đồ minh họa rõ hơn cách tiếp cận chung.

Trong sơ đồ trên,
Lưu ý: Trong cả hai trường hợp, cả hai đều cần sử dụng cùng một dịch vụ của bên thứ ba nên việc trừu tượng hóa chức năng này thành một API độc lập là hợp lý.
API độc lập mẫu (
Tôi biết bạn đang nghĩ gì: CORS! Thôi, ngồi yên nào. Tôi sẽ đề cập đến vấn đề này ngay.
Đây là tình huống tôi gặp phải với MDX Embed. Trang web tài liệu cho dự án này được xây dựng bằng Storybook. Storybook không có khả năng không có máy chủ nhưng tôi thực sự cần giao tiếp giữa máy chủ với máy chủ. Giải pháp của tôi? Tôi đã tạo một API độc lập có tên là Paulie API.
Để bật thanh toán Stripe từ MDX Embed, tôi đã tạo một điểm cuối
Sau khi tạo thành công một lần thanh toán, Stripe API sẽ trả về một URL. URL này được chuyển trở lại MDX Embed, nơi sẽ mở một cửa sổ mới trong trình duyệt, nơi "khách hàng" có thể nhập thông tin thanh toán của họ một cách an toàn trên trang web Stripe… và thế là xong! Bạn được trả tiền!
Dưới đây là sơ đồ minh họa rõ hơn cách thức hoạt động của việc này:

Nhưng trước khi đi sâu hơn nữa, chúng ta cần giải thích lý do tại sao tôi không sử dụng
Đây là ảnh chụp màn hình "sản phẩm" MDX Embed mà tôi đã thiết lập trong bảng điều khiển Stripe của mình. Lưu ý giá là 1,00 đô la.

Nếu tôi sử dụng react-stripe-js để kích hoạt thanh toán thì tất cả "khách hàng" sẽ được yêu cầu thanh toán cùng một số tiền. Trong trường hợp này, chỉ có 1,00 đô la và số tiền đó sẽ không đủ để thanh toán hóa đơn phải không!
Để bật tính năng "Thanh toán theo ý muốn" (ví dụ: số tiền danh nghĩa do "khách hàng" lựa chọn), bạn phải tìm hiểu sâu hơn một chút và sử dụng giao tiếp giữa máy chủ với máy chủ và gửi số tiền này đến API Stripe bằng yêu cầu HTTP tùy chỉnh. Đây là nơi tôi sử dụng Hàm Gatsby và tôi truyền vào một giá trị động sau đó sẽ được sử dụng để tạo trải nghiệm "thanh toán" và ghi đè giá được xác định trong bảng điều khiển Stripe của tôi.
Trên MDX Embed, tôi đã thêm một HTML
Đây là một video nhỏ tôi đã thực hiện để cho thấy MDX Embed, Paulie API và Stripe API hoạt động cùng nhau như thế nào:
[*] Cách MDX Embed, Paulie API và Stripe API hoạt động cùng nhau để cho phép "Trả những gì bạn muốn".
Bằng cách chuyển giá trị đầu vào từ MDX Embed đến Paulie API, sau đó kết nối với Stripe API, tôi có thể tạo một giao dịch thanh toán "động".
Lưu ý: Điều này có nghĩa là "khách hàng" có thể quyết định dự án có giá trị như thế nào đối với họ và đặt số tiền phù hợp để đóng góp.
Tôi muốn đề cập đến Benedicte Raae tại thời điểm này, người đầu tiên chỉ cho tôi cách tiếp cận này trong khóa học Summer Functions tuyệt vời của cô ấy. Bạn có thể tìm hiểu thêm bằng cách truy cập Queen Raae Codes. (Cảm ơn Benedicte, bạn là người giỏi nhất!)
Sau đây là một đoạn mã để hiển thị cách tôi xử lý CORS trong điểm cuối
Trong đoạn mã trên, bạn sẽ thấy tôi đã định nghĩa một mảng
Hàm này cũng chấp nhận một số tham số body, một trong số đó là
Tôi đã đề cập đến một vài điều trong quá trình giải thích lý do tại sao tôi quyết định đi theo con đường này. Rốt cuộc, có vẻ như đây là cách phức tạp hơn để sử dụng Serverless Functions nhưng tôi có lý do của mình và tôi nghĩ rằng điều đó là xứng đáng. Sau đây là lý do tại sao. 
Paulie API vừa là Cross-Origin API vừa là trang web tài liệu. Đương nhiên, nếu bạn định viết một API thì API đó phải được ghi chép lại đúng không?
Đây là nơi tôi thấy có lợi khi sử dụng Gatsby để hỗ trợ API của mình vì cùng với các khả năng Không có máy chủ, Paulie API cũng là một trang web Gatsby và vì thực tế đây là một trang web nên tôi có thể điền nội dung vào đó và làm cho nó trông đẹp, nhưng hãy đợi đã, vẫn còn nhiều điều nữa…
Lưu ý: Paulie API cũng là một sân chơi API tương tác!
Mỗi hàm đều có liên kết
Tôi cũng sử dụng API này để cung cấp chức năng tương tự ở phía máy chủ cho các trang web khác của mình.

Bạn sẽ thấy từ sơ đồ trên rằng https://paulie.dev cũng sử dụng điểm cuối Stripe. Tôi đã sử dụng cùng một cách tiếp cận như với MDX Embed để kích hoạt chức năng "Trả những gì bạn muốn". Đây là một điều nhỏ, nhưng vì điểm cuối
Trang web https://paulie.dev cũng có các Chức năng Gatsby Serverless riêng mà tôi sử dụng để đăng phản hồi của người dùng về Fauna và thu thập đăng ký Bản tin. Chức năng này là duy nhất đối với trang web này nên tôi chưa tóm tắt điều này. Tuy nhiên, nếu tôi muốn đăng ký nhận bản tin trên https://www.pauliescanlon.io, đây sẽ là thời điểm tôi di chuyển chức năng này sang Paulie API.

Tôi chắc chắn được hưởng lợi từ việc sử dụng phương pháp này và có kế hoạch phát triển thêm API của mình để cung cấp nhiều chức năng hơn cho một số trang web của riêng tôi, nhưng nếu bạn quan tâm đến việc kiếm tiền từ mã nguồn mở và trang web của bạn không được xây dựng bằng Gatsby, thì phương pháp này có thể là câu trả lời bạn đang tìm kiếm.
Bạn có muốn bắt đầu với Gatsby Functions không? Hãy xem tài liệu về Gatsby Functions để bắt đầu!
Cảm ơn bạn đã đọc và nếu bạn muốn thảo luận về bất kỳ điều gì được đề cập trong bài viết này, hãy để lại bình luận bên dưới hoặc tìm tôi trên Twitter.
Lưu ý: MDX Embed cho phép bạn dễ dàng nhúng nội dung phương tiện truyền thông phổ biến của bên thứ ba như video YouTube, Tweet, bài đăng trên Instagram, bài học Egghead, Spotify, TikTok và nhiều nội dung khác trực tiếp vào
.mdx
của bạn — không cần nhập.Gatsby Serverless Functions
Gatsby Functions mở ra một thế giới hoàn toàn mới cho các nhà phát triển front-end vì chúng cung cấp một cách để viết và sử dụng mã phía máy chủ mà không cần phải lo lắng về việc duy trì máy chủ. Các ứng dụng của Serverless Functions bao gồm từ đăng ký Bản tin với ConvertKit, gửi email bằng SendGrid, lưu dữ liệu trong cơ sở dữ liệu như Fauna hoặc trong trường hợp này, chấp nhận thanh toán an toàn bằng Stripe — danh sách này thực sự vô tận!Các dịch vụ của bên thứ ba như những dịch vụ được đề cập ở trên sẽ chỉ chấp nhận các yêu cầu được gửi phía máy chủ. Có một số lý do cho điều này nhưng sử dụng khóa bảo mật hoặc khóa riêng tư thường là một trong số đó. Sử dụng các khóa này ở phía máy chủ có nghĩa là chúng không được hiển thị cho máy khách (trình duyệt) và không thể bị lạm dụng, và đây chính là lúc Serverless Functions của Gatsby có thể giúp ích.
Gatsby cung cấp cùng một cách tiếp cận hợp lý đối với Serverless Functions như cách họ làm với các trang. Ví dụ: các trang web nằm trong
src/pages
và Serverless Functions nằm trong src/api
.Tất nhiên, còn nhiều hơn thế nữa nhưng trải nghiệm của nhà phát triển Gatsby vừa hợp lý vừa nhất quán, và cá nhân tôi hoàn toàn thích điều đó!
Same Origin Functions
Chín trong mười lần khi làm việc với Serverless Functions, bạn sẽ sử dụng chúng theo cách chúng được cho là phải sử dụng, Ví dụ: trang web của bạn sử dụng các chức năng riêng của nó. Tôi gọi cách sử dụng này là Same Origin Functions hay viết tắt là SOF. Trong trường hợp này, cả Front-end và API đều được triển khai đến cùng một nguồn gốc, Ví dụ: www.my-website.com và www.my-website.com/api, và giao tiếp giữa hai bên đều liền mạch và tất nhiên là cực nhanh!Dưới đây là sơ đồ giúp minh họa cho cách thức hoạt động này:

Hàm Cross-Origin
Tuy nhiên, có ít nhất hai trường hợp tôi gặp phải khi tôi cần đến cái mà tôi gọi là "Hàm Cross-Origin" (hay gọi tắt là COF). Hai tình huống mà tôi cần COF như sau:- Tôi cần các khả năng phía máy chủ nhưng trang web gốc không thể chạy Serverless Functions.
- Serverless Function được sử dụng bởi nhiều nguồn gốc.
Lần đầu tiên tôi thử nghiệm phương pháp này là vào tháng 11 năm 2020 trước khi phát hành Gatsby Functions và sử dụng Netlify Functions để cung cấp giao tiếp giữa máy chủ với máy chủ bằng Twitter API và blog Gatsby cùng danh mục đầu tư thương mại của tôi. Bạn có thể đọc về cách tiếp cận này tại đây: Sử dụng Netlify Functions và Twitter API v2 làm CMS cho blog Gatsby của bạn.
Sau khi phát hành Gatsby Functions vào tháng 6 năm 2021, tôi đã tái cấu trúc phần trên để hoạt động với Gatsby Functions và sau đây là một số thông tin thêm về cách tôi thực hiện và lý do tại sao: Sử dụng Gatsby Functions làm API trừu tượng.
Sau đây là sơ đồ minh họa rõ hơn cách tiếp cận chung.

Trong sơ đồ trên,
website-1.com
được xây dựng bằng Gatsby và có thể sử dụng Serverless Functions (nhưng không) và website-2.com
được xây dựng bằng thứ gì đó không có khả năng Serverless Function.Lưu ý: Trong cả hai trường hợp, cả hai đều cần sử dụng cùng một dịch vụ của bên thứ ba nên việc trừu tượng hóa chức năng này thành một API độc lập là hợp lý.
API độc lập mẫu (
my-api.com
) cũng là một trang web Gatsby và có các khả năng Chức năng không có máy chủ, nhưng quan trọng hơn, nó cho phép các trang web từ các nguồn khác sử dụng các Chức năng không có máy chủ của nó.Tôi biết bạn đang nghĩ gì: CORS! Thôi, ngồi yên nào. Tôi sẽ đề cập đến vấn đề này ngay.
Kiếm tiền từ MDX Embed
Đây là tình huống tôi gặp phải với MDX Embed. Trang web tài liệu cho dự án này được xây dựng bằng Storybook. Storybook không có khả năng không có máy chủ nhưng tôi thực sự cần giao tiếp giữa máy chủ với máy chủ. Giải pháp của tôi? Tôi đã tạo một API độc lập có tên là Paulie API.Paulie API
Paulie API (giống như ví dụ về API độc lập được đề cập ở trên) có thể chấp nhận các yêu cầu từ các trang web có nguồn gốc khác nhau và có thể kết nối với một số dịch vụ của bên thứ ba khác nhau, một trong số đó là Stripe.Để bật thanh toán Stripe từ MDX Embed, tôi đã tạo một điểm cuối
api/make-stripe-payment
trên Paulie API có thể truyền thông tin có liên quan từ MDX Embed thông qua Hàm không máy chủ của riêng nó và đến Stripe API để tạo "thanh toán". Bạn có thể xem mã src tại đây.Sau khi tạo thành công một lần thanh toán, Stripe API sẽ trả về một URL. URL này được chuyển trở lại MDX Embed, nơi sẽ mở một cửa sổ mới trong trình duyệt, nơi "khách hàng" có thể nhập thông tin thanh toán của họ một cách an toàn trên trang web Stripe… và thế là xong! Bạn được trả tiền!
Dưới đây là sơ đồ minh họa rõ hơn cách thức hoạt động của việc này:

Nhưng trước khi đi sâu hơn nữa, chúng ta cần giải thích lý do tại sao tôi không sử dụng
react-stripe-js
.react-stripe-js
react-stripe-js
là bộ công cụ phía máy khách (trình duyệt) cho phép bạn tạo các thành phần và thanh toán Stripe trong dự án React của mình. Với react-stripe-js, bạn có thể thiết lập phương thức chấp nhận thanh toán an toàn mà không cần giao tiếp phía máy chủ, nhưng… và có một điều nhưng. Tôi muốn triển khai các đóng góp "Trả những gì bạn muốn". Cho phép tôi giải thích.Đây là ảnh chụp màn hình "sản phẩm" MDX Embed mà tôi đã thiết lập trong bảng điều khiển Stripe của mình. Lưu ý giá là 1,00 đô la.

Nếu tôi sử dụng react-stripe-js để kích hoạt thanh toán thì tất cả "khách hàng" sẽ được yêu cầu thanh toán cùng một số tiền. Trong trường hợp này, chỉ có 1,00 đô la và số tiền đó sẽ không đủ để thanh toán hóa đơn phải không!
Để bật tính năng "Thanh toán theo ý muốn" (ví dụ: số tiền danh nghĩa do "khách hàng" lựa chọn), bạn phải tìm hiểu sâu hơn một chút và sử dụng giao tiếp giữa máy chủ với máy chủ và gửi số tiền này đến API Stripe bằng yêu cầu HTTP tùy chỉnh. Đây là nơi tôi sử dụng Hàm Gatsby và tôi truyền vào một giá trị động sau đó sẽ được sử dụng để tạo trải nghiệm "thanh toán" và ghi đè giá được xác định trong bảng điều khiển Stripe của tôi.
Trên MDX Embed, tôi đã thêm một HTML
cho phép "khách hàng" đặt số tiền thay vì trả một số tiền được xác định trước — giá như tất cả thương mại điện tử đều như thế này!Đây là một video nhỏ tôi đã thực hiện để cho thấy MDX Embed, Paulie API và Stripe API hoạt động cùng nhau như thế nào:
[*] Cách MDX Embed, Paulie API và Stripe API hoạt động cùng nhau để cho phép "Trả những gì bạn muốn".
Bằng cách chuyển giá trị đầu vào từ MDX Embed đến Paulie API, sau đó kết nối với Stripe API, tôi có thể tạo một giao dịch thanh toán "động".
Lưu ý: Điều này có nghĩa là "khách hàng" có thể quyết định dự án có giá trị như thế nào đối với họ và đặt số tiền phù hợp để đóng góp.
Tôi muốn đề cập đến Benedicte Raae tại thời điểm này, người đầu tiên chỉ cho tôi cách tiếp cận này trong khóa học Summer Functions tuyệt vời của cô ấy. Bạn có thể tìm hiểu thêm bằng cách truy cập Queen Raae Codes. (Cảm ơn Benedicte, bạn là người giỏi nhất!)
Hãy nói về CORS
Theo mặc định, các hàm không máy chủ Gatsby sẽ không bị CORS chặn vì Front-end và API được triển khai đến cùng một nguồn gốc. Tuy nhiên, khi phát triển các hàm Cross-Origin, bạn sẽ cần cấu hình API của mình để nó chấp nhận các yêu cầu từ các nguồn gốc khác với nguồn gốc của chính nó.Sau đây là một đoạn mã để hiển thị cách tôi xử lý CORS trong điểm cuối
api/make-stripe-payment
:
Mã:
// src/api/make-stripe-paymentconst stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)import Cors from 'cors'const allowedOrigins = [ 'https://www.mdx-embed.com', 'https://paulie.dev',]const cors = Cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) { callback(null, true) } else { callback(new Error()) } },})const runCorsMiddleware = (yêu cầu, độ phân giải) => { return new Promise((resolve, reject) => { cors(req, res, (result) => { if (result instanceof Error) { return reject(result) } return resolve(result) }) })}export default async function handler(req, res) { const { success_url, cancel_url, amount, product } = req.body try { await runCorsMiddleware(req, res) try { const session = await stripe.checkout.sessions.create({ success_url: success_url, cancel_url: cancel_url, payment_method_types: ['card'], line_items: [ { quantity: 1, price_data: { unit_amount: amount * 100, currency: 'usd', product: product, }, }, ], mode: 'payment', }) res.status(200).json({ message: '🕺 Stripe checkout created ok', url: session.url }) } catch (error) { res.status(500).json({ message: '🚫 Stripe checkout error' }) } } catch (error) { res.status(403).json({ message: '🚫 Request blocked by CORS' }) }}
allowedOrigins
, đây là những origin duy nhất được phép sử dụng điểm cuối này. Các yêu cầu từ bất kỳ origin nào khác sẽ nhận được mã trạng thái 403
và thông báo 🚫 Request blocked by CORS
.Hàm này cũng chấp nhận một số tham số body, một trong số đó là
số tiền
mà "khách hàng" đã quyết định thanh toán, đây là giá trị từ đầu vào HTML trên trang MDX Embed. Bạn cũng sẽ nhận thấy tham số product
, đây là id sản phẩm được xác định trong bảng điều khiển Stripe của tôi và cách API Stripe tạo URL "thanh toán" chính xác. Việc truyền giá trị này dưới dạng tham số body thay vì mã hóa cứng trong hàm cho phép tôi sử dụng lại điểm cuối này cho các sản phẩm Stripe khác.
Liệu Juice có đáng để Squeeze không?
Tôi đã đề cập đến một vài điều trong quá trình giải thích lý do tại sao tôi quyết định đi theo con đường này. Rốt cuộc, có vẻ như đây là cách phức tạp hơn để sử dụng Serverless Functions nhưng tôi có lý do của mình và tôi nghĩ rằng điều đó là xứng đáng. Sau đây là lý do tại sao. 
Paulie API vừa là Cross-Origin API vừa là trang web tài liệu. Đương nhiên, nếu bạn định viết một API thì API đó phải được ghi chép lại đúng không?
Đây là nơi tôi thấy có lợi khi sử dụng Gatsby để hỗ trợ API của mình vì cùng với các khả năng Không có máy chủ, Paulie API cũng là một trang web Gatsby và vì thực tế đây là một trang web nên tôi có thể điền nội dung vào đó và làm cho nó trông đẹp, nhưng hãy đợi đã, vẫn còn nhiều điều nữa…
Lưu ý: Paulie API cũng là một sân chơi API tương tác!

Mỗi hàm đều có liên kết
▶ Chạy trong trình duyệt
. Liên kết này sẽ đưa bạn đến một trang trên trang web nơi bạn có thể tương tác với hàm. Nó vừa đóng vai trò là nơi thử nghiệm hữu ích trong khi tôi đang phát triển chức năng vừa là cách dễ dàng để chứng minh chức năng hoạt động như thế nào, tài liệu thì tốt, tài liệu tương tác thì tốt hơn!Tôi cũng sử dụng API này để cung cấp chức năng tương tự ở phía máy chủ cho các trang web khác của mình.

Bạn sẽ thấy từ sơ đồ trên rằng https://paulie.dev cũng sử dụng điểm cuối Stripe. Tôi đã sử dụng cùng một cách tiếp cận như với MDX Embed để kích hoạt chức năng "Trả những gì bạn muốn". Đây là một điều nhỏ, nhưng vì điểm cuối
make-stripe-payment
đã được viết và hoạt động, tôi có thể sử dụng lại và tránh trùng lặp chức năng này.Trang web https://paulie.dev cũng có các Chức năng Gatsby Serverless riêng mà tôi sử dụng để đăng phản hồi của người dùng về Fauna và thu thập đăng ký Bản tin. Chức năng này là duy nhất đối với trang web này nên tôi chưa tóm tắt điều này. Tuy nhiên, nếu tôi muốn đăng ký nhận bản tin trên https://www.pauliescanlon.io, đây sẽ là thời điểm tôi di chuyển chức năng này sang Paulie API.

Abstraction
Điều này có vẻ như là một bước thụt lùi khi trừu tượng hóa các Hàm không có máy chủ của bạn. Xét cho cùng, một trong những điều tuyệt vời nhất khi chuyển sang không có máy chủ là cả mã front-end và back-end của bạn đều hoạt động ở cùng một nơi. Như tôi đã trình bày, có những lúc việc trừu tượng hóa có ý nghĩa — ít nhất là với tôi.Tôi chắc chắn được hưởng lợi từ việc sử dụng phương pháp này và có kế hoạch phát triển thêm API của mình để cung cấp nhiều chức năng hơn cho một số trang web của riêng tôi, nhưng nếu bạn quan tâm đến việc kiếm tiền từ mã nguồn mở và trang web của bạn không được xây dựng bằng Gatsby, thì phương pháp này có thể là câu trả lời bạn đang tìm kiếm.
Bạn có muốn bắt đầu với Gatsby Functions không? Hãy xem tài liệu về Gatsby Functions để bắt đầu!
Các tài nguyên khác
Nếu bạn muốn tìm hiểu thêm về Serverless Functions, tôi xin giới thiệu:- Swizec Teller, “Serverless Handbook For Frontend Engineers”
- Khóa học Summer Functions của Benedict
- …và tất nhiên, tài liệu Gatsby
FuncJam
Từ tháng 8 Từ ngày 17 đến ngày 30 tháng 9, những người của Gatsby sẽ tổ chức một cuộc thi cộng đồng với một số giải thưởng cực khủng. Nếu vẫn còn thời gian, hãy hãy ghé thăm FuncJam và tham gia. Ngoài ra, hãy xem phần Byte-size của bài đăng trên blog này; bài viết này chứa các video hữu ích và liên kết đến một số hàm ví dụ.Cảm ơn bạn đã đọc và nếu bạn muốn thảo luận về bất kỳ điều gì được đề cập trong bài viết này, hãy để lại bình luận bên dưới hoặc tìm tôi trên Twitter.
Đọc thêm
- Giải mã Khung Gatsby Mới
- Tạo Biểu mẫu Nhiều bước Hiệu quả để Trải nghiệm Người dùng Tốt hơn
- Lý do Nên sử dụng Prisma trong Jamstack
- Xây dựng Trình tạo MadLib Tĩnh với Văn bản Di động và Các hàm Xây dựng Theo yêu cầu của Netlify