🔍 搜尋結果:id

🔍 搜尋結果:id

我正在建立一個人工智慧專案:這是我將要使用的程式庫......

有了正確的函式庫,任何開發人員都可以在他們的應用程式中建立強大的人工智慧功能(如 Ninja 🥷)。 在此列表中,我編譯了 7 個很棒的 AI 庫,您現在可以使用它們(相對)輕鬆地發布功能。 不要忘記為這些圖書館加註星標以表達您的支持。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qqoipyuoxgb83swyoo4a.gif) https://github.com/CopilotKit/CopilotKit --- 1. [CopilotPortal](https://github.com/CopilotKit/CopilotKit) :建構應用程式原生人工智慧聊天機器人 ------------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0x1bwwzvc2mnrfrvsqn7.png) 應用程式內人工智慧聊天機器人助理可以「查看」您目前的應用程式狀態並在前端和後端採取操作。 一組完全可自訂的反應元件和掛鉤以及用於建立 LLM 和您的應用程式之間互動的架構。 定義*useMakeCopilotReadable* 、 *useMakeCopilotActionable*和*CopilotSidebarUIProvider*使其運作。 ``` import "@copilotkit/react-ui/styles.css"; import { CopilotProvider } from "@copilotkit/react-core"; import { CopilotSidebarUIProvider } from "@copilotkit/react-ui"; export default function App(): JSX.Element { return ( <CopilotProvider chatApiEndpoint="/api/copilotkit/chat"> <CopilotSidebarUIProvider> <YourContent /> </CopilotSidebarUIProvider> </CopilotProvider> ); } ``` https://github.com/CopilotKit/CopilotKit --- 2. [RAGxplorer](https://github.com/gabrielchua/RAGxplorer) - 視覺化並探索您的 RAG 文件 ---------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z365bk6wa7i4md3w4b5z.png) RAGxplorer 是一個 Python 工具,用於視覺化機器學習和自然語言處理中的 RAG(檢索增強生成)文件。 以互動方式探索 RAG 流程中使用的文件中的聯繫和內容。 若要設定 RAGxplorer,請在程式碼中定義 RAG 檢查點路徑並安裝指定的依賴項。 ``` import streamlit as st from utils.rag import build_vector_database st.set_page_config(page_title="RAGxplorer", page_icon="🔍") uploaded_file = st.file_uploader("Upload your PDF", type='pdf') query = st.text_input("Enter your query") search = st.button("Search") top_k = st.number_input("Number of Chunks", value=5, min_value=1) st.session_state["chroma"] = build_vector_database(uploaded_file, ...) st.session_state['retrieved_id'] = query_chroma(...) plot_embeddings(...) ``` https://github.com/gabrielchua/RAGxplorer --- 3. [Tavily GPT 研究員](https://github.com/assafelovic/gpt-researcher)- 獲得法學碩士以搜尋網路和資料庫 ----------------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4accv5t5ep1l1tkj4ze2.png) Tavilly 可讓您將 GPT 支援的研究和內容產生工具新增至您的 React 應用程式中,從而增強其資料處理和內容建立功能。 ``` # Create an assistant assistant = client.beta.assistants.create( instructions=assistant_prompt_instruction, model="gpt-4-1106-preview", tools=[{ "type": "function", "function": { "name": "tavily_search", "description": "Get information on recent events from the web.", "parameters": { "type": "object", "properties": { "query": {"type": "string", "description": "The search query to use. For example: 'Latest news on Nvidia stock performance'"}, }, "required": ["query"] } } }] ) ``` https://github.com/assafelovic/gpt-researcher --- 4. [Pezzo.ai](https://github.com/pezzolabs/pezzo) - 開發者優先的 LLMOps 平台 -------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nxvbgi5zkghkb0t64npw.jpeg) 用於管理 OpenAI 通話的集中平台。 優化您的提示和令牌使用。追蹤您的人工智慧使用情況。 免費且易於整合。 ``` const prompt = await pezzo.getPrompt("AnalyzeSentiment"); const response = await openai.chat.completions.create(prompt); ``` https://github.com/pezzolabs/pezzo --- 5. [DeepEval](https://github.com/confident-ai/deepeval) - 評估 LLM、RAG 和微調性能 -------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dowjupr91bepvopxsudd.jpeg) DeepEval 是一個開源框架,透過將評估視為單元測試來簡化法學碩士的評估。 它提供了評估 LLM 輸出的各種指標,其模組化設計允許開發人員定制他們的評估流程 要使用它,您需要安裝該程式庫、編寫測試案例並執行這些用例來評估您的 LLM 的效能。 ``` Pytest Integration: from deepeval import assert_test from deepeval.metrics import HallucinationMetric from deepeval.test_case import LLMTestCase test_case = LLMTestCase( input="How many evaluation metrics does DeepEval offers?", actual_output="14+ evaluation metrics", context=["DeepEval offers 14+ evaluation metrics"] ) metric = HallucinationMetric(minimum_score=0.7) def test_hallucination(): assert_test(test_case, [metric]) ``` https://github.com/confident-ai/deepeval --- 6. [CopilotTextarea](https://github.com/RecursivelyAI/CopilotKit) - React 應用程式中的 AI 驅動寫作 ---------------------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2ctyhzd1hytek22s500.gif) 具有 Github CopilotX 功能的任何 React `<textarea>`的直接替代品。 自動完成、插入、編輯。 可以即時或由開發人員提前提供任何上下文。 ``` import { CopilotTextarea } from "@copilotkit/react-textarea"; import { CopilotProvider } from "@copilotkit/react-core"; // Provide context... useMakeCopilotReadable(...) // in your component... <CopilotProvider> <CopilotTextarea/> </CopilotProvider>` ``` https://github.com/RecursivelyAI/CopilotKit --- 7. [SwirlSearch](https://github.com/swirlai/swirl-search) - 人工智慧驅動的搜尋。 ---------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b8f4hycstwmx2gev8di7.gif) Swirl Search 是一個開源平台,它使用人工智慧同時搜尋多個資料來源並提供有關這些資料的起草報告。 它可以跨各種來源進行搜尋,包括搜尋引擎、資料庫和雲端服務,並且可以按照儲存庫中提供的安裝說明輕鬆設定。 Swirl Search 建置在 Python/Django 堆疊上,在 Apache 2.0 授權下發布,並作為 Docker 映像提供,使其可供使用者存取和自訂。 https://github.com/swirlai/swirl-search --- 謝謝閱讀!不要忘記為文章加入書籤,給出您的反應,並支持和查看提到的很棒的庫。 乾杯! --- 原文出處:https://dev.to/copilotkit/im-building-an-ai-project-here-are-the-libraries-im-going-to-use-pd0

開源 SaaS:您無需為 SaaS 模板付費

展示開放 SaaS 🎉 ----------- 我們非常高興推出[Open SaaS](https://opensaas.sh) ,這是適用於 React、NodeJS 和 Prisma 的完全免費、開源、生產級 SaaS 樣板。 在這裡查看它的實際效果: https://www.youtube.com/watch?v=rfO5SbLfyFE Open SaaS 擁有您最近看到的那些付費 SaaS 入門者的所有功能,除了它完全**免費**且**開源**。 **我們覺得為一些需要自己管理的樣板程式碼支付 300-2,000 美元是瘋狂的**。最重要的是,許多樣板文件嚴重依賴第三方服務。再加上託管和其他費用,您需要花費大量資金才能將您的想法推向世界。 **這就是為什麼透過開放 SaaS,我們有意識地決定盡可能嘗試使用開源和免費服務。**例如,我們在[OpenSaaS.sh](http://OpenSaaS.sh)上託管的演示應用程式及其管理儀表板由 Plausible 分析的自架版本提供支援。希望您的 SaaS 具有相同的功能嗎?那麼,Open SaaS 已為您預先配置好! 此外,Open SaaS 使用的[Wasp 框架](https://wasp.sh)可以為您建立許多功能,例如 Auth 和 Cron 作業,這樣您就不必支付第三方服務費用或完全自己編寫程式碼(我們稍後會更詳細地解釋這一點)。 在我們開始之前... ---------- 悠悠悠悠👋 [![開放 SaaS - 開源且 100% 免費的 React 和 Node.js SaaS 初學者! |產品搜尋](https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=436467&theme=light)](https://www.producthunt.com/posts/open-saas?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-open-saas) Open SaaS[現已在 Product Hunt](https://www.producthunt.com/posts/open-saas)上線!快來支持我們的免費開源倡議🙏 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wppn8mlby0p7h1f8xl6w.png)](https://www.producthunt.com/posts/open-saas) 為什麼我們要建造它......然後免費贈送它 ---------------------- [我們預發布版本](https://devhunt.org/tool/open-saas)中的初步回饋基本上是正面的,但我們也收到了一些問題,例如: - “它會保持免費嗎?” - “您開源這個的動機是什麼?” 所以我們認為我們應該先回答這些問題。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5rac9o1rxgrwfx51mc50.png) 首先,是的,它是 100% 免費和開源的,並將保持這種狀態。 其次,我們相信,開發者、獨立駭客和個人企業家社群的集體知識將比個人或小團體產生更好的樣板。當您從某些開發人員那裡購買SaaS 入門版時,您已經獲得了一個固執己見的堆棧,然後除此之外,您還獲得了按照他們認為最好的方式建置的應用程式- 這可能並不總是最適合*您。* 第三, [Open SaaS](https://opensaas.sh)是[Wasp](https://wasp.sh)的一個專案,一個超強的開源React + NodeJS + Prisma全端框架。我們 Wasp 團隊相信 Wasp 非常適合快速且有效率地建立 SaaS 應用程式,我們希望這個模板能夠證明這一點。另外,身為開發人員,我們從其他開源專案中學到了很多東西,而 Wasp 本身就是一個開源專案。 基本上,我們熱愛開源理念,並且希望將其發揚光大。 🙏 因此,我們希望能夠為開發者社群提供非常有價值的資產,同時宣傳我們的開源全端框架。我們很高興看到社區為其做出貢獻,以便它不斷發展並成為最好的 SaaS 樣板。 開放 SaaS 是由什麼組成的 --------------- 我們在 Open SaaS 上投入了大量的精力,包括[文件](https://docs.opensaas.sh),以便開發人員可以自信、輕鬆地啟動 SaaS 應用程式。 我們還花了一些時間檢查其他免費的開源 SaaS 啟動器,並希望確保 Open SaaS 具有可立即投入生產的啟動器的所有正確功能,而不顯得臃腫。我們認為我們已經在很大程度上實現了這一點,儘管我們將繼續加入功能並隨著時間的推移進行改進。 目前的主要特點如下: - 🔐 身份驗證(電子郵件驗證、Google、github) - 📩 電子郵件(sendgrid、emailgun、SMTP) - 📈 管理儀表板(合理或谷歌分析) - 🤑 Stripe 付款(只需加入您的訂閱產品 ID) - ⌨️ 端對端類型安全性(無需配置) - 🤖 OpenAI 整合(AI 驅動的範例應用程式) - 📖 Astro 博客 - 🚀 部署在任何地方 - 📄 完整的文件和社群支持 值得深入了解其中每個功能的細節,所以讓我們開始吧。 ### 授權 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wbistoghxrxft9zxxra1.png)](https://www.producthunt.com/posts/open-saas) 感謝 Wasp,Open SaaS 附帶了許多可能的身份驗證方法: - 使用者名稱和密碼(最簡單/最容易進行開發測試) - 已驗證電子郵件並重設密碼 - Google 和/或 Github 社群登入 這就是 Wasp 真正發揮作用的地方,因為設定全端 Auth 並取得預先配置的 UI 元件所需要做的就是: ``` //main.wasp app SaaSTemplate { auth: { userEntity: User, methods: { usernameAndPassword: {}, google: {}, gitHub: {}, } } } ``` 嚴重地。就是這樣! 只需確保您已設定社交身份驗證並擁有 API 金鑰以及定義的`User`和`ExternalAuth`實體,就可以開始了。不用擔心,這部分內容已在[Open SaaS Docs](https://docs.opensaas.sh)中詳細記錄和解釋。 最重要的是,Open SaaS 預先配置了一些範例,說明如何自訂和建立一些真正強大的身份驗證流程。 ### 管理儀表板和分析 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4mm6s1c3txxgm49e2k7w.png)](https://www.producthunt.com/posts/open-saas) 透過利用[Wasp 的工作功能](https://wasp-lang.dev/docs/advanced/jobs),Open SaaS 每小時從 Plausible 或 Google 的網站分析(您的選擇!)和 Stripe 的資料 API 中提取資料,並將其保存到我們的資料庫中。然後,該資料將顯示在我們的管理儀表板上(前往[OpenSaaS.sh](https://OpenSaaS.sh)查看其實際情況)。好的部分是,要為您自己的應用程式存取這些資料,您所要做的就是按照我們的指南獲取分析 API 金鑰,插入提供的腳本,然後就可以開始了! 再次強調,Wasp 讓整個過程變得非常簡單。透過已經為您定義的查詢 API 和取得我們需要的資料的功能,Open SaaS 然後在`main.wasp`設定檔中使用 Wasp 作業: ``` job dailyStatsJob { executor: PgBoss, perform: { fn: import { calculateDailyStats } from "@server/workers/calculateDailyStats.js" }, schedule: { cron: "0 * * * *" }, entities: [User, DailyStats, Logs, PageViewSource] } ``` 就是這樣! Wasp 負責為您設定和執行 cron 作業。 ### 條紋支付 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ugy3mx9xo1d9i9vfysr7.png)](https://www.producthunt.com/posts/open-saas) 如果您是以前從未建立過自己的 SaaS 的開發人員,那麼與 Stripe 這樣的支付處理器整合可能是您將面臨的少數挑戰之一。 當我建立第一個 SaaS [CoverLetterGPT.xyz](https://coverlettergpt.xyz)時,我的情況就是如此。這實際上是我建造它的主要動機之一;了解如何將 Stripe 支付整合到應用程式以及 OpenAI API 中。 儘管 Stripe 因擁有豐富的文件而聞名,但這個過程仍然令人畏懼。你必須: - 建立正確的產品類型 - 設定 webhook 端點 - 告訴 Stripe 將正確的 Webhook 事件傳送給您 - 正確使用事件 - 處理重複付款和失敗付款 - 在上線之前透過 CLI 進行正確測試 這就是為什麼為您設定 Stripe 訂閱付款是一個巨大的勝利。 但比這更重要的是,為您方便地記錄整個過程!這就是為什麼 Open SaaS[在我們的文件中為您提供方便的 Stripe 指南](https://docs.opensaas.sh)🙂 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uehwot350u3dl02s4w7r.png)](https://www.producthunt.com/posts/open-saas) ### 端對端類型安全 Open SaaS 是使用 Typescript 建置的,因為它是一個全棧應用程式,所以從後端到前端的類型安全可以成為真正的救星。我的意思是,一些[固執己見的堆疊](https://create.t3.gg/)在此基礎上變得非常流行。 幸運的是,Wasp 為您提供開箱即用的端到端類型安全性(無需配置!),因此 Open SaaS 可以輕鬆利用它。 這是一個例子: 1. 讓 Wasp 了解您的伺服器操作: ``` // main.wasp action getResponse { fn: import { getResponse } from "@server/actions.js", entities: [Response] } ``` 2. 輸入並實施您的伺服器操作。 ``` // src/srever/actions.ts type RespArgs = { hours: string; }; const getResponse: GetResponse<RespArgs, string> = async ({ hours }) => { } ``` 3. 導入並在客戶端呼叫。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fah81r1g4bg3vdqapju.png) 客戶端類型將被正確推斷! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7n04yh6de9slhhnjrgf3.png) ### AI 驅動的範例應用程式(附有 OpenAI API) [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbbc2gkxbxjl3q2y01a3.png)](https://www.producthunt.com/posts/open-saas) 人工智慧正在使新的應用程式創意成為可能,這也是我們看到開發人員對建立 SaaS 應用程式的興趣重新抬頭的部分原因。正如我上面提到的,我建造的第一個 SaaS 應用程式[CoverLetterGPT](https://coverlettergpt.xyz)是「GPT 包裝器」之一,我很自豪地說它帶來了約350 美元MRR(每月經常性收入)的可觀被動收入。 我個人認為,我們在軟體開發方面處於最佳狀態,開發新的、有利可圖的人工智慧應用程式有很大的潛力,尤其是「獨立駭客」和「個人企業家」。 這就是 Open SaaS 推出 AI 調度助手演示應用程式的原因。您輸入任務及其分配的時間,AI Scheduler 會為您的一天建立詳細的計劃。 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j4suf7g9jm5w93ri3bqx.png)](https://www.producthunt.com/posts/open-saas) 在幕後,這是使用 OpenAI 的 API 為每個任務分配優先級,並將它們分解為詳細的子任務,包括喝咖啡休息時間!它還利用 OpenAI 的函數呼叫功能以使用者定義的 JSON 物件形式回傳回應,以便客戶端每次都能正確使用它。此外,我們計劃在未來加入開源法學碩士,敬請期待! 示範版 AI Scheduler 可協助開發人員學習如何有效使用 OpenAI API,並激發一些 SaaS 應用程式創意! ### 隨處部署。容易地。 許多流行的 SaaS 新創公司都使用依賴託管的框架,這意味著您只能依賴一個提供者進行部署。雖然這些都是簡單的選擇,但它可能並不總是最適合您的應用程式。 Wasp 為您提供了部署全端應用程式的無限可能性: - 使用`wasp deploy`一鍵部署到[Fly.io](http://Fly.io) - 使用`wasp build`並部署 Dockerfiles 和客戶端,無論您喜歡什麼! `wasp deploy`的優點在於它會自動產生和部署您的資料庫、伺服器和用戶端,並為您設定環境變數。 Open SaaS 還內建了環境變數和常數驗證器,以確保您已正確設定部署所需的所有內容,以及文件中的部署指南 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fihbij250xtbdtjbjoks.png)](https://www.producthunt.com/posts/open-saas) 最後,您擁有自己的程式碼,並且可以自由地將其部署到任何地方,而無需受供應商鎖定。 幫助我們,幫助你 -------- [![開放 SaaS - 開源且 100% 免費的 React 和 Node.js SaaS 初學者! |產品搜尋](https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=436467&theme=light)](https://www.producthunt.com/posts/open-saas?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-open-saas) 想支持我們的免費開源計畫嗎?那麼現在就去[Product Hunt 上](https://www.producthunt.com/posts/open-saas)向我們提供一些支援吧! 🙏 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wppn8mlby0p7h1f8xl6w.png)](https://www.producthunt.com/posts/open-saas) 現在就開始建立您的 SaaS! --------------- 我們希望 Open SaaS 能夠讓更多的開發人員能夠發布他們的想法和副專案。我們也希望從開發人員那裡獲得一些回饋和意見,以便我們能夠使其成為最好的 SaaS 樣板啟動器。 因此,如果您有任何意見或發現任何錯誤,請[在此處提交問題](https://github.com/wasp-lang/open-saas/issues)。 如果您發現 Open SaaS 和/或 Wasp 很有用,最簡單的支援方法就是給我們一顆星: - 為[Open SaaS 儲存庫](https://github.com/wasp-lang/open-saas)加註星標 - 給[黃蜂倉庫](https://github.com/wasp-lang/wasp)加註星標 --- 原文出處:https://dev.to/wasp/you-dont-need-to-pay-for-saas-boilerplates-open-saas-56lj

資料庫 101:如何為 100 萬玩家的遊戲建立排行榜模型。

有沒有想過像**《英雄聯盟》** 、 **《要塞英雄**》甚至**《Rockband》**這樣的遊戲是如何建立排行榜模型的?在本文中,我們將了解如何正確建模模式以以極其高效的方式處理它們! 如果您剛開始使用一般資料庫或資料庫,您可能需要閱讀我的第一篇文章[《資料庫 101:初學者的資料一致性](https://dev.to/danielhe4rt/database-101-why-so-interesting-1344)》。那篇文章記錄了我自己對有多少資料庫範例的探索,因為我的眼光遠遠超出了我以前僅使用 SQL 和 MySQL 的經驗。我正在**資料庫 101**系列中追蹤我的研究。 > 距離我發表本系列的第一篇文章已經快一年了!感謝您在我學習主題時與我在一起。您的評論和想法總是非常有幫助! 1. 序言 ----- ![YARG 遊戲玩法截圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvensca2v67ma66vssnh.png) 從我還是個孩子的時候起,就像大多數普通開發者一樣,我就對遊戲及其製作方式著迷。說到這裡,我要跟大家介紹一下我兒時最喜歡的遊戲:《吉他英雄3:搖滾傳奇》。 十多年後,我決定嘗試在開源環境中為一些遊戲做出貢獻,例如[rust-ro(Rust Ragnarok Emulator)](https://github.com/nmeylan/rust-ro)以及本文的主角: [YARG(Yet Another Rhythm Game)](https://github.com/YARC-Official/YARG) 。 YARG 實際上是另一個節奏遊戲,但這個專案的不同之處在於它是完全**開源的**,他們聯合了遊戲開發和設計方面的傳奇貢獻者來讓這個專案能夠運作。 突然之間,這款遊戲被 Twitch 上的 Guitar Hero/Rockband 主播們所採用並玩,我想:好吧,這是一個開源專案,所以也許我可以利用我的資料庫技能來建立一個**速度極快的排行榜**或儲存過去的比賽。 一開始只是在他們的 Discord 上進行了一次簡單的聊天,後來變成了關於如何讓這個專案更快發展的長時間討論。 然後我決定和我的老闆談談,問他我是否可以和 YARG 的人一起工作,條件是建立一些足夠酷的東西來實現[ScyllaDB(NoSQL 寬列資料庫)](https://scylladb.com/) ,因為我在那裡擔任開發倡導者。您不會相信ScyllaDB帶來的簡單性和可擴展性如何完美契合YARG.in的需求! 無論如何,談話是廉價的。讓我向您展示一些程式碼和概念! 2.QDD-查詢驅動的資料建模 --------------- ![NoSQL 與關係型資料庫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivkj9j8ni2fakkctx53n.png) 當我們談論使用**NoSQL**進行開發時,大多數情況下我們應該理解,根據範例(文件、圖形、寬列等),您應該先了解**要執行哪個查詢**。 在 MySQL 中,主要目標是了解一致性,而在 Scylla 中,您應該專注於查詢並基於該查詢建立模式。 在這個專案中,我們將處理兩種類型的範例,它們是: - 核心價值 - 寬列(聚類) 現在讓我們來談談我們建模的查詢/功能。 ### 2.1 功能:儲存匹配 ![提交詳情 YARG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaw4q7349upgrsa5p5g3.png) 每次完成 YARG 遊戲時,最有趣的事情就是提交您的分數以及許多其他遊戲內指標。 基本上它將是基於主索引的單一查詢,僅此而已。 ``` SELECT score, stars, missed_notes, instrument, ... FROM leaderboard.submisisons WHERE submission_id = 'some-uuid-here-omg' ``` ### 2.2 功能:排行榜 ![排行榜 Figma 文件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69jp0vgxef71titt9ks0.png) 現在我們的主要目標是:一個超酷的**排行榜**,在良好的資料建模之後你不需要關心它。排行榜是按歌曲計算的,因此每次您播放特定歌曲時,您的最佳成績都會被保存並排名。 然而,這個介面有一個重要的點,那就是有過濾器來準確地知道要帶來「哪個」排行榜: - 歌曲 ID:必填 - 儀器:必填 - 修飾符:必需 - 難度:必填 - 玩家 ID:可選 - 分數:可選 想像一下我們的查詢如下所示,它會傳回按分數降序排列的結果: ``` SELECT player_id, score, ... FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND track_id = 'dani-california' LIMIT 100; -- player_id | score ----------------+------- -- tzach | 12000 -- danielhe4rt | 10000 -- kadoodle | 9999 ----------------+------- ``` 現在我們知道了將在這裡使用的功能,但是您能想像最終的模式將如何嗎? 不?好的,讓我來幫助你! 3. 資料建模時間! ---------- 是時候深入研究 ScyllaDB 的資料建模並更好地了解如何擴展它了。 ### 3.1 - 匹配建模 ![遊戲結束畫面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6kedk7iu67zg7myj9mp.png) 首先,讓我們先來了解遊戲本身: - 這是一個節奏遊戲; - 您一次播放一首特定的歌曲; - 您可以在遊戲前啟動“修改器”,讓您的生活變得更輕鬆或更困難; - 您必須選擇一種樂器(例如吉他、鼓、貝斯和麥克風)。 - 遊戲玩法的各個方面都會被跟踪,例如: - Score; - Missed notes; - Overdrive count; - Play speed (1.5x ~ 1.0x); - Date/time of gameplay; - And other cool stuff. 考慮到這一點,我們可以輕鬆地開始我們的資料建模,這將變成這樣: ``` CREATE TABLE IF NOT EXISTS leaderboard.submissions ( submission_id uuid, track_id text, player_id text, modifiers frozen<set<text>>, score int, difficulty text, instrument text, stars int, accuracy_percentage float, missed_count int, ghost_notes_count int, max_combo_count int, overdrive_count int, speed int, played_at timestamp, PRIMARY KEY (submission_id, played_at) ); ``` 讓我們跳過所有`int/text`值並跳到`set<text>` 。 **集合**類型可讓您儲存特定類型的專案清單。我決定使用這個清單來儲存修飾符,因為它非常適合。看看查詢是如何執行的: ``` INSERT INTO leaderboard.submissions ( submission_id, track_id, modifiers, played_at ) VALUES ( some-cool-uuid-here, 'starlight-muse' {'all-taps', 'hell-mode', 'no-hopos'}, '2024-01-01 00:00:00' ); ``` 使用這種類型,您可以輕鬆儲存專案清單以供以後檢索。 另一個很酷的資訊是這個查詢是一個鍵值對!這意味著什麼? 由於您始終僅透過`submission_id`來查詢它,因此它可以歸類為鍵值。 ### 3.2 排行榜建模 ![排行榜濾鏡 Figma](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpmzngra3jk5ipf3os3i.png) 在本文的這一部分中,您將學習一些很酷的寬列資料庫概念。 在我們的排行榜查詢中,如前所述,我們總是需要在 WHERE 子句中使用一些動態值,這意味著這些值將屬於**分區鍵**,而**聚類鍵**將具有可以是「可選」的值。 **分區鍵**是基於您新增的用於標識值**的欄位組合的**雜湊。你明白了嗎?不?好吧,我也花了一段時間才明白這一點,但讓我向你展示一些東西: 假設您玩了`Starlight - Muse` 100 次。如果您要查詢此訊息,將透過`score`或`player_id`等聚類鍵區分出100倍不同的結果。 ``` SELECT player_id, score --- FROM leaderboard.song_leaderboard WHERE track_id = 'starlight-muse' LIMIT 100; ``` 如果有 1.000.000 個玩家播放這首歌,你的查詢會變得很慢,並且將來會成為一個問題,因為你的分區鍵只包含一個字段,即`track_id` 。 但是,如果您向**Partition Key**加入更多字段,例如玩遊戲之前的強制性內容,也許我們可以縮小這些可能性以實現更快的查詢。現在你看到大局了嗎?加入諸如**“樂器”** 、 **“難度**”和**“修改器”等**欄位將為您提供一種均勻分割有關特定曲目的資訊的方法。 讓我們想像一些簡單的數字: ``` -- Query Partition ID: '1' SELECT player_id, score, ... FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND -- Modifiers Changed track_id = 'starlight-muse' LIMIT 100; -- Query Partition ID: '2' SELECT player_id, score, ... FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'all-hopos'} AND -- Modifiers Changed track_id = 'starlight-muse' LIMIT 100; ``` 因此,如果您以特定形狀建立查詢,它將始終查找特定令牌並根據這些特定分區鍵檢索資料。 我們來看看最終的建模,談談聚類鍵和應用層: ``` CREATE TABLE IF NOT EXISTS leaderboard.song_leaderboard ( submission_id uuid, track_id text, player_id text, modifiers frozen<set<text>>, score int, difficulty text, instrument text, stars int, accuracy_percentage float, missed_count int, ghost_notes_count int, max_combo_count int, overdrive_count int, speed int, played_at timestamp, PRIMARY KEY ((track_id, modifiers, difficulty, instrument), score, player_id) ) WITH CLUSTERING ORDER BY (score DESC, player_id ASC); ``` 分區鍵的定義如上所述,由我們**所需的參數**組成,例如:track\_id、修飾符、難度和樂器。在**聚類鍵**上,我們新增了**Score**和**player\_id** 。 > 請注意,預設情況下,聚類欄位按`score DESC`排序,以防萬一玩家得分相同,選擇獲勝者的標準將按`alphabetical` ¯\\\_(ツ)\_/¯。 首先很容易理解的是,我們**每個玩家只有一個分數**,但透過這種建模,如果玩家以不同的分數兩次經歷同一條賽道,它將產生兩個不同的條目。 ``` INSERT INTO leaderboard.song_leaderboard ( track_id, player_id, modifiers, score, difficulty, instrument, stars, played_at ) VALUES ( 'starlight-muse', 'daniel-reis', {'none'}, 133700, 'expert', 'guitar', '2023-11-23 00:00:00' ); INSERT INTO leaderboard.song_leaderboard ( track_id, player_id, modifiers, score, difficulty, instrument, stars, played_at ) VALUES ( 'starlight-muse', 'daniel-reis', {'none'}, 123700, 'expert', 'guitar', '2023-11-23 00:00:00' ); SELECT player_id, score FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND track_id = 'starlight-muse' LIMIT 2; -- player_id | score ----------------+------- -- daniel-reis | 133700 -- daniel-reis | 123700 ----------------+------- ``` 那我們要如何解決這個問題呢?嗯,這本身不是問題。這是一個特點!哈哈 身為開發人員,您必須根據專案需求建立自己的業務規則,這也不例外。我這麼說是什麼意思? 您可以在插入新條目之前執行簡單的**DELETE**查詢,並確保在該特定**分區鍵**組內, **player\_id**中的特定資料不會低於新**分數**。 ``` -- Before Insert the new Gampleplay DELETE FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND track_id = 'starlight-muse' AND player_id = 'daniel-reis' AND score <= 'your-new-score-here'; -- Now you can insert the new payload... ``` 這樣我們就完成了簡單的排行榜系統,該系統與 YARG 中執行的系統相同,也可以在每秒數百萬個條目的遊戲中使用:D 4. 如何為 YARG 做出貢獻 ---------------- 這是我邀請您為這個精彩的開源專案做出貢獻的文字部分! 今天,我們正在為所有玩家建立一個全新的平台,使用: - 遊戲:Unity3d [(儲存庫)](https://github.com/YARC-Official/YARG) - 前端:NextJS [(儲存庫)](https://github.com/YARC-Official/yarg.in) - 後端:Laravel 10.x [(儲存庫)](https://github.com/YARC-Official/yarg-api) 我們將需要盡可能多的開發人員和測試人員與主要貢獻者一起討論遊戲的未來實現! ![YARG 不和諧](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5b2pdxvrth2o6jfmada.png) 首先,請確保加入他們的[Discord 社群](https://discord.gg/sqpu4R552r)。在進入開發板之前,所有技術討論都會在社群後台進行。 此外,在 Discord 之外,YARG 社群主要關注[EliteAsian](https://twitter.com/EliteAsian123) (核心貢獻者和專案所有者)Twitter 帳戶的開發展示。一定要跟著他去那裡。 https://twitter.com/EliteAsian123/status/1736149319382671766 僅供參考,遊戲的**首席美術師**(又稱[Kadu)](https://twitter.com/kaduyarg)也是**Elgato**的**廣播專家**和**產品創新**開發人員,曾與以下串流媒體合作: - 忍者 - 納德肖特 - 石山64 - 以及傳奇 DJ Marshmello。 Kadu 也使用他的 Twitter 分享一些見解以及 YARG 新功能和實驗的早期預覽。所以,別忘了在 Twitter 上關注他! https://twitter.com/kaduyarg/status/1689489132060397568 以下是一些有用的連結,可以幫助您了解有關該專案的更多訊息: - [官方網站](https://yarg.in/) - [Github 儲存庫](https://github.com/YARC-Official/YARG) - [任務板](https://yarg.youtrack.cloud/agiles/147-7/current) > 有趣的事實:YARG 受到了 Guitar Hero 專案負責人[Brian Bright](https://twitter.com/BrianBright/status/1744533504531317194)的關注,他喜歡該專案的開源特性。太棒了,對吧? 5. 結論 ----- 資料建模有時具有挑戰性,這項研究花了 3 個月的時間研究了許多新的 ScyllaDB 概念,並與我在 Twitch 的社群一起進行了大量測試。 我還發布了[遊戲排行榜演示](https://github.com/scylladb/gaming-leaderboard-demo),您可以在其中獲得有關如何使用**NextJS**和**ScyllaDB**實現同一專案的一些見解! 另外,如果您喜歡 ScyllaDB 並想了解更多訊息,我強烈建議您觀看我們的免費[大師班課程](https://lp.scylladb.com/masterclass-ondemand-main?siteplacement=navigation)或存取[ScyllaDB 大學](https://university.scylladb.com/)! 不要忘記喜歡這篇文章,在社交上關注我並填滿你的水瓶 xD 下一篇文章見! [在推特上關注我](https://twitter.com/danielhe4rt) [在 Github 上關注我](https://twitter.com/danielhe4rt) [在 Github 上關注我](https://twitter.com/danielhe4rt) [關注並訂閱我的 Twitch 頻道](https://twitch.tv/danielhe4rt) --- 原文出處:https://dev.to/danielhe4rt/database-101-how-to-model-leaderboards-for-1m-players-game-2pfa

使用 Flexbox 實現極為簡單的行和列佈局

CSS 中的超簡單響應式行和列 ================== 網格佈局是 Web 開發設計的基礎,您很可能已經使用 Bootstrap 或 Foundation 等工具來使您的佈局成為現實。但是,像你們大多數人一樣,我不喜歡執行 Bootstrap 或 Foundation 所需的依賴項,也不喜歡頁面加載時間的叮噹聲。 事實上,當我將Bootstrap 用於我正在編寫的應用程式時,我幾乎只將它用於網格佈局,有時我會將它用於通知或基本的相當合理的CSS 預設值,但90% 的時間,我想要的都是是網格佈局。 我也不喜歡只有將列拆分為 12 列或更少的選項。感覺有時你必須做一些瘋狂的工作才能讓列成列,或類似奇怪的事情。 我們如何更快、更輕鬆地進行網格佈局? Flexbox 就是您的答案。我認為 ### flexbox 此時,flexbox 幾乎無所不在。所有主要[瀏覽器](https://caniuse.com/#feat=flexbox)都支援它。它允許更簡單的佈局,並且受到 React-Native 的支持,這意味著當我為 React-Native 佈局頁面時,我首先會使用 Flexbox,但我發現自己在 Web 開發中也首先使用了 Flexbox。 事實上,我佈置的最後一個應用程式完全是使用 Flexbox 完成的。我發現它*很*容易使用。 如果您對 Flex Box 不太了解。我喜歡這個頁面,它很好地介紹了[Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) ### layout 首先,我將整個頁麵包裹在一個 div 中。 ``` <div class='some-page-wrapper'> </div> ``` 然後我定義一個可以幫助佈局的`.row`和`.column`類別。 ``` .row { display: flex; flex-direction: row; flex-wrap: wrap; width: 100%; } .column { display: flex; flex-direction: column; flex-basis: 100%; flex: 1; } ``` 現在,如果我們想要兩列佈局: ``` <div class='some-page-wrapper'> <div class='row'> <div class='column'> <div class='blue-column'> Some Text in Column One </div> </div> <div class='column'> <div class='green-column'> Some Text in Column Two </div> </div> </div> </div> ``` CSS 看起來像: ``` .some-page-wrapper { margin: 15px; background-color: red; } .row { display: flex; flex-direction: row; flex-wrap: wrap; width: 100%; } .column { display: flex; flex-direction: column; flex-basis: 100%; flex: 1; } .blue-column { background-color: blue; height: 100px; } .green-column { background-color: green; height: 100px; } ``` https://codepen.io/drews256/pen/zLerNx 如果我們想新增第三列怎麼辦? HTML 可以輕鬆更新為: ``` <div class='some-page-wrapper'> <div class='row'> <div class='column'> <div class='blue-column'> Some Text in Column One </div> </div> <div class='column'> <div class='green-column'> Some Text in Column Two </div> </div> <div class='column'> <div class='orange-column'> Some Text in Column Two </div> </div> </div> </div> ``` https://codepen.io/drews256/pen/djaYKo 我們新增了第三列。這無縫地融入了我們的行。 https://codepen.io/drews256/pen/djaYKo 現在如果我們想要更複雜的佈局呢? 我們可以加入更多行,這非常簡單。 ``` <div class='some-page-wrapper'> <div class='row'> <div class='column'> <div class='orange-column'> Some Text in Column One </div> </div> <div class='column'> <div class='blue-column'> Some Text in Column Two </div> </div> <div class='column'> <div class='green-column'> Some Text in Column Three </div> </div> </div> <div class='row 2'> <div class='column'> <div class='green-column'> Some Text in Row 2, Column One </div> </div> <div class='column'> <div class='orange-column'> Some Text in Row 2, Column Two </div> </div> <div class='column'> <div class='blue-column'> Some Text in Row2, Column Three </div> </div> </div> </div> ``` https://codepen.io/drews256/pen/WKPwxN 或者我們可以調整列的大小。 要擁有雙列,我們可以新增一個`.double-column`類別。不過,這可以適用於任何尺寸的列,您可以做60/40,您可以做10/10/10/10/10/10/10/10/10/10,老實說,這裡任何組合都是可能的。您可以做 1 X 100。或 10 x 1,然後 20 x 3,然後 30 x 1。選項是無窮無盡的! 在一種佈局上,我在“列”周圍加入了很大的邊距,並且由於行將向下滾動,因此我有一行包含所需數量的“列”。這些列是固定寬度的卡片,因此它們只是換行到下一行,而彈性盒巧妙地響應式地將卡片沿著螢幕包裹起來。 ``` .double-column { display: flex; flex-direction: column; flex-basis: 100%; flex: 2; } ``` https://codepen.io/drews256/pen/djaMWj 但這不是很敏感嗎?我們可以使用媒體查詢來加入一些響應性。 只需將`flex: 1`和`flex: 2`移動到媒體查詢(大小取決於應用程式,我只是提供一個選項) ``` @media screen and (min-width: 800px) { .column { flex: 1 } .double-column { flex: 2 } } ``` `> 800` 像素時: ![反應速度大,大於 800](https://thepracticaldev.s3.amazonaws.com/i/vzblza9096iap76a55ju.png) `< 800` 像素時: ![低於800時有響應](https://thepracticaldev.s3.amazonaws.com/i/g4vz31amzqbpn5duuu5l.png) 最終的codepen,提示點擊右下角的1x或0.5x按鈕來查看「響應式」佈局的差異。 https://codepen.io/drews256/pen/bjzpvd 本質上,我們只是用 20 行 CSS 將 bootstrap 的行/列從水中炸出來。我們有一種快速建立行/列佈局的方法,而且由於我們使用 Flexbox,我們幾乎不必擔心佈局會破壞或出現任何問題。它可以輕鬆適應各種用途,並允許大量的可自訂性。您對彈性盒有何看法?你試過了嗎? 另一個隱藏的好處是,如果我以這種方式佈局 React 元件,那麼很容易佈局 React-Native 元件,使其看起來相似。 我通常在我的專案中使用 SCSS,所以如果您發現一些不完美的 CSS,請告訴我! --- 原文出處:https://dev.to/drews256/ridiculously-easy-row-and-column-layouts-with-flexbox-1k01

🪄與您的簡歷製作者聊天 - 使用 Next.js、OpenAI 和 CopilotKit 📑✨

#TL;博士 在本文中,您將了解如何使用 Nextjs、CopilotKit 和 OpenAI 建立人工智慧驅動的簡歷產生器應用程式。 我們將涵蓋: - 利用 ChatGPT 撰寫履歷和求職信 📑 - 透過與履歷聊天逐漸完善你的履歷💬 - 將您的履歷和求職信匯出為 PDF 🖨️ ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxzcx6jqet2anmr2pu6c.gif) --- ## CopilotKit:建構深度整合的應用內人工智慧聊天機器人 💬 只是簡單介紹一下我們的背景。 CopilotKit 是[開源 AI 副駕駛平台。](https://github.com/CopilotKit/CopilotKit) 我們可以輕鬆地將強大的 AI 聊天機器人整合到您的 React 應用程式中。完全可定制和深度集成。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6wf9zcyvtu9q293uej2n.gif) {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} 現在回到文章。 --- ## **先決條件** 要開始學習本教程,您需要在電腦上安裝以下軟體: - 文字編輯器(例如 Visual Studio Code) - 節點.js - 套件管理器 ## **使用 NextJS 建立簡歷應用程式前端** **步驟 1:** 開啟命令提示字元並執行下列命令。 ``` npx create-next-app@latest ``` --- **第 2 步:** 系統將提示您選擇一些選項,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mvk0mgct4ypra7ao9u18.png) **步驟 3:** 使用您選擇的文字編輯器開啟新建立的 Nextjs 專案。然後,在命令列上執行以下命令,以使用 Tailwind CSS 安裝帶有 NextJS 的 Preline UI。依照[本指南](https://preline.co/docs/frameworks-nextjs.html)完成 Preline 設定。 ``` npm install preline ``` --- **步驟4:** 在resume/app/page.tsx檔案中,新增以下程式碼內容。 ``` export default function Home() { return ( <> <header className="flex flex-wrap sm:justify-start sm:flex-nowrap z-50 w-full bg-slate-900 bg-gradient-to-b from-violet-600/[.15] via-transparent text-sm py-3 sm:py-0 dark:bg-gray-800 dark:border-gray-700"> <nav className="relative max-w-7xl w-full mx-auto px-4 sm:flex sm:items-center sm:justify-between sm:px-6 lg:px-8 " aria-label="Global"> <div className="flex items-center justify-between"> <a className="flex-none text-xl text-gray-200 font-semibold dark:text-white py-8" href="#" aria-label="Brand"> ResumeBuilder </a> </div> </nav> </header> {/* <!-- Hero --> */} <div className="bg-slate-900 h-screen"> <div className="bg-gradient-to-b from-violet-600/[.15] via-transparent"> <div className="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 py-24 space-y-8"> {/* <!-- Title --> */} <div className="max-w-3xl text-center mx-auto pt-10"> <h1 className="block font-medium text-gray-200 text-4xl sm:text-5xl md:text-6xl lg:text-7xl"> Craft A Compelling Resume With AI Resume Builder </h1> </div> {/* <!-- End Title --> */} <div className="max-w-3xl text-center mx-auto"> <p className="text-lg text-gray-400"> ResumeBuilder helps you create a resume that effectively highlights your skills and experience. </p> </div> {/* <!-- Buttons --> */} <div className="text-center"> <a className="inline-flex justify-center items-center gap-x-3 text-center bg-gradient-to-tl from-blue-600 to-violet-600 shadow-lg shadow-transparent hover:shadow-blue-700/50 border border-transparent text-white text-sm font-medium rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white py-3 px-6 dark:focus:ring-offset-gray-800" href="#"> Get started <svg className="flex-shrink-0 w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="m9 18 6-6-6-6" /> </svg> </a> </div> {/* <!-- End Buttons --> */} </div> </div> </div> {/* <!-- End Hero --> */} </> ); } ``` **步驟 5:** 在命令列上執行命令 *npm run dev*。導航至 http://localhost:3000/,您應該會看到新建立的 NextJS 專案。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/56ymnb9iir7z14bx4ofm.png) --- ## 使用 GitHub GraphQL 從 GitHub 取得履歷資料 **步驟 1:** 使用下列命令安裝 Axios HTTP 用戶端。 ``` npm i axios ``` **步驟 2:** 在應用程式資料夾中,建立一個名為 API 的資料夾。然後,在 API 資料夾中建立一個名為 GitHub 的資料夾。在GitHub資料夾中建立一個名為route.ts的檔案並加入以下程式碼。 ``` import { NextResponse } from "next/server"; import axios from "axios"; // Environment variables for GitHub API token and user details const GITHUB_TOKEN = "Your GitHub personal access token"; const GITHUB_USERNAME = "Your GitHub account username"; // Axios instance for GitHub GraphQL API const githubApi = axios.create({ baseURL: "https://api.github.com/graphql", headers: { Authorization: `bearer ${GITHUB_TOKEN}`, "Content-Type": "application/json", }, }); // GraphQL query to fetch user and repository data const getUserAndReposQuery = ` query { user(login: "${GITHUB_USERNAME}") { name email company bio repositories(first: 3, orderBy: {field: CREATED_AT, direction: DESC}) { edges { node { name url description createdAt ... on Repository { primaryLanguage{ name } stargazers { totalCount } } } } } } } `; // API route to handle resume data fetching export async function GET(request: any) { try { // Fetch data from GitHub const response = await githubApi.post("", { query: getUserAndReposQuery }); const userData = response.data.data.user; // Format resume data const resumeData = { name: userData.name, email: userData.email, company: userData.company, bio: userData.bio, repositories: userData.repositories.edges.map((repo: any) => ({ name: repo.node.name, url: repo.node.url, created: repo.node.createdAt, description: repo.node.description, language: repo.node.primaryLanguage.name, stars: repo.node.stargazers.totalCount, })), }; // Return formatted resume data return NextResponse.json(resumeData); } catch (error) { console.error("Error fetching data from GitHub:", error); return NextResponse.json({ message: "Internal Server Error" }); } } ``` **步驟 3:** 在應用程式資料夾中,建立一個名為 Components 的資料夾。然後,在元件資料夾中建立一個名為 githubdata.tsx 的檔案並新增以下程式碼。 ``` "use client"; import React, { useEffect, useState } from "react"; import axios from "axios"; // Resume data interface interface ResumeData { name: string; email: string; company: string; bio: string; repositories: { name: string; url: string; created: string; description: string; language: string; stars: number; }[]; } export const useGithubData = () => { const [resumeData, setResumeData] = useState<ResumeData | null>(null); // Fetch resume data from API useEffect(() => { axios .get("/api/github") .then((response) => { setResumeData(response.data); }) }, []); return { resumeData, }; } ``` --- ## 建立求職信和履歷功能 **步驟 1:** 透過在命令列上執行以下命令來安裝 CopilotKit 前端軟體包。 ``` npm i @copilotkit/react-core @copilotkit/react-ui @copilotkit/react-textarea ``` **步驟2:** 在元件資料夾中建立一個名為resume.tsx 的檔案。然後在檔案頂端匯入 useMakeCopilotReadable、useMakeCopilotActionable 和 useGithubData 自訂掛鉤,如下所示。 ``` import React, { useState } from "react"; import { useGithubData } from "./githubdata"; import { useMakeCopilotReadable, useMakeCopilotActionable, } from "@copilotkit/react-core"; ``` **第 3 步:** 建立一個名為 CoverLetterAndResume 的元件。在元件內部,使用 useGithubData 掛鉤檢索從 GitHub 取得的資料。然後,宣告一個名為 createCoverLetterAndResume 的狀態變數和一個用於更新它的名為 setCreateCoverLetterAndResume 的函數。使用包含 letter 和 resume 兩個屬性的物件初始化 useState,如下所示。 ``` export const CoverLetterAndResume = () => { const {resumeData } = useGithubData(); const [createCoverLetterAndResume, setCreateCoverLetterAndResume] = useState({ letter: "", resume: "" }); } ``` **步驟 4:** 使用 useMakeCopilotReadable 掛鉤將從 GitHub 取得的資料新增為應用程式內聊天機器人的上下文。 ``` useMakeCopilotReadable(JSON.stringify(resumeData)); ``` **步驟 5:** 使用 useMakeCopilotActionable 掛鉤設定一個名為 createCoverLetterAndResume 的操作,其中包含描述和實作函數,該函數使用提供的求職信和簡歷更新 createCoverLetterAndResume 狀態,如下所示。 ``` useMakeCopilotActionable( { name: "createCoverLetterAndResume", description: "Create a cover letter and resume for a software developer job application.", argumentAnnotations: [ { name: "coverLetterMarkdown", type: "string", description: "Markdown text for a cover letter to introduce yourself and briefly summarize your professional background as a software developer.", required: true, }, { name: "resumeMarkdown", type: "string", description: "Markdown text for a resume that displays your professional background and relevant skills.", required: true, }, ], implementation: async (coverLetterMarkdown, resumeMarkdown) => { setCreateCoverLetterAndResume((prevState) => ({ ...prevState, letter: coverLetterMarkdown, resume: resumeMarkdown, })); }, }, [] ); ``` **步驟 6:** 在 CoverLetterAndResume 元件外部,建立一個名為 CoverLetterResume 的元件,用於在 Web 應用程式 UI 上顯示求職信和履歷。 ``` type CoverLetterResumeProps = { letter: string; resume: string; }; const CoverLetterResume = ({ letter, resume }: CoverLetterResumeProps) => { return ( <div className="px-4 sm:px-6 lg:px-8 bg-slate-50 py-4"> <div className="sm:flex sm:items-center"> <div className="sm:flex-auto"> <h1 className="text-3xl font-semibold leading-6 text-gray-900"> ResumeBuilder </h1> </div> </div> {/* Cover Letter Start */} <div className="mt-8 flow-root bg-slate-200"> <div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> <div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8"> <div> <h2 className="text-lg font-semibold leading-6 text-gray-900 mb-4 p-2"> Cover Letter </h2> <div className="min-w-full divide-y divide-gray-300 p-2"> {/* <Thead /> */} <div className="divide-y divide-gray-200 bg-white p-2"> <ReactMarkdown>{letter}</ReactMarkdown> </div> </div> </div> </div> </div> </div> {/* Cover Letter End */} {/* Cover Letter Preview Start */} <div className="mt-8 flow-root bg-slate-200"> <div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> <div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8"> <div> <h2 className="text-lg font-semibold leading-6 text-gray-900 mb-4 p-2"> Cover Letter Preview </h2> <div className="min-w-full divide-y divide-gray-300"> {/* <Thead /> */} <div className="divide-y divide-gray-200 bg-white"> <textarea className="p-2" id="coverLetter" value={letter} rows={20} cols={113} /> </div> </div> </div> </div> </div> </div> {/* Cover Letter Preview End */} {/* Resume Start */} <div className="mt-8 flow-root bg-slate-200"> <div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> <div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8"> <h2 className="text-lg font-semibold leading-6 text-gray-900 mb-4 p-2"> Resume </h2> <div className="min-w-full divide-y divide-gray-300"> {/* <Thead /> */} <div className="divide-y divide-gray-200 bg-white"> <ReactMarkdown>{resume}</ReactMarkdown> </div> </div> </div> </div> </div> {/* Resume End */} {/* Cover Letter Preview Start */} <div className="mt-8 flow-root bg-slate-200"> <div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> <div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8"> <div> <h2 className="text-lg font-semibold leading-6 text-gray-900 mb-4 p-2"> Cover Letter Preview </h2> <div className="min-w-full divide-y divide-gray-300"> {/* <Thead /> */} <div className="divide-y divide-gray-200 bg-white"> {/* {letter} */} {/* <ReactMarkdown>{letter}</ReactMarkdown> */} <textarea className="p-2" id="resume" value={resume} rows={20} cols={113} /> </div> </div> </div> </div> </div> </div> {/* Cover Letter Preview End */} </div> ); }; ``` **第7步:**然後返回CoverLetterAndResume元件內的CoverLetterResume元件,如下圖所示。 ``` return <CoverLetterResume {...createCoverLetterAndResume}/>; ``` **第8步:** 在應用程式資料夾中建立一個名為resumeandcoverletter的資料夾。然後,建立一個名為 page.tsx 的檔案並新增以下程式碼。 ``` "use client"; import { CopilotProvider } from "@copilotkit/react-core"; import { CopilotSidebarUIProvider } from "@copilotkit/react-ui"; import "@copilotkit/react-textarea/styles.css"; // also import this if you want to use the CopilotTextarea component import "@copilotkit/react-ui/styles.css"; // also import this if you want to use the chatbot component import React, { useEffect, useState } from "react"; import { CoverLetterAndResume } from "../components/resume"; function buildResume () { return ( <CopilotProvider chatApiEndpoint="./../api/copilotkit/chat"> <CopilotSidebarUIProvider> <CoverLetterAndResume /> </CopilotSidebarUIProvider> </CopilotProvider> ); } export default buildResume; ``` **步驟 9:** 使用下列指令安裝 openai 軟體套件。 ``` npm i openai ``` **步驟 10:** 在應用程式資料夾中,建立一個名為 API 的資料夾。然後,在 API 資料夾中建立一個名為 copilotkit 的資料夾。在 copilotkit 資料夾中,建立一個名為 chat 的資料夾。然後,在聊天資料夾中建立一個名為route.ts的檔案並新增以下程式碼。 ``` import OpenAI from "openai"; const openai = new OpenAI({ apiKey: "Your ChatGPT API key", }); export const runtime = "edge"; export async function POST(req: Request): Promise<Response> { try { const forwardedProps = await req.json(); const stream = openai.beta.chat.completions .stream({ model: "gpt-4-1106-preview", ...forwardedProps, stream: true, }) .toReadableStream(); return new Response(stream); } catch (error: any) { return new Response("", { status: 500, statusText: error.error.message }); } } ``` **步驟 11:** 在應用程式資料夾中的 page.tsx 檔案中,在「開始」按鈕中新增一個連結,用於導航到簡歷和求職信頁面,如下所示。 ``` <div className="text-center"> <Link className="inline-flex justify-center items-center gap-x-3 text-center bg-gradient-to-tl from-blue-600 to-violet-600 shadow-lg shadow-transparent hover:shadow-blue-700/50 border border-transparent text-white text-sm font-medium rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white py-3 px-6 dark:focus:ring-offset-gray-800" href="/resumeandcoverletter"> Get started <svg className="flex-shrink-0 w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="m9 18 6-6-6-6" /> </svg> </Link> </div> ``` **第12步:**導航至http://localhost:3000/,點擊「開始」按鈕,您將被重新導向到與聊天機器人整合的履歷和求職信頁面,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqfjykc75pherkjxut4p.png) **第 13 步:** 向右側的聊天機器人發出諸如“建立求職信和簡歷”之類的提示。聊天機器人將開始產生回應,完成後,它將在頁面左側顯示產生的求職信和履歷,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7muhhi4a85ol0ddyi1l.png) --- ## 建立更新求職信功能 **第 1 步:** 宣告一個名為 updateLetter 的變數,用於保存先前產生的求職信。 ``` const updateLetter = createCoverLetterAndResume.letter; ``` **步驟 2:** 使用 useMakeCopilotReadable 掛鉤新增 updateLetter 作為應用程式內聊天機器人的上下文。 ``` useMakeCopilotReadable("Cover Letter:" + JSON.stringify(updateLetter)); ``` **步驟 3:** 使用 useMakeCopilotActionable 掛鉤設定一個名為 updateCoverLetter 的操作,其中包含描述和實作函數,該函數使用提供的求職信更新來更新 createCoverLetterAndResume 狀態,如下所示。 ``` useMakeCopilotActionable( { name: "updateCoverLetter", description: "Update cover letter for a software developer job application.", argumentAnnotations: [ { name: "updateCoverLetterMarkdown", type: "string", description: "Update markdown text for a cover letter to introduce yourself and briefly summarize your professional background as a software developer.", required: true, }, { name: "resumeMarkdown", type: "string", description: "Markdown text for a resume that displays your professional background and relevant skills.", required: true, }, ], implementation: async (updatedCoverLetterMarkdown) => { setCreateCoverLetterAndResume((prevState) => ({ ...prevState, letter: updatedCoverLetterMarkdown, })); }, }, [] ); ``` ** 步驟 4:** 給聊天機器人一個提示,例如“更新求職信並加入我正在申請 CopilotKit 的技術寫作職位。”如下圖所示,您可以看到求職信已更新。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dkm8zacgbmn19j9qtw6.png) --- ## 建立更新復原功能 **第 1 步:** 宣告一個名為 updateResume 的變數,用於保存先前產生的求職信。 ``` const updateResume = createCoverLetterAndResume.resume; ``` **步驟 2:** 使用 useMakeCopilotReadable 掛鉤新增 updateResume 作為應用程式內聊天機器人的上下文。 ``` useMakeCopilotReadable("Resume:" + JSON.stringify(updateResume)); ``` **步驟 3:** 使用 useMakeCopilotActionable 掛鉤設定一個名為 updateResume 的操作,其中包含描述和實作函數,該函數使用提供的求職信更新來更新 createCoverLetterAndResume 狀態,如下所示。 ``` useMakeCopilotActionable( { name: "updateResume", description: "Update resume for a software developer job application.", argumentAnnotations: [ { name: "updateResumeMarkdown", type: "string", description: "Update markdown text for a resume that displays your professional background and relevant skills.", required: true, }, ], implementation: async (updatedResumeMarkdown) => { setCreateCoverLetterAndResume((prevState) => ({ ...prevState, resume: updatedResumeMarkdown, })); }, }, [] ); ``` **第 4 步:** 向聊天機器人發出提示,例如「更新履歷並將我的姓名加入為 John Doe,將我的電子郵件加入為 [email protected]」。如下圖所示,可以看到履歷已更新。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2d9y6pmfynxwzff8be86.png) --- ## 建立下載求職信和履歷表 Pdfs 功能 **第 1 步:** 安裝 jsPDF,一個用 JavaScript 產生 PDF 的函式庫。 ``` npm i jspdf ``` **步驟 2:** 在 CoverLetterAndResume 元件內,使用 useMakeCopilotActionable 掛鉤設定一個名為“downloadPdfs”的操作,其中包含描述和實現函數,該函數使用 jsPDF 庫為求職信和簡歷建立 PDF,然後保存它們, 如下所示。 ``` function addTextToPDF(doc: any, text: any, x: any, y: any, maxWidth: any) { // Split the text into lines const lines = doc.splitTextToSize(text, maxWidth); // Add lines to the document doc.text(lines, x, y); } useMakeCopilotActionable( { name: "downloadPdfs", description: "Download pdfs of the cover letter and resume.", argumentAnnotations: [ { name: "coverLetterPdfA4", type: "string", description: "A Pdf that contains the cover letter converted from markdown text and fits A4 paper.", required: true, }, { name: "resumePdfA4Paper", type: "string", description: "A Pdf that contains the resume converted from markdown text and fits A4 paper.", required: true, }, ], implementation: async () => { const marginLeft = 10; const marginTop = 10; const maxWidth = 180; const coverLetterDoc = new jsPDF(); addTextToPDF( coverLetterDoc, createCoverLetterAndResume.letter, marginLeft, marginTop, maxWidth ); coverLetterDoc.save("coverLetter.pdf"); const resumeDoc = new jsPDF(); addTextToPDF( resumeDoc, createCoverLetterAndResume.resume, marginLeft, marginTop, maxWidth ); resumeDoc.save("resume.pdf"); }, }, [createCoverLetterAndResume] ); ``` **第 3 步:** 返回網頁應用程式中的聊天機器人,並提示「下載求職信和簡歷的 pdf 檔案」。 PDF 將開始下載,如果您開啟 coverLetter.pdf,您應該會看到產生的求職信,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4p853urbqn43jh6454at.png) --- ## 結論 總而言之,您可以使用 CopilotKit 建立應用內 AI 聊天機器人,該機器人可以查看當前應用程式狀態並在應用程式內執行操作。 AI 聊天機器人可以與您的應用程式前端、後端和第三方服務對話。 對於完整的源程式碼: https://github.com/TheGreatBonnie/AIPoweredResumeBuilder --- 原文出處:https://dev.to/copilotkit/how-to-build-the-with-nextjs-openai-1mhb

伺服器端渲染的優缺點。何時使用它以及何時選擇其他東西

--- 標題:伺服器端渲染的優點和缺點。何時使用它以及何時選擇其他東西 發表:真實 描述:伺服器端渲染的優缺點。何時使用它以及何時選擇其他東西 標籤:[react、javascript、webdev、ssr] 封面圖:https://thepracticaldev.s3.amazonaws.com/i/pr5kh72wjga9rplx6c2z.jpg --- > 攝影:Daniel H. Tong 在 Unsplash 上 ## 什麼是 SSR?為什麼要關心? SSR 代表伺服器端渲染。我將主要討論 React,但我想這對其他框架也有意義。 如果您關心以下內容,則需要 SSR: - **第一次有意義的繪畫**。僅 SSR 並不能保證良好的結果。您還需要關鍵的 CSS 和接近客戶等。 - **SEO** 並支援其他機器人,如 Twitter 和 Facebook - **優雅降級**。對於這一點,您需要確保您的服務無需 JS 即可使用 ## 這有什麼難的? SSR 就像一個新的維度。無論您使用什麼,都需要為 SSR 重新配置它。 - 您是否使用「componentDidMount」來取得資料?您需要使用“getInitialProps”(來自 next.js 或 after.js)或 Redux 等狀態管理庫來使其在伺服器上執行 - 你使用路由器嗎?需要在伺服器上進行配置 - 你使用 i18n 嗎?需要在伺服器上進行配置 - 你使用 HMR 嗎?您將需要重新載入瀏覽器和伺服器的程式碼 - 你使用反應頭盔嗎?需要在伺服器上進行配置 - 你使用react-loadable嗎?您需要配置伺服器以傳遞使用的模組,以便客戶端可以預先載入它們 - 你使用 Redux 嗎?您需要序列化儲存並將其傳遞給客戶端 - 你使用 CSS-in-JS 嗎?您需要將其配置為在伺服器上產生關鍵 CSS 並將其內聯到 HTML 回應中 別誤會我的意思,這都是可以解決的。 Next.js 和 Razzle 解決了大部分問題。我想向您展示的是 SSR 如何將所有內容加倍(另一個維度),並且大多數時候都需要樣板。 好的。現在讓我們超越利益。 ## 第一個有意義的油漆 如果你正在做 SSR,這並不意味著你會得到開箱即用的第一個有意義的油漆。 - 您的設定是否有良好的第一個位元組時間?如果您的伺服器速度緩慢或過載 - 您將會遇到問題。確保使用最新的節點,縮小伺服器程式碼,[使用串流渲染](https://zeit.co/blog/streaming-server-rendering-at-spectrum),最佳化子查詢(資料庫或網路)(如果有) 。 - 你們有提供關鍵的 CSS 嗎?否則,瀏覽器無法開始渲染頁面。 - 你使用網頁字體嗎?如果是,你會[優化](https://www.zachleat.com/web/compressive-webfonts/)嗎? - 你的伺服器靠近客戶端嗎? **如果您的伺服器在歐洲,但客戶端在日本,SSR 將無法幫助您**。從 CDN 提供「shell」可能會比 SSR 更快(從印象的角度來看)。如果因為法律限制您無法將伺服器移至離客戶端更近的地方怎麼辦? - 您是否確保沒有不必要的重定向?否則,在慢速 3G 上重定向將毀掉你好不容易獲得的毫秒數。 SSR 並不是首次有意義的繪製的靈丹妙藥。如果您的後端很慢或距離很遠,您需要檢查「shell」和 CDN 是否可以更好地工作。您可以使用 [react-snap](https://github.com/stereobooster/react-snap) 之類的東西來預渲染靜態頁面並為其他頁面產生「shell」。 如果您的網站往往更靜態,您可以使用預渲染而不是 SSR。查看[react-static](https://react-static.js.org/) 或[gatsby](https://www.gatsbyjs.org/) 或[react-snap](https://github.com /react-snap)。com/stereobooster/react-snap)。 ## 這 這裡有3個選項: - 固態繼電器 - 預先渲染,如react-snap、react-static、gatsby等。 - 按需預渲染,如 rendertron、puppetron、pupperender 等。 如果可以的話,選擇預渲染。如果您唯一關心的是 SEO,則可以隨時輕鬆加入按需預渲染。 ## 優雅降級 這一點很棘手。這實際上取決於您想要實現多少降級? - 你想支持連結嗎?這應該可以工作 - 你想像 https://www.seek.com.au/ 那樣支援下拉式選單嗎?你需要使用 CSS 和複選框的一些技巧 - 您需要支援表格嗎?除了現有的 JSON API 之外,您還需要端點來處理這些表單 有些功能沒有 JS 是相當困難的,例如組合框或地圖 ## 結論 SSR不錯,可以試試看。另外,請確保您的用戶真正從中受益。 如果您無法使用 SSR,請嘗試預渲染器,有時這是最簡單的選擇。 在 [twitter](https://twitter.com/stereobooster) 和 [github](https://github.com/stereobooster) 上關注我。 --- 原文出處:https://dev.to/stereobooster/server-side-rendering-or-ssr-what-is-it-for-and-when-to-use-it-2cpg

讓我們加密:使用 Certbot 的通配符憑證

--- 標題:讓我們加密:使用 Certbot 的通配符憑證 發表:真實 說明:Let's Encrypt 使用 DNS-01 質詢透過 ACMEv2 支援通配符憑證,該質詢於 2018 年 3 月 13 日開始。其用戶端 Certbot 提供 --manual 選項來執行此操作。我寫瞭如何使用 Certbot 產生通配符憑證。 標籤: LetsEncrypt、 certbot、 憑證、 安全 封面圖片:https://thepracticaldev.s3.amazonaws.com/i/wxi7s3zr664nv3u5d2ig.jpg 系列:OpenBSD TLS 連接 --- *\* 封面圖片最初由 [OpenClipart-Vectors](https://pixabay.com/users/OpenClipart-Vectors-30363/) 製作並經過精心編輯。* --- ## 介紹 [Let's Encrypt](https://letsencrypt.org/) 透過 ACMEv2 支援[通配符憑證](https://letsencrypt.org/docs/faq/#does-let-s-encrypt-issue-wildcard-certificates) [ DNS-01 挑戰](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge),[於2018 年3 月13 日開始](https://letsencrypt.org/2017/ 07 /06/wildcard-certificates-coming-jan-2018.html)。 [Certbot](https://certbot.eff.org/),其客戶端,提供「--manual」選項來[執行](https://certbot.eff.org/faq/#does-let- s -加密-頒發-通配符-憑證)。 我真誠地感謝他們。 我寫瞭如何使用 Certbot 產生通配符憑證。 這是一個非常簡單的任務:) 此外,所需要做的就是將 Certbot 指定的 TXT 記錄新增至 DNS 伺服器。 \* 注意:[有必要每 90 天更新一次 Let's Encrypt 的憑證](https://letsencrypt.org/docs/faq/#what-is-the-lifetime-for-let-s-encrypt-certificates- for -how-long-are-they-valid),[每次續約時都需要新的TXT 記錄](https://community.letsencrypt.org/t/how-to-renew-wildcard-cert-with- cert -機器人自動/60723)。 ## 身體 #### 環境 - [OpenBSD](https://www.openbsd.org/): [6.5](https://www.openbsd.org/65.html) - 憑證機器人:0.32.0 #### 教程 命令是這樣的: ``` # certbot certonly --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual-public-ip-logging-ok -d '*.<your.domain>' -d <your.domain> ``` 確保引用 `*.<your.domain>` 以避免錯誤「未找到符合專案:*.\<your.domain\>」。 *\* 注意:`-d *.<your.domain>` 和 `-d <your.domain>` 的順序似乎不重要。* 以下是「certonly」選項與單一憑證的比較: ``` - --webroot -w <dir-path> + --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual-public-ip-logging-ok ``` 此外,其命令列選項的詳細資訊請參閱[此處](https://certbot.eff.org/docs/using.html#certbot-command-line-options)。 然後,命令回覆: ``` Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator manual, Installer None Obtaining a new certificate Performing the following challenges: dns-01 challenge for <your.domain> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please deploy a DNS TXT record under the name _acme-challenge.<your.domain> with the following value: <acme-challenge-value> Before continuing, verify the record is deployed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Press Enter to Continue ``` 配置 DNS 伺服器以將記錄新增至您的網域。 記錄是這樣的: |哪裡 |什麼 | | -----| --- | |類型 |文字 | |名稱 | `_acme-挑戰` | |價值| \<acme-challenge-value\> 指令顯示如上 | *\* 注意:您可能會在這裡等待一段時間以進行 DNS 傳播。* 然後按 Enter 鍵。 ``` Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/<your.domain>/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/<your.domain>/privkey.pem Your cert will expire on 2019-08-01. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le ``` 完畢 : ) ## 結論 因此,我獲得了通配符憑證並應用於我的幾台伺服器。 今天它運作良好,我的工作量減少了,安全性幾乎相同。 如果您正在尋找如何將 Let's Encrypt 的憑證應用到 OpenBSD httpd 伺服器,我在這裡寫道: {% 連結 nabbisen/lets-encrypt-certbot-for-openbsds-httpd-3ofd %} 感謝您的閱讀。 快樂安全。 --- 原文出處:https://dev.to/nabbisen/let-s-encrypt-wildcard-certificate-with-certbot-plo

React 和 NextJS 2024 最佳免費開源 SaaS 初學者

## 長篇大論;博士 SaaS 樣板啟動器隨處可見,但它們非常昂貴(約 200-800 美元)。 我想為 React 和 NextJS 找到最好的免費開源 SaaS Starters,這些 Starters 將在 2024 年積極維護。 在下面的文章中,我將介紹每個初學者的功能及其優缺點,所以如果您有興趣,請繼續閱讀。但我還在下面整理了這個漂亮的圖表,可以一目了然地對它們進行比較(順便說一句,文章底部有同一圖表的文本版本,帶有可點擊的連結)。 享受! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wr6z6jqmypnl5hzrgyr1.png) ## 介紹 軟體即服務 (SaaS) 應用程式是獨立駭客和個人企業家賺錢的最佳方式之一。這就是為什麼 SaaS 樣板啟動器正在崛起!但其中一些售價高達 2,000 美元以上,平均價格約為 200 美元。 這就是為什麼我開始尋找是否有免費的開源 SaaS 啟動器以及它們的表現如何。在找到了很多但注意到大多數不再積極維護後,我將範圍縮小到這四個免費的開源 SaaS Starter:BoxyHQ 的 SaaS Starter、Open SaaS、SaaS Starter Kit 和 Next SaaS Stripe Starter。 ## BOXYHQ SaaS 入門套件 “**您的終極企業級 Next.js 樣板”** ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51svaqq6lu6s3ldoy5i0.png) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xd6cftpnl9robmmtw36b.png) - GitHub:https://github.com/boxyhq/saas-starter-kit - 影片演練:[https://www.youtube.com/watch?v=oF8QIwQIhyo](https://www.youtube.com/watch?v=oF8QIwQIhyo) BoxyHQ 是一家專注於安全的公司,專注於單一登入 (SSO) 和企業安全解決方案。因此,這個 SaaS 入門套件雖然免費且開源,但更專注於企業需求也就不足為奇了。 因此,如果您正在尋找一個外觀簡潔、具有安全 SAML SSO、使用者帳戶建立、團隊建立和管理以及 Webhooks 和事件整合功能的樣板,那麼這就是您的範本。 優點: - SAML 單一登入 - 全面的角色和權限 - 專注於企業SaaS應用程式開發 缺點: - 更適合企業級應用程式,這對於較小的專案來說可能有點過分 - 一些即將推出的功能(例如計費和訂閱)尚未實現 ## 開放 SaaS 「***免費*具有超能力的 SaaS 範本」** ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/awz3renuql3k5awlvkms.png) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ptji6f1viufkonb3bzw.png) - 網站與示範:https://OpenSaaS.sh - Github:https://github.com/wasp-lang/open-saas Open SaaS 專注於建立一個功能齊全的開源 SaaS 樣板,它擁有您期望從付費模板中獲得的一切,包括整合的人工智慧。範例、為您的網站流量和收入統計配置的分析儀表板以及完整的文件和支援。 它由 Wasp 團隊為您帶來,這是一個全端 React / NodeJS / Prisma 框架,可透過設定檔為您管理功能。例如,這意味著您只需幾行程式碼即可“推出您自己的身份驗證”,因為 Wasp 會為您管理樣板檔案。 優點: - 利用Wasp進行全端開發,減少開發時間 - 擁有完整的文件和多元化且支持性的社區 - 與 OpenAI API 集成,並包含人工智慧驅動的應用程式範例 - 開箱即用的端到端類型安全 缺點: - 可能缺少一些更廣泛的 SaaS 應用程式功能,例如測試 - 依賴 Wasp,一個鮮為人知但高效能的全端框架 ## SaaS 入門套件 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdy7kkxnwvddia1qcxii.png) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vqikv8rshdqq0yj1sas6.png) - 網站與示範:[https://www.saasstarterkit.com/](https://www.saasstarterkit.com/) - GitHub:[https://github.com/Saas-Starter-Kit](https://github.com/Saas-Starter-Kit) SaaS 入門套件是一個現代 SaaS 樣板,旨在建立具有免費/開源和專業/付費選項的全面 SaaS 解決方案。 這是一個簡單、乾淨的 UI,包含許多漂亮的 UI 元件,包括 Shadcn UI 分析儀表板元件。但不幸的是,您必須將它們與您自己的資料來源集成,因為大多數樣板都沒有管道。 目前它缺少很多配置,但看起來它在未來可能是一個有前途的模板 優點: - 提供免費版和專業版,使其能夠滿足多種需求 - 精心設計的 UI 元件,專門用於管理儀表板 缺點: - 具有增強功能的專業版不是免費的,這可能會讓一些用戶望而卻步 - 主要是內建Auth的UI元件集合,所以開發者還需要做很多工作 ## 下一個 SaaS Stripe 入門者 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ui7rg0yqafp9mf5nki0d.png) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pd9uqi903h358oqu37w9.png) - 網站與示範:[https://next-saas-stripe-starter.vercel.app/](https://next-saas-stripe-starter.vercel.app/) - GitHub:https://github.com/mickasmt/next-saas-stripe-starter Next SaaS Stripe Starter 是一個簡單、乾淨的 SaaS 樣板,可利用現代、流行的工具。儘管它不像其他一些軟體那麼功能齊全,但由於使用了 Shadcn UI 和 Contentlayer,它看起來很漂亮,並且有一個時尚的部落格。一般來說,它處於良好的狀態,可以用作 SaaS 的基礎。 如果您正在尋找一個最小的 NextJS 模板並且可以進行大量自訂和功能開發,那麼這就是適合您的模板。 優點: - 看起來不錯並且利用了各種流行的工具。 - 它包括未來的更新,涵蓋成功訂閱和切換訂閱計劃的重新發送功能。 缺點: - 很少甚至沒有文件 - 不像其他模板那樣功能豐富。 ##六。結論與建議 雖然所有 SaaS Starter 都為您的專案提供了良好的基礎,但如果您正在開發企業級應用程式,請考慮 BOXYHQ。如果您正在尋找可立即投入生產的模板並希望快速交付,那麼 Open SaaS 將是理想的整體模板,而如果您正在建置簡單/微型 SaaS 並且想要現代設計美感,則 Next SaaS Stripe Starter 則適合您。 | | [BoxyHQ SaaS 入門套件](https://github.com/boxyhq/saas-starter-kit) | [開放SaaS](https://opensaas.sh) | [SaaS 入門套件](https://www.saasstarterkit.com/) | [下一個 SaaS Stripe 入門](https://next-saas-stripe-starter.vercel.app/) | | --- | --- | --- | --- | --- | | **適合** | 🏢 📈<br/>企業。對於需要 Teams 功能的應用程式 | 🧑‍💻🤖 <br/>獨立駭客和新創公司快速建立現代 (AI) 應用程式 | 🧑‍💻🔧 <br/>獨立駭客正在尋找優秀的 UI 元件集合 | 🧑‍💻🎨 <br/>獨立駭客正在尋找簡約、時尚的 SaaS 樣板。 | | **易於使用** | 6/10 <br/>複雜,以企業為中心。 | 8/10 <br/>精簡且快速。有據可查。 | 5/10 <br/>需要大量額外設定。 | 7/10 <br/>良好的基礎,但缺乏一些功能 | | **授權** |透過 Auth.js 驗證電子郵件、SAML SSO、Google、Github |電子郵件已驗證,Google,Github 透過 Wasp w/ Lucia |電子郵件、Google 透過 Auth.js |谷歌透過 Auth.js | | **管理儀表板** |限團隊管理 |內建和預先配置的網站和收入分析 |用於收入分析的 UI 元件(未配置) |無 | | **付款** |否(即將推出)|條紋| Stripe(+ Lemonsqueezy 付費版)|條紋| | **分析** |透過 Mixpanel 進行第 3 方(付費)|合理(免費、開源)或 Google | Vercel 分析(付費)| Vercel 分析(付費)| | **人工智慧.準備好了** |沒有 |內建 AI 支援 https://opensaas.sh (OpenAI API) |沒有 |沒有 | | **端對端類型安全性** |沒有 |是的 |沒有 |沒有 | | **電子郵件發送器** |郵件發送 | SendGrid、EmailGun 或 SMTP |重新發送 |重新發送 | | **內建部落格** |沒有 |是(透過 https://astro.build/)|否(付費版本,是)|是(透過 https://contentlayer.dev/)| | **造型** |順風|順風| Tailwind,Shadcn ui | Tailwind,Shadcn ui | | **使用者介面與設計** |基本 |款式好看|帶有漂亮 UI 元件的基本 |現代、時尚的造型| | **社區支持** | https://discord.gg/uyb7pYt4Pa | https://discord.gg/aCamt5wCpS | https://www.reddit.com/r/saas_kit/(發佈時沒有討論)|無 | | **文件** |基本 |非常詳細|基本 |可憐| | **演示應用程式** |無 | https://opensaas.sh | https://www.saasstarterkit.com/ | https://next-saas-stripe-starter.vercel.app/ | https://next-saas-stripe-starter.vercel.app/ --- 原文出處:https://dev.to/vincanger/best-free-open-source-saas-starters-for-react-nextjs-2024-4nbn

😎 2024 年值得關注的 9 個熱門開源專案

身為一名熱衷於開源的開發人員,我不斷關注新興的專案、函式庫和服務。 你知道那些,似乎有那種特殊的醬汁。 ![燈泡時刻](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aj2mtk0t0oa7doj1midk.gif) 我整理了一份小清單,列出了我在新的一年中看到的趨勢或預期的趨勢。 讓我們來看看我最近遇到的一些最令人驚訝和印象深刻的專案。 ## 1. [Wing](https://github.com/winglang/wing) ![翼](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kj3n6z4negxh2rvthj3a.gif) Wing 開發了一種名為 **[Winglang](https://www.winglang.io/)** 的面向雲端的程式語言,專門用於解決雲端開發人員面臨的需求和挑戰。 將基礎設施和執行時程式碼組合成一種語言,並具有內建的本機模擬器以及可觀察性和偵錯控制台。 Wing 減少了認知負荷和上下文切換,使開發人員能夠保持創作流程。 Wing 如何促進您的發展: - 更快的迭代周期 - 透過機翼模擬器進行在地化測試 - 透過編寫更少的程式碼部署到雲端 {% cta https://dub.sh/wing-cloud %} 請star ⭐ Winglang {% endcta %} <小時/> ## 2. [也許](https://dub.sh/wing-cloud) ![也許](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8sdivkavkiuht8tgtsuq.gif) Maybe 最近開源了他們的個人理財 + 財富管理應用程式 一些功能包括: - 投資標桿 - 投資組合分配 - 債務洞察 {% cta https://github.com/maybe-finance/maybe %} 請加註星標 ⭐ 也許 {% endcta %} <小時/> ## 3. [Wstunnel](https://github.com/erebe/wstunnel?tab=readme-ov-file) ![Wstunnel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24jmmutuudqssociwxg9.gif) Wstunnel使用與http相容的WebSocket協定來繞過防火牆和代理程式。 這允許您傳輸您想要的任何流量並存取您需要的任何資源/網站。 {% cta https://github.com/erebe/wstunnel?tab=readme-ov-file %} 請加註星標 ⭐ wstunnel {% endcta %} <小時/> ## 4. [Spotube](https://github.com/KRTirtho/spotube) ![wstunnel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nhcqt9wvdd0lchc3tsut.gif) 開源、跨平台的 Spotify 用戶端,利用 Spotify 的資料 API 和 YouTube(或 Piped.video 或 JioSaavn)作為音訊來源,跨多個平台相容, 不再需要 Spotify Premium。 順便說一句,這不是另一個 Electron 應用程式😉 {% cta https://github.com/KRTirtho/spotube %} 請加註星標 ⭐ Spotube {% endcta %} <小時/> ## 5. [柔術](https://github.com/martinvonz/jj) ![Jujutzu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcy49y6dpnwav2t4i8mw.gif) Jujutsu 是一個軟體專案的版本控制系統,以 Rust 編寫。 您用它來: - 取得/複製您的程式碼 - 追蹤程式碼的更改 - 發布這些變更以供其他人查看和使用。 {% cta https://github.com/martinvonz/jj %} 請star ⭐ Jujutsu {% endcta %} <小時/> ## 6. [黃蜂](https://github.com/wasp-lang/wasp) ![黃蜂](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1f3vyg7g6gn0wke26g9h.gif) Wasp(Web 應用程式規格)是一個類似 Rails 的 React、Node.js 和 Prisma 框架。 在一天之內建立您的應用程式並使用單一 CLI 命令進行部署! - 快速開始 - 無樣板 - 沒有鎖定 {% cta https://github.com/wasp-lang/wasp %} 請加註星 ⭐ 黃蜂 {% endcta %} <小時/> ## 7. [最佳化](https://github.com/refinedev/refine) ![精煉](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/atf3c2rldmw5zsk181cb.gif) 用於建立內部工具、管理面板、儀表板和 B2B 應用程式的 React 框架,具有無與倫比的靈活性。 Refine 不限於一組預先設計樣式的元件,而是提供以下集合: - 輔助掛鉤 - 成分 - 供應商 {% cta https://github.com/refinedev/refine %} 請加註星 ⭐ Refine {% endcta %} <小時/> ## 8. [DbGate](https://github.com/dbgate/dbgate) ![DbGate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3uwv1e66powp9mtli147.gif) DbGate 是一個跨平台資料庫管理器,其設計目的是在同時處理更多資料庫時使用簡單且有效率。 **支援的資料庫:** - MySQL - PostgreSQL - SQL伺服器 - 甲骨文(實驗性) - MongoDB - 雷迪斯 - SQLite - 亞馬遜紅移 - CockroachDB - 瑪麗亞資料庫 {% cta https://github.com/dbgate/dbgate %} 請star ⭐ DBGate {% endcta %} <小時/> ## 9. [ivy](https://github.com/unifyai/ivy) ![常春藤](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6z2k5064eyhfpdf3y71k.gif) Ivy是一個開源機器學習框架: - 自動調整您的模型 - 將程式碼轉換為任何框架 - 編寫與框架無關的程式碼 {% cta https://github.com/unifyai/ivy %} 請star ⭐ Ive {% endcta %} <小時/> --- 原文出處:https://dev.to/winglang/9-top-trending-open-source-projects-to-watch-for-in-2024-emb

反應性的推導

當您第一次了解反應式系統時,範例總是看起來像這樣,這是有原因的: ``` let name = state("John"); effect(() => { console.log("Hi" + name); }) ``` > *我們將使用偽程式碼,而不是為了迎合特定庫或框架的語法。* 不需要太多就能理解,當我更新此狀態時,會發生一個呼叫我的副作用的事件。自己實現這種行為也不是太困難。但這還遠遠不是故事的全部。 無論您是想忘記 React、使用 Svelte 探索符文還是想嘗試 Angular;無論您是建立 Solid 應用程式、在 Vue 中建立視圖還是生活在 QwikCity 中,這個主題都相關。它超越了虛擬 DOM 或訊號。在您認為「useEffect」被建立為每個人存在的禍根之前,讓我們先來看看反應性最重要的部分:派生。 ----------------- ## 派生與同步 您可能已經在您選擇的 JS 框架/反應系統中看到了派生值。它可能看起來像“useMemo”,或者可能是“compulated”,或者可能就在分配了值的“$”後面。但所有這些的不變之處是你被告知它們是為了產生一種反應性關係。即使 B 或 C 發生變化,A 也是 B + C 總和: ``` let a = state(1); let b = state(1); const c = memo(() => a + b); effect(() => console.log(c)); ``` 他們可能告訴您派生值應該是純粹的——也就是說它不應該寫入任何其他狀態——但該規則也適用於它的內部。 您可以先將其應用為派生狀態的心理模型: ``` function memo(fn) { let internal = state(); effect(() => internal = fn()); return internal; } ``` 但這永遠無法正常工作。 大多數 UI 框架都關心提供互動性。即取得使用者操作的輸入,將其套用到某種狀態,然後更新 UI。我們看到它形式化為“ui = fn(state)”,但這是一個重複的循環。 就反應性而言,它看起來像: > 更新狀態-> > 執行純計算 -> > 執行副作用(例如更新 DOM) 原因是最終用戶與 UI 互動需要一致性。他們看到的(和看不到的)應該全部同步。您無法與過時的頁面部分進行交互,因為它設定了錯誤的期望。 UI 庫安排其副作用同步執行,以確保最終用戶可以信任體驗。 這意味著程式碼執行有明確的階段。庫需要確保在渲染之前解決所有相關計算。 這導致了以下之間的確切區別: ``` let name = state("John"); const upperName = memo(() => name.toUpperCase()); updateUI(name, upperName); ``` ``` let name = state("John"); let upperName = state(); effect(() => upperName = name.toUpperCase()); updateUI(name, upperName); ``` 第一個例子是推導,其中推導的狀態是它所依賴的狀態的函數。第二個範例是同步,其中狀態的變更會導致其他狀態更新。這是一個重要的區別。 在第二個範例中,根據您的反應模型,可能會發生不同的事情,而不是簡單地按預期立即顯示所有內容。根據效果安排時間與 UI 渲染時間的不同,當您更新「name」時,您可能會短暫看到更新後的「name」和「upperName」的先前值。在像 React 這樣的粗粒度渲染框架中,您的元件可能會執行兩次。因為更新效果中的狀態會再次開始循環。 ---------------- ## 無故障一致性 即使您始終可以在渲染之前進行同步,您仍然有可能使用不同中間狀態(可能是意外狀態)的值多次執行表達式,直到圖形穩定下來。推導可以提供可預測性。 現在,許多反應式系統保證對於任何狀態更新,每個節點最多只執行一次,並且執行時不會出現故障。透過無故障,開發人員向庫提供的程式碼永遠不會觀察到中間或過時狀態。 考慮: ``` let a = state(1); const b = memo(() => a + 1); const c = memo(() => a + 1); const d = memo(() => c + 1); const e = memo(() => b + d); effect(() => console.log(e)); ``` 或作為圖表 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kg9w4yehyeqhgry1wkvk.png) 不同的系統運作方式不同,但在所有情況下,我們期望初始執行產生值為 5 的「e」。 同樣清楚的是,某些狀態依賴其他狀態。當我們更新“a = 2”時,無論機制如何,如果我們只想執行每個節點一次,“c”必須在“d”之前解析,“d”必須在“e”之前解析。 ---------------- ## 推與拉 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1004yrongpx1usdsxe0x.jpg) 那我們要如何處理這個問題呢?它通常從以下兩個想法之一開始。調度(拉)和事件(推)。讓我們使用上一節中的範例來分別了解。 ### 拉動(調度) 這個想法是從副作用(目標)開始,然後詢問遇到的值。 React 通常被認為具有基於「拉」的反應性。在此系統中,當狀態更新時,它會安排檢查以查看是否需要執行任何工作。 但它檢查什麼?天真地,也許一切都改變了,因為它不知道發生了什麼變化。然而,許多 UI 庫都處理元件。如果狀態由元件擁有,那麼這可以作為起點。當元件狀態更新時,安排此元件運作。 基於拉動的系統是粗粒度的。也就是說,他們依賴自上而下地重播所有內容,因為他們不知道發生了什麼變化。如果我們想像一個更細粒度的「拉動」系統,它就無法知道任何變化,直到它追溯到變化的源頭,而變化的源頭可能存在於其依賴項中,也可能不存在。當最終需要向下執行時,額外的遍歷只是額外的工作。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kg9w4yehyeqhgry1wkvk.png) 在我們的範例中,圖片中我們首先執行要求“e”的效果。如果不在之前執行“b”或“d”,我們不知道“e”是否已更改。明確依賴項(如 React 的依賴項陣列)可以在不執行節點的情況下給出向上的路徑。所以我們可以回溯`e`、`b`、`a`,然後執行`b`,然後回溯`d`、`c`、`a`,然後執行`c`、`d`、 ` e` 在最終執行我們的效果之前。但考慮到我們無論如何都在執行整個範圍(元件),即使其中一部分沒有改變,這都是不必要的。 記憶(通常以推導的形式)允許提前退出,有助於優化這種情況,但這種方法雖然一致,但從根本上來說效率很低。 ### 推送(事件) 這個想法是更新從已更改的來源狀態向外傳播。 RxJS 是基於「推送」的反應性的常見範例。它將讓每個節點訂閱其依賴項中的更改事件,然後在收到通知時執行並在其值發生更改時通知其觀察者。 考慮深度優先傳播,因為它反映了最初建立時執行的方式。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kg9w4yehyeqhgry1wkvk.png) `a` 更新,通知 `b` 和 `c`。然後“b”執行並通知“e”。然後“e”執行並看到“b”的更新值,但隨後它遇到了“d”,它尚未執行並且具有舊值... 廣度優先也有類似的問題,因為「d」和「e」與來源「a」的距離相同,再次導致過時的值。它會嘗試執行“b”、“c”,然後執行“e”、“d”,結果發現“d”在“e”之前沒有被計算。 基於「推送」的系統很難確保我們有效地尋求保證。進行排序插入可以工作。但即使最後沒有任何效果器在監聽,它仍然可以工作。它確切地知道傳播時發生了什麼變化,但不知道該變化會產生什麼影響。 ### 推拉 第三種選擇是結合這兩種技術。訊號是事實上的「推拉」反應系統。訂閱和通知的製作方式類似於“推”,但工作的安排類似於基於“拉”的系統。透過這種方式,只安排會改變的事情,並且保持一致。 在我們更新“a”的範例中,“b”和“c”被通知它們可能會發生更改,進而通知“e”和“d”。最後,監聽「e」的效果被排隊。然後,我們的效果首先執行,在觸及值時拉低值,類似於我們上面描述的假設的細粒度「拉」系統。只不過這次只有可能受影響的效果才會排隊。 它知道發生了什麼變化以及這些變化的影響,確保我們只做所需的工作。 如果您對推拉演算法如何在各種訊號庫中工作的更多細節感興趣,請查看: {% 連結 https://dev.to/modderme123/super-charging-fine-grained-reactive-performance-47ph %} ---------------- ## 可以推導的應該推導 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxmqpzohmk1az3k92anp.png) 我不是 100% 確定這句話最初來自哪裡,但我第一次聽到這句話來自 MobX 的建立者 Michel Westrate。這些都是我們賴以生存的話語。 不言而喻,我們所期望的函式庫和框架的一致性僅靠狀態和效果是不可能實現的。當效果寫入狀態時,您不再可以遍歷依賴關係圖來了解需要計算的內容。依賴性消失了。這不僅僅是低效。這是很容易出錯的。 這是一個很深奧的話題。就這麼多,我只觸及了表面。 「推」與「拉」還有其他含義,即使在查看屬於同一類別的系統時也有很多細節。下一次,我們將研究惰性派生與急切派生以及處理非同步的潛力。 -------------- 特別感謝 Atila Fassina、Fabio Spampinato 和 Daniel Afonso 的審閱。 --- 原文出處:https://dev.to/this-is-learning/derivations-in-reactivity-4fo1

📈 RAG 檢索增強生成:5 個適合初學者的開源程式庫 🚀

#RAG簡介 作為開發人員,您今天可以學到的最有價值的技能之一是學習如何使用大型語言模型 (LLM) 建立檢索增強生成 (RAG) 應用程式。 ## 為什麼? 因為世界上有超過 64 ZB 的資料,這甚至不包括書籍或實體文件等實體資料。 (供您參考,1澤字節是一兆千兆位元組。) 不僅如此,全球90%的資料都是在過去兩年建立的,而且資料量每兩年就會翻倍。基本上,公司都在海量的資料中游泳,而且這些資料每天都在變得越來越大。 公司將如何存取和使用所有這些資料? 現在每個人都聽說過使用檢索增強生成(RAG)來透過人工智慧尋找資訊。能夠存取和使用不斷增長的資料量是每個公司都需要的關鍵技能。 即使您知道 RAG 基本上是描述將文件或知識連結到 LLM 的工作流程的簡寫方式,許多開發人員自己(還)還沒有嘗試或試驗過這一點。 網路上充滿了圖書館列表,但如何開始呢? 以下是幫助您開始使用 RAG 的最佳庫的簡短清單。 --- # 1. [LLMWare](https://github.com/llmware-ai/llmware) 在LLMWare中,您可以上傳文件,並透過幾行程式碼開始檢索資訊。它處理 RAG 所需的整個過程:文件攝取、解析、分塊、索引、嵌入、儲存到向量資料庫以及連結到 LLM 以檢索答案。 LLMWare 被設計為整合和端到端,因此所有這些步驟都可以開箱即用。它組裝了所有部件,因此您無需這樣做。 LLMWare 使其非常簡單且易於上手: - 只需幾行程式碼即可透過端到端範例實現 RAG 工作流程 - 建立庫並無縫載入文件 - 輕鬆產生嵌入 - 輕鬆進行語意搜尋 - 利用任何 Hugging Face 模型或 GPT-4 等封閉源模型來回答資料中的問題 - 範例包括無需 GPU 的 RAG 模型 https://github.com/llmware-ai/llmware ![LLMWARE](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy22hfga9az7uol150ar.png) --- # 2. [MongoDB](https://github.com/mongodb/mongo) MongoDB 是一種廣泛使用的開源 NoSQL 資料庫程式。它屬於以文件為導向的資料庫類別,這意味著它以類似於 JSON 文件的格式儲存和組織資料。 MongoDB 的設計具有靈活性和可擴展性,使其適合各種應用程式和行業。 資料庫(如 MongoDB)是 RAG 中非常重要的一步,因為它們在嵌入之前儲存從文件或知識庫中提取的訊息,包括重要的元資料。 https://github.com/mongodb/mongo ![MongodbVector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ii6vl3tu41gfo6v3zt5g.png) --- # 3. [Milvus 向量資料庫](https://github.com/milvus-io/milvus) Milvus 是一個開源向量資料庫,旨在為嵌入相似性搜尋和人工智慧應用程式提供支援。 Milvus 讓非結構化資料搜尋更容易存取,無論部署環境如何,都可以提供一致的使用者體驗。 Milvus DB,或類似的向量 DB,是 RAG 中至關重要的一步。它是存儲向量嵌入以進行相似性搜尋的地方。該資料庫允許人們用自然語言提出問題並檢索相關結果。如果沒有良好的嵌入和向量資料庫,LLM 模型將無法接收正確的文字區塊來讀取。 https://github.com/milvus-io/milvus ![Milvus DB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5t6jyfaidyfvxwd8nb7.png) --- # 4. [擁抱臉](https://github.com/huggingface) 如果你還沒去過 Hugging Face,你真的應該去看看。這是所有開源模型的去處,並且可以單槍匹馬地將世界從人工智慧壟斷中拯救出來。就像 Github 用於開源專案一樣,Hugging Face 用於開源模型。有超過 450,000 個模型,所有模型都免費供任何想要使用它們的人使用。 Hugging Face 的 Transformers 庫是首選庫 提供數千個預訓練模型來執行不同模式(例如文字、視覺和音訊)的任務。 這些模型可應用於: - 文本,用於文本分類、資訊提取、問答、摘要、翻譯和文本生成等任務,支援 100 多種語言。 - 影像,用於影像分類、物件偵測和分割等任務。 - 音頻,用於語音辨識和音頻分類等任務。 Transformer 模型還可以組合執行多種模式的任務,例如表格問答、光學字元辨識、從掃描文件中提取資訊、視訊分類和視覺問答。 https://github.com/huggingface ![擁抱臉](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pn47bs3bd97eu4gulkzb.png) --- #5. [Llama.cpp](https://github.com/ggerganov/llama.cpp) 沒有GPU?沒問題! Llama.cpp 來救援! llama.cpp 的主要目標是在 MacBook 上使用 4 位元整數化來執行 LLaMA 模型。 * 無依賴的純 C/C++ 實現 * Apple Silicon 一等公民 - 透過 ARM NEON、Accelerate 和 Metal 框架進行最佳化 * 對 x86 架構的 AVX、AVX2 和 AVX512 支持 * 混合F16/F32精度 * 支援2位、3位、4位、5位、6位和8位整數化 * CUDA、Metal 和 OpenCL GPU 後端支持 一旦量化,更大的模型就可以在 CPU 上執行,而效能損失很小。尋找 GGUF 版本的模型來嘗試使用 LLMWare 或其他 RAG 工作流程。 https://github.com/ggerganov/llama.cpp ![Llama.cpp](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vev1gzen7oolvnug4vfl.png) --- 這是幫助您開始使用 RAG 的非常基本的概述。如果您想要一個讓所有這些庫無縫協作的一站式整合解決方案,請造訪 LLMWare 的 GitHub 庫,找到 50 多個優秀範例來幫助您入門。 [在不和諧中找到我們](https://discord.gg/fCztJQeV7J) - 我們很樂意聽到您的來信! --- 原文出處:https://dev.to/llmware/top-5-beginner-friendly-open-source-libraries-for-rag-1mhb

SQL 查詢優化 23 倍!!!

所以我現在已經進入 Web 開發大約 3 年了,專業也有一年多了,這是我處理一個與資料庫查詢最佳化相關的問題的時候,我不是 SQL 專家,我可以得到這份工作完成。沒有花哨的查詢、觸發器、預存程序等。無論如何,我不得不穀歌搜尋最後一個。 長話短說..我們的 ORM (TypeORM) 把我們搞砸了.. ## 免責聲明: 這並不是要誹謗 TypeORM 或任何 ORM。它們是為其建置目的而設計的特殊工具。我在最後附加了一些參考連結,這些連結是人們面臨類似問題的公開討論。無論如何,讓我們繼續這篇文章。 ## 問題! 我們的提交表有超過 70 萬筆記錄,表現非常糟糕。從表中取得資料的最長時間超過 6 秒。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5dqlrbtn491upu8lwxs.png) 查詢相當簡單。我們所擁有的只是 4 個連接、幾個 where 子句(大約 4 個)、排序(在created_at time 字段上的 DESC)、限制和跳過。 ## 根本原因分析.. 導致我們的提交表大幅放緩的幾個因素如下:- - **索引** - 對用於連接表的欄位進行不正確的索引或未進行索引。 - **不必要的連接** - 我們的查詢中有一些不必要的連接,可以將其刪除以獲得更多效能。 - **空字串錯誤** - 我們程式碼中的一個錯誤,如果沒有為這些列提供使用者輸入,我們將與作為查詢的 where 條件一部分的所有列的空字串 (“”) 進行比較。 - **ORM** - ORM 正在執行一個超級愚蠢的查詢來獲取資料。 這些是我在檢查程式碼和資料庫模式以及分析正在執行以獲取所需資料的查詢時發現的精確點。 ## 對提到的每個問題進行分析和測試。 ###<u>原因 1:索引</u> 在進行了一些谷歌搜尋並閱讀了人們的類似問題後,我發現我們的問題並不是那麼大。人們正在為數百萬行而苦苦掙扎,而我們的只是其中的一小部分,所以一定是我們做錯了什麼。 早期解決這些問題的社區提出了許多建議。我發現進行適當的索引會有很大幫助。 因此,為了進行測試,我從 beta 資料庫中獲取了提交內容,該資料庫擁有大約超過 **100k 記錄**。 在沒有任何最佳化的情況下,執行整個過程平均需要 **2.3 秒**。 (當然,這個時間不僅包括在資料庫上執行查詢的時間,還包括透過網路傳播資料的時間) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2mgewrjv4khpzrst86nb.png) 在向列加入索引後,我確實發現它縮短了幾毫秒的時間,但這還不夠。它仍然在 **2 秒** 左右,而且往往不止於此。 所以有點令人失望!無論如何,繼續下一個目標。 ### <u>原因 2:空字串錯誤</u> 因此,我們的時間從 **2.3** 秒縮短到了大約 2 秒,這對於索引來說並不算多。但後來我在我們的程式碼中發現了一個小錯誤,假設有四個輸入欄位供使用者根據四個不同的列鍵入和過濾結果。如果使用者沒有在任何輸入上鍵入任何內容(主要是在頁面首次載入時),且 API 呼叫會直接取得最新資料,而不進行任何過濾,僅進行連接和排序。 因此,在那一刻,我們為資料庫中的所有列傳遞了“”字串,這似乎無害,但實際上發生的情況是,資料庫正在對所有四列進行查找,您猜對了“”字串。所以進行了大量的查找,實際上什麼都沒有。 因此,當我將其更改為空(如empty/null)時(相當於從查詢中刪除where子句),查詢時間從**2.3秒變為1.3秒**。 如果您想知道使用使用者提供的實際輸入進行過濾需要多長時間。大約**500ms**(這是可以接受的)。 結論 - 即使您的資料庫使用所有可搜尋列進行索引,“”字串也不能很好地發揮作用。 好的,我們正朝著正確的方向前進。我們整整縮短了 1 秒,但我們仍然必須將其控制在 **200/150ms** 以下,所以還有很長的路要走。 ### <u>原因 3:不必要的連接</u> 在查詢提交時,我們正在與不需要的比賽和課程表進行連接。因此,當所有內容都加入到程式碼中時,我們只是刪除了它,但這表明審閱者並沒有給予太多關注(我是其中之一)。 ### <u>原因 4:ORM</u> 這是造成最多的問題.. 好.. 問題!!. 所以有一種叫做 **主動記錄模式** 的東西,TypeORM 為我們提供了使用類似 JSON 的物件產生 SQL 查詢的東西,一個例子就是。 ``` model.find({ select: { userName : true, firstName : true }, where: { userName : “SomeUsername” }, relations: { user : true, contest: true, problem: true }, order: { created_at : “ASC/DESC” , skip: 0, take: 10, }) ``` 因此,這使得開發變得快速、簡單,對於不擅長編寫原始 SQL 查詢的開發人員來說,感覺非常直觀,因為這是最抽象的版本,您實際上是在建立 JSON 物件來產生 SQL 查詢。 這種方法看起來不錯,而且大多數時候都有效,但在我們的例子中,它做了一些非常愚蠢的事情,我不會輸入它在做什麼,這樣你就可以自己看到查詢。 簡而言之,它正在執行兩個查詢,首先對於這種情況根本不需要,它可以通過我稍後編寫並測試的一個簡單的單個查詢輕鬆完成。 它不僅執行兩個單獨的查詢(原因尚不清楚,因為這是一個已知問題,有時在使用typeorm 的活動記錄模式時發生),它還將四個表連接兩次,每個查詢一次,然後還排序兩次各一次。 (這實際上沒有任何意義) 這也是表演受到最大打擊的地方。自己看看下面的查詢。 ``` SELECT DISTINCT `distinctAlias`.`Submission_id` AS `ids_Submission_id`, `distinctAlias`.`Submission_created_at` FROM (SELECT `Submission`.`id` AS `Submission_id`, ... more selects FROM `submission` `Submission` LEFT JOIN `problem` `SubmissionSubmission_problem` ON `SubmissionSubmission_problem`.`id`=`Submission`.`problemId`  LEFT JOIN `user` `SubmissionSubmission_user` ON `Submission_Submission_user`.`id`=`Submission`.`userId`) `distinctAlias` ORDER BY `distinctAlias`.`Submission_created_at` DESC, `Submission_id` ASC LIMIT 10 ``` ``` SELECT `Submission`.`id` AS `Submission_id`, `Submission`.`language` AS `Submission_language`, `Submission`.`verdictCode` AS `Submission_verdictCode`, `Submission`.`tokens` ... shit ton of selects FROM `submission` `Submission` LEFT JOIN `problem` `SubmissionSubmission_problem` ON `SubmissionSubmission_problem`.`id`=`Submission`.`problemId`  LEFT JOIN `user` `SubmissionSubmission_user` ON `Submission_Submission_user`.`id`=`Submission`.`userId` WHERE `Submission`.`id` IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ORDER BY `Submission`.`created_at` DESC ``` 所以這兩個查詢是問題的主要原因,也是主要原因之一。 因此,我編寫了一個簡單的原始 SQL 查詢來執行與它嘗試使用 2 個單獨的查詢執行的完全相同的操作,查詢如下:- ``` SELECT   Submission.id,   Submission.language,   Submission.verdictCode, ... FROM   submission AS Submission   LEFT JOIN problem ...   LEFT JOIN user ... ORDER BY   Submission.created_at DESC LIMIT 10 ``` 當我們執行這個查詢時,它的執行時間僅為 **100ms!!!** 因此,我們現在從 **1.3** 秒移至 **100ms**,總體從 **2.3** 秒移至 **100ms** 效能提升超過 **23 倍。** 之後我就去睡覺了。仍然需要做更多的測試,並嘗試找出邊緣情況(如果有),並提出為此編寫查詢的最佳方法。目前,我正在考慮使用 TypeORM 提供的儲存庫模式或查詢建構器模式。 第二天: 又來了.. ### <u>全文索引</u> **全文索引**可以提高從這些索引列中搜尋單字和短語的效率,我們也可以嘗試一下。 (這是我的同事 Jay 提出的一個非常好的觀點,它進一步提高了表現)。 ###<u>發現了一些更重要的點。</u> 在 MySQL 中最佳化具有唯一索引的資料列上的「LIKE」查詢時,可以採用一些策略來提高效能。以下是一些建議: 1. **索引優化:** - **使用全文索引:** 如果您的「LIKE」查詢涉及在列中搜尋單字或片語,請考慮使用全文索引而不是常規唯一索引。全文索引是專門為基於文字的搜尋而設計的,可以提供更快、更準確的結果。 - **使用排序規則:** 確保列的排序規則不區分大小寫和重音。這可以透過使用「utf8_general_ci」或「utf8mb4_general_ci」等排序規則來實現。它允許更有效地利用索引,因為搜尋變得不區分大小寫和重音。 2. **查詢最佳化:** - **前綴搜尋:**如果您的`LIKE`查詢在末尾使用通配符(例如,`column LIKE 'prefix%'`),索引仍然可以有效地使用。但是,如果通配符位於開頭(例如“column LIKE '%suffix'”),則不會使用索引。在這種情況下,請考慮使用替代技術,例如全文搜尋或儲存列的反向值以實現高效的後綴搜尋。 - **最小化通配符:** 模式開頭的通配符(`'%suffix'`)會使查詢速度明顯變慢。如果可能,請嘗試建立查詢,使通配符僅出現在模式的末尾(「前綴%」)。 - **參數綁定:** 如果您從應用程式內執行「LIKE」查詢,請使用參數綁定或準備好的語句,而不是直接連接查詢字串。這有助於防止SQL注入並允許資料庫更有效地快取執行計劃。 3. **快取和查詢結果:** - **快取查詢結果:** 如果`LIKE`查詢結果相對靜態或不需要即時,可以考慮實作像memcached或Redis這樣的快取機制。快取可以透過直接從記憶體提供結果來顯著縮短反應時間。 - **物化視圖:** 如果經常執行「LIKE」查詢且資料列的資料相對靜態,請考慮建立物化視圖來預先計算並儲存「LIKE」查詢的結果。如果查詢物化視圖所帶來的效能提升超過了額外的儲存和維護需求,則此方法可能會很有用。 值得注意的是,這些優化策略的有效性可能會根據您的特定用例而有所不同。 ### 經過所有測試後建議的改進點。 1. 修正將空字串傳遞到 where/過濾條件的問題。 2. 在效能至關重要的讀取操作中,轉而使用查詢建構器而不是活動記錄模式。 3. 在用於搜尋和過濾的欄位中新增索引。另外,在不唯一且用於搜尋的列上新增全文索引。 4. 刪除/避免不必要的連線。如果可能的話,重組架構以在必要時複製資料。 5. 使用 LIKE 運算子搜尋時,使用「prefix%」模式,而不是我們使用的預設模式「%suff+pref%」。使用前綴模式有助於資料庫使用索引並提供更好的結果。 儘管如此,我們成功地將查詢時間從 **7 秒** 降低到 **<=150 毫秒**,這樣做後感覺很好,因為這是我第一次涉足性能和優化並尋找從我們已有的資源中榨取更多資源的方法。 特別感謝[Mitesh Sir](https://www.linkedin.com/in/miteshskj/) 在這次調查期間指出了潛在的原因並引導我走向正確的方向,並一遍又一遍地重新啟動測試伺服器😂因為由於記憶體限制,在多次執行測試後,資料庫會變得非常慢。 如果您想更多地談論與這一切相關的內容,請在 X 上關注我,https://twitter.com/RishiNavneet ### 參考 1. https://github.com/typeorm/typeorm/issues/3857#issuecomment-714758799 2. https://github.com/typeorm/typeorm/issues/3857 3. https://stackoverflow.com/questions/714950/mysql-performance-optimization-order-by-datetime-field 4. https://stackoverflow.com/questions/22411979/mysql-select-millions-of-rows 5. https://dba.stackexchange.com/questions/20335/can-mysql-reasonously-perform-queries-on-billions-of-rows 6. https://stackoverflow.com/questions/38346613/mysql-and-a-table-with-100-millions-of-rows 7. https://github.com/typeorm/typeorm/issues/3191 PS - 這些改進很久以前就完成了,我只是懶得發布它😬。 --- 原文出處:https://dev.to/navneet7716/optimizing-sql-queries-h9j

🏞️5 個可供學習並獲得靈感的開源網路應用程式🙇‍♀️💡

如標題所示,在這篇文章中,我們將介紹您可以學習並用作下一個專案起點的開源 Web 應用程式。堅持到最後,因為那裡有超酷的獎勵等著你! 在我們開始討論之前,先說幾句智慧之言(希望如此): ## (開源)榜樣的重要性 ![你很漂亮](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqf1wss7puysn3q0rhso.gif) **從頭開始一個新專案時,您可以做的最有幫助的事情之一就是選擇一個或多個角色模型。**例如,如果您正在建立一個新的生產力應用程式,您可能會關注Trello 等產品或體式。當然,您的應用程式不會相同,並且您可能會想到一些使您的應用程式獨一無二的核心差異,但仍然會有很多您不想重新發明的共享概念和機制。 即使您的角色模型是一個閉源應用程式,您仍然可以透過在野外觀察它來獲得很多價值 - 設計元素、UI、用戶旅程和使用的術語,... **但是現在想像一下,如果您決定學習的應用程式是開源的,並且您可以輕鬆地在 GitHub 上存取其完整原始程式碼 - 這將打開一個全新的可能性世界!** 接下來只需從“外面」並猜測幕後發生了什麼,現在您可以看到每一個細節並了解所做的每一個決定。架構、部署、API 設計、庫和使用的演算法 - 一切都在那裡供您查看! ## 注意規模(也就是不要過度設計) 另一件需要記住的事情是您的專案目前所處的階段。下面,我們將看到開源 SaaS 應用程式的不同範例,從獨立駭客、「週末建置」副專案到企業級 Web 平台。 **儘管您可能會發現擁有數百萬用戶的專案是一個令人驚嘆的學習資源,但請記住,並非他們所做的一切都是您必須嚴格遵循的。由於他們每天遇到的用戶規模和數量龐大**,他們的架構和設計決策通常會更加複雜。如果您剛開始,最好堅持使用最簡單(但仍然合理)的方法,直到您希望需要更高級的方法。 > 從現在開始,對於我們提到的每個應用程式,我們將使用“T 卹尺寸”方法(S、M、L...),讓您大致了解其尺寸和複雜性(無論是在功能還是功能方面)。使用者。 現在,前言結束了,讓我們一起來看看一些令人驚嘆的開源應用程式,您可以立即開始學習: ![樂趣現在開始](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m7z4q2cxeiocgpgj3ofs.gif) ## [CoverLetterGPT](https://coverlettergpt.xyz/) - 人工智慧驅動的 SaaS 的完美起點 💾 **原始碼**:https://github.com/vincanger/coverlettergpt 👕 **尺寸**:S **🛠️ Stack**:Chakra UI、React、Node.js 和 Prisma,由 [Wasp](https://github.com/wasp-lang/wasp) 提供支持 [CoverLetterGPT.xyz](http://CoverLetterGPT.xyz) 是每個獨立駭客的夢想- **它是一個由GPT 支援的SaaS,完全開源,最重要的是,它是人們每天使用並付費的真實產品為了**!根據您的履歷和職位描述,該工具將產生一封專業撰寫的求職信。然後,您可以進一步調整每個段落的語氣或手動編輯。 它非常適合學習,因為它不太大,架構也很簡單,但它具有應用程式中可能需要的所有功能 - 社交身份驗證 (Google)、cron 作業、文件上傳、GPT 集成、透過 Stripe 進行支付集成,甚至可以透過比特幣付款! CoverLetterGPT 由 React、Node.js 和 Prisma 製成,由 [Wasp 框架](https://github.com/wasp-lang/wasp) 提供支持,它負責所有管道並刪除大量樣板檔案。 **最好的部分是,當您準備好時,可以透過執行單一 CLI 命令來免費部署應用程式**:「wasp deploy」。 <center><h3>🚨注意🚨</h3></center> > 提示:Wasp 團隊最近發布了 [OpenSaaS](https://kdta.io/github-wasp-lang-open_3),**一個完全免費且開源的 React 和 Node.js 樣板啟動器**。它包含提到的所有內容 + Tailwind、管理儀表板、登陸頁面、部落格等。 [在此處查看](https://kdta.io/github-wasp-lang-open_4) 以更快地開始使用。 ## Supabase Studio - 儀表板傑作🖼️ ![Supabase 工作室](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jc2pz1vhg1wysk7o9148.gif) 💾 **原始碼**:https://github.com/supabase/supabase/tree/master/apps/studio **👕 尺寸**:M/L **🛠️ 堆疊:** Next.js (React)、Tailwind [Supabase](https://supabase.com/) 是一個著名的開源專案,其核心是用 Elixir 編寫的。但是,由於我們在本文中專注於 Web 應用程式,因此我們將看一下 **Supabase Studio - 一個儀表板,您可以在其中查看和管理所有專案。它本身就是一部傑作,而且完全開源!** 該設計是使用 Tailwind 定制的,您可能希望在自己的專案中重複使用許多元素 - 用戶管理、表格、列表等。它還有自己的 AI 集成,用於編寫 SQL 查詢,效果出奇的好。 ## Papermark - 開源 DocSend 替代方案 ✉️ ![papermark_banner](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kt76y923xnpjhbglbvmn.png) 💾 **原始碼**:https://github.com/mfts/papermark 👕 **尺寸**:M **🛠️ 堆疊**:Next.js (React)、Tailwind、Prisma [Papermark](https://github.com/mfts/papermark) 最近受到社群的廣泛喜愛,尤其是其簡潔的設計和直覺的介面。雖然從外觀上看起來很簡單,但該應用程式包含許多功能,使一切順利執行:文件上傳、電子郵件發送、內建分析和自訂網域... **如果您正在建立涉及大量文件管理和使用者協作的專案**,這絕對是您應該考慮的專案。 ## [Crowd.dev](http://Crowd.dev) - 開發社群資料平台,使用 Vue 製作 📊👩‍💻 ![crowd_dev_banner](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ykd2vxomnrl02j46i7mm.png) 💾 **原始碼**:https://github.com/CrowdDotDev/crowd.dev **👕 尺寸**:M **🛠️ 堆疊:** Vue、Node.js [Crowd.dev](http://Crowd.dev) 是 GitHub 最新的後起之秀之一 - 它是一個用於監控社區活動的平台,無論是在 Slack 還是 Discord 上。如果您正在經營自己的開發者社區,那麼這樣的工具是必須具備的,以便了解正在發生的事情以及最活躍的成員是誰。 它在儀表板方面提供了很多功能,但它的另一個強項是**集成 - 如果您正在建置一個從外部源獲取和處理大量資料的應用程式,那麼這是您的首選角色模型**。如果你是 Vue 愛好者,那就加分了,因為這個專案就是用它製作的! ## Habitica - 作為角色扮演遊戲的習慣追蹤器🐲⚔️ ![habitica_banner](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g69lfe93k931fyoj1fzv.png) 💾 **原始碼**:https://github.com/HabitRPG/habitica **👕 尺寸**:L **🛠️ 堆疊:** Vue、Bootstrap、SAAS、Node.js、MongoDB [Habitica](https://habitica.com/) 是我見過的最酷的網頁應用程式之一(他們也有 iOS 和 Android 應用程式) - 它可以幫助您透過角色扮演遊戲!想像 Trello 這樣的看板,但對於您完成的每項任務,您都可以獲得 XP 和金幣,甚至可以與朋友組隊接受任務。 Habitica 已經存在 10 年了,它通過 Vue、Node.js/Express 和 MongoDB 的經典堆疊完美地經受住了時間的考驗。 **如果您想了解建立了多麼豐富的互動式 UI,以及執行這種規模的專案需要什麼樣的架構,那麼這個應用程式絕對值得一試。**誰知道,您甚至可能最終成為居住自己! ## 🏆 **獎勵** 🏆 Appflowy - Rust 和 Flutter 中的概念替代品 🤯 ![appflowy_banner](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlzizemi22g9wkb48yfz.png) 💾 **原始碼**:https://github.com/AppFlowy-IO/AppFlowy **👕 尺寸**:M **🛠️ 堆疊:** Flutter、Rust 如果您走到這一步,您應該得到特別的待遇!這不是一個網絡應用程式,但它太酷了,我無法控制自己 - 它是**一個用 Rust 和 Flutter 建置的 Notion 替代品(因此可以做筆記)**!由於其本地優先的性質,用戶體驗非常流暢,並且它還將所有內容同步到雲端(如果您願意,您可以自行託管)。 **如果您一直在使用 Rust,但也在尋找一個可以每天使用的專案,Appflowy 可能是完美的選擇。** 它擁有從資料儲存到業務邏輯和 UI 的所有內容,全部都包含在其中一個包供您學習並查看您認為最有趣的內容。 ## 就是這樣!我很想聽聽你的訊息🫵 ![that_is_all](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ovyclq3iyi3d15kfxcaw.gif) 這就是我們今天的全部內容(*放下麥克風*),非常感謝您的閱讀!我希望您發現它有用和/或有趣。 我在撰寫本文時遇到了很多開源 Web 應用程式,很難只選擇其中 5 個。 **現在,我很想聽聽您的來信 - 您最喜歡的開源應用程式是什麼,以及您如何使用它們?寫在下面的評論👇** 謝謝您,下次再見! 👋 --- 原文出處:https://dev.to/matijasos/5-beautiful-open-source-web-apps-to-learn-from-and-get-inspired-280f

GitHub README 文件:響應式? 🤔 動畫? 🤯 淺色和深色模式? 😱

是的,你沒聽錯,我的 GitHub 自述文件有淺色和深色模式,甚至是響應式的。在這篇文章中,我將簡要介紹我用來實現這一目標的技巧(以及使它變得困難的事情!) 但首先,讓我們看看我的個人資料在不同的螢幕尺寸和顏色偏好下是什麼樣子(或者親自嘗試一下 [GrahamTheDevRel 在 GitHub 上的個人資料](https://github.com/GrahamTheDevRel)! ## 深色模式 ![GrahamTheDevRel GitHub 設定檔在桌面上處於深色模式。頂部有 5 個按鈕,就像一個選單,格雷厄姆在一個對話氣泡旁邊豎起大拇指,上面寫著「很好,我看到使用黑暗模式,就像一個真正的開發人員!呵呵!」。以下有 4 個部分討論他所做的專案和工作。![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oo5kj6fueo591w13a4tq.png) ## 移動的 請注意以下部分的不同按鈕設計和佈局。 建立這些按鈕比您想像的要困難得多! ![GrahamTheDevRel GitHub 個人資料在行動裝置上處於深色模式。頂部有5 個按鈕,就像一個顯示社交圖標的選單,格雷厄姆在對話氣泡下方豎起大拇指,上面寫著「很好,我看到使用黑暗模式,就像一個真正的開發人員!呵呵!」。以下有4 個部分討論他所做的專案和工作,這些專案和工作的佈局與桌面不同,以適應較小的螢幕尺寸。![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3zo2c9hay32tcvmoc3ek.png) ## 燈光模式 我忍不住在英雄部分錶達了不同的訊息,當然我只是在開玩笑! 🤣💗 ![GrahamTheDevRel GitHub 設定檔在桌面上處於輕型模式。頂部有5 個按鈕,就像黑底白字的選單,格雷厄姆拇指朝下,旁邊有一個對話氣泡,上面寫著「哦不,不是淺色模式,你不知道開發人員只使用深色模式嗎?」。以下有 4 個部分討論他在淺色方案中所做的專案和工作。](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cgipfop82t8499i5fukw.png) ## 喔...我有沒有提到它是動畫的? 請記住,前 5 個按鈕都是單獨的圖像!花了一點功夫才把它弄好! ## 使用了一些技巧! 好吧,所以你來這裡不僅僅是為了看我的個人資料! (如果你這樣做了,也愛你!🤣💗) 不,你是來學一些技巧的,這樣你就可以自己做對吧? 嗯,有一個“技巧”,然後只需一個 HTML 功能,您就可以自己完成此操作。 讓我們從最有趣的開始: ## 製作響應式按鈕和圖像的技巧! 網站上的按鈕和英雄圖像是有趣的部分。 為了讓它們發揮作用,我們使用了許多人沒有聽說過的 SVG 功能「<foreignObject>」。 ## `<foreignObject>` 和 SVG 獲勝! 這是使事物響應的最大技巧。 你看,在 markdown 文件中我們能做的事情非常有限(這就是為什麼我們看到人們使用 `<table>` 等進行佈局......ewww)。 但 SVG 有一個獨特的功能,[`<foreignObject>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject)。 這允許您在 SVG 中包含許多內容,**包括 HTML 和 CSS。** 有了它,我們就有了更多的力量! 您可以在 CodePen 的演示中看到(單擊按鈕可以更改外部容器的大小,它代表頁面上圖像的可用空間): ### SVG 中 CSS 的 CodePen 演示 **一定要查看 html 面板**,所有技巧都在那裡! https://codepen.io/GrahamTheDev/pen/mdomxyy 關鍵部分在這裡: ``` <svg xmlns="http://www.w3.org/2000/svg" fill="none"> <foreignObject width="100%" height="100%"> <div xmlns="http://www.w3.org/1999/xhtml"> <!--we can include <style> elements, html elements etc. here now, with a few restrictions! Note it must be in xHTML style (so <img src="" /> not <img src="" > to be valid --> </div> </foreignObject> </svg> ``` 從那裡我們可以使用內聯 `<style>` 元素和標準 HTML 元素來建立響應式映像。 但您可能會注意到該演示中使用的標記的另一件事。 ## 圖片很吸引人! 我將圖像(SVG 氣泡和我的圖像)作為 [`data` URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs )。 這是因為所謂的[內容安全策略 (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 及其在 GitHub 上的實作方式。 現在我不會解釋 CSP,但本質上它們有一條規則:「嘿,除了當前上下文之外,不能從任何地方加載圖像」。 對於普通圖像來說這不是問題,但這是圖像中的圖像,並且該圖像的“上下文”就是其本身。 因此,如果我們嘗試在 SVG 中包含另一個圖像,它將來自不同的位置並破壞我們的 SVG。 幸運的是,「資料」 URI 被視為相同的上下文/來源。 這就是為什麼它們在我們的範例中使用的原因,如果您想自己實現的話,還需要考慮另一件事! ## 最後一個技巧,「<picture>」元素且沒有空格。 我的意思是,這甚至不是一個技巧! 我的自述文件中的最後 4 個框是響應式的(並尊重顏色偏好),但它們使用標準媒體查詢來工作。 這裡唯一的考慮是嘗試找到一個有效的斷點,恰好是 GitHub 上的 768px。 然後我建立了 4 組圖像: - 深色模式和桌面 - 黑暗模式和移動設備 - 燈光模式和桌面 - 燈光模式和移動。 ### 大或小圖像 為了獲得正確的圖像,我們在每個來源上對桌面(大)圖像使用“media =”(min-width:769px)`,對於移動(小)圖像使用“media =“max-width:768px)”放入我們的“<picture>”元素。 ### 淺色和深色模式 若要取得淺色或深色模式,我們使用[`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme)媒體查詢。 ### 結合我們的查詢和來源 然後我們只需設定「<picture>」元素來使用「(**寬度查詢**)和(顏色首選項)」的組合來選擇我們想要的來源: ``` <picture> <source media="(min-width: 769px) and (prefers-color-scheme: light)" srcset="readme/[email protected]"> <source media="(max-width: 768px) and (prefers-color-scheme: light)" srcset="readme/[email protected]"> <source media="(max-width: 768px) and (prefers-color-scheme: dark)" srcset="readme/[email protected]"> <img src="readme/[email protected]" alt="You will find me writing about tech, web dev, accessibility, breaking the internet and more over on DEV! Purple and neon pink design with Graham pointing at the next section" width="50%" title="My writing on DEV"> </picture> ``` 本身並不困難,但建立 4 種圖像變體非常耗時。 ### 沒有空格 我遇到了最後一個問題。 底部實際上由 4 個不同的圖像組成(是的,我必須為其建立 16 個不同的圖像...)。 這樣做的原因是每個部分都是一個可點擊的連結。 並不複雜,但有一個小問題要注意。 如果您想要讓兩個影像直接並排接觸(因此兩個影像的寬度均為 50%),則必須刪除錨點、圖片元素甚至這些圖片元素內的來源之間的所有空白。 否則 GitHub 會為你的元素加入一些邊距,並且它們將不會在同一行。 另外,儘管我刪除了所有空白,但我遇到了另一個限制,但第一行和第二行之間仍然有 8px 的間隙,您無法遺憾地刪除它(因此之間的線!)。 ## 包起來! 我可能會在未來對內容安全策略、「<picture>」元素技巧,當然還有「<foreignObject>」做一些更深入的解釋。 這更多的是對概念的介紹,以便您可以自己使用它們,而不是教程。 但現在你已經了解我使用的技巧,我希望看到你建立一個比我的更漂亮的 GitHub 自述文件了! 如果您這樣做,請在評論中分享! 💪🏼🙏🏼💗 大家編碼愉快! 💗 --- 原文出處:https://dev.to/grahamthedev/take-your-github-readme-to-the-next-level-responsive-and-light-and-dark-modes--3kpc

React.js,你到底要發展成怎樣?

我正在寫這些隨機筆記作為**公開信,寫給我在 React**(更廣泛地說,開源)**社區**中深深信任的人。像是坦納·林斯利、勞裡·沃斯、卡西迪·威廉斯、麥可·傑克森、馬克·艾瑞克森、凱爾·馬修斯、蘇菲·阿爾珀特等人。 **在過去的幾個月裡,我一直對 React 感到矛盾**。它始於伺服器元件基本上在框架會議上宣布的日子,React 文件開始建議使用外部框架進行 React 開發。昨晚閱讀了 [Cassidy 的帖子](https://blog.cassidoo.co/post/annoyed-at-react/) 並分享了她的願景後,我也有表達我的擔憂的衝動。 **我在 2016 年愛上了 React**,當時 Angular 發布了 Angular 2,我們擔心會發生重大變化。我立即愛上了 React 社區,儘管我從未積極參與。 我記得蘇菲·阿爾珀特和丹·阿布拉莫夫之間的推文。我還記得 2016 年 Michele Bertoli 在 ReactJsDay(義大利)上的第一次演講,讓我眼前一亮。我無法忘記 2018 年版的 ReactJsDay,當時 Michael Jackson 在我們面前重新建立了大部分 React Router 實時編碼 - 那真是美好的日子! 無論是作為 Web 開發機構還是現在作為產品公司,React 一直是我們的成功選擇。當我想起那一天(我相信是2020 年1 月2 日)時,我仍然很激動,當時我向Guillermo Rauch 展示了React Bricks 的第一個MVP,他是第一個相信這個專案的人,並給了我繼續下去的信心。 。 **然而,今天我看到兩個問題,讓我對 React 的喜愛少了一些**,並讓我擔心新開發人員可能會被它嚇倒:所有權和復雜性。 ## 所有權 至於所有權,我不是特別喜歡: 1. React [建議使用框架](https://react.dev/learn/start-a-new-react-project)啟動專案,建議使用三大主流開源框架之一,而不是僅使用反應。 2. 在框架會議期間,React Server 元件等新的 React 功能首次向社群的很大一部分介紹,就好像這只是一個框架成就一樣。 3. 最受歡迎的框架,它僱用了一些來自React 核心團隊的人員(這不是一件壞事,但肯定為他們提供了對開發的特權洞察力)使用金絲雀版本,而[React 的最後一個版本](https://github.com/facebook/react/releases) (18.2) 是2022 年6 月。透過這種方式,金絲雀功能進入了許多新React 專案的程式碼庫,成為“事實上的”穩定版本,但僅適用於 a可以安全地利用金絲雀功能的框架。 此外,諸如伺服器操作之類的功能(在雲端平台上託管時會觸發計量無伺服器函數呼叫)可能會增加未來前端應用程式的託管成本。雖然目前這不是問題,因為不存在壟斷,我們有選擇的自由,但**我希望**為社區提供一種方式**以保證明天仍然有多種選擇**可用。請理解,在這方面我不認為任何人是「邪惡的」。私人公司和社區之間的合作可以帶來偉大的成就。這只是一個分離關注點和責任的問題。 ## 複雜性 我從 1996 年開始建立網站,當時我 17 歲。當時,您建立了 HTML 檔案並將它們上傳到 FTP 伺服器上由 Web 伺服器提供服務的資料夾中。我管理自己的實體伺服器(Pentium 120),將其安置在當地的網路供應商。它在 Windows NT4 IIS 上執行作為 Web 伺服器,在 BIND 上執行 DNS,在 IPSwitch IMail 伺服器上執行電子郵件。一切都簡單明了。 如今,Web 開發變得更加強大,但也更加複雜。隨著轉譯器、捆綁器和框架的引入,我們已經失去了對幕後發生的事情的了解。然而,React 以其乾淨的單向資料流而脫穎而出。鉤子的事情變得有點複雜(它有一些幕後黑魔法:),但它是可以管理的,並且最終是一個不錯的選擇。 **使用伺服器元件,一切都變得更加複雜,難以掌握**。而且,事實上它們是最廣泛使用的 React 框架的預設選擇,這在某種程度上迫使新手也學習這種新範例。我了解 RSC 的優勢,但現在我們甚至可以在同一個 React 框架內使用[兩種不同的方式](https://overreacted.io/the-two-reacts/)來建立東西。 我們最近完成了讓 React Bricks 函式庫與 RSC 相容的任務。這需要一個月的工作和數千行程式碼。然而,結果是,最終為開發者提供的 API 並不像以前那麼乾淨。我不確定為了輕微的效能提升而犧牲簡單性是否會真正使我們的客戶受益。儘管如此,由於它既是「預設」又是閃亮的新事物,我們必須擁有它。 **同時,隨著新框架的出現,React 世界之外發生了許多有趣的事情**。我不想成為新程式設計師現在就嘗試選擇他們的第一個框架,因為這個決定非常艱難。 React 是最受歡迎的,Vue 更容易使用,Svelte 是一個很酷的想法,Astro 真的很棒,然後還有由非常聰明和謙遜的 Ryan Carniato 開發的信號和 SolidJS。 Qwik 也非常聰明,我喜歡這種方法(它是由 React Bricks 的競爭對手建立的……但我非常尊重他們:)。所以……基礎框架的選擇已經這麼複雜了! ## 一個夢? 在這種複雜的場景中,**擁有一個「預設的官方」React 框架將是有益的,該框架涵蓋建立 SEO 友善網站的基本需求**,具有路由、SSG、SSR、ISR(以及所有排列)這些字母;)。我知道 Remix 團隊不會同意 SSG 的必要性,但我認為它有一個有效的用例。我希望它始終能夠在 Linux 機器上自行託管。 我設想這個預設框架由 React 社群開發,並有一個由來自 React 生態系統的公認貢獻者組成的**指導委員會(透過投票過程?)**。我知道通常開源不會以這種方式工作,但是......我夢想著這個“probi viri Fellowship of the Ring”做出決定。 這個預設框架**不應該旨在包含所有閃亮的新東西**,這些新東西可以在我使用和喜愛的 Remix 或 Next.js 等其他框架中找到。我相信它應該作為社區創造的堅實起點。我認為我們今天已經有了一些很棒的東西可以開始(坦納?)。 至於 RSC,我認為避免水合的概念很棒,但我們需要一種新型的伺服器客戶端整合來使它們易於使用。如果它們仍然很複雜,在當前的限制下,以簡單性換取效能對大多數網站來說不會有好處。無論如何,與 Qwik 之類的東西相比,RSC 可能在效能方面有所損失,因為它們執行相同的工作兩次,處理客戶端上序列化 JSON 的區塊。然而,這是需要單獨討論的材料。 ## 開放問題 所以,經過這麼長時間的意識流,我想向社區提出一些問題: 1. 您對React的未來有何看法? 2. 您認為在沒有贊助公司但有選舉的指導委員會的情況下建立一個社區驅動的框架是否可行?這個獨立的指導委員會如何能夠得到社區或企業用戶的經濟支持,以保持其獨立性? 馬泰奧·弗拉納 2023 年 1 月 16 日 --- 原文出處:https://dev.to/matfrana/react-where-are-you-going-5284

🐍 Python Playground:16 種入門方法📚

## 簡介 本文是一份指南,旨在透過易於使用且引人入勝的資源來幫助 Python 程式設計新手。從適合初學者的庫到互動式編碼平台,您應該找到最適合您的! ![介紹 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9my6x9r0e94l27b92o5.gif) --- # 圖書館 以下 Python 函式庫易於使用,非常適合 Python 入門。 ![Python 函式庫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h692caetdehj9360jceg.png) ## 1- [Taipy](https://github.com/Avaiga/taipy) Taipy 是 Python 領域的一個新程式庫,非常適合用最少的程式碼建立強大的 Web 應用程式。使用 Taipy 開始使用 Web 應用程式。 🔑特點: - 豐富的互動性 - 為您的佈局、樣式等提供更多自訂功能(無需 CSS) - 多頁和多用戶應用程式 --- ![QueenB GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0un08vhstrk6zpst5yti.gif) 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- ## 2- [海龜圖形](https://docs.python.org/3/library/turtle.html) 絕對初學者的起點。這個預先安裝的 Python 程式庫以有趣且直覺的方式教您 Python 程式設計的基礎知識。 --- ## 3- [EasyGUI](https://easygui.sourceforge.net/) 開始使用此庫的圖形使用者介面 (GUI)。 它的簡單性使其成為初學者建立基本 GUI 的首選。 --- ## 4- [Matplotlib](https://github.com/matplotlib/matplotlib) 這個小部件庫成為 Python 領域的首選是有充分理由的。憑藉廣泛的圖表類型,您可以繪製任何 2D 圖表。 該庫允許透過細粒度的圖形元素進行顯著的客製化。 --- ## 5- [Pandas](https://github.com/pandas-dev/pandas) 即使所有 Pythonista 都使用 Pandas,這個函式庫也很容易理解,並且允許您做很多事情。 您可以了解資料框和系列以及如何有效地處理資料。 🔑特點: - 從各種來源載入資料 - 重塑資料框 - 透過基本統計進行基本資料分析 --- ## 6-[桑尼](https://thonny.org/) Thonny 對於初學者來說是一個很棒的 IDE。 它具有幫助理解程式設計過程以及直接編寫和除錯 Python 程式碼的出色功能。您可以在這個輕鬆的環境中嘗試以前的庫。 --- # 編碼平台 程式設計平台提供類似學術的環境,非常適合快速、結構化的學習。 ![編碼平台](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqkaqb15vava1iuwg42l.png) ## 7- [Datacamp](https://www.datacamp.com/) 這是我開始使用Python的平台,怎麼能不包括它呢? Datacamp 是一個互動式學習平台,專注於圍繞資料科學和分析進行程式設計。他們有不同程度的課程,使其成為開始學習 Python 和資料分析概念的好地方。 --- ## 8-【程式碼實戰】(https://codecombat.com/) Code Combat 讓學習變得有趣,就像您在玩遊戲的同時學習 Python 一樣。 這個平台有一個世界,您可以在遊戲中提升角色,同時學習如何編碼。 這個網站適合年輕一代,但我建議任何年齡的初學者嘗試! --- ## 9- [Sololearn](https://www.sololearn.com/) 這個平台透過他們的社區旋轉和發展。 Sololearn 專注於簡短的 Python 課程,是隨時隨地學習 Python 的絕佳工具。 --- # 教學與挑戰 教學和挑戰是透過小型且可管理的專案來增強和測試 Python 技能的絕佳方法。 ![教學](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v195zko860x4d3bffznm.png) ## 10- [Codechef](https://www.codechef.com/) 該網站以程式設計競賽為特色。 對於那些透過競賽學得更好的人來說,Codechef 適合您。它們提供各種挑戰來滿足所有程式設計等級的需求。 --- ## 11- [Codewars](https://www.codewars.com/) 該社區網站還提供程式設計挑戰。 這是使用 Python 學習和挑戰自己的好方法。 --- ## 12- [精通機器學習](https://machinelearningmastery.com/) Machine Learning Mastery 提供機器學習和 Python 的教學和書籍。 這些教程對我的一些機器學習專案很有幫助,我仍然不時回顧它們! --- # 完整專案 使用 Python 建立整個專案是在現實場景中測試您的技能的好方法。一般來說,這些專案是對你的投資組合的一個很好的補充。 ![完整專案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/la3zqq1e7kr7gmncblxa.png) ## 13- [Kaggle](https://www.kaggle.com/) 這個平台是我測試 Python 和機器學習技能的首選平台。該平台展示資料科學專案。 Kaggle 也是加入到您的履歷中的一個很好的資源。 --- ## 14- [freeCodeCamp](https://www.freecodecamp.org/) 儘管 freeCodeCamp 專注於 Web 開發,但該平台也使用 Python 專案。邊做邊學的好方法。 --- # 黑客松 黑客馬拉松是在動態和協作的環境中學習的好方法。參加黑客馬拉鬆在學術和專業上都很有價值。 ![黑客松](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w9xcuqaoj7tsw7a7ri0b.png) ## 15- [駭客大聯盟](https://mlh.io/) MLH 為來自世界各地的學生舉辦黑客馬拉松。他們的黑客馬拉松可以在現場進行,也可以在網路上進行。 黑客馬拉松非常適合將 Python 技能應用到實際專案中。 此外,這是在面試或履歷中展示專案的好方法。 --- ## 16- [Devpost](https://devpost.com/) Devpost 是一個線上黑客馬拉松網站。他們提供的活動<在主題和獎品方面有很多選擇! --- ## 結論 這些資源提供了多種方式來透過這些易於使用的函式庫、互動式學習平台和實際挑戰來啟動您的 Python 程式設計之旅。 --- ![GIF 結束](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvimkpxsq91d6m1jfei1.gif) 如果您有任何問題或回饋,請隨時與我們聯繫! --- 原文出處:https://dev.to/taipy/python-playground-16-ways-to-get-started-4fgg

使用 Next.js、Resend 和 Trigger.dev 建立後台電子郵件通知

## 您會在本文中找到什麼? 電子郵件通知是讓使用者了解應用程式所執行操作的最常用方法。典型的通知包括:有人追蹤您、有人喜歡您的貼文、有人查看了您的內容。在這篇文章中,我們將探索如何使用 Next.js、Resend 和 Trigger.dev 建立一個簡單的非同步電子郵件通知系統。 我們將使用 Next.js 作為框架來建立我們的應用程式。我們將使用 Resend 發送電子郵件,並使用 Trigger.dev 非同步卸載和發送電子郵件。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jwlb0t41kg2s3djcb072.gif) ## Papermark - 開源 DocSend 替代品。 在我們開始之前,讓我與您分享 Papermark。它是 DocSend 的開源替代方案,可幫助您安全地共享文件並從查看者那裡獲取即時的逐頁分析。全部都是開源的! 如果您能給我們一顆星星,我會非常高興!別忘了在留言區分享你的想法❤️ [https://github.com/mfts/papermark](https://github.com/mfts/papermark) [![Papermark 應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/igzk8cdssbmla9uf1544.png)](https://github.com/mfts/papermark) ## 設定專案 讓我們繼續為我們的電子郵件後台通知系統設定專案環境。我們將建立一個 Next.js 應用程式,並設定為重新發送,最重要的是,設定觸發器來處理非同步電子郵件通知。 ### 使用 TypeScript 和 Tailwindcss 設定 Next.js 我們將使用「create-next-app」產生一個新的 Next.js 專案。我們還將使用 TypeScript 和 Tailwind CSS,因此請確保在出現提示時選擇這些選項。 ``` npx create-next-app # --- # you'll be asked the following prompts What is your project named? my-app Would you like to add TypeScript with this project? Y/N # select `Y` for typescript Would you like to use ESLint with this project? Y/N # select `Y` for ESLint Would you like to use Tailwind CSS with this project? Y/N # select `Y` for Tailwind CSS Would you like to use the `src/ directory` with this project? Y/N # select `N` for `src/` directory What import alias would you like configured? `@/*` # enter `@/*` for import alias ``` ### 安裝重新傳送和 React-Email Resend 是開發人員優先的事務性電子郵件服務。我們將使用它向我們的用戶發送電子郵件。 `react-email` 是一個 React 元件庫,可以輕鬆建立漂亮的電子郵件。 ``` npm install resend react-email ``` ### 安裝觸發器 Trigger 是 TypeScript 的後台作業框架。它允許您從主應用程式中卸載長時間執行的任務並非同步執行它們。我們將使用它非同步發送電子郵件。 觸發器 CLI 是在新的或現有的 Next.js 專案中設定觸發器的最簡單方法。有關更多訊息,請查看[他們的文件](https://trigger.dev/docs/documentation/quickstarts/nextjs)。 ``` npx @trigger.dev/cli@latest init ``` ## 建立應用程式 現在我們已經完成了設置,我們準備開始建立我們的應用程式。我們將介紹的主要功能是: - 設定重新發送電子郵件 - 編寫API路由來發送電子郵件 - 新增觸發器作業以使電子郵件發送非同步 ### #1 設定重新傳送電子郵件 首先,我們需要設定重新發送來發送電子郵件。我們將在專案中建立一個新檔案「resend-notification.ts」並新增以下程式碼。 ``` // lib/emails/resend-notification.ts import { Resend } from "resend"; import { NotificationEmail } from "@/components/emails/notification"; const resend = new Resend(process.env.RESEND_API_KEY!); export async function sendNotificationEmail({ name, email, }: { name: string | null | undefined; email: string | null | undefined; }) { const emailTemplate = NotificationEmail({ name }); try { // Send the email using the Resend API await resend.emails.send({ from: "Marc from Papermark <[email protected]>", to: email as string, subject: "You have a new view on your document!", react: emailTemplate, }); } catch (error) { // Log any errors and re-throw the error console.log({ error }); throw error; } } ``` 使用「react-email」的通知電子郵件範本將如下所示: ``` // components/emails/notification.tsx import React from "react"; import { Body, Button, Container, Head, Heading, Html, Preview, Section, Text, Tailwind, } from "@react-email/components"; export default function ViewedDocument({ name, }: { name: string | null | undefined; }) { return ( <Html> <Head /> <Preview>See who visited your document</Preview> <Tailwind> <Body className="bg-white my-auto mx-auto font-sans"> <Container className="my-10 mx-auto p-5 w-[465px]"> <Heading className="text-2xl font-normal text-center p-0 mt-4 mb-8 mx-0"> <span className="font-bold tracking-tighter">Papermark</span> </Heading> <Heading className="mx-0 my-7 p-0 text-center text-xl font-semibold text-black"> New Document Visitor </Heading> <Text className="text-sm leading-6 text-black"> Your document was just viewed by someone. </Text> <Text className="text-sm leading-6 text-black"> You can get the detailed engagement insights like time-spent per page and total duration for this document on Papermark. </Text> <Section className="my-8 text-center"> <Button className="bg-black rounded text-white text-xs font-semibold no-underline text-center" href={`${process.env.NEXT_PUBLIC_BASE_URL}/documents`} style={{ padding: "12px 20px" }}> See my document insights </Button> </Section> <Text className="text-sm"> Cheers, <br /> The Papermark Team </Text> </Container> </Body> </Tailwind> </Html> ); } ``` ### #2 撰寫API路由發送電子郵件 現在,我們已經準備好了電子郵件範本。我們可以使用它向我們的用戶發送電子郵件。我們將建立一個無伺服器函數,該函數會取得使用者的“姓名”和“電子郵件”,並使用我們之前建立的“sendNotificationEmail”函數向他們發送電子郵件。 ``` // pages/api/send-notification.ts import { NextApiRequest, NextApiResponse } from "next"; import prisma from "@/lib/prisma"; import { sendViewedDocumentEmail } from "@/lib/emails/resend-notification"; export const config = { maxDuration: 60, }; export default async function handle( req: NextApiRequest, res: NextApiResponse ) { // We only allow POST requests if (req.method !== "POST") { res.status(405).json({ message: "Method Not Allowed" }); return; } // POST /api/send-notification try { const { viewId } = req.body as { viewId: string; }; // Fetch the link to verify the settings const view = await prisma.view.findUnique({ where: { id: viewId, }, select: { document: { select: { owner: { select: { email: true, name: true, }, }, }, }, }, }); if (!view) { res.status(404).json({ message: "View / Document not found." }); return; } // send email to document owner that document await sendViewedDocumentEmail({ email: view.document.owner.email as string, name: view.document.owner.name as string, }); res.status(200).json({ message: "Successfully sent notification", viewId }); return; } catch (error) { console.log("Error:", error); return res.status(500).json({ message: (error as Error).message }); } } ``` ### #3 新增觸發器作業,使電子郵件傳送非同步 我們的電子郵件發送功能已準備就緒,但我們不想同步發送電子郵件,因此要等到電子郵件發送後應用程式才會回應使用者。我們希望將電子郵件傳送任務轉移到後台作業。我們將使用觸發器來做到這一點。 在設定中,Trigger CLI 在我們的專案中建立了一個「jobs」目錄。我們將在該目錄中建立一個新檔案“notification-job.ts”並新增以下程式碼。 ``` // jobs/notification-job.ts import { client } from "@/trigger"; import { eventTrigger, retry } from "@trigger.dev/sdk"; import { z } from "zod"; client.defineJob({ id: "send-notification", name: "Send Notification", version: "0.0.1", trigger: eventTrigger({ name: "link.viewed", schema: z.object({ viewId: z.string(), }), }), run: async (payload, io, ctx) => { const { viewId } = payload; // get file url from document version const notification = await io.runTask( "send-notification", async () => { const response = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL}/api/send-notification`, { method: "POST", body: JSON.stringify({ viewId }), headers: { "Content-Type": "application/json", }, } ); if (!response.ok) { await io.logger.error("Failed to send notification", { payload }); return; } const { message } = (await response.json()) as { message: string; }; await io.logger.info("Notification sent", { message, payload }); return { message }; }, { retry: retry.standardBackoff } ); return { success: true, message: "Successfully sent notification", }; }, }); ``` 將匯出新增至作業索引文件,否則觸發器將不知道該作業。雖然是小細節,但連我都忘記了這一點,並花了一個小時尋找錯誤。 ``` // jobs/index.ts export * from "./notification-job"; ``` ### 獎勵:防止惡意存取 API 路由 我們已準備好 API 路由,但我們不想允許任何人存取它。我們希望確保只有我們的應用程式可以存取它。我們將使用一個簡單的標頭身份驗證金鑰來做到這一點。 在觸發器作業中,我們將標頭加入到請求中: ``` // jobs/notification-job.ts .. ... const response = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL}/api/jobs/send-notification`, { method: "POST", body: JSON.stringify({ viewId }), headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.INTERNAL_API_KEY}`, // <- add the authenication header with a local env variable }, }, ); ... .. ``` 在 API 路由中,我們將在「try {} catch {}」區塊之前檢查 API 金鑰是否符合: ``` // pages/api/send-notification.ts .. ... // Extract the API Key from the Authorization header const authHeader = req.headers.authorization; const token = authHeader?.split(" ")[1]; // Assuming the format is "Bearer [token]" // Check if the API Key matches if (token !== process.env.INTERNAL_API_KEY) { res.status(401).json({ message: "Unauthorized" }); return; } ... .. ``` 確保將“INTERNAL_API_KEY”新增至“.env”檔案中。 ``` # .env INTERNAL_API_KEY="YOUR_API_KEY" ``` ## 結論 瞧!我們已經準備好非同步電子郵件通知系統。我們現在可以非同步向用戶發送電子郵件,而不會影響用戶等待時間。我們還可以使用觸發器從主應用程式中卸載許多我們不希望用戶等待的其他任務。 感謝您的閱讀。我是 Marc,開源倡導者。我正在建立 [papermark.io](https://www.papermark.io) - DocSend 的開源替代品。 繼續編碼! ## 幫幫我! 如果您覺得這篇文章有幫助,並且對觸發器和後台任務有了更好的理解,如果您能給我們一顆星,我將非常高興!別忘了在評論中分享你的想法❤️ [https://github.com/mfts/papermark](https://github.com/mfts/papermark) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nk9c8ktyv1tf3n6jgbxh.gif) --- 原文出處:https://dev.to/mfts/building-background-email-notifications-with-nextjs-resend-and-triggerdev-4cem

從 Next.js 到 Rails 再到 Elixir:我的 React.js 倦怠之旅

我自 2019 年以來一直是 Web 開發人員。我使用 React.js 和基於 React 的框架,如 Gatsby、Next、Remix、Astro 和 Hydrogen。我從來沒有對這些工具感到完全滿意,但是,作為一個深入 JS 生態系統的初學者,我從同行那裡聽到的都是這樣的話:「這就是方式,任何其他程式語言要么慢,要么老」。 ![就是這樣](https://media.giphy.com/media/stnjSj2vpLcM4rwmEH/giphy.gif) 結果,我習慣了巨大的複雜性:多個獨立的儲存庫、數千個函式庫和框架來實現簡單的事情、GraphQL、微服務、無伺服器、靜態網站產生、增量靜態再生、部分水化、 redux 、redux-thunk、babel、webpack、react 伺服器元件、伺服器操作等。這個清單還可以再持續 10 分鐘。 直到有一天我說**受夠了!** 讓我們來看看我慢慢發瘋的完整時間線。這需要一段時間,在閱讀長篇文章之前,請隨意煮點咖啡! --- ## 倦怠的時間表 ### [Gatsby.js](https://www.gatsbyjs.com/) 我記得完成我的訓練營並想:“我終於能夠建立我的作品集了!”,所以我做到了。只有一個小問題,我想在 Google 上建立索引,但是使用舊的「create-react-app」使這項任務幾乎不可能完成。很快我了解了 SEO 和 React 的水合循環,這讓我找到了這個問題的「解決方案」:Gatsby.js。靜態網站產生的想法對當時的我來說簡直是革命性的,畢竟沒有什麼比預先渲染 HTML 檔案更快了,對吧? 我決定透過閱讀文件來學習這個新框架,讓我告訴你,這**不是**一次有趣的體驗。我以前從未聽說過 GraphQL,顯然,您需要它來產生所有靜態檔案(到底是什麼???)。我問我的一些網友,很難學習這些過度設計的廢話是否正常,他們回答說「技能問題,再努力一點!」。於是我更加努力,終於學會了之後,我把我的個人網站移植到了Gatsby上。 ![再努力一點](https://media.giphy.com/media/gzRiZROEyDCznPofKj/giphy.gif) 我的大部分頁面都成功在 Google 上建立了索引,幾個月來,我對結果非常滿意。然後另一個問題出現了:我的**很多**開發者朋友開始說“Gatsby 死了!建立 Next 是為了簡化靜態站點生成並提供伺服器端渲染”。 ### [Next.js](https://nextjs.org/) 我快速瀏覽了 Next 文件並**立即**愛上了它。我能夠在沒有 GraphQL 的情況下用三分之一的程式碼做與 Gatsby 相同的事情!我再次將我的作品集移植到另一個框架:Next。 這次我確實有一次美好的經驗。部署到 Vercel 輕而易舉,「getStaticProps」和「getServerSideProps」功能很簡單,但功能非常強大,我可以選擇每個頁面的渲染樣式,整體來說非常靈活。 不幸的是,我透過慘痛的教訓學到了一些東西:在 JavaScript 生態系統中,所有美好的事情都會結束。 ### [混音](https://remix.run/) 我清楚記得 Remix 發佈時的情景。多名科技影響者開始發布有關它的內容(一如既往)。然而,當時我在主頁上看到它不支援靜態網站生成,只支援伺服器端渲染,所以我想「等一下,這些年來投資於 [JAMstack](https://jamstack.org/) 都被扔在這裡了嗎?不可能,這個框架不會長久」。然而,令我驚訝的是,Remix 不僅生存了下來,而且還被 Shopify 收購 https://shopify.engineering/remix-joins-shopify ,並成為 Next 的重要競爭對手。 幾個月過去了,我決定嘗試看看。我再一次感到驚訝,Remix 的主要座右銘是使用 Web 基礎知識,而不是像 Next 這樣過於複雜的快取系統。因此,在Remix 中編碼時,我腦中需要的思維模型要簡單10 倍:沒有全域狀態管理器,只需使用URL,更少的客戶端狀態,將所有邏輯移至伺服器,並使用cookie,無需使用完整堆疊中間的 REST API 非常簡單,只需將資料庫查詢移至「loader」函數即可。 ### 離開矩陣 ![離開矩陣](https://media.giphy.com/media/11e0gEWxYoSYTK/giphy.gif) 然後,突然間,真相呈現在我面前,我服下了紅色藥丸。我的腦海中開始浮現出多個問題:Remix 不就像所有其他「古老而無聊」的框架(如 Rails、Laravel 和 Django)一樣嗎?幾十年來,我們一直在使用伺服器端渲染進行全端 Web 開發,但 JavaScript 黑手黨集體認為這種方法是垃圾,將所有內容移至客戶端才是未來。難道同一個黑手黨認為 Rails 一直都是對的嗎?用 JS 框架做所有那些過度設計的怪物不是正確的舉動嗎?我開始質疑一切。這種「新」的 Web 開發方式更加簡單、快速。 ### 我已經完成了 Next 和 Vercel 我透過 [Next.js 應用程式路由器](https://nextjs.org/docs/app) 達到了臨界點。以下是 Vercel 向 Next 推送的所有錯誤的完整清單: - 曾經簡單的:「getStaticProps」和「getServerSideProps」函數現在變得複雜而麻煩。目前,沒有特定的位置來新增 API 呼叫或資料庫查詢,您可以將它們寫入任何您想要的位置!在多年前使用 PHP 犯了同樣的錯誤之後,我們開始再次將業務邏輯與 UI 混合。難道前端開發者不吸取過去的教訓嗎?如果我刪除按鈕會發生什麼事?這是否會破壞我的使用者身份驗證流程,因為資料庫呼叫位於其中?您的前端應該 100% 可廢棄且可更換。你相對於競爭對手的競爭優勢在於業務邏輯,它應該與 UI 層完全隔離。 ![可怕的 Next.js 程式碼](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kp41ds14loo21xgimcza.png) - 接下來是伺服器優先。這聽起來沒那麼糟吧?畢竟,這解決了 SEO 問題並立即向用戶展示新鮮內容。問題在於,大多數現有的 Next 程式碼庫都依賴客戶端程式庫,例如樣式元件和一些全域狀態管理器。這是什麼意思?隨著此類重大變化的不斷發生,您的應用程式將在幾週而不是幾年內變成遺留軟體。更多的時間花在保持所有依賴項最新上,而不是做重要的事情:發布功能。 - Vercel 從 Meta 聘請了多名 React 核心團隊成員。這帶來了嚴重的利益衝突,因為這些工程師現在(據稱)正在發布有利於 Next 的功能,而不是優先考慮那些可以幫助所有基於 React 的框架(如 Remix)的功能。 ![Vercel 正在破壞 React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ye40ykjgrd3z10t5nx7.png) 我再也受不了了。我對自己說:你知道嗎?我厭倦了一遍又一遍地重新學習相同的框架,我完全不同意這種新的範式。 毫不奇怪,其他內容創作者也經歷了類似的情況: https://youtu.be/zkCBSz353fc?si=z3-FDVgcB3xfp06h https://youtu.be/Zt8mO_Aqzw8?si=10fy1d-ZoB7t3Uc_ --- ## 啟蒙之路 我非常累。在厭倦了所有的 React 工具後,我開始了尋找更簡單的 Web 框架的旅程。以下是我一直在尋找的先決條件: - 含電池 - 約定優於配置 - 良好的開發體驗 - 現代化且高性能的前端 我的第一個反應是查看 [Stack Overflow Survey 2023](https://survey.stackoverflow.co/2023/#section-most-popular-technologies-web-frameworks-and-technologies) 中的頂級框架。我立即從清單中刪除了所有與 JS、C# 和 Java 相關的內容。我從來沒有興趣學習後兩個,它們看起來醜陋且冗長。所以剩下的選項是:Laravel (PHP)、Django (Python)、Rails (Ruby) 和 Phoenix (Elixir)。 Python 是我在網路工程學位期間使用的語言,我獲得了非常愉快的體驗。 Django 似乎遵循約定優於配置的理念,但最終讓我放棄它的是沒有一個好的內建工具來在前端工作。論壇上的大多數人都說他們使用[HTMX](https://htmx.org/) 和[Alpine](https://alpinejs.dev/),但是,兩者都是您需要安裝的外部依賴項。 放棄Laravel 是非常困難的,因為它具有驚人的成本效益,有數百個官方軟體包可以處理新創公司可能需要的幾乎所有內容,例如託管、身份驗證、條紋支付等。對於前端,他們創造了[慣性。Node.js](https://inertiajs.com/),這是一種非常簡單而優雅的方式,可以在前端使用 React 的同時保持 Laravel 的高生產力和強大功能。百分之百誠實地說,我沒有選擇 Laravel 的唯一原因是 PHP 的語法,它看起來很難看,到處都是一堆 `$` 和 `->`。 ### Ruby on Rails Ruby on Rails 無需介紹。它是 Web 開發框架的元年,其革命性的「15 分鐘建立部落格」至今仍令人印象深刻。在我開始抱怨我發現的所有問題之前,讓我們先從好的方面開始。 與 Python 類似,Ruby 是一種可以向非技術人員展示的語言,他們會理解該軟體想要做什麼。它是**迄今為止**我見過的最容易閱讀和最美麗的語言。我很快就意識到,[編寫視覺上令人愉悅的程式碼](https://world.hey.com/dhh/a-writer-s-ruby-2050b634) 是Rails 團隊的首要任務,這對我來說來說是新的。 更不用說 Rails 幾乎發明了「包含電池」和「約定優於配置」的哲學,所以這不會是一個問題。在一份文件中,我提供了任何類型的 Web 應用程式所需的一切。 在前端,有 [Hotwire](https://hotwired.dev/),這是一種非常簡單且輕量級的方法,可以實現 SPA 框架提供的所有 UX 改進。我一直很好奇測試這個庫的極限,它看起來非常有前途。 好吧,Rails 在紙面上滿足了我想要的框架的所有先決條件。我們來試試吧!我在本地測試的第一件事是“railsscaffold”命令。我立即感到震驚。一個指令就能產生 CRUD 所需的一切?決不! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58lbioexmot9412kojr5.png) 在 Node + React 領域,要實現相同的目標,我需要手動編寫所有程式碼(這裡沒有生成器)並安裝一堆程式庫,例如:Vite、prisma、express、react router、redux、redux-thunk 、 vitest、cypress 、react 測試庫、zod、typescript、eslint、prettier、1000 個不同的插件,甚至可能還有GraphQL 或tRPC。基本上就是一個已經有 900 個依賴項的 package.json。 在“railsscaffold”最初的震驚之後,當我從控制器打開程式碼時,我再次震驚了: ``` class ArticlesController < ApplicationController def index @articles = Article.all end def show @article = Article.find(params[:id]) end def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to @article else render :new, status: :unprocessable_entity end end def edit @article = Article.find(params[:id]) end def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render :edit, status: :unprocessable_entity end end def destroy @article = Article.find(params[:id]) @article.destroy redirect_to root_path, status: :see_other end private def article_params params.require(:article).permit(:title, :body) end end ``` 這是所有後端程式碼嗎?只需幾行?這不可能!這非常簡單,看起來就像一個「低程式碼」工具。它簡單、優雅、可讀性極強,這是我們在 JS 領域很少見的。 好吧,好吧,你現在一定在想:「這個來自網路的瘋狂 React 開發者說他最終使用了 Elixir,所以 ruby 一定有問題!」。你是對的,我的匿名朋友,有些事情讓我很惱火,讓我們談談。 首先,我們需要解決房間裡的大象:從 React + Typescript 轉向動態類型語言並不容易。從我開始編寫程式碼的那一刻起,我的 VScode 上就沒有出現智慧感知或充滿程式碼建議的下拉式選單,我感到盲目和迷失。這是一種可怕的感覺,我可能會在函數名稱上輸入錯誤,直到網站投入使用時才意識到!我知道我們可以編寫測試,但這是我希望在 IDE 上立即辨識的錯誤類型,而不是在測試或部署期間辨識。 另一件我以為我會喜歡但最終討厭它的事情是:太多的魔法。在 Typescript 程式碼庫中,我可以點擊任何類別或函數的頂部,前往原始程式碼並查看其實作方式。在 Rails 上,我到底在哪裡進行驗證(例如)?我是否在控制器內建立私有函數?有專門的資料夾嗎?不,正確的位置是在模型內部。為什麼?因為這就是它的工作原理,所以您要么採用該約定,要么很難編寫 Ruby 程式碼。我根本無法對一切在幕後如何運作產生“直覺”,我必須盲目地相信維護者在組織一切方面做得很好。 為了解決我的挫折感,我開始寫前端程式碼。如何建立元件? [部分](https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials)。如何定義該元件的 prop 類型?沒有辦法做到這一點,您需要打開它並直觀地查找其中的所有變數。做一些互動怎麼樣?建立國家?嗯,有帶有 [Stimulus](https://stimulus.hotwired.dev/) 的 Hotwire,但是正如您所看到的,您需要手動建立“重新渲染”功能,它沒有找到一種方法像React 這樣改變狀態後自動重新渲染頁面。 ``` // src/controllers/slideshow_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = [ "slide" ] initialize() { this.index = 0 this.showCurrentSlide() } next() { this.index++ this.showCurrentSlide() } previous() { this.index-- this.showCurrentSlide() } showCurrentSlide() { this.slideTargets.forEach((element, index) => { element.hidden = index !== this.index }) } } ``` 我再一次感到沮喪。我非常接近找到完美的框架!如果 Rails 失敗,我想嘗試的下一個框架是什麼?靈丹妙藥。 ### 長生不老藥和鳳凰 我必須說實話,我已經沒有耐心了。我嘗試了多種不同的生態系統,我幾乎確信要堅持使用 Ruby on Rails,並放棄對完美的追求。直到我的 YouTube 推薦部分出現了一個影片: https://www.youtube.com/live/bfrzGXM-Z88?si=Xsa7yCKeVSY5R3sT 堅持,稍等!在這裡我們可以看到一位 React 開發人員說了很多關於函數式程式設計、Elixir 和 Phoenix Live View 的好話。也許我應該嘗試一下! 我做的第一件事就是打開Elixir 和Phoenix 的文件,我真的很喜歡這樣一個事實:所有包都使用[Hex Docs](https://hexdocs.pm/) 以相同的方式進行記錄,您只需要取得習慣於單一介面以學習新事物。 另一個好處是,您只需閱讀文件即可真正學習 Elixir,無需昂貴的課程!在其他所有生態系統中,我必須透過付費課程學習語言,然後透過閱讀文件來學習框架。 然後是時候開始編寫程式碼了。很快我就明白函數式程式設計與 OOP 有很大不同。我們來做一個小小的比較: ``` // JS const obj = {name: "daniel"} obj.age = 25 // result: obj = {name: "daniel", age: 25} ``` ``` # Elixir obj = %{name: "daniel"} obj = Map.put(obj, :age, 25) # result: obj = %{name: "daniel", age: 25} ``` 或者您可以使用管道運算子透過更簡單的語法實現相同的效果: ``` # Elixir with pipe operator obj = %{name: "daniel"} |> Map.put(:age, 25) # result: obj = %{name: "daniel", age: 25} ``` 最初,您可能會發現它的可讀性較差且更複雜,但我保證隨著時間的推移它會變得有意義!嗯,至少對我來說是這樣。身為 React 開發人員,我已經習慣了到處都可以看到多個函數,甚至前端元件也是函數!更不用說建立類別有時被 JavaScript 黑手黨視為一種程式碼味道。我的大腦已經針對這種新範式進行了“塑造”,這對我來說很自然。自從我在大學獲得網路工程學位以來,我上過幾門關於物件導向程式設計的課程,但它從來沒有「受歡迎」。我無法將複雜的問題建模為類別和物件。隨著時間的推移,使用多個函數來「改變」一個變數是我在腦海中建模的方式。 主要框架怎麼樣?包含鳳凰電池嗎?約定優於配置? **是的!** 老實說,生態系統與 Rails 不在同一水平,但已經達到了 95%。除非您需要非常具體的功能,Phoenix 都能滿足您的需求。 我幾乎被 Elixir 迷住了,我的清單中缺少兩件事:良好的開發人員體驗和現代/高效能的前端程式碼。 José Valim 宣布他正在嘗試為該語言加入類型,但 Elixir 目前還沒有這些類型,所以我很擔心。如何在沒有類型的情況下獲得智能感知和自動完成?很快我發現這些功能不一定相關。在 VScode 上安裝 [ElixirLS 擴充功能](https://marketplace.visualstudio.com/items?itemName=JakeBecker.elixir-ls) 後,我感到很驚訝。可以在隨機資料夾的隨機模組內定義函數,將其導入其他位置,並取得它的智慧感知和文件!我從靜態類型語言中獲得了這些好處,而無需編寫類型的麻煩,簡直太棒了! https://elixir-lang.org/blog/2022/10/05/my-future-with-elixir-set-theoretic-types/ 我對前端的最後一個擔憂是由 Phoenix [Live View](https://hexdocs.pm/phoenix_live_view/welcome.html) 解決的。在程式碼方面,這正是文件主頁中讓我信服的部分: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5sjzj90khytebnk523fm.png) 您可以為每個元件定義“props”,如果類型不匹配,您的 IDE 中會出現錯誤,就像 React 一樣!感人的! 使用者體驗怎麼樣?每當使用者點擊連結時是否會載入整個頁面?一定不行!即時視圖與客戶端建立 WebSocket 連接,然後每次頁面轉換只是透過 Websocket 進行內容交換,不會發出新的 HTTP 請求。此外,所有狀態都在伺服器端進行管理,這意味著 Trello 等豐富的用戶體驗過去由於加載過多的 JavaScript 而在客戶端非常卡頓,現在變得非常快! Elixir 處理所有複雜的狀態邏輯並將頁面的更新部分傳送到前端。看看這裡的完整解釋: https://youtu.be/wrmVk2czqMg?si=ZoWAlPjQC-svmV3Y 由於我們使用 WebSocket 來建立 UI,因此建立像 Twitter 這樣的「即時」應用程式只需要幾行程式碼! https://youtu.be/MZvmYaFkNJI?si=gAow6oIjgf8_OTkg ## 結論 可以肯定地說,「完美的技術堆疊」並不存在。解決所有問題的靈丹妙藥是我們在腦中創造的幻覺,以不斷尋找和建構最優化的工具。 然而,在個人層面上,完美的堆疊確實存在。因為每個開發人員都有偏好,您可以輕鬆找到適合您標準的工具。如果你有和我類似的旅程,完美的可能就是長生不老藥和鳳凰!所以試試看吧,也許你會像我現在一樣喜歡它。 如果您讀到了這篇文章的結尾,那您就太棒了!非常感謝您抽出寶貴的時間,希望我能為您的職業生涯帶來一些價值。 ![結束](https://media.giphy.com/media/lD76yTC5zxZPG/giphy.gif) --- 原文出處:https://dev.to/danielbergholz/from-nextjs-to-rails-then-elixir-my-journey-through-reactjs-burnout-h8d

極為簡單的 Python 專案結構與導入

喜歡這些文章嗎?買書吧! [***Jason C. McDonald 的《Dead Simple Python》可從 No Starch Press 取得。](https://nostarch.com/dead-simple-python) --- 教程最糟糕的部分始終是它們的簡單性,不是嗎?您很少會發現一個包含多個文件的文件,更罕見的是包含多個目錄的文件。 我發現**建立 Python 專案**是語言教學中最常被忽略的部分之一。更糟的是,許多開發人員都會犯錯,在一堆常見錯誤中跌跌撞撞,直到他們得到至少「有效」的東西。 好訊息是:您不必成為他們中的一員! 在《Dead Simple Python》系列的本期中,我們將探索「import」語句、模組、包,以及如何將所有內容組合在一起而不費力氣。我們甚至會涉及 VCS、PEP 和 Python 之禪。係好安全帶! # 設定儲存庫 在我們深入研究實際的專案結構之前,讓我們先討論一下它如何適合我們的版本控制系統 [VCS]…從您*需要* VCS 的事實開始!有幾個原因是... * 追蹤您所做的每一個更改, * 弄清楚你什麼時候弄壞了東西, * 能夠查看舊版的程式碼, * 備份您的程式碼,以及 * 與他人合作。 您有很多選擇。 **Git** 是最明顯的,尤其是當您不知道還可以使用什麼時。您可以在 GitHub、GitLab、Bitbucket 或 Gitote 等上免費託管 Git 儲存庫。如果您想要 Git 以外的東西,還有許多其他選擇,包括 Mercurial、Bazaar、Subversion(儘管如果您使用最後一個,您可能會被同行視為恐龍。) 我將悄悄假設您在本指南的其餘部分中使用 Git,因為這是我專門使用的。 建立儲存庫並將「本機副本」複製到電腦後,您就可以開始設定專案了。您至少需要建立以下內容: - `README.md`:您的專案及其目標的描述。 - `LICENSE.md`:您的專案的許可證(如果它是開源的)。 (有關選擇一個的更多訊息,請參閱 [opensource.org](https://opensource.org/)。) - `.gitignore`:一個特殊文件,告訴 Git 要忽略哪些文件和目錄。 (如果您使用其他 VCS,則該檔案具有不同的名稱。請尋找。) - 包含您的專案名稱的目錄。 沒錯...**我們的Python 程式碼檔案實際上屬於一個單獨的子目錄!** 這非常重要,因為我們的儲存庫的根目錄將變得非常混亂,其中包含建置檔案、打包腳本、虛擬環境以及各種方式其他實際上不屬於原始碼的內容。 僅為了舉例,我們將虛構的專案稱為「awesomething」。 # PEP 8 和命名 Python 風格主要由一組稱為 **Python 增強提案**(縮寫為 **PEP**)的文件管轄。當然,並非所有 PEP 都被實際採納——這就是它們被稱為「提案」的原因——但有些是被採納的。您可以在Python官方網站上瀏覽主PEP索引。此索引的正式名稱為 [PEP 0](https://www.python.org/dev/peps/)。 現在,我們主要關注 [**PEP 8**](https://www.python.org/dev/peps/pep-0008/),它最初由 Python 語言建立者 Guido van Rossum 於2001 年。該文件正式概述了所有Python 開發人員應普遍遵循的程式設計風格。把它放在枕頭下!學習它,遵循它,鼓勵其他人也這樣做。 (附註:PEP 8 指出樣式規則總是有例外。它是*指南*,而不是*命令*。) 現在,我們主要關注標題為 [“包和模組名稱”](https://www.python.org/dev/peps/pep-0008/#package-and-module-names)的部分。。 > 模組應該有簡短的、全小寫的名稱。如果可以提高可讀性,可以在模組名稱中使用下劃線。 Python 套件也應該有短的、全小寫的名稱,儘管不鼓勵使用底線。 我們稍後會了解*模組*和*包*到底是什麼,但現在,請了解**模組由檔案名稱命名**,而**套件由其目錄名稱命名**。 換句話說,**檔案名稱應全部小寫,如果可以提高可讀性,則使用下劃線。**同樣,**目錄名稱應全部小寫,如果可以避免,則不使用下劃線**。換句話說... + 執行此動作:`awesomething/data/load_settings.py` + 不是這個:`awesomething/Data/LoadSettings.py` 我知道,我知道,這是一種冗長的表達方式,但至少我在你的步驟中加入了一點 PEP。 (*你好?這個東西開著嗎?*) # 套件和模組 這會讓人感覺虎頭蛇尾,但這裡是那些承諾的定義: **任何Python(`.py`)檔案都是一個*模組*,目錄中的一堆模組是一個*套件*。** 嗯……差不多了。要讓目錄成為包,您還必須做另一件事,那就是將名為「__init__.py」的檔案貼到其中。實際上,您不必將任何內容*放入*該文件中。它必須在那裡。 您也可以使用`__init__.py` 做其他很酷的事情,但這超出了本指南的範圍,因此[請閱讀文件以了解更多資訊](https://docs.python.org/3/tutorial/modules.html#packages)。 如果你*確實*忘記了套件中的`__init__.py`,它會做一些比失敗更奇怪的事情,因為這使它成為一個**隱式命名空間包**。您可以使用這種特殊類型的套件做一些有趣的事情,但我不會在這裡討論。像往常一樣,您可以透過閱讀文件來了解更多:[PEP 420:隱式命名空間包](https://www.python.org/dev/peps/pep-0420/)。 所以,如果我們看看我們的專案結構,`awesomething` 實際上是一個包,它可以包含其他包。因此,我們可以將「awesomething」稱為我們的*頂級包*,以及其*子包*下的所有包。一旦我們開始進口東西,這將非常重要。 讓我們看一下我的現實專案“遺漏”的快照,以了解我們如何建置東西... ``` omission-git ├── LICENSE.md ├── omission │ ├── app.py │   ├── common │   │   ├── classproperty.py │   │   ├── constants.py │   │   ├── game_enums.py │   │   └── __init__.py │   ├── data │   │   ├── data_loader.py │   │   ├── game_round_settings.py │   │   ├── __init__.py │   │   ├── scoreboard.py │   │   └── settings.py │   ├── game │   │   ├── content_loader.py │   │   ├── game_item.py │   │   ├── game_round.py │   │   ├── __init__.py │   │   └── timer.py │   ├── __init__.py │   ├── __main__.py │   ├── resources │   └── tests │   ├── __init__.py │   ├── test_game_item.py │   ├── test_game_round_settings.py │   ├── test_scoreboard.py │   ├── test_settings.py │   ├── test_test.py │   └── test_timer.py ├── pylintrc ├── README.md └── .gitignore ``` (如果您想知道的話,我使用 UNIX 程式“tree”來製作上面的小圖。) 您會看到我有一個名為“omission”的頂級包,它有四個子包:“common”、“data”、“game”和“tests”。我還有“resources”目錄,但只包含遊戲音訊、圖像等(為簡潔起見,此處省略)。 `resources` 不是一個包,因為它不包含 `__init__.py`。 我的頂層包中還有另一個特殊檔案:`__main__.py`。這是當我們直接透過「python -m omission」執行頂級套件時執行的檔案。我們稍後會討論「__main__.py」中的內容。 # 導入如何進行 如果您以前編寫過任何有意義的 Python 程式碼,那麼您幾乎肯定熟悉「import」語句。例如... ``` import re ``` 知道當我們導入模組時,我們實際上是在執行它是有幫助的。這意味著模組中的任何“import”語句也正在執行。 例如,[`re.py`](https://github.com/python/cpython/blob/3.7/Lib/re.py#L122) 有幾個自己的 import 語句,當我們說 `導入重新`。這並不意味著它們可用於我們從*導入“re”的文件,但這確實意味著這些文件必須存在。如果(由於某種不太可能的原因)“enum.py”在您的環境中被刪除,並且您執行了“import re”,它將失敗並出現錯誤... > 回溯(最近一次呼叫最後一次): > 檔案“weird.py”,第 1 行,位於 <module> 中 > 進口再 > 檔案“re.py”,第 122 行,位於 <module> 中 > 導入枚舉 > ModuleNotFoundError:沒有名為「enum」的模組 當然,讀到這裡,你可能會有點困惑。有人問我為什麼找不到外部模組(在本例中為“re”)。其他人想知道為什麼要導入內部模組(此處為“enum”),因為他們沒有直接在程式碼中請求它。答案很簡單:我們導入了 `re`,然後導入了 `enum`。 當然,上面的場景是虛構的:「import enum」和「import re」在正常情況下永遠不會失敗,因為這兩個模組都是Python核心庫的一部分。這只是一個愚蠢的例子。 ;) # 匯入註意事項 實際上有多種導入方式,但其中大多數應該很少使用(如果有的話)。 對於下面的所有範例,我們假設有一個名為「smart_door.py」的檔案: ``` # smart_door.py def close(): print("Ahhhhhhhhhhhh.") def open(): print("Thank you for making a simple door very happy.") ``` 例如,我們將在 Python 互動式 shell 中執行本節中的其餘程式碼,執行位置與「smart_door.py」相同。 如果我們想執行`open()`函數,我們必須先導入模組`smart_door`。最簡單的方法是...... ``` import smart_door smart_door.open() smart_door.close() ``` 我們實際上會說“smart_door”是“open()”和“close()”的**命名空間**。 Python 開發人員非常喜歡命名空間,因為它們讓函數和其他內容的來源一目了然。 (順便說一句,不要將 *命名空間* 與 *隱式命名空間包* 混淆。它們是兩個不同的東西。) **Python 之禪**,也稱為 [PEP 20](https://www.python.org/dev/peps/pep-0020/),定義了 Python 語言背後的哲學。最後一行有一個聲明解決了這個問題: > 命名空間是一個非常棒的想法——讓我們做更多這樣的事情! 然而,在某種程度上,命名空間可能會變得很痛苦,尤其是對於嵌套包來說。 `foo.bar.baz.whatever.doThing()` 太醜了。值得慶幸的是,我們確實有辦法避免*每次*呼叫函數時都必須使用命名空間。 如果我們希望能夠使用 `open()` 函數,而不必總是在其前面加上模組名稱,我們可以這樣做... ``` from smart_door import open open() ``` 但請注意,「close()」和「smart_door.close()」在最後一個場景中都不起作用,因為我們沒有直接匯入該函數。要使用它,我們必須將程式碼更改為這樣... ``` from smart_door import open, close open() close() ``` 在之前可怕的嵌套包噩夢中,我們現在可以說“from foo.bar.baz.whatever import doThing”,然後直接使用“doThing()”。或者,如果我們想要一點命名空間,我們可以說“from foo.bar.baz importwhatever”,然後說“whatever.doThing()”。 “導入”系統非常靈活。 但不久之後,您可能會發現自己說“但是我的模組中有數百個函數,我想全部使用它們!”這是許多開發人員偏離軌道的地方,這樣做... ``` from smart_door import * ``` **這非常非常糟糕!** 簡而言之,它直接導入模組中的所有內容,這是一個問題。想像一下下面的程式碼... ``` from smart_door import * from gzip import * open() ``` 你認為會發生什麼事?答案是,「gzip.open()」將是被呼叫的函數,因為這是在我們的程式碼中導入並定義的「open()」的最後一個版本。 `smart_door.open()` 已被 **shadowed** - 我們不能稱之為 `open()`,這意味著我們實際上根本無法呼叫它。 當然,由於我們通常不知道,或者至少不記得每個導入的模組中的*每個*函數、類別和變數,所以我們很容易陷入一堆混亂。 *Python 之禪* 也解決了這個情況... > 顯式優於隱式。 您永遠不必“猜測”函數或變數來自何處。文件中的某個位置應該有程式碼“明確”告訴我們它來自哪裡。前兩個場景證明了這一點。 我還應該提到,早期的 `foo.bar.baz.whatever.doThing()` 場景是 Python 開發人員不喜歡看到的。也來自 *Python 之禪*... > 扁平比嵌套更好。 一些包的嵌套是可以的,但是當你的專案開始看起來像一套精緻的俄羅斯娃娃時,你就做錯了。將模組組織到包中,但保持相當簡單。 # 在您的專案中匯入 我們之前建立的專案文件結構即將「非常方便」。回想一下我的「遺漏」專案... ``` omission-git ├── LICENSE.md ├── omission │ ├── app.py │ ├── common │ │ ├── classproperty.py │ │ ├── constants.py │ │ ├── game_enums.py │ │ └── __init__.py │ ├── data │ │ ├── data_loader.py │ │ ├── game_round_settings.py │ │ ├── __init__.py │ │ ├── scoreboard.py │ │ └── settings.py │ ├── game │ │ ├── content_loader.py │ │ ├── game_item.py │ │ ├── game_round.py │ │ ├── __init__.py │ │ └── timer.py │ ├── __init__.py │ ├── __main__.py │ ├── resources │ └── tests │ ├── __init__.py │ ├── test_game_item.py │ ├── test_game_round_settings.py │ ├── test_scoreboard.py │ ├── test_settings.py │ ├── test_test.py │ └── test_timer.py ├── pylintrc ├── README.md └── .gitignore ``` 在我的“game_round_settings”模組中,由“omission/data/game_round_settings.py”定義,我想使用“GameMode”類別。類別在「omission/common/game_enums.py」中定義。我怎樣才能到達它? 因為我將“omission”定義為包,並將模組組織到子包中,所以實際上非常簡單。在“game_round_settings.py”中,我說...... ``` from omission.common.game_enums import GameMode ``` 這稱為**絕對導入**。它從頂級包“omission”開始,然後進入“common”包,在其中查找“game_enums.py”。 一些開發人員向我提供更像「from common.game_enums import GameMode」的導入語句,並想知道為什麼它不起作用。簡而言之,「data」套件(「game_round_settings.py」所在的位置)不知道其兄弟包。 然而,它確實知道它的父母。正因為如此,Python 有一種叫做「相對導入」的東西,它可以讓我們做同樣的事情,就像這樣... ``` from ..common.game_enums import GameMode ``` `..` 表示“此套件的直接父包”,在本例中為“omission”。因此,導入後退一級,進入“common”,並找到“game_enums.py”。 關於是否使用絕對導入或相對導入有許多爭論。就我個人而言,我更喜歡盡可能使用絕對導入,因為它使程式碼更具可讀性。不過,您可以自己做決定。唯一重要的部分是結果是「顯而易見的」——任何東西的來源都不應該是神秘的。 (繼續閱讀:[Real Python - Python 中的絕對導入與相對導入](https://realpython.com/absolute-vs-relative-python-imports/) 這裡還隱藏著另一個陷阱!在 `omission/data/settings.py` 中,我有這一行: ``` from omission.data.game_round_settings import GameRoundSettings ``` 當然,由於這兩個模組都在同一個包中,我們應該可以直接說“from game_round_settings import GameRoundSettings”,對嗎? *錯誤!* 它實際上無法找到“game_round_settings.py”。這是因為我們正在執行頂級包“omission”,這意味著**搜尋路徑**(Python 查找模組的位置以及順序)的工作方式不同。 但是,我們可以使用相對導入來代替: ``` from .game_round_settings import GameRoundSettings ``` 在這種情況下,單一“.”表示“這個包”。 如果您熟悉典型的 UNIX 檔案系統,這應該開始有意義。 `..` 表示“後一級”,“.` 表示“目前位置”。當然,Python 更進一步:`...` 表示“後兩級”,`....` 表示“後三級”,依此類推。 但是,請記住,這些「等級」不僅僅是簡單的目錄。他們是包裹。如果在一個不是包的普通目錄中有兩個不同的包,則不能使用相對導入從一個包跳到另一個包。為此,您必須使用 Python 搜尋路徑,但這超出了本指南的範圍。 (請參閱本文末尾的文件。) # `__main__.py` 還記得我提到在我們的頂級包中建立一個 `__main__.py` 嗎?這是一個特殊的文件,當我們直接使用 Python 執行套件時會執行該文件。我的“omission”包可以使用“python -m omission”從我的存儲庫的根目錄執行。 這是該文件的內容: ``` from omission import app if __name__ == '__main__': app.run() ``` 是的,實際上就是這樣!我正在從頂級包“omission”導入我的模組“app”。 請記住,我也可以說「來自…」。改為導入應用程式。或者,如果我只想說“run()”而不是“app.run()”,我可以執行“from omission.app import run”或“from .app import run”。最後,只要程式碼可讀,我如何進行導入並沒有太大的技術差異。 (附註:我們可以爭論為我的主要`run()` 函數設定一個單獨的`app.py` 對我來說是否合乎邏輯,但我有我的理由......而且它們超出了本指南的範圍。 ) 首先讓大多數人感到困惑的部分是整個「if __name__ == '__main__'」語句。 Python 沒有太多**樣板** - 必須非常普遍地使用且幾乎不需要修改的程式碼 - 但這是那些罕見的位元之一。 `__name__` 是每個 Python 模組的特殊字串屬性。如果我將“print(__name__)”行貼在“omission/data/settings.py”的頂部,當該模組被導入(並因此執行)時,我們會看到“omission.data.settings”被打印出去。 當模組直接透過「python -m some_module」運作時,模組會被指派一個特殊值「__name__」:「__main__」。 因此,「if __name__ == '__main__':」實際上是在檢查該模組是否以 *main* 模組執行。如果是,它將在條件下執行程式碼。 您可以透過另一種方式看到這一點。如果我將以下內容加入到“app.py”的底部... ``` if __name__ == '__main__': run() ``` ……然後我可以直接透過 `python -m omission.app` 執行該模組,結果與 `python -m omission` 相同。現在`__main__.py`被完全忽略,`omission/app.py`的`__name__`是`"__main__.py"`。 同時,如果我只是執行“python -m omission”,“app.py”中的特殊程式碼將被忽略,因為它的“__name__”現在又是“omission.app”。 看看效果如何? # 總結 我們來複習。 * 每個專案都應該使用 VCS,例如 Git。有很多選項可供選擇。 * 每個 Python 程式碼檔案 (`.py`) 都是一個 **模組**。 * 將您的模組組織到**包**中。每個包必須包含一個特殊的「__init__.py」檔案。 * 您的專案通常應由一個頂級包組成,通常包含子包。該頂級包通常共享您的專案的名稱,並作為專案存儲庫根目錄中的目錄存在。 * **永遠不要**在導入語句中使用「*」。在考慮可能的例外之前,Python 之禪指出「特殊情況並沒有特殊到足以違反規則」。 * 使用絕對或相對導入來引用專案中的其他模組。 * 可執行專案的頂層套件中應該有一個`__main__.py`。然後,您可以使用「python -m myproject」直接執行該套件。 當然,我們可以在建立 Python 專案時使用許多更高級的概念和技巧,但我們不會在這裡討論。我強烈建議閱讀文件: + [Python 參考:導入系統](https://docs.python.org/3/reference/import.html) + [Python 教學:模組](https://docs.python.org/3/tutorial/modules.html) + [PEP 8:Python 風格指南](https://www.python.org/dev/peps/pep-0008/) + [PEP 20:Python 之禪](https://www.python.org/dev/peps/pep-0020/) + [PEP 240:隱式命名空間套件](https://www.python.org/dev/peps/pep-0420/) --- *感謝 `grym`、`deniska` (Freenode IRC `#python`)、@cbrintnall 和 @rhymes (Dev) 提出的修改建議。* --- 原文出處:https://dev.to/codemouse92/dead-simple-python-project-structure-and-imports-38c6

每個開發者都必須知道的 12 個網站 🤩

**開發者們大家好!** 歡迎來到我的另一篇博文。 在這篇文章中,我想分享一些每個開發人員都必須了解的基本網站或工具。 所以讓我們**開始**👇並且不要**忘記**“💖🦄🔥”。 --- ## 1. [omatsuri.app](https://omatsuri.app) 🍡 ![omatsuri](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ic3rw7rpncvtsbas0an9.jpeg) Omatsuri 是一個提供網頁開發人員資源的日本網站。 “Omatsuri”,一個漸進式 Web 應用程式 (PWA),提供 **12 個開源前端工具的集合**。 這些資源**免費使用**和自訂,這在您設計新網站或應用程式時非常有幫助。 --- ## 2. [htmlrev.com](https://htmlrev.com/) 📄 ![htmlrev](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qa8wq2cfu7bn12h34l85.jpeg) HTMLrev 是一個**尋找 HTML 範本**和設計資源的絕佳網站。 他們為網站、登陸頁面、部落格、作品集等提供免費的 html 模板。 這些模板隨時可用且易於自訂。這是滿足您所有範本需求的一站式場所。 --- ## 3. [Unicornicons.com](https://unicornicons.com/) 🦄 ![unicorcicons](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zb4alzy6dmxa67p4prfk.jpeg) Unicornicons 擁有**漂亮的動畫圖示**,您可以在專案中使用它們。 他們有高級圖標包,但也提供許多**免費圖標**。這些圖標有助於使介面更具吸引力和樂趣。 您還可以輕鬆自訂顏色。 --- ## 4. [UiVerse.io](https://uiverse.io/)✨ ![uiverse](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iko1dy9qzowtp0m2pxs4.jpeg) UiVerse 是一個使用 CSS 和 Tailwind 建立的 UI 元素社群。 他們擁有超過 **3000 個元素,可以在 MIT 許可下免費**使用。 這對於建立 UI 元件並節省開發時間非常有用。您可以搜尋、篩選元素並直接取得要複製的程式碼。 --- ## 5. [undraw.co](https://undraw.co/illustrations) 🖌 ![取消繪製](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ejqgeh89p0m4bxhqres4.jpeg) Undraw 是一個開源插圖函式庫。他們提供**美麗的 SVG 插圖**,您可以免費使用。 這些插圖很現代,可以輕鬆自訂。這對於登陸頁面、有關部分和產品行銷的內容非常有幫助。 他們也不斷加入新的插圖。 --- ## 6. [patternpad.com](https://patternpad.com/) 🎨 ![patternpad](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1dmudn1m4qkn5kb4ukl.jpeg) PatternPad 讓您設計來自無限顏色和形狀變化的圖案。您可以在這裡非常輕鬆地**建立獨特的品牌模式**、簡報、社交貼文等。 圖案匯出為 SVG 以供靈活使用。這是一個很好的工具,可以為您的設計增添視覺吸引力。 --- ## 7. [shapeivider.app](https://www.shapeivider.app/) 🗺 ![shapeivider](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2rofzquhdbh1rh0zd4z.jpeg) ShapeDivider 可協助您非常輕鬆地**在**標題、段落或部分之間新增曲線形狀。它是設計中經常使用的技術。 該網站允許您透過選擇形狀和顏色類型來產生程式碼。您可以**直接複製並貼上程式碼**。非常有用的工具! --- ## 8. [photopea.com](https://www.photopea.com/) 📸 ![photopea](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/811c325yaic55z5dyxnm.jpeg) Photopea 是一款線上照片編輯器,支援 PSD、XCF、Sketch、XD 和 CDR 格式。 **您可以免費開啟、編輯和儲存照片**,無需安裝任何軟體。 它具有類似於 Photoshop 的工具,但對初學者非常友好。這非常適合開發人員的基本影像編輯需求。 --- ## 9. [quickref.me](https://quickref.me/) 🧑‍💻 ![quickref](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/we3ozwf4mz5emjduqs9g.jpeg) QuickRef 是各種**開發人員工具、框架和技術**的備忘單集合。它們涵蓋了從程式語言、資料庫、設計工具到終端命令的所有內容。 這些備忘單可以幫助您更快學習,並且在開發過程中也非常方便。 **將此加入書籤!**。 --- ## 10. [devdocs.io](https://devdocs.io/) 📚 ![devdocs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dfm13a7p6avflurnp7kc.jpeg) DevDocs 為許多程式庫和框架提供 API 文件。 **它從各種來源收集文件**並以有組織的方式呈現它們。 在開發過程中,經常需要參考文件。該網站使您可以輕鬆快速地找到所需的內容。 --- ## 11. [devhints.io](https://devhints.io/) 📝 ![devhints](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/233ziqtf3v6e0w9lkgyn.jpeg) Devhints 包含各種技術和工具的簡明備忘單。這些就像**開發人員的袖珍參考卡**。該資訊清晰呈現,沒有額外的細節。 他們專注於最重要的功能。這是一個很棒的網站,可以找到快速提醒。 --- ## 12. [開發工具](https://developer.chrome.com/docs/devtools/) 🛠 Chrome 開發者工具或 DevTools 是一套強大但有時令人難以抗拒的 Web 開發者工具。 developer.chrome 上的文件可協助您掌握這些工具。它涵蓋了每個面板的使用、鍵盤快捷鍵以及提示和技巧。任何開發人員都不應忽略 Chrome DevTools 文件。 --- ## 就是這樣😁 感謝您閱讀這篇部落格🙏,我希望這能為您帶來一些新的去處! 如果您發現任何其他有用的網站,請發表評論📩。 並且不要忘記加上“💖🦄🔥” **快樂編碼👋** --- 原文出處:https://dev.to/random_ti/top-12-websites-that-every-developer-must-know-2a67