Chức năng không cần máy chủ của Gatsby và Trạm vũ trụ quốc tế

theanh

Administrator
Nhân viên
Gatsby gần đây đã công bố ra mắt Functions, mở ra một chiều hướng khả thi mới — và tôi thì không thể phấn khích hơn! Với Gatsby hiện cung cấp Serverless Functions trên Gatsby Cloud (và Netlify cũng cung cấp hỗ trợ thông qua @netlify/plugin-gatsby), khuôn khổ từng bị hiểu lầm là "chỉ dành cho blog" giờ đây (theo tôi) trở thành nhà cung cấp công nghệ thú vị nhất trong không gian Jamstack hơn bao giờ hết.

Bản demo trong bài viết này là kết quả của một dự án gần đây mà tôi đã làm, trong đó tôi cần vẽ các vị trí địa lý xung quanh một quả cầu 3D và tôi nghĩ rằng sẽ rất thú vị nếu xem liệu có thể sử dụng cùng một kỹ thuật bằng cách sử dụng các vị trí ngoài hành tinh hay không. Cảnh báo tiết lộ: Hoàn toàn có thể! Nếu bạn muốn nhảy về phía trước, bạn có thể tìm thấy mã hoàn chỉnh tại đây.

Bắt đầu​

Với Gatsby Functions, bạn có thể tạo các ứng dụng động hơn bằng các kỹ thuật thường liên quan đến các ứng dụng phía máy khách bằng cách thêm thư mục api vào dự án của mình và xuất một hàm, ví dụ:
Mã:
|-- src |-- api -- some-function.js |-- pages
Mã:
// src/api/some-function.jsexport default function handler(req, res) { res.status(200).json({ hello: `world` })}
Nếu bạn đã thiết lập dự án Gatsby, thật tuyệt! nhưng hãy đảm bảo rằng bạn đã nâng cấp Gatsby lên ít nhất phiên bản v3.7
Mã:
npm install gatsby@latest --save
Nếu chưa, hãy thoải mái sao chép kho lưu trữ khởi động Gatsby hoàn toàn cơ bản của tôi: mr-minimum.

Trước khi có thể bắt đầu sử dụng Hàm Gatsby để theo dõi Trạm vũ trụ quốc tế, trước tiên tôi cần tạo một quả địa cầu để nó quay quanh quỹ đạo.


Bước 1: Xây dựng Quả cầu tương tác 3D​

Tôi bắt đầu bằng cách thiết lập một quả cầu tương tác 3D có thể được sử dụng sau này để vẽ vị trí ISS hiện tại.
Cài đặt các phụ thuộc​
Mã:
npm install @react-three/fiber @react-three/drei three three-geojson-geometry axios --save
Tạo cảnh​
Tạo tệp mới trong src/components có tên là three-scene.js
Mã:
// src/components/three-scene.jsimport React from 'react';import { Canvas } from '@react-three/fiber';import { OrbitControls } from '@react-three/drei';const ThreeScene = () => { return (  { gl.setClearColor('#ffffff'); }} style={{ width: '100vw', height: '100vh', cursor: 'move' }} >   );};export default ThreeScene;
Phần trên thiết lập một phần tử mới và có thể được cấu hình bằng các props được React Three Fibre cung cấp.

Các phần tử được trả về dưới dạng phần tử con của thành phần canvas sẽ được hiển thị như một phần của cảnh 3D. Bạn sẽ thấy ở trên rằng tôi đã bao gồm để thêm tương tác chạm/chuột cho phép người dùng xoay cảnh trong không gian 3D

Đảm bảo ThreeScene được nhập và hiển thị trên một trang nào đó trong trang web của bạn. Trong kho lưu trữ ví dụ của tôi, tôi đã thêm ThreeScene vào index.js:
Mã:
// src/pages/index.jsimport React from 'react';import ThreeScene from '../components/three-scene';const IndexPage = () => { return (    );};export default IndexPage;
Điều này sẽ không có tác dụng nhiều vào lúc này vì không có gì để hiển thị trong cảnh. Hãy sửa lỗi đó!
Tạo hình cầu​
Tạo một tệp trong src/components có tên là three-sphere.js:
Mã:
// src/components/three-sphere.jsimport React from 'react';const ThreeSphere = () => { return (     );};export default ThreeSphere;
Nếu cú pháp ở trên trông hơi khác so với cú pháp của tài liệu Three.js thì đó là do React Three Fibre sử dụng phương pháp khai báo để sử dụng Three.js trong React.

Bạn có thể xem giải thích hay về cách hoạt động của đối số hàm tạo trong React Three Fibre trong tài liệu tại đây: Đối số hàm tạo

Bây giờ hãy thêm ThreeSphere vào ThreeScene:
Mã:
// src/components/three-scene.jsimport React from 'react';nhập { Canvas } từ '@react-three/fiber';nhập { OrbitControls } từ '@react-three/drei';+ nhập ThreeSphere từ './three-sphere';const ThreeScene = () => { return (  { gl.setClearColor('#ffffff'); }} style={{ width: '100vw', height: '100vh', cursor: 'move' }} > +   );};xuất mặc định ThreeScene;
Bây giờ bạn sẽ thấy một cái gì đó tương tự như hình ảnh bên dưới.



Không thú vị lắm phải không? Hãy làm gì đó về điều đó!
Tạo hình học (để trực quan hóa các quốc gia trên hành tinh Trái đất)​
Bước tiếp theo này yêu cầu sử dụng three-geojson-geometry và một tài nguyên CDN có chứa Dữ liệu Trái đất tự nhiên. Bạn có thể chọn từ danh sách đầy đủ các hình học phù hợp tại đây.

Tôi sẽ sử dụng admin 0 quốc gia. Tôi chọn tùy chọn này vì nó cung cấp đủ chi tiết hình học để xem từng quốc gia, nhưng không quá nhiều đến mức gây thêm gánh nặng không cần thiết cho GPU của máy tính.

Bây giờ, hãy tạo một tệp trong src/components có tên là three-geo.js:
Mã:
// src/components/three-geo.jsimport React, { Fragment, useState, useEffect } from 'react';import { GeoJsonGeometry } from 'three-geojson-geometry';import axios from 'axios';const ThreeGeo = () => {const [isLoading, setIsLoading] = useState(true); const [geoJson, setGeoJson] = useState(null); useEffect(() => { axios .get( 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_0_countries.geojson' ) .then((phản hồi) => { setIsLoading(false); setGeoJson(phản hồi.data); }) .catch((lỗi) => { console.log(lỗi); ném Lỗi mới(); }); }, []); return (  {!isLoading ? (  {geoJson.features.map(({ geometry }, index) => { return ( 
[*]    ); })}  ) : null}  );};export default ThreeGeo;
Có khá nhiều thứ đang diễn ra trong tệp này nên tôi sẽ hướng dẫn bạn.
  1. Tạo một thể hiện trạng thái isLoading bằng cách sử dụng React hooks và đặt nó thành true. Điều này ngăn React cố gắng trả về dữ liệu mà tôi chưa có.
  2. Sử dụng useEffect, tôi yêu cầu geojson từ CloudFront CDN.
  3. Sau khi truy xuất thành công, tôi đặt phản hồi ở trạng thái React bằng cách sử dụng setGeoJson(...) và đặt isLoading thành false
  4. Sử dụng Array.prototype.map, tôi lặp lại các "tính năng" có trong phản hồi geojson và trả về lineSegments với lineBasicMaterial cho mỗi hình học
  5. Tôi đặt lineSegments hình học thành giá trị trả về được cung cấp bởi GeoJsonGeomtry được truyền qua các "tính năng" hình học cùng với bán kính 100.
(Bạn có thể nhận thấy tôi đã sử dụng cùng bán kính 100 ở đây như tôi đã sử dụng trong sphereGeometry args trong three-sphere.js. Bạn không cần phải đặt bán kính thành cùng một giá trị nhưng việc sử dụng cùng một bán kính cho ThreeSphereThreeGeo là hợp lý.

Nếu bạn muốn biết thêm về cách thức hoạt động của GeoJsonGeometry, đây là kho lưu trữ mã nguồn mở để tham khảo: https://github.com/vasturiano/three-geojson-geometry. Kho lưu trữ có một thư mục example tuy nhiên, cú pháp hơi khác so với những gì bạn thấy ở đây vì các ví dụ được viết bằng JavaScript thuần túy chứ không phải React.
Kết hợp hình cầu và hình học​
Bây giờ là lúc phủ hình học lên trên hình cầu trống: Thêm ThreeGeo vào ThreeScene
Mã:
// src/components/three-scene.jsimport React from 'react';import { Canvas } from '@react-three/fiber';import { OrbitControls } from '@react-three/drei';import ThreeSphere from './three-sphere';+ import ThreeGeo từ './three-geo';const ThreeScene = () => { return (  { gl.setClearColor('#ffffff'); }} style={{ width: '100vw', height: '100vh', cursor: 'move' }} >  +   );};
Bây giờ bạn sẽ thấy một thứ tương tự như hình ảnh bên dưới.



Giờ thì thú vị hơn một chút rồi!

Bước 2: Xây dựng hàm không máy chủ​

Tạo hàm​
Bước tiếp theo là nơi tôi sử dụng hàm Gatsby để yêu cầu dữ liệu từ ISS ở đâu, hàm này trả về vị trí hiện tại của Trạm vũ trụ quốc tế Trạm.

Tạo một tệp trong src/api có tên là get-iss-location.js:
Mã:
// src/api/get-iss-location.jsconst axios = require('axios');export default async function handler(req, res) { try { const { data } = await axios.get( 'https://api.wheretheiss.at/v1/satellites/25544' ); res.status(200).json({ iss_now: data }); } catch (error) { res.status(500).json({ error }); }}
Hàm này chịu trách nhiệm lấy dữ liệu từ api.whereistheiss.at và khi thành công sẽ trả về data và mã trạng thái 200 cho trình duyệt.

Các kỹ sư của Gatsby đã thực hiện một công việc tuyệt vời trong việc đơn giản hóa các hàm không có máy chủ mà những điều trên là tất cả những gì bạn thực sự cần để bắt đầu, nhưng sau đây là một số thông tin chi tiết hơn về những gì đang diễn ra.
  • Hàm này là mặc định xuất từ tệp có tên get-iss-location.js;
  • Với Hàm Gatsby, tên tệp sẽ trở thành đường dẫn tệp được sử dụng trong yêu cầu get phía máy khách có tiền tố api, ví dụ: /api/get-iss-location;
  • Nếu yêu cầu "ISS ở đâu" thành công, tôi sẽ trả về đối tượng iss_now chứa dữ liệu từ API ISS ở đâu và mã trạng thái 200 trở lại máy khách;
  • Nếu yêu cầu có lỗi, tôi sẽ gửi lỗi trở lại máy khách.

Bước 3: Xây dựng Trạm vũ trụ quốc tế​

Tạo hình cầu ISS​
Trong bước tiếp theo này, tôi sử dụng Hàm Gatsby để định vị một hình cầu biểu diễn Trạm vũ trụ quốc tế khi nó quay quanh quả địa cầu. Tôi thực hiện điều này bằng cách gọi liên tục một yêu cầu axios.get từ một hàm poll và thiết lập phản hồi ở trạng thái React.

Tạo một tệp trong src/components có tên là three-iss.js
Mã:
// src/components/three-iss.jsimport React, { Fragment, useEffect, useState } from 'react';import * as THREE from 'three';import axios from 'axios';export const getVertex = (latitude, longitude, radius) => { const vector = new THREE.Vector3().setFromSpherical( new THREE.Spherical( radius, THREE.MathUtils.degToRad(90 - vĩ độ), THREE.MathUtils.degToRad(kinh độ) ) ); return vector;};const ThreeIss = () => { const [issNow, setIssNow] = useState(null); const poll = () => { axios .get('/api/get-iss-location') .then((response) => { setIssNow(response.data.iss_now); }) .catch((error) => { console.log(error); throw new Error(); }); }; useEffect(() => { const pollInterval = setInterval(() => { poll(); }, 5000); poll(); return () => clearInterval(pollInterval); }, []); return (  {issNow ? (     ) : null}  );};export default ThreeIss;
Có khá nhiều thứ diễn ra trong tệp này nên tôi sẽ hướng dẫn bạn.
  1. Tạo một thể hiện trạng thái issNow bằng cách sử dụng các hook React và đặt nó thành null. Điều này ngăn React cố gắng trả về dữ liệu mà tôi chưa có;
  2. Sử dụng useEffect, tôi tạo một khoảng thời gian JavaScript gọi hàm poll sau mỗi 5 giây;
  3. Hàm poll là nơi tôi yêu cầu vị trí ISS từ điểm cuối Hàm Gatsby (/api/get-iss-location);
  4. Sau khi truy xuất thành công, tôi đặt phản hồi ở trạng thái React bằng cách sử dụng setIssNow(...);
  5. Tôi truyền vĩ độkinh độ vào một hàm tùy chỉnh có tên là getVertex, cùng với bán kính.
Bạn có thể nhận thấy rằng ở đây tôi đang sử dụng bán kính 120. Điều này khác với giá trị bán kính 100 được sử dụng trong ThreeSphereThreeGeo. Hiệu ứng của bán kính lớn hơn là định vị ISS cao hơn trong bối cảnh 3D, thay vì ở mặt đất — vì về mặt logic, đó là nơi ISS sẽ ở, đúng không?
100 có hiệu ứng hình cầu và hình học chồng lên nhau để biểu diễn Trái đất, và 120 đối với ISS có hiệu ứng trạm vũ trụ "quay quanh" quả cầu mà tôi đã tạo ra.

Một điều cần phải tìm hiểu một chút, ít nhất là đối với tôi, là cách sử dụng tọa độ hai chiều hình cầu (vĩ độ và kinh độ) trong ba chiều, ví dụ x, y, z. Khái niệm này đã được giải thích khá rõ trong bài đăng này của Mike Bostock.

Chìa khóa để vẽ vĩ độ / kinh độ trong không gian 3D nằm trong công thức này… mà tôi hoàn toàn không hiểu!
Mã:
x=rcos(ϕ)cos(λ)y=rsin(ϕ)z=−rcos(ϕ)sin(λ)
May mắn thay, Three.js có một bộ MathUtils mà tôi đã sử dụng như sau:
  • Truyền vĩ độ, kinh độradius vào hàm getVertex(...)
  • Tạo đối tượng THREE.Spherical mới từ các tham số được đặt tên ở trên
  • Đặt đối tượng THREE.Vector3 bằng cách sử dụng các giá trị Spherical được trả về bởi hàm trợ giúp setFromSpherical.
Bây giờ có thể sử dụng các số này để định vị các phần tử trong không gian 3D trên trục x, y, z tương ứng của chúng — thật may! Cảm ơn, Three.js!

Bây giờ hãy thêm ThreeIss vào ThreeScene:
Mã:
import React từ 'react';import { Canvas } từ '@react-three/fiber';import { OrbitControls } từ '@react-three/drei';import ThreeSphere từ './three-sphere';import ThreeGeo từ './three-geo';+ import ThreeIss từ './three-iss';const ThreeScene = () => { return (  { gl.setClearColor('#ffffff'); }} style={{ width: '100vw', height: '100vh', cursor: 'move' }} >   +   );};xuất mặc định ThreeScene;
Et voilà! Bây giờ bạn sẽ thấy một hình ảnh tương tự như hình ảnh bên dưới.



Hàm poll sẽ liên tục gọi Hàm Gatsby, hàm này sẽ yêu cầu vị trí hiện tại của ISS và kết xuất lại thành phần React mỗi khi phản hồi thành công. Bạn sẽ phải quan sát cẩn thận nhưng ISS sẽ thay đổi vị trí rất nhỏ sau mỗi 5 giây.

ISS đang di chuyển với tốc độ khoảng 28.000 km/h và việc thăm dò Hàm Gatsby ít thường xuyên hơn sẽ tiết lộ những bước nhảy lớn hơn về vị trí. Tôi đã sử dụng 5 giây ở đây vì đó là thời gian yêu cầu thường xuyên nhất được cho phép bởi API Where is ISS at

Bạn cũng có thể nhận thấy rằng không cần xác thực để yêu cầu dữ liệu từ API Where is ISS at. Nghĩa là về mặt kỹ thuật, tôi có thể gọi API trực tiếp từ trình duyệt, tuy nhiên, tôi đã quyết định thực hiện cuộc gọi API này ở phía máy chủ bằng cách sử dụng Hàm Gatsby vì hai lý do:
  1. Sẽ không có bài đăng trên blog hay nào về Hàm Gatsby nếu tôi không sử dụng chúng.
  2. Ai biết được tương lai của Where is ISS at sẽ ra sao, tại một thời điểm nào đó, nó có thể yêu cầu xác thực và việc thêm khóa API vào các yêu cầu API phía máy chủ khá đơn giản, hơn nữa, thay đổi này sẽ không yêu cầu bất kỳ bản cập nhật nào cho mã phía máy khách.

Bước 4: Làm cho nó trở nên thú vị hơn! (Tùy chọn)​

Tôi đã sử dụng cách tiếp cận trên để tạo ra triển khai hấp dẫn hơn một chút này: https://whereisiss.gatsbyjs.io,

Trong trang web này, tôi đã trực quan hóa độ trễ thời gian từ hàm poll bằng cách triển khai hoạt ảnh đếm ngược Svg và thêm bổ sung với stroke-dashoffset để tạo các đường đứt nét bao quanh nó.


Bước 5: Áp dụng các kỹ năng kết xuất địa lý mới của bạn theo những cách thú vị khác!​

Gần đây tôi đã sử dụng phương pháp này để vẽ vị trí địa lý cho những người chiến thắng trong cuộc thi 500 Bottles: https://500bottles.gatsbyjs.io. Quà tặng MIỄN PHÍ phiên bản giới hạn mà tôi đã làm việc cùng nhóm tiếp thị của Gatsby.



Bạn có thể đọc tất cả về cách tạo trang web này trên blog Gatsby: Cách chúng tôi thực hiện chương trình tặng thưởng 500 chai Gatsby

Trong trang 500 Bottles, tôi vẽ vị trí địa lý của từng người chiến thắng trong cuộc thi bằng phương pháp tương tự như được mô tả trong ThreeIss, cho phép bất kỳ ai truy cập trang web đều có thể xem những người chiến thắng ở đâu trên thế giới.


Suy nghĩ kết thúc​

Gatsby Functions thực sự mở ra rất nhiều khả năng cho các nhà phát triển Jamstack và không bao giờ phải lo lắng về việc khởi động hoặc mở rộng quy mô máy chủ, giúp loại bỏ rất nhiều vấn đề, giúp chúng ta rảnh tay suy nghĩ về những cách mới để sử dụng chúng.

Tôi có một số ý tưởng muốn khám phá bằng cách sử dụng V4 Space X API, vì vậy hãy theo dõi tôi nếu bạn thích: @PaulieScanlon

Các nguồn tài nguyên khác​

Tôi hy vọng bạn thích bài đăng này. Ttfn 🕺!

Đọc thêm​

  • Giới thiệu về khả năng soạn thảo toàn bộ ngăn xếp
  • Cài đặt blog solo miễn phí tối ưu với Ghost và Gatsby
  • Lý do nên dùng Prisma trong Jamstack
  • Regexes Got Good: Lịch sử và tương lai của biểu thức chính quy trong JavaScript
 
Back
Bên trên