嘿,讓我們使用Jamstack創建功能日曆應用程序
我一直想知道動態安排是如何工作的,所以我決定進行廣泛的研究,學習新事物並撰寫有關旅程的技術部分。警告您是很公平的:我涵蓋的所有內容都是三個星期的研究凝結成一篇文章。即使對初學者友好,但它還是很健康的閱讀量。因此,請拉起椅子,坐下來,讓我們冒險。
我的計劃是構建看起來像Google日曆的東西,但僅展示了三個核心功能:
- 在日曆上列出所有現有事件
- 創建新事件
- 根據創建期間選擇的日期計劃和電子郵件通知。時間表應運行一些代碼,以在時間合適時通過電子郵件發送給用戶。
漂亮,對嗎?到本文的結尾,因為這就是我們將要做的。
我要求我的代碼在以後或延期時間運行的唯一知識是Cron Jobs。使用CRON作業的最簡單方法是在您的代碼中靜態定義作業。這是臨時的 -從靜態上講,我不能簡單地安排像Google日曆這樣的事件,並可以輕鬆地更新我的Cron代碼。如果您在寫Cron Triggers方面經驗豐富,您會感到我的痛苦。如果不是,您很幸運,您可能永遠不必以這種方式使用Cron。
為了詳細說明我的挫敗感,我需要根據HTTP請求的有效載荷觸發時間表。有關此時間表的日期和信息將通過HTTP請求傳遞。這意味著沒有辦法事先知道預定日期之類的事情。
我們(我和我的同事)想出了一種做出這項工作的方法,並且在莎拉·德拉斯納(Sarah Drasner)關於持久功能的文章的幫助下,我理解了我需要學習的東西(並且在此方面不理)。您將了解我在本文中工作的所有內容,從活動創建到電子郵件計劃再到日曆列表。這是該應用程序中的視頻:
https://www.youtube.com/watch?v=SIMAM4FXPOO&
您可能會注意到微妙的延遲。這與時間表的執行時間或運行代碼無關。我正在使用一個免費的SendGrid帳戶進行測試,我懷疑該帳戶具有某種形式的延遲。您可以通過在不發送電子郵件的情況下測試無服務器函數來確認這一點。您會注意到該代碼在計劃的時間正好運行。
工具和架構
這是該項目的三個基本單元:
- React Frontend :日曆UI,包括用於創建,更新或刪除事件的UI。
- 8Base GraphQl :應用程序的後端數據庫層。這是我們將存儲,閱讀和更新日期的地方。有趣的部分是您不會為此後端編寫任何代碼。
- 耐用功能:耐用功能是一種無服務器功能,具有從先前執行中記住其狀態的功能。這就是替代Cron作業的原因,並解決了我們前面描述的臨時問題。
本文的其餘部分將根據我們在上面看到的三個單元進行三個主要部分。我們將彼此接一個,將它們構建,對其進行測試,甚至部署工作。在進行此操作之前,讓我們使用我為我們開始的開頭項目進行設置。
項目回購
入門
您可以以不同的方式設置此項目 - 要么是一個全堆棧項目,其中一個項目中的三個單元,要么是一個獨立項目,每個單元都生活在其根本上。好吧,我選擇了第一個,因為它更簡潔,更易於教學,並且可以管理,因為它是一個項目。
該應用程序將是一個創建反應項目,我為我們降低設置的障礙而做了一個開始。它帶有補充代碼和邏輯,我們不需要解釋,因為它們不超出文章的範圍。為我們設置以下內容:
- 日曆組件
- 表示事件表格的模態和彈出組件
- 事件形式組件
- 一些GraphQl邏輯查詢和突變數據
- 耐用的無服務器功能腳手架,我們將編寫調度程序
提示:我們關心的每個現有文件都在文檔頂部都有一個評論塊。該註釋塊告訴您代碼文件中當前正在發生的事情和待辦事項部分,該部分描述了我們接下來需要做的事情。
首先將起動器形式github克隆出來:
git克隆-b啟動器-Single-Branch https://github.com/christiannwamba/calendar-app.git
安裝root package.json文件以及無服務器軟件包中描述的NPM依賴項。
NPM安裝
精心策劃的耐用功能用於調度
在我們了解這個術語是什麼之前,我們需要首先擺脫兩個詞:編排和耐用。
編排最初用於描述一個協調良好的事件,動作等的組裝。在計算中,它大量借用了計算機系統的平滑協調。關鍵詞是坐標。我們需要以協調的方式將兩個或多個系統單元放在一起。
耐用的用來描述具有持久更長的出色功能的任何事物。
將系統協調和持久放在一起,您將獲得持久的功能。如果Azure的無服務器功能,這是最強大的功能。耐用的功能基於我們現在知道的這兩個功能:
- 它們可用於組裝兩個或多個功能的執行並協調它們,以免發生種族條件(編排)。
- 耐用的功能記住事情。這就是使它如此強大的原因。它打破了HTTP:無狀態的第一規則。耐用的功能使其狀態保持完整,無論他們必須等待多長時間。創建未來1,000年的時間表,持久功能將在一百萬年後執行,同時記住在觸發之日傳遞給它的參數。這意味著耐用的功能是有狀態的。
這些耐用性功能可以解鎖無服務器功能的新機會,這就是為什麼我們今天探索這些功能之一的原因。我強烈建議莎拉(Sarah)的文章又一次,用於可視化的某些耐用功能的可能用例的可視化版本。
我還對我們今天要寫的耐用功能的行為進行了視覺表示。以動畫架構圖為動畫:
來自外部系統(8Base)的數據突變通過調用HTTP觸發器觸發編排。然後觸發器調用安排事件的編排功能。當到期執行時間時,編排功能再次調用,但是這次跳過了編排並調用活動功能。活動函數是動作表演者。這是發生的實際事情,例如“發送電子郵件通知”。
創建精心策劃的耐用功能
讓我通過使用VS代碼來引導您通過創建功能。您需要兩件事:
- 一個Azure帳戶
- VS代碼
兩者都設置後,您需要將它們綁在一起。您可以使用VS代碼擴展名和節點CLI工具來執行此操作。從安裝CLI工具開始:
NPM安裝-g azure-functions核心工具 # 或者 釀造淡淡的Azure/功能 釀造安裝Azure-funnctions核心工具
接下來,安裝Azure函數擴展程序以使VS代碼與Azure上的函數相關。您可以從我上一篇文章中閱讀有關設置Azure功能的更多信息。
現在您已經完成了所有設置,讓我們開始創建這些功能。我們將創建的功能將映射到以下文件夾。
文件夾 | 功能 |
---|---|
日程 | 耐用的HTTP觸發器 |
SchooporeSterator | 耐用的編排 |
sendemail | 耐用的活動 |
從扳機開始。
- 單擊Azure擴展圖標,然後按照下圖創建時間表功能
- 由於這是第一個功能,因此我們選擇文件夾圖標來創建一個功能項目。之後的圖標創建一個單個函數(不是項目)。
- 單擊“瀏覽”,然後在項目內部創建無服務器文件夾。選擇新的無服務器文件夾。
- 選擇JavaScript作為語言。如果您的果醬是打字稿(或任何其他語言),請自由。
- 選擇耐用功能HTTP啟動器。這是觸發器。
- 將第一個功能命名為時間表
接下來,創建編排者。而不是創建功能項目,而是創建功能。
- 單擊功能圖標:
- 選擇耐用功能編排。
- 給它一個名字,scheworestertor,然後命中Enter 。
- 您將被要求選擇一個存儲帳戶。樂隊使用存儲來保留在過程中的功能狀態。
- 在您的Azure帳戶中選擇訂閱。就我而言,我選擇了免費的試用訂閱。
- 請按照剩餘的步驟創建存儲帳戶。
最後,重複上一步以創建活動。這次,以下內容應不同:
- 選擇耐用的功能活動。
- 命名它。
- 不需要存儲帳戶。
使用耐用的HTTP觸發器進行調度
無需觸摸的無服務器/附表/index.js中的代碼。這是最初使用VS代碼或CLI工具腳手架的函數時的樣子。
const df = require(“耐用功能”); 模塊。 Exports= async函數(context,req){ const client = df.getClient(context); const instanceID =等待client.startnew(req.params.functionName,undefined,req.body); context.log(``啟動以id ='$ {instanceid}'。 返回client.createcheckstatusresponse(context.bindingdata.req,instanceid); };
這裡發生了什麼?
- 我們正在基於請求上下文的客戶端創建一個耐用的功能。
- 我們使用客戶端的startNew()函數來調用編排器。樂隊函數名稱被作為第一個通過params對像作為startNew()的參數傳遞。 Req.body也將傳遞給StartNew()作為第三個參數,該論點轉發給了編排者。
- 最後,我們返回一組數據,可用於檢查編目功能的狀態,甚至可以在完成之前取消該數據的狀態。
調用上述函數的URL看起來像這樣:
http:// localhost:7071/api/排請求/{functionName}
where functionName是傳遞給startnew的名稱。在我們的情況下,應該是:
// LOCALHOST:7071/API/編排/Scheperorchestrator
也很高興知道您可以更改此URL的外觀。
用耐用的編排編排
HTTP Trigger Startnew調用呼叫調用函數,該函數基於我們傳遞給它的名稱。該名稱對應於保存編排邏輯的功能和文件夾的名稱。無服務器/scheperorchestrator/index.js文件導出耐用功能。用以下內容替換內容:
const df = require(“耐用功能”); Module.exports = df.orchestrator(function*(context){ const input = context.df.getInput() // todo- 1 // todo- 2 });
編目函數使用Context.df.getInput()從HTTP觸發器檢索請求主體。
替換todo -1用以下代碼行替換,這可能是整個演示中最重要的事情:
收益上下文。 df.createTimer(新日期(input.startat))
該線路確實使用耐用函數來根據通過HTTP觸發器從請求主體傳遞的日期創建一個計時器。
當此功能執行並到達此處時,它將觸發計時器並臨時保釋。時間表到期時,它將返回,跳過此行,並撥打以下行,您應該使用該行代替TODO -2。
返回收益率上下文。 df.callactivity('sendemail',輸入);
該功能將調用活動函數發送電子郵件。我們還將有效載荷作為第二個參數。
這就是完整的功能的樣子:
const df = require(“耐用功能”); Module.exports = df.orchestrator(function*(context){ const input = context.df.getInput() 收益上下文。 df.createTimer(新日期(input.startat)) 返回收益率上下文。 df.callactivity('sendemail',輸入); });
發送帶有持久活動的電子郵件
當定期時間表時,編排者會回來調用活動。活動文件屬於無服務器/sendemail/index.js。用以下內容更換其中的內容:
const sgmail = require('@sendgrid/mail'); sgmail.setapikey(process.env ['sendgrid_api_key']); 模塊。 exports= async函數(上下文){ // todo- 1 const msg = {} // todo- 2 返回msg; };
當前,它導入SendGrid的郵件並設置API密鑰。您可以按照以下說明獲取API密鑰。
我正在設置環境變量中的鑰匙,以確保我的憑證安全。您可以通過在serverless/local.settings.json中使用sendgrid鍵在serverless/local.settings.json中使用sendgrid_api_key鍵來安全地存儲自己的方式:
{ “ isencrypted”:false, “值”:{ “ azurewebjobsstorage”:“ ”, “ functions_worker_runtime”:“ node”, “ sendgrid_api_key”:“ ” } }
替換todo -1用以下行:
const {電子郵件,title,startat,description} = context.bindings.payload;
這從編目函數的輸入中汲取了事件信息。輸入連接到上下文。結合。有效載荷可以是您命名的任何東西,因此請轉到無服務器/sendemail/function.json並將名稱值更改為有效負載:
{ “綁定”:[ { “名稱”:“有效載荷”, “ type”:“ ActivityTrigger”, “方向”:“在” } 這是給出的 }
接下來,更新todo -2帶有以下塊發送電子郵件:
const msg = { 到:電子郵件, 來自:{電子郵件:'[[電子郵件保護]',名稱:'codebeast日曆'}, 主題:`事件:$ {title}`, html:`<h4 id="title-startat"> $ {title} @ $ {startat} </h4> <p> $ {description} </p>`` }; sgmail.send(msg); 返回msg;
這是完整版本:
const sgmail = require('@sendgrid/mail'); sgmail.setapikey(process.env ['sendgrid_api_key']); 模塊。 exports= async函數(上下文){ const {電子郵件,title,startat,description} = context.bindings.payload; const msg = { 到:電子郵件, 來自:{電子郵件:'[[電子郵件保護]',名稱:'codebeast日曆'}, 主題:`事件:$ {title}`, html:`<h4 id="title-startat"> $ {title} @ $ {startat} </h4> <p> $ {description} </p>`` }; sgmail.send(msg); 返回msg; };
將功能部署到Azure
將功能部署到Azure很容易。這僅僅是從VS代碼編輯器中單擊。單擊循環圖標以部署並獲得部署URL:
仍然和我在一起嗎?您正在取得巨大進步!在這裡休息一下,午睡,伸展或休息是完全可以的。我在寫這篇文章時肯定做到了。
帶有8Base的數據和GraphQl層
我對8base的最簡單描述和理解是“ GraphQl的firebase”。 8base是您可以想到的任何類型的應用程序的數據庫層,最有趣的方面是基於GraphQl。
描述8個鍵在堆棧中的最佳方法是繪製場景的圖片。
想像一下,您是一家自由職業者開發人員,擁有小型到中等規模的合同,為客戶建立電子商務商店。您的核心技能在網絡上,因此您的後端不太舒適。雖然您可以寫一些節點。
不幸的是,電子商務需要管理庫存,訂單管理,管理購買,管理身份驗證和身份等。在基本層面上“管理”只是意味著數據CRUD和數據訪問。
與其在後端代碼中創建,閱讀,更新,刪除和管理訪問訪問的多餘和無聊的過程,如果我們可以在UI中描述這些業務需求,該怎麼辦?如果我們可以創建允許我們配置CRUD操作,AUTH和訪問的表,該怎麼辦?如果我們有這樣的幫助,只專注於構建前端代碼和編寫查詢怎麼辦?我們剛剛描述的一切都通過8base解決
這是一個無後端應用程序的架構,它依賴於8個鍵的數據層:
創建一個用於事件存儲和檢索的8base表
在創建表格之前,我們需要做的第一件事是創建一個帳戶。有一個帳戶後,創建一個工作空間,該工作空間可以保留給定項目的所有表和邏輯。
接下來,創建一個表,命名表事件並填寫表字段。
我們需要配置訪問級別。目前,每個用戶都沒有什麼可隱藏的,因此我們可以打開對我們創建的事件表的所有訪問:
設置auth具有8個鍵,因為它與auth0集成在一起。如果您的實體需要受到保護或想擴展我們的示例以使用AUTH,請瘋狂。
最後,抓住您的端點URL以供在React應用中使用:
測試操場上的GraphQl查詢和突變
只是為了確保我們準備將URL帶到野外並開始構建客戶端,讓我們首先使用GraphQL操場測試API,然後看看設置是否還不錯。單擊探險家。
將以下查詢粘貼到編輯器中。
詢問 { eventslist { 數數 專案 { ID 標題 Startat Endat 描述 Allday 電子郵件 } } }
我通過8Base UI創建了一些測試數據,並且在運行時會收回結果:
您可以使用探索頁面右端的架構文檔探索整個數據庫。
日曆和事件形式接口
我們項目的第三個(也是最後一個)單元是構建用戶界面的React應用程序。有四個主要組件構成了UI,其中包括:
- 日曆:列出所有現有事件的日曆UI
- 事件模態:一種反應模式,它渲染事件形式組件創建一個組件
- 事件popover: popover UI讀取單個事件,使用EventForm或Delete Event更新事件
- 事件表格:用於創建新事件的HTML表格
在我們直接深入日曆組件之前,我們需要設置React React Apollo客戶端。 React Apollo提供商為您提供了使用React模式查詢GraphQL數據源的工具。原始提供商允許您使用高階組件或渲染道具來查詢和突變數據。我們將向原始提供商使用包裝器,該包裝器允許您使用React鉤查詢和突變。
在src/index.js中,導入React Apollo Hooks和Todo中的8base客戶端-1:
從“ react-apollo-hooks”中導入{apolloprovider}; 從'@8base/apollo-client'導入{八baseapolloclient};
在todo -2,用端點URL配置客戶端,我們在8base設置階段中獲得:
const uri ='https://api.8base.com/cjvuk51i0000701ss0hvvcbnxg'; const apolloclient =新的八baseapolloclient({{ Uri:Uri, withauth:false });
使用此客戶端將整個應用程序樹包裹在TODO上的提供商-3:
Reactdom.render( <apolloprovider client="{apolloclient}"> <app></app> </apolloprovider>, document.getElementById('root') );
在日曆上顯示事件
日曆組件在應用程序組件內渲染,並從NPM渲染bigcalendar組件。然後 :
- 我們渲染日曆,其中包括事件列表。
- 我們為日曆提供了一個自定義的彈出式(EventPopover)組件,該組件將用於編輯事件。
- 我們渲染將用於創建新事件的模態(事件模式)。
我們唯一需要更新的是事件列表。我們不使用靜態事件,而是要查詢所有商店事件的8base。
替換todo -1用以下行:
const {數據,錯誤,加載} = usequery(events_query);
從NPM導入USEQUERY庫和文件開頭的Events_query:
從'react-apollo-hooks'導入{usequery}; 從'../ ../ queries'導入{events_query};
events_query與我們在8Base Explorer中測試的查詢完全相同。它生活在SRC/查詢中,看起來像這樣:
導出const events_query = gql` 詢問 { eventslist { 數數 專案 { ID ... } } } `;
讓我們添加一個簡單的錯誤,並在todo上加載處理程序-2:
if(error)return console.log(error); 如果(加載) 返回 ( <div classname="“" calendar> <p>加載... </p> </div> );
請注意,日曆組件使用EventPopover組件渲染自定義事件。您還可以觀察到日曆組件文件也呈現EventModal。這兩個組件均已為您設置,它們的唯一責任是渲染事件形式。
使用事件表單組件創建,更新和刪除事件
src/組件/event/eventform.js中的組件呈現一個表單。該表格用於創建,編輯或刪除事件。在Todo -1,導入UsecReateupDatemutt和usedeletemnout:
導入{usecreateupdatemuont,undereletemnount}從'./eventmunthooks'
- USECREATEUPDATEMUNT:此突變要么根據事件已經存在,因此會創建或更新事件。
- USEDERETEMENT:此突變刪除了現有事件。
對這些功能的任何一個呼叫都會返回另一個功能。返回的功能可以用作均勻處理程序。
現在,繼續替換todo -2呼叫兩個功能:
const createUpdateEvent = usecreateupdatemunt( 有效載荷, 事件, EventExists, ()=> clocemodal() ); const deleteevent = undereletemontoution(event,()=> cockemodal());
這些是我寫的自定義鉤子,以包裝React Apollo鉤子所揭示的用戶。每個鉤子都會產生一個突變,並將突變變量傳遞到用戶符號查詢。在SRC/組件/事件/EventMunthooks.js中看起來如下的塊是最重要的部分:
USEMUNT(MutationType,{ 變量:{ 數據 },, 更新:( cache,{data})=> { const {eventList} = cache.readquery({{ 查詢:events_query }); cache.writequery({ 查詢:events_query, 數據: { eventslist:transformcacheupdatedata(eventlist,數據) } }); // .. } });
調用來自8Base的耐用功能HTTP觸發器
我們花了很多時間來構建日曆應用程序的無服務器結構,數據存儲和UI層。為了回顧一下,UI將數據發送到8base進行存儲, 8Base保存數據並觸發耐用的功能HTTP觸發器,HTTP觸發器在編排中踢球,其餘就是歷史記錄。當前,我們正在使用突變保存數據,但我們沒有在8base中任何地方調用無服務器功能。
8base允許您編寫自定義邏輯,這就是使其非常強大且可擴展的原因。自定義邏輯是基於在8Base數據庫上執行的操作調用的簡單函數。例如,我們可以設置一個邏輯,每次在表上發生突變時都被調用。讓我們創建創建事件時稱為的。
首先安裝8base CLI:
NPM安裝-G 8Base
在日曆上,應用程序項目運行以下命令以創建一個入門邏輯:
8base Init 8base
8base Init命令創建一個新的8base邏輯項目。您可以將其傳遞一個目錄名稱,在這種情況下,我們將其命名為8base邏輯文件夾8base - 不要扭曲它。
觸發調度邏輯
刪除8base/src中的所有內容,然後在SRC文件夾中創建一個triggerschedule.js文件。完成此操作後,將以下內容放入文件中:
const fetch = require('node-fetch'); 模塊。 Exports= async event => { const res =等待fetch('<http>',{ 方法:“帖子”, 正文:json.stringify(event.data), 標題:{'content-type':'application/json'} })) const json =等待res.json(); console.log(event,json) 返回JSON; };</http>
有關GraphQL突變的信息可作為數據可用。
部署功能後,將
您還需要安裝Node-fetch模塊,該模塊將從API中獲取數據:
npm安裝 - 保存節點fetch
8base邏輯配置
接下來要做的是告訴8base觸發此邏輯需要什麼確切的突變或查詢。在我們的情況下,在事件表上創建突變。您可以在8base.yml文件中描述此信息:
功能: triggerschedule: 處理者: 代碼:src/triggerschedule.js 類型:觸發器 操作:events.greate
從某種意義上說,這就是說,當事件表上發生創建突變時,請在突變發生後致電src/triggerschedule.js。
我們想部署所有的東西
在部署任何內容之前,我們需要登錄到8Base帳戶,我們可以通過命令行進行:
8base登錄
然後,讓我們運行部署命令以在您的工作區實例中發送和設置APP邏輯。
8base部署
測試整個流程
要在其所有榮耀中查看該應用程序,請單擊日曆的日子之一。您應該獲得包含表單的事件模式。填寫並放置未來的開始日期,以便我們觸發通知。嘗試與當前時間相距超過2-5分鐘的日期,因為我無法更快地觸發通知。
https://www.youtube.com/watch?v=SIMAM4FXPOO&
是的,去檢查您的電子郵件!由於SendGrid,該電子郵件應該到達。現在,我們擁有一個應用程序,該應用程序允許我們創建事件並通過事件提交的詳細信息通知。
以上是嘿,讓我們使用Jamstack創建功能日曆應用程序的詳細內容。更多資訊請關注PHP中文網其他相關文章!

對於Astro,我們可以在構建過程中生成大部分網站,但是有一小部分服務器端代碼可以使用Fuse.js之類的搜索功能來處理搜索功能。在此演示中,我們將使用保險絲搜索一組個人“書籤”


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SublimeText3 Linux新版
SublimeText3 Linux最新版

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

禪工作室 13.0.1
強大的PHP整合開發環境

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。