🔍 搜尋結果:API

🔍 搜尋結果:API

資料庫 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

🪄與您的簡歷製作者聊天 - 使用 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

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

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

使用 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

每個開發者都必須知道的 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

✨ 5 個被低估的開源專案 🫵🤐

## 簡介 本文列出了五個不太受歡迎的優秀專案,您應該嘗試一下。 🔥 這些工具旨在改進**資料處理**、**API 開發**、**後端測試**、**身份驗證**和**安全隧道**。 諸如此類的開源專案依賴社群支持🙏,因此請考慮探索並為這些儲存庫加註星標,以促進它們的發展。 ![擁抱 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxhja1odmmx414wrts5a.gif) *** ## 1. [集算器](http://scudata.com) **- 資料處理** > 💡 集算器是一種用於資料處理的腳本語言,具有豐富的函式庫函數和強大的語法。 ![集算器資料處理腳本語言](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z9dts1lgr1zy96k6zveu.jpg) 集算器是一個針對結構化和半結構化資料的計算和處理引擎。集算器既不是SQL系統,也不是NoSQL技術(如MongoDB),而是採用自創的SPL(結構化處理語言)語法,編碼更簡單,可以利用現有的資料處理技術建立高效的程式。 集算器是**純Java**編寫的,可以輕鬆為您的Java🍵應用程式加入強大的資料處理功能,但非Java應用程式可以透過RESTful API呼叫集算器。 ### 熱門常見問題解答🤔 > **⬇️集算器可以執行在哪些平台上?** 由於它純粹是用 Java 建置,因此可以在任何配備 JVM(Java 虛擬機)、雲端伺服器甚至容器的作業系統中流暢執行。 😎 > **⬇️集算器可以基於現有資料庫運作嗎?** 是的當然!集算器支援數十種資料來源,包括資料庫、文字、excel、json/xml、web服務等。 > **⬇️ 為什麼要放棄 SQL 而選擇集算器?** 簡化的逐步程式碼,易於編寫和除錯。相較於SQL降低N倍的開發、硬體、維運成本。 > 🟢我最近寫了一篇關於這個工具的文章,重點介紹了它的強大功能。看看吧👇。 https://dev.to/shricodev/one-must-have-tool-for-anyone-in-data-field-2jek > 如果你想更深入地了解這個工具的潛力,**[jbx1279](https://dev.to/jbx1279)**分享了一些關於集算器和SPL本身的富有洞察力的文章。請務必也檢查一下它們。 https://github.com/SPLWare/esProc *** ## 2. [Firecamp](https://firecamp.dev/) **- 郵差替代方案** > 💡 API 開發平台,幫助開發人員輕鬆設計、開發、測試和記錄他們的 API。 ![Firecamp 工具 Postman 替代品](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uigr65jz5z6yh731x9gm.jpg) Firecamp 是開放原始碼 Postman 的替代方案,具有 VScode DX,這是一個優先考慮開發人員體驗的 API 開發平台,並為設計、測試和記錄 API 提供無縫環境。 🎯 借助 Firecamp,跨工作區和團隊就 API 集合進行協作,並更快地建立 API,而無需在工具和應用程式之間切換。文件、CLI、CI/CD 一站式提供。 > **⬇️ 從 Postman 切換到 Firecamp 對我來說有挑戰性嗎?** 您可以將 Postman 腳本和資料(例如 **API Collection** 和 **環境變數**)無縫傳輸到 Firecamp,沒有任何問題。 ![Firecamp Postman 替代方案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q74wl17yc9b7clse6m3h.png) https://github.com/firecamp-dev/firecamp *** ## 3. [Keploy](https://keploy.io/) **- 後端測試** > 💡 為您的應用程式產生實際有效的測試和存根! ![Keploy 產生後端測試](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ry5awt5wtk5qyiqccbwp.jpg) Keploy 是您的開源、以開發人員為中心的後端測試工具。它使工程團隊的後端測試變得簡單且有效率。使用 Keploy,我們不必編寫手動測試用例。 它記錄 API 互動和預期回應,並產生測試案例和資料模擬,使我們的工作變得輕鬆高效,顯著加快發布速度並增強可靠性。 📈 > **⬇️ 它是一個單元測試框架嗎?還是它完全取代了單元測試?** Keploy 與「go-test」、「Pytest」或「Jest」等單元測試框架配合得很好,可簡化測試流程並節省高達 80% 的工作。雖然它涵蓋了大多數情況,但您仍然可以選擇為非 API 可呼叫方法編寫測試。 > **⬇️ 我需要更改程式碼才能將 Keploy 整合到我的應用程式中嗎?** 不需要。Keploy 可以很好地與您現有的程式碼庫配合,無需更改程式碼。 ![Keploy 後端測試示範](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdsnkmq2efgxltzplfq9.gif) https://github.com/keploy/keploy *** ## 4. [Hanko](https://hanko.io) **- 金鑰驗證** > 💡 支援 FIDO2 和 WebAuthn 標準的無密碼身份驗證伺服器。 ![Hanko 金鑰驗證](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqifvf1i536y0afh7nhe.jpg) Hanko 是一款輕量級開源用戶身份驗證解決方案,可帶您踏上超越密碼的旅程。它支援 FIDO2 和 WebAuthn 標準,提供安全、無縫的使用者身份驗證體驗。 > **⬇️ Hanko 如何運作?** Hanko 的工作原理是使用使用者自己的裝置(例如智慧型手機、筆記型電腦或安全金鑰)註冊和驗證使用者。這些裝置可作為加密令牌,無需密碼或其他憑證即可證明使用者的身分。 Hanko 還支援各種身份驗證方法,例如行動應用程式中的生物辨識或 OAuth 登入。 > **⬇️ 我該如何開始使用 Hanko?** 您可以透過註冊免費帳戶並按照文件和教學課程開始使用 Hanko。對於生產用途,請選擇 Hanko Cloud。 > 🟢 我最近使用 Hanko Passkeys 身份驗證建立了一個專案。查看**[此處](https://github.com/shricodev/pdfwhisper-openai)**。 ![Hanko 登陸頁](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emte4gfglhdft8g8dlhh.png) https://github.com/teamhanko/hanko *** ## 5. [Zrok](https://zrok.io/) **- Ngrok 類固醇** > 💡 Ngrok 的替代品,提供增強的功能和免費的 SaaS 型號。 ![Zrok ngrok 替代方案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x4n31emowwxoamfqzawm.jpg) Zrok 是一個建立在 **OpenZiti** 之上的工具,有助於共享正在執行的服務,例如 Web 伺服器或網路套接字,或安全地將靜態檔案目錄共享到網際網路。它是 Ngrok 的替代品,但具有一些增強功能和**免費 SaaS** 型號。 借助 Zrok,您可以為應用程式建立安全隧道,從而更輕鬆地共享和協作專案。 > **⬇️ 使用 Zrok 相對於 Ngrok 有什麼好處?** Zrok 擁有內建的身份驗證系統、用於管理隧道的 Web 儀表板以及免費的 SaaS 模型。它也是完全**可自我託管**。 > **⬇️ 我該如何開始使用 Zrok?** 若要開始使用 Zrok,請下載適合您平台的 Zrok 用戶端或使用 Web 介面建立隧道。您也可以使用 Zrok CLI 從命令列建立和管理隧道。 ![Zrok 安全隧道](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bp8bguor0wj3i8h6ail1.png) https://github.com/openziti/zrok *** > 如果您認為您使用的任何其他方便的專案沒有應有的受歡迎,請在下面的評論部分分享。 👇 非常感謝您的閱讀! 🎉🫡 --- 原文出處:https://dev.to/shricodev/top-5-underrated-open-source-projects-that-no-one-talks-about-2gki

我們用於建立人工智慧/資料全端應用程式的開源專案獲得了資助! 🎉🎉

𝗛𝗶𝗖𝗼𝗺𝗺𝘂𝗻𝗶𝘁𝘆, 我們很高興與您分享這個好訊息:我們上個月完成了 500 萬美元的種子輪融資,以幫助開發人員建立 AI/資料全端應用程式。 𝗧𝗵𝗲 𝗧𝗮𝗶𝗽𝘆 𝗦𝘁𝗼𝗿𝘆 幾年前,Albert 和我在為大型組織領導人工智慧專案多年後,決定是時候過渡到完整的 Python 開發並停止使用傳統的 Java、JS、.Net 堆疊等。 我們非常清楚我們正在尋找哪些功能,但令我們驚訝的是,我們在許多現有的 Python 套件中找不到它們。 我們的使命既簡單又雄心勃勃:提供缺少的磚塊,阻止如此多的人工智慧/資料試點成功部署專案。 特別是,我們希望將最終用戶帶回「人工智慧/資料」畫面。今天我仍然驚訝地發現,關於最終用戶的提及如此之少:從資料科學家到資料工程師,都是關於資料流、公開演算法等?沒有提及人類將如何與人工智慧/資料模型互動......我們想改變這一切! 所以我們決定建造 Taipy… 𝗧𝗮𝗶𝗽𝘆𝗰𝗼𝗺𝗯𝗶𝗻𝗲𝘀: - 功能強大的互動式前端應用程式產生器,但學習/使用非常簡單。 - 「場景」是最終用戶(以及資料科學家)輕鬆與資料和演算法互動的可能性。 2022 年,我們首次推出了 Taipy 作為開源專案(請查看我們的 [GitHub 頁面](https://github.com/Avaiga/taipy)),隨後於當年稍後推出了企業版本。 感謝這個令人驚嘆的社區的大力支持和興趣,我們的 GitHub 計畫不僅流行,而且受歡迎程度也顯著上升,在幾週內從 100 顆星增加到 3,000 多顆星!我們非常感謝您的支持和熱情。 [隨意 ⭐ Taipy 儲存庫](https://github.com/Avaiga/taipy) 我還要感謝我們早期的企業採用者,他們在驗證和測試新技術方面非常重要。感謝麥當勞、KnowledgeTouch、Groupe Les Mousquetaires、Total Energies、Textil Apparel Limited、IFP-EN 等提供的特價。 𝗣𝗿𝗼𝗱𝘂𝗰𝘁𝗦𝘁𝗮𝘁𝘂𝘀 我們最近發布了: - [Taipy Cloud](https://www.taipy.io/posts/introducing-taipy-cloud-the-easiest-way-to-deploy-your-taipy-applications)允許社群使用者部署、託管和與世界其他地方分享他們的應用程式 - 重要的後端功能:Taipy Studio、應用程式版本控制、任務排程、Python API、用於場景管理的視覺化元件、新的 CLI 等等... - 在前端方面:一個新的樣式套件、一組用於即時應用程式建立的預設樣式表範本、新圖表... - [TalkToTaipy](https://talk-to-taipy.tapy.cloud/),基於 LLM 的應用程式,僅使用自然語言探索資料集 𝗧𝗮𝗶𝗽𝘆’𝘀𝗳𝘂𝘁𝘂𝗿𝗲 這項重大投資使我們能夠繼續全職致力於改進 Taipy。這筆資金也是實現我們願景的關鍵一步,將 Taipy 定位為 Python 人工智慧/資料專案的領先平台。 𝗧𝗵𝗲 𝗻𝗲𝘅𝘁 𝗿𝗲𝗹𝗲𝗮𝘀𝗲 (𝗽𝗹𝗮𝗻 𝟰) 即將(本季)推出的精彩版本包含主要新功能: - 全新的**無程式碼 GUI 設計器**:您無需編碼即可建立 GUI 頁面!抱歉劇透,但這位新設計師是個殺手! - **分散式計算:** 在遠端叢集上執行以並行場景/任務執行。 - **與主要平台整合**:如 Databricks、Dataiku 等。 所有這一切,同時忠於我們的開源根源! 𝗢𝗻 𝘁𝗵𝗲 𝗰𝗼𝗺𝗺𝘂𝗻𝗶𝗰𝗮𝘁𝗶𝗼𝗻 𝘀𝗙 - 我們現在出現在多個社群平台:[Discord](https://discord.com/invite/SJyz2VJGxV)、[LinkedIn](https://www.linkedin.com/company/taipy-io)、[ X](https://twitter.com/Taipy_io) 和[YouTube](https://www.youtube.com/@taipy_io)。 - 我們贊助了多項活動:會議(PyData、Pycon、ODSC...)、黑客馬拉松、派對、網路研討會... - 我們也計劃很快開始定期舉辦 Taipy 技術講座。 。 是的,所有這些都是開源的! 我們總是渴望收到您的來信,因此,如果您認為 Taipy 需要改進或加入哪些內容,請告訴我們。您的意見對於制定我們的路線圖非常寶貴。 謝謝大家的支持。沒有您,我們不可能達到這個里程碑! 文森特·戈塞林和阿爾伯特·安托萬 太皮聯合創辦人 還沒看過 Taipy 嗎?歡迎造訪我們的[GitHub頁面](https://github.com/Avaiga/taipy )。 --- 原文出處:https://dev.to/taipy/our-open-source-project-for-building-ai-data-full-stack-apps-got-funded-4e68

网页文件加载失败如何重试

> 本文主要讲解脚本文件加载失败时的处理,对于其他类型的文件加载错误时,解决方向大致一样 ## 背景 在我们开发网站应用时,我们可能会遇到脚本加载失败的情况,导致脚本加载失败的原因有很多,比如用户的网络问题、终端设备问题、用户浏览器版本等诸多因素。 ## 解决方案 在 JavaScript 中,我们可以创建一个监听来监听脚本加载失败的情况,然后针对加载失败的脚本进行重新加载。 重新加载的方案,一般是通过更换域名来解决。我们给每个脚本添加一个映射关系表,用来在加载失败时匹配新的域名进行重试。 具体的解决方案,下面我一步一步讲解,另外希望大家可以仔细阅读注释中的内容 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>脚本加载失败如何重试</title> <script> window.addEventListener( "error", // 监听全局错误 function (e) { console.log(e); }, true // 由于脚本加载失败不会冒泡,所以我们要在捕获阶段进行监听 ); </script> </head> <body> <script src="https://www.zowlsat.com/api/1.js"></script> <script src="https://www.qqqqqqq.com/api/2.js"></script> <script src="https://www.zowlsat.com/api/3.js"></script> </body> </html> ``` 此时我们可以在浏览器控制台看到以下效果 ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/1.png) 但是这个监听方法会监听到很多其他的错误,我们只需要监听脚本加载失败的错误,所以我们要通过这个监听事件的参数 e 来判断了 ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/2.png) 根据上图我们可以发现,普通错误的类型是 ErrorEvent,而脚本加载失败的类型是 Event,并且他的 target 会指向 script 标签,所以我们根据这个区别过滤掉其他的错误,这样剩下的情况才是我们需要处理的。 ```js window.addEventListener( "error", function (e) { if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return; console.log(e); }, true ); ``` 接下来就是如何来实现重新加载,我们先给需要重新加载的域名建立一个映射关系,用于替换映射关系表中的域名。然后就是挨个匹配,当还是加载失败时继续匹配下一个,直到成功为止。 ```js const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"]; const retry = {}; window.addEventListener( "error", function (e) { if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return; // 创建一个URL对象 const url = new URL(e.target.src); // 获取文件路径 const key = url.pathname; // 假如映射表中没有这个文件路径,那么就初始化一个映射键 if (!(key in retry)) { retry[key] = 0; } // 假如匹配完整个映射表都没重新加载成功,则放弃 const index = retry[key]; if (index >= domainList.length) { return; } // 获取新的完整路径 const domain = domainList[index]; // 替换域名 url.host = domain; // 创建新的script标签 const script = document.createElement("script"); script.src = url.toString(); // 将新的script标签追加到加载失败的script标签之前 document.body.insertBefore(script, e.target); retry[key]++; }, true // 由于脚本加载失败不会冒泡,所以我们要在捕获阶段进行监听 ); ``` 到此为止,我们功能已经基本实现,效果如下图 ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/3.png) 但是有一个很关键的问题,就是假如我 2.js 这个文件中的内容,在 3.js 中要使用,那这样的话,2.js 就必须加载到 3.js 之前,否则就会报错。此时,我们就需要在 2.js 加载失败时,阻塞浏览器的解析,知道重新加载完成或者放弃重新加载时,再继续渲染之后的内容。 那这样的话我们该怎么做呢?🤔 其实很简单,在我们入门 js 时就学到过一个知识点,就是使用`document.write` `document.write`这个方法在解析期间使用的话,会阻塞浏览器的解析,而我们现在就是需要阻塞浏览器解析,那此时我们只需要将创建 script 标签的方法更换为`document.write`方法即可。 修改之后的代码如下: ```js const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"]; const retry = {}; window.addEventListener( "error", function (e) { if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return; const url = new URL(e.target.src); const key = url.pathname; if (!(key in retry)) { retry[key] = 0; } const index = retry[key]; if (index >= domainList.length) { return; } const domain = domainList[index]; url.host = domain; // 此处加上转译是因为防止编译器识别script标签为结束标签报错 document.write(`\<script src="${url.toString()}">\<\/script>`); // const script = document.createElement("script"); // script.src = url.toString(); // document.body.insertBefore(script, e.target); retry[key]++; }, true ); ``` 现在我们再打开控制台查看,现在js文件按它原来的顺序执行了,这样既不会改变原有的代码逻辑,又可以在可控范围内进行重新加载。 效果如下图: ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/4.png) 以上是简单实现了一个js文件重新加载错误的方案,其实这个方案也可以运用到其他很多类型的文件,不限于js文件。 然后我们还需要更加细化这个方法的话,我们可能还需要考虑到这个script标签是否带有`async`、`defer`等属性,还有诸多需要考虑的点,但是沿着这个方向解决的话,大体是没有问题的。

✨2024 我的決心:更以開源專案為中心思想!

## 簡介 當(幾乎)總是有一個開源替代品可以完成同樣的工作(如果不是更好的話)時,為什麼還要依賴專有軟體和服務呢? 以下是我一直在使用的 10 個開源替代方案,涵蓋從專案管理和通訊到資料分析的所有內容。 ![Gif 簡介](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypv9s82s7843ecb1a36t.gif) --- ## 1- [Taipy](https://github.com/Avaiga/taipy) 而不是 Tableau Tableau 可能是資料視覺化領域的頂級參與者之一,但 Taipy 提供了強大的替代方案。 Taipy 是一個開源 Python 程式庫,可讓您建立全面的 Web 應用程式來展示資料視覺化。 Taipy 程式碼量低、高度可自訂,並且在建立儀表板時提供更大的靈活性。 ![Taipy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lai9u2uqawun2j5mf7ur.gif) --- ![QueenB GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0un08vhstrk6zpst5yti.gif) 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- ## 2- [Cal.com](http://Cal.com) 而非 Calendly Calendly 是簡化日程安排的變革者,但 [Cal.com](http://Cal.com) 成功地將其提升到了一個新的水平。這個開源 gem 有以下功能: - 團隊調度 - 整合視訊會議 - 自動時區偵測 ![Cal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bjea3cr44s86z5deirt.gif) --- ## 3- [Plausible](https://github.com/plausible/analytics) 而非 Google Analytics 當然,Google Analytics 是一個大牌,但有時較小的工具也能提供同樣多的功能,一個很好的例子就是 Plausible。 這個開源工具提供像Google一樣的網站分析功能,不,他們不會損害資料隱私。 ![看似合理](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cmonhrmf5gch5kn6fe0e.gif) --- ## 4- [AppFlowy](https://github.com/AppFlowy-IO/AppFlowy) 而非 Notion Notion 是一個非常適合做筆記和專案管理的工作空間,但如果您想要一個更簡單的選項,請嘗試 AppFlowy。 該工具提供了一種極簡主義的替代方案,專注於簡單地建立和組織清單、註釋和任務。 介面非常人性化;您很快就會成為專業人士。 ![AppFlowy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wko5i9mphadcq1pa6bsh.gif) --- ## 5- [Penpot](https://github.com/penpot/penpot) 而非 Figma Figma 是一個設計巨頭,但它的開源表弟 Penpot 在過去一年中一直在增長勢頭。 以下是 Penpot 的主要功能: - 協同設計能力 - 向量編輯 - 互動式原型 - 成本效益 ![Penpot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pkg8ayeuw0y1q0tme50t.gif) --- ## 6- [Fonoster](https://github.com/fonoster) 而非 Twilio Twilio 是一個通訊平台,提供簡訊、語音、視訊和身份驗證 API,並提供無縫的客戶體驗。 讓我向您介紹 Fonoster,這是一種經濟高效的替代方案。 Fonoster 提供類似的語音和訊息服務。 Fonoster 專注於可擴展性,同時為您提供無縫的客戶體驗。 ![Fonoster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jk20ziqppgcpbfr6e37.gif) --- ## 7- [NextCloud](https://github.com/nextcloud/server) 而不是 Dropbox NextCloud 是 Dropbox 的開源競爭對手。 它提供文件託管、協作和同步功能,同時保持資料的隱私性並處於您的控制之下。 ![NextCloud](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szichu2pjf9xzah9v64y.gif) --- ## 8- [Jitsi](https://github.com/jitsi/jitsi-meet) 而非 Google Meets Jitsi 是 Google Meets 的替代品,提供類似的視訊會議功能。 他們的主要特徵: - 端對端加密 - 螢幕分享 - 並且無需註冊! ![Jitsi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwnxa8hy6a0svqb4yo1d.gif) --- ## 9- [Padloc](https://github.com/padloc/padloc) 與 1Password 1Password 在密碼管理領域享有盛譽,但開源工具 Padloc 同樣注重隱私和安全性。 您可以使用 Padloc 安全地儲存和管理您的敏感和私人訊息,就像 1Password 一樣。 ![Padloc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4st8nymwlf3wlslz029k.gif) --- ## 10- [Crowd.dev](https://github.com/CrowdDotDev/crowd.dev) 而非公共房間 Common Room 在社區建設領域一直勢頭強勁,但不要忽視他們的開源替代方案「crowd.dev」。 無論是專案管理、資金還是協作,「crowd.dev」對於建立和發展線上社群都是不可忽視的。 ![人群](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9j3mxkbk6wuwyt2g1fdh.gif) --- ## 結論 選擇工具時,請記住查看開源選項。 開源帶來了透明度、可自訂性和成本效益,在大多數情況下都是不錯的選擇。 ![GIF 結束](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvimkpxsq91d6m1jfei1.gif) 恭喜你,你已經走到最後了!如果您有任何疑問,請隨時諮詢。 --- 原文出處:https://dev.to/taipy/2024-resolution-be-more-open-source-centric-1jje

如何製作精彩的 GitHub 個人資料

如果您是 GitHub 新手或主要使用私人 GitHub 儲存庫,那麼您可能還沒有 GitHub 個人資料。 GitHub 個人資料有助於為存取您個人資料的人提供基本資訊。擁有良好的個人資料甚至可以幫助您脫穎而出,尤其是當您開始為開源專案做出貢獻並且人們開始注意到您時。 在本文中,我將展示如何建立您自己的 GitHub 設定檔。我還將分享從哪裡獲得個人資料的靈感。最後,我將分享資源和技巧,幫助您建立出色的 GitHub 個人資料! ## 建立您的 GitHub 個人資料 在開始自訂 GitHub 個人資料之前,您首先需要建立一個。 這是一個[簡短指南](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme)來自 GitHub,了解如何設定您的個人資料。 但您需要做的就是: - 建立一個新的儲存庫,**與您的 GitHub 使用者名稱**相同。 - 將 `README.md` 檔案新增至您的新儲存庫。 例如,我的 GitHub 使用者名稱是 [kshyun28](https://github.com/kshyun28)。要建立我的個人資料,我需要建立一個也名為 [kshyun28](https://github.com/kshyun28/kshyun28) 的儲存庫,然後新增一個「README.md」檔案。 ![範例 GitHub 設定檔儲存庫](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616186/GitHub%20Profile/github-profile-repository-example_veplgh.png) 設定「儲存庫」和「README.md」檔案後,透過前往您的 GitHub 個人資料(網址為 https://github.com/YOUR-USERNAME )來驗證您的個人資料是否可見。 就我而言,它將是 https://github.com/kshyun28。 ## 自訂您的 GitHub 個人資料 現在您已經有了 GitHub 個人資料,是時候發揮創意了! 這裡的關鍵是**讓你的個性在你的個人資料上展現**。你的 GitHub 個人資料不必像 LinkedIn 那樣太正式。 我還建議**從簡單開始**。這有助於您的 GitHub 設定檔啟動並執行。當您有新想法時,您可以隨時改進您的個人資料。 ### GitHub 風格的 Markdown、格式和 HTML 為了自訂 GitHub 設定檔的“README.md”,您將使用 **GitHub Flavored Markdown**。如果您以前寫過 Markdown 內容,那麼格式化對您來說應該很容易。 如果你是第一次用Markdown 寫作,你可以去[GitHub 的文件](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) 來熟悉可用的格式化選項。 您也可以使用 **HTML** 作為您的個人資料的其他格式選項。 我發現以下 HTML 標記很有用: - 不間斷空格:`nbsp;` - div 居中對齊:`<divalign="center"></div>` 您可以使用大多數 HTML 標籤,但 GitHub Flavored Markdown 會過濾掉以下 HTML 標籤: - `<標題>` - `<文字區域>` - `<樣式>` - `<xmp>` - `<iframe>` - `<無嵌入>` - `<無框架>` - `<腳本>` - `<明文>` > 💡:要了解更多訊息,請參閱與 HTML 區塊相關的 [GitHub Flavored Markdown Spec](https://github.github.com/gfm/#html-blocks)。 ### 尋找靈感 為了幫助您入門,我建議您查看其他很棒的 GitHub 設定檔以獲取想法。你可以造訪 [awesome-github-profile-readme](https://github.com/abhisheknaiidu/awesome-github-profile-readme),我在製作個人資料時找到了靈感。 由於設定檔是開源的,您可以將一些好主意用於您的精彩設定檔! 您也可以查看[我的個人資料](https://github.com/kshyun28)以獲取一些想法。 😉 ### 新增徽章 要為您的個人資料加入徽章,您可以查看 [markdown-badges](https://github.com/Ileriayo/markdown-badges)。該存儲庫有多種徽章可供選擇,從程式語言到 Netflix 等串流平台。 如果您找不到所需的內容或想要建立自訂徽章,可以前往 [shields.io](https://shields.io/),這就是 [markdown-badges](https://github.com/Ileriayo/markdown-badges) 使用。 這是我在個人資料中使用 [markdown-badges](https://github.com/Ileriayo/markdown-badges) 的範例。 ![Markdown 徽章範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/badges-example_t6jyr6.png) ### 新增圖標 要在您的個人資料中加入“技能”或“技術堆疊”部分,我建議使用 [skill-icons](https://github.com/tandpfun/skill-icons),它提供漂亮的圖標。 如果您的圖示不受支持,您可以造訪 [simpleicons](https://simpleicons.org/),其中包含超過 2900 個流行品牌的 SVG 圖示。 這是一個範例,我在個人資料的技術堆疊部分使用了 [skill-icons](https://github.com/tandpfun/skill-icons)。 ![圖示範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/icons-example_nyo1sn.png) ### 使用表情符號 在 GitHub Flavored Markdown 中,您可以使用表情符號。要查看支援的表情符號的完整列表,您可以存取此 [emoji-cheat-sheet](https://github.com/ikatyang/emoji-cheat-sheet)。 如果您想自己取得支援的表情符號列表,可以使用 [GitHub 的 Emoji API](https://docs.github.com/en/rest/emojis/emojis#get-emojis)。 在瀏覽器上造訪 https://api.github.com/emojis 應該會顯示所有支援的表情符號的 JSON 回應。 ``` { "+1": "https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png?v8", "-1": "https://github.githubassets.com/images/icons/emoji/unicode/1f44e.png?v8", "100": "https://github.githubassets.com/images/icons/emoji/unicode/1f4af.png?v8", "1234": "https://github.githubassets.com/images/icons/emoji/unicode/1f522.png?v8", "1st_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f947.png?v8", "2nd_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f948.png?v8", "3rd_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f949.png?v8", "8ball": "https://github.githubassets.com/images/icons/emoji/unicode/1f3b1.png?v8", ... ``` 這是我在個人資料中使用表情符號的範例。 ![表情符號範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/emojis-example_yfzhef.png) ### 新增 GitHub 統計訊息 要為 GitHub 活動加入卡片和統計訊息,我建議使用 [github-readme-stats](https://github.com/anuraghazra/github-readme-stats)。您可以使用不同的版面配置和主題自訂統計卡。 以下是我將 GitHub 統計資料新增至我的個人資料的範例。 ![GitHub 統計資訊範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616186/GitHub%20Profile/github-stats-example_ndhxk3.png) ### 新增引號 在您的個人資料中加入隨機引用可以為訪客增添一抹亮色。我發現 [github-readme-quotes](https://github.com/PiyushSuthar/github-readme-quotes) 對於這樣做很有用。 這是我的個人資料上的樣子。我個人喜歡加入引號,為我的個人資料訪客提供一些價值。 ![報價範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/quote-example_dfvjrh.png) ### 提高可存取性 自訂您的個人資料時,請確保它**可供盡可能多的人查看**。並非每個人都可以查看或載入圖像。有些人有殘疾,而有些人的網路連線速度很慢。 提高個人資料的[輔助功能](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility)的一種方法是向圖像加入描述性「替代文字」。 ``` <!-- Markdown Image --> ![Image Alt Text](image-source) <!-- HTML Image Tag --> <img alt="Image Alt Text" src="image-source" /> ``` 然後,要測試您的個人資料的可存取性,您可以嘗試停用網頁瀏覽器上的圖像載入。這是有關如何停用 Google Chrome 映像載入的[指南](https://www.wikihow.com/Disable-Images-in-Google-Chrome)。 這是我的個人資料在 Google Chrome 上停用圖片載入後的樣子。 ![GitHub 設定檔可存取性範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704717170/GitHub%20Profile/github-profile-accessibility_vixcg8.png) ### 更多想法 要為您的個人資料加入更多資訊圖表,我建議查看 [metrics](https://github.com/lowlighter/metrics)。這是 GitHub 上最受好評的存儲庫之一,其中包含“github-profile”主題,因此我不能忽略它。 然後我發現了這個漂亮的資源 [beautify-github-profile](https://github.com/rzashakeri/beautify-github-profile),在這裡您可以找到更多自訂個人資料的方法。 如果您也喜歡冒險,可以在[此處](https://github.com/topics/github-profile)探索「github-profile」主題。預設情況下,儲存庫會按星數排序。 請隨意探索有「github-profile」主題的儲存庫。您甚至可能會發現那些使用頻率不高但正是您所需要的。 ### GitHub 簡介 成就 雖然這與自訂 GitHub 設定檔的「README.md」無關,但我覺得有必要包含它。 如果您前往 GitHub 個人資料,您會注意到左側邊欄上有一個「成就」部分。 ![GitHub 個人資料成就](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704632356/GitHub%20Profile/github-profile-achievements_tlqp3p.png) 收集這些成就很有趣,並且可以改善您的整體 GitHub 檔案。 要了解有關可用成就以及如何獲得這些成就的更多訊息,請查看 [GitHub 個人資料成就列表](https://github.com/Schweinepriester/github-profile-achievements)。 ## 結論 回顧一下,我們演練如何建立 GitHub 個人資料。然後我展示瞭如何使用 GitHub Flavored Markdown 和 HTML 格式化您的個人資料。之後,我分享了您可以從哪裡獲得個人資料的靈感。最後,我提供了有關如何自訂個人資料的提示和資源。 我希望這可以幫助您製作精彩的 GitHub 個人資料。我很想看看你能想出什麼辦法! 感謝您的閱讀,請隨時發表評論或與我聯繫[此處](https://linktr.ee/kshyun28)。 --- 原文出處:https://dev.to/kshyun28/how-to-make-your-awesome-github-profile-hog

創作 RawJS 之後,我再也沒有碰過 React。

早在 2012 年 10 月,TypeScript 0.8 就發布了。當時我正在開發一個中型 JavaScript 專案。它發布的那天,我閱讀了最初的規範,在玩了大約 10 分鐘後,我確信這將是未來,因此我開始用 TypeScript 重寫我的整個應用程式。相對於標準無型別 JavaScript 的好處是巨大的。 我對 [RawJS](https://www.squaresapp.org/rawjs/) 也有同樣的感覺。 [RawJS 是一個小型函式庫](https://github.com/squaresapp/rawjs),它使普通 JavaScript 應用程式開發更符合人體工學。它不僅僅是當今最新的 Web 框架,可以與 React、Vue、Svelte 或其他框架競爭。 RawJS 是不同的。 RawJS 直觀地說明了為什麼框架本身的整個前提可能有點誤導。它表明大多數應用程式最好使用普通 JS 並採用某些程式模式。 我知道這是一個非常大膽的聲明。但我懇請您研究一下 RawJS 誕生背後的心態和想法。 ## React 往往會破壞專案的複雜性 我不認為我說 React 太複雜是太過分了。畢竟,Svelte 正是因此而專門建立的。 React 會導致應用程式臃腫。舉個例子——我最近接到了一項任務,負責監督一個 React 應用程式的開發,該應用程式的複雜性已經失控。我最終扔掉了整個應用程式,並使用 RawJS 重建了整個應用程式,使用了一個從未接觸過 RawJS 的團隊,甚至根本沒有做過很多直接的 DOM 操作。幾週之內,團隊就加快了速度,現在該應用程式比以前的 React 應用程式小了約 90%。不,這不是一個錯字。 我們現在已經到了這樣一個階段:React 是「沒有人會因為購買 IBM 而被解僱」的選擇。問題是——人們「應該」因為購買 IBM 而被解僱。這是一個隱喻,指的是那些懶得做充分的需求分析、默認從眾心態、出於恐懼和懶惰而盲目跟隨大多數其他人正在使用的東西的人。 一旦您有幸使用 RawJS 加速的普通 JavaScript 開發應用程式,React 的過度複雜程度就會變得更加清晰。 RawJS 對 props、state、hooks、JSX、從特定基礎強制繼承(React.Component)、虛擬 DOM、自動資料綁定以及 React 所做的一切的必要性提出了質疑。 React 的膨脹及其施加的限制(例如禁止您直接編輯 DOM)都集中在試圖維護其虛擬 DOM 系統的完整性,我認為這是針對特定領域問題的解決方案對於facebook.com,那些精心建置的應用程式根本不具備。 所謂的直接 DOM 操作的效能劣勢被嚴重誇大了。事實上,如果做得正確,直接 DOM 操作通常會提高效能。這是因為您能夠精確控制 DOM 的更新方式。它允許您根據需要使用手術刀更新 DOM 的微小區域。虛擬 DOM 與此相反。它是一個生硬的工具,在大量 DOM 子樹上執行複雜的比較演算法,以便自動計算需要更新的內容。 自動資料綁定和反應性的有用性也被誇大了。假設您的程式碼組織良好,那麼建立您的應用程式以便 DOM 由於資料變更而更新似乎不會比僅建置應用程式以在必要時明確更新 DOM 所需的程式碼少。但與前者的區別在於,它給你強加了一個巨大的難以除錯的黑盒子,並迫使你遵守他們的官僚機構層。除非您組裝了一個精心建置的普通 JS 應用程式(例如使用 RawJS!),否則很難體會到擺脫這種情況的好處。 ## 為什麼沒有人談論匿名控制器類別? 匿名控制器類別(ACC)是一種需要引起更多關注的模式。它們是將普通 JavaScript 應用程式從雜亂無章轉變為連貫且美觀的關鍵想法之一。 ACC 的基本前提是建立一個與 DOM 中單一元素鬆散連接的物件,並且其垃圾收集生命週期等於所連接元素的生命週期。這是對繼承 HTMLElement 的一個進步,HTMLElement 是另一種選擇(但我不喜歡這種選擇,原因我將在另一篇文章中討論)。 考慮以下程式碼: ``` class SomeComponent { readonly head; constructor() { this.head = document.createElement("div"); this.head.addEventListener("click', () => this.click()); // Probably do some other stuff to this.head } private handleClick() { alert("Clicked!") } } ``` ACC 是建立單一 .head 元素(可能還有其他巢狀元素)、連接事件偵聽器、分配樣式等的類別。它們具有通常是事件處理程序或其他輔助方法的方法。然後實例化該元件,並將元件的 .head 元素加入 DOM: ``` const component = new SomeComponent(); document.body.append(component.head); ``` 該類別被視為“匿名”,因為一旦元件實例附加到 DOM,您就可以丟棄該實例。一旦元素從 DOM 中刪除並被垃圾回收,該類別的實例就會被垃圾回收,因為 DOM 是唯一擁有對它的引用的東西。例如: ``` class SomeComponent { readonly head; constructor() { this.head = document.createElement("div"); this.head.addEventListener("click', () => this.remove()); // Probably do some other stuff to this.head } private remove() { // Remove the component's .head element from the DOM, // which will by extension garbage collect this instance of // SomeComponent. this.head.remove(); } } ``` ACC 的優點在於它們基本上不會施加任何限制。他們可以繼承任何東西(或什麼都不繼承)。它們只是一個想法——您可以將它們塑造成您喜歡的樣子。 當然,在許多情況下您可能想要取得與特定元素關聯的 ACC。例如,想像一下迭代 this.head 元素的祖先元素,並取得與其關聯的 ACC 以呼叫某些公共方法。有一個名為 [HatJS](https://github.com/squaresapp/hatjs) 的輕量級程式庫,旨在改善使用 ACC 的人體工學。 **編輯:我是 HatJS 的作者。 「匿名控制器類別」是我發明的一個術語。這是在實驗過程中出現的模式,儘管我懷疑我是第一個發現它的人,因為這個概念非常明顯。就像 JSON 之前有名字一樣。您不需要將 HatJS 與 RawJS 一起使用。許多人正在建立普通的JavaScript 應用程式(或者對於迂腐的人來說是「普通的TypeScript 應用程式」),並且僅僅透過建立繼承自HTMLElement 的自訂元素,有效地將元素和控制器合併到同一個實體中,就取得了巨大的成功。我已經用這種方法建置了一些應用程式,並認為 ACC 更好,原因我會在以後的文章中介紹。** ## 改進 document.createElement() 具有令人驚訝的強大影響 儘管本文試圖為直接使用 DOM API 提供最有力的案例,但這些 API 絕對失敗的一個領域是使用屬性、樣式和事件附件來建立複雜的 DOM 層次結構。 DOM API 的這一部分非常冗長,如果沒有一些外部幫助,您的程式碼將比所需的長度長約 10 倍。這就是 RawJS 的用武之地。 RawJS 的設計正是為了一個目的。它使 document.createElement() 的人體工學性能提高了 10 倍。呼叫函數並取得 HTMLElement 實例的層次結構。它沒有任何其他作用。沒有奇怪的背景魔法。您可能不認為這聽起來很有影響力。但你的評估是錯的。 事實證明,在過去 15 年圍繞框架模式的構思中,我們不需要虛擬 DOM、反應性、資料綁定預編譯器或任何其他野生科學專案。我們需要匿名控制器類別模式和更好的方法來建立 HTMLElement 實例。 使用這兩種技術,我可以肯定地說,我永遠不會再故意使用 React 或任何其他競爭框架。這類框架根本無法提供超出 JavaScript 已經可以完成的功能,無法保證它們所施加的巨大權重和官僚作風。 那麼 RawJS 程式碼是什麼樣的呢?對 RawJS 建立者函數的呼叫遵循以下形式: ``` const htmlElement = raw.div(...parameters); ``` 強大的人體工學來自於可接受的參數的廣度(在 RawJS 中輸入為“Raw.Param”)。 參數可以是字串、數字、布林值、陣列、函數、DOM 節點實例、對 `raw.on("event", ...)` 的呼叫(建立可移植事件附件)以及幾乎任何其他內容。 RawJS 總是做你所期望的。 我不會重申使用 RawJS 來建立層次結構可以做的很棒的事情。快速入門對此進行了詳細介紹。 主要想法是,因為幾乎任何東西都可以是 Raw.Param,所以您可以建立迷你函數庫來產生 Raw.Params 列表並返回它們。由此可實現的程式碼重用水準是前所未有的。再說一次,除非你真正使用過它,否則很難欣賞它。我討厭與 LISP / 閉包進行比較,但還是有相似之處。 ## 我見過的最好的 CSS-in-JS 解決方案 如果不建構對應的 CSS,HTML 元素層次結建置構器有什麼用呢? RawJS 還擁有一流的 CSS-in-JS 解決方案,它可以完成我在任何其他解決方案中未見過的功能。例如,RawJS 完全支援僅限於特定元素的 CSS。 ``` const anchor = raw.a( // This constructs CSS within a global style sheet, // and the rules below will be scoped to the containing // anchor element. raw.css( ":focus", { outline: 0 }, ":visited": { color: "red" } ), raw.text("Hyperlink!") ); ``` 使用 RawJS 的 CSS-in-JS 解決方案還可以做很多其他事情。本文並不是 RawJS 教程,但如果您正在尋找此類內容,這裡有一個快速入門和一個演示應用程式。 ## 使用 DOM 作為狀態管理器實際上很好。 我們收到的一個常見的反對意見是,您將應用程式狀態儲存在哪裡?答案是使用 DOM 作為狀態管理器。 在你對此感到不寒而慄之前,請記住tailwind 如何率先提出在HTML 元素上刪除數百萬個類名的想法,有效地重新建立內聯CSS 的等價物,多年來,內聯CSS 一直被認為是一種反模式,但開發人員堅持它其實是很好,現在大家都在做嗎?同樣的想法也適用於使用 DOM 作為狀態管理器。 如今,每個人決定建立應用程式的方式都是從某種被視為「真相來源」的資料結構開始,然後您需要以某種方式將其笨拙地投影到 UI 中。以另一種方式做這件事被認為是“天真的”,甚至是反模式。但是,我想建議擁有兩個需要保持同步的獨立表示本身就是一種反模式。 嘗試使用某種框架以宣告方式將資料對應到 DOM 會導致複雜度大幅增加。這種技術的問題在於,對同一件事物有兩種不同的表示自然會比假設的只有一種這種表示的替代技術更加臃腫。 事實證明,如果您讓 ACC 接受輸入資料以便自行渲染,效果實際上會好得多。然後,您可以使用某種保存函數來檢查 DOM 的狀態以產生可保存的資料塊。這樣,您的事實來源不必與 DOM 同步,因為您的事實來源就是 DOM。 檢查以下程式碼範例: ``` class FormComponent { readonly head; private readonly firstNameInput; private readonly lastNameInput; constructor(firstName: string, lastName: string) { this.head = raw.form( this.firstNameInput = raw.input({ type: "text", value: firstName }), this.lastNameInput = raw.input({ type: "text", value: lastName }), raw.button( raw.text("Save"), raw.on("submit", () => this.save()) ) ); } private save() { const firstName = this.firstNameInput.value; const lastName = this.lastNameInput.value; SomeDatabaseSomewhere.save({ firstName, lastName }); alert("Saved!"); } } ``` 看?您只需將值儲存在 DOM 中即可。在本例中,我們使用文字輸入的值,但您也可以將資料儲存為 HTML 屬性、類別名稱或任何有意義的內容。 當然,在某些情況下,您需要儲存無法分解為字串、數字和布林值的狀態。我還看到一些狀態儲存在 ACC 內的屬性中的情況。做任何對你有用的事。 ## 元件之間的通信 在某些情況下,您可能需要更新多個元件以回應一項操作,或更簡單地在 ACC 之間發送訊息。 HatJS 可以幫助解決這個問題。 請記住,ACC 建立了一種隱藏的控制器層次結構。您擁有典型的 DOM 元素層次結構,但只有某些元素是 ACC 的頭元素。因此,這將建立自己的 ACC 層次結構,它是整個 DOM 元素層次結構的嚴格子集。 [HatJS](https://github.com/squaresapp/hatjs) 具有遍歷 ACC 層次結構的功能,並快速擷取可能位於或不位於元素後面的 ACC 實例。 ``` class ParentComponent { readonly head; constructor() { this.head = raw.div( new ChildComponent().head ); // Call Hat.wear() to define the object as a "hat" // and make it discoverable by HatJS Hat.wear(this); } callAlert() { alert("Hello!"); } } class ChildComponent { readonly head; constructor() { this.head = raw.div( raw.on("click", () => { // Hat.over finds the "Hat" (or the ACC) that exists // above the specified element in the hierarchy. // And passing ParentComponent gives you type-safe // tells HatJS what kind of component you're looking // for, and also gives you type-safe access to it. Hat.over(this, ParentComponent).callAlert() }) ); } } ``` 除了「Hat.over()」之外,還有「Hat.under()」、「Hat.nearest()」等方法來尋找 DOM 相對中可能存在或不存在的特定類型的其他 ACC到指定的元素。 ## 興奮起來! 那麼,我是否說服您啟動您的 React 應用程式並使用 RawJS 來重建您一生的工作?如果您想開始使用,請造訪 [這裡是 RawJS 網站](https://www.squaresapp.org/rawjs/)。 RawJS 的儲存庫是[此處](https://github.com/squaresapp/rawjs),HatJS 的儲存庫是[此處](https://github.com/squaresapp/hatjs) --- 原文出處:https://dev.to/paulgordon/after-using-rawjs-im-never-touching-react-again-or-any-framework-vanilla-javascript-is-the-future-3ac1

React 終極閱讀清單:2024 年 15 篇必讀文章

React 是一個用於建立使用者介面的流行 JavaScript 函式庫,其生態系統不斷發展。為了幫助您隨時了解 React 及其生態系統的最新發展,我整理了 2024 年一些必讀文章的清單。這些文章涵蓋了廣泛的主題,從 React 最佳實踐到性能對 React 生態系統的優化等等。無論您是初學者還是經驗豐富的 React 開發人員,這些資源都可以幫助您更深入地了解 React 及其生態系統。名單如下:✨ --- ### 🚀 React 渲染互動指南 [🔗 連結](https://ui.dev/why-react-renders) 🔖 難度等級 - 中級 ![React 渲染互動指南](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8s1ij3v0nafviz529u51.png) 本文深入探討了 React 中渲染的概念,解釋了 React 何時以及如何更新視圖。它提供了一個簡單的心理模型來理解 React 的工作原理,並旨在澄清有關 React 渲染的常見誤解。 --- ### 🚀 新文件中的 React JS 最佳實踐 [🔗連結](https://sebastiancarlos.com/react-js-best-practices-from-the-new-docs-1c65570e785d) 🔖 難度等級 - 中級、專家 ![新文件中的 React JS 最佳實踐](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rhkaq0wyzivzcttknn5.png) 本文介紹了基於新 React 文件的 React 開發最佳實務。它旨在按順序閱讀,涵蓋了 React 的各個方面,適合有經驗和中級的 React 開發人員。 --- ### 🚀 索引作為鍵是一種反模式 [🔗 連結](https://robinpokorny.medium.com/index-as-a-key-is-an-anti-pattern-e0349aece318) 🔖 難度等級 - 初級 本文討論了在 React 中使用索引作為鍵以及為什麼它是一種反模式。它解釋了使用索引作為鍵在更新或刪除清單中的專案時如何導致問題,並提供了為清單專案分配鍵的替代解決方案。 --- ### 🚀 治癒 React useState Hell 的方法? [🔗連結](https://www.builder.io/blog/use-reducer) 🔖 難度等級 - 中級 ![React useState Hell 的治癒方法?](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2n42610mw5vqi2v9h27d.png) 本文討論了 React 中使用 useState 鉤子管理狀態的挑戰,並建議使用 useReducer 鉤子作為解決方案。它強調了 useState 在管理複雜狀態方面的局限性,並提供了使用 useReducer 來解決這些限制的範例。 --- ### 🚀 使用 React 設定 ESLint [🔗 連結](https://z1.digital/blog/eslint-guide-how-to-use-it-with-confidence) 🔖 難度等級 - 中級 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gng3ylrfo3avggbyum7i.png) 本文提供了有關在 React 中使用 ESLint 的全面指南,深入了解如何在 React 專案中有效地設定和使用 ESLint。它涵蓋了 React 開發中 ESLint 的最佳實踐和常見配置。 --- ### 🚀 React 18 中的自動批次:你應該知道什麼 [🔗連結](https://blog.bitsrc.io/automatic-batching-in-react-18-what-you-should-know-d50141dc096e) 🔖 難度等級 - 中級 本文介紹了 React 18 中自動批次的新功能,該功能預設批次從任何位置呼叫的狀態更新。它提供了一個簡單的範例來了解自動批次的工作原理以及它如何提高 React 應用程式的效能。本文的難度為中等。 --- ### 🚀 進階 React 元件組合指南 [🔗連結](https://frontendmastery.com/posts/advanced-react-component-composition-guide/) 🔖 難度等級 - 中級 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s60c8h3umt0ferz4a4e5.png) 本文是高階 React 元件組合的綜合指南,涵蓋了複雜 React 應用程式中組合元件和管理狀態的各種技術。它提供了建立可重複使用和可維護的 React 元件的實際範例和最佳實踐。本文的難度等級為中級到專家級。 --- ### 🚀 奇妙的閉包 [🔗 連結](https://www.developerway.com/posts/fantastic-closures) 🔖 難度等級 - 中級、專家 ![神奇的閉包](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbc289miygudkmem99sa.png) 本文解釋了 JavaScript 中閉包的概念,以及如何在 React 中使用閉包來管理狀態和處理事件。它提供了使用閉包建立可重複使用元件的範例,並討論了在 React 中使用閉包的優點和缺點。 --- ### 🚀 帶有 tRPC 和 React 的全端 TypeScript [🔗連結](https://www.robinwieruch.de/react-trpc/) 🔖 難度等級 - 中級 ![使用 tRPC 和 React 的 TypeScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afg8iuxzz2forqkqv1xs.png) 本文提供了在 React/TypeScript 應用程式中實作 tRPC(用於建立 API 的 TypeScript 框架)的指南。它涵蓋了 tRPC 客戶端和伺服器相依性的安裝,並解釋了前端專案的具體實作。 --- ### 🚀 重新思考 React 最佳實踐 [🔗連結](https://frontendmastery.com/posts/rethinking-react-best-practices/) 🔖 難度等級 - 中級、專家 ![重新思考 React 最佳實踐](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dhfs0g00mffloojru15s.png) 本文討論了 React 最佳實踐的演變,特別是在 React 18 和 React Server Components (RSC) 的背景下。它探討了 React 的核心約束、過去的管理方法以及 Remix 和 Next.js 等 React 框架中不斷變化的思維模型。 --- ### 🚀 反應性能 [🔗連結](https://www.causal.app/blog/react-perf) 🔖 難度等級 - 中級、專家 ![反應表現](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w3n4c4enue5jkne7u5mc.png) 本文討論了提高 React 應用程式效能的各種技術,包括優化渲染、減小套件大小以及使用 React.memo 和 useMemo 掛鉤。它提供了提高 React 應用程式效能的實際範例和最佳實踐。 --- ### 🚀 下一張圖片的事實 [🔗 連結](https://dev.to/alex_barashkov/things-you-might-not-know-about-next-image-5go8) 🔖 難度等級 - 中級 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/56363g9jfn1pc1az0f77.png) 本文介紹了有關 Next.js Image 元件的各種見解和詳細訊息,涵蓋了開發人員可能不知道的方面。它提供了有關使用 Next.js Image 及其功能的實用訊息,對於使用 Next.js 的開發人員非常有用。 --- ### 🚀 建立聊天:使用 React、WebSockets 和 Web Push 的瀏覽器通知 [🔗連結](https://dev.to/novu/building-a-chat-browser-notifications-with-react-websockets-and-web-push-1h1j) 🔖 難度等級 - 中級 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2tgb2z4agzxya64sw2q.png) 本文提供了使用 React、WebSockets 和 Web Push 建立帶有瀏覽器通知的聊天應用程式的綜合指南。它提供了對這些技術整合的深入見解,並提供了在 Web 應用程式中實現聊天和通知的實用方法。 --- ### 🚀 如何使用 React 和 OpenAI API 建置和部署 ChatGPT 克隆應用程式 [🔗連結](https://kinsta.com/blog/chatgpt-clone/) 🔖 難度等級 - 中級 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ekfcw5i06qn5g3wls85.png) 本文提供了使用 React 和 OpenAI API 建置和部署 ChatGPT 克隆應用程式的逐步指南。它涵蓋了依賴項的安裝、建置前端以及將應用程式部署到 Kinsta 的應用程式託管平台。 --- ### 🚀 React 批評的歷史參考 [🔗連結](https://www.zachleat.com/web/react-criticism/) 🔖 難度等級 - 中級、專家 本文提供了對 React 的批評的歷史參考,涵蓋了開發人員和專家多年來提出的各種擔憂和批評。它探討了 React 的局限性和缺點,並提供了有關 React 作為框架的演變的見解。 --- 總而言之,精選的「2024 年關於 React 的 15 篇最佳文章」可以為渴望了解不斷變化的 React 開發格局的開發人員提供全面的指南。這些文章根據其相關性、深度和見解而精心挑選,提供了今年掌握 React 的路線圖。透過深入研究這些資源,開發人員可以保持在 React 生態系統的最前沿,利用建立尖端 Web 應用程式所需的知識和技能來增強自己的能力。 --- ## 關於我 嘿,我是 Dhruv Kothari 👋 一位全端 Web 開發人員和 UI/UX 愛好者,目前在 Upraised 擔任軟體工程師。我也是一名有競爭力的程式設計師、50 歲以下的立方愛好者、集郵家和錢幣學家。您可以透過 [GitHub](https://github.com/kothariji) 和 [Twitter](https://twitter.com/_kothariji) 與我聯繫 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/slfb7me1gnr43epsib99.png) --- 原文出處:https://dev.to/kothariji/the-ultimate-react-reading-list-top-15-must-read-articles-in-2024-2c3

Docker 絕對初學者

Docker 是一個工具,允許開發人員將他們的應用程式及其所有依賴項打包到一個容器中。然後,這個容器就可以輕鬆地在任何安裝了 Docker 的機器上傳輸和執行,而不必擔心環境的差異。這就像是打包和執行軟體的標準化方式。 **容器是什麼?** ![Docker 容器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/imsgbstga86vnxjwgebr.png) 容器就像一個小包,其中包含程式執行所需的一切,可以輕鬆地在不同電腦上移動和執行,而不會造成任何麻煩。 最酷的部分是這個迷你電腦(容器)就像一個披著斗篷的超級英雄。它可以在任何電腦上執行,無論它們有多麼不同,因為它自帶特殊的環境。這是一種保持軟體井然有序的方式,並確保它無論在哪裡都能以相同的方式運作。 ![容器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1z5zcued8ya2onerpzwt.png) **為什麼我們需要 Docker?** 1. **一致性:** Docker 確保軟體在您的電腦、您朋友的電腦或任何電腦上以相同的方式運作。它使事情保持一致。 2. **可移植性:** 您可以將您的軟體及其朋友打包到 Docker 容器中,並且它可以移動到任何地方。這就像將您的遊戲及其所有規則放在手提箱中並在朋友家中玩。 3. **隔離:** Docker 容器就像小氣泡。氣泡內發生的事只會留在氣泡內。這意味著容器中的一個程式不會幹擾容器外的另一個程式。 4. **效率:** Docker有助於節省電腦資源。您可以讓許多容器在同一台電腦上執行,而不會相互妨礙,而不是讓一整台電腦只用於一個程式。 5. **速度:** Docker 讓啟動、停止和共享軟體變得快速、輕鬆。這就像打開和關閉遊戲機一樣 - 快速而簡單。 **什麼是 Docker 映像?** ![Docker 映像](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/817t1rsad728snnighkj.png) Docker 映像像是程式及其運作所需的所有內容的快照。它是一個打包版本,包括程式碼、工具和設置,就像包含所有成分的餅乾食譜的快照一樣。 **圖像是配方,容器是當您按照該配方實際製作和執行程序時所得到的。** **一些基本的 Docker 命令。** ![基本 Docker 指令](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xq1pwt8896lvster3ppl.png) 1. **`docker執行nginx`** - 此命令告訴 Docker 使用「nginx」映像執行容器。這就像告訴 Docker 啟動一個預製程式的新實例(nginx,它是一個 Web 伺服器)。 2. **`docker ps`** - 顯示正在執行的容器的清單。這就像檢查當前正在執行哪些程式。 3. **`docker ps -a`** - 顯示所有容器的列表,包括已停止的容器。這就像檢查您執行過的所有程式的歷史記錄。 4. **`docker stopsilly_sammet'** - 停止名為「silly_sammet」的正在運作的容器。這就像關閉當前正在執行的程式。 5. **`docker rmsilly_sammet'** - 刪除名為「silly_sammet」的已停止容器。這就像丟掉你不再需要的程式的指令一樣。 6. **`docker 映像`** - 列出您擁有的所有 Docker 映像。這就像查看您可以執行的所有不同程式的選單一樣。 7. **`docker rmi nginx`** - 刪除“nginx”圖像。這就像刪除您不想再使用的程式的配方。 8. **`docker拉nginx`** - 從網路下載「nginx」映像。這就像從食譜中獲取新食譜一樣。 9. **`docker 執行 ubuntu sleep 5`** - 使用「ubuntu」映像檔執行容器並使其休眠 5 秒。這就像啟動一個程序,只是等待一小會兒,然後就停止了。 10. **`docker exectracted_mcclintock cat /etc/hosts`** - 在名為「distracted_mcclintock」的正在執行的容器內執行命令。這就像在食譜書中偷看特定頁面一樣。 11. **`docker run -d kodekloud/simple-webapp`** - 從「kodekloud/simple-webapp」鏡像以分離模式執行容器。這就像啟動一個程式並讓它在背景執行。 12. **`docker Attach a043d`** - 將您的終端附加到 ID 為「a043d」的正在執行的容器。這就像跳入正在執行的程式來查看發生了什麼。 **一些 Docker 概念:** 1. **使用標籤執行:** - 標籤就像程式的版本。它指定您要執行哪個版本。 - 範例程式碼:`docker run nginx:latest` - 這將執行最新版本的 Nginx 程式。 2. **使用標準輸入執行:** - STDIN 就像在鍵盤上打字一樣。有些程式需要您的輸入。 - 範例程式碼:`docker run -i -t ubuntu` - 這會在 Ubuntu 容器內執行互動終端,讓您可以鍵入命令。 3. **使用連接埠映射執行:** - 連接埠就像門。程式使用它們與外界進行通訊。 - 範例程式碼:`docker run -p 8080:80 nginx` - 這將執行 Nginx,並打開電腦連接埠 8080 上的門,將其連接到容器的連接埠 80。 4. **使用磁碟區映射執行:** - 磁碟區就像共用資料夾。它們讓您可以將東西存放在容器之外。 - 範例程式碼:`docker run -v /your/local/folder:/container/folder nginx` - 這將執行 Nginx 並將電腦上的資料夾連接到容器內的資料夾。 5. **檢查容器:** - 檢查就像仔細檢查正在執行的程式。 - 範例程式碼:`docker檢查container_name` - 這為您提供有關正在執行或已停止的容器的詳細資訊。 6. **容器日誌:** - 日誌就像日記。他們記錄程式正在做什麼。 - 範例程式碼:“docker 日誌容器名稱” - 這會向您顯示特定容器的日誌或活動。 ##環境變數 環境變數就像程式用來尋找重要資訊的便利筆記,有點像是程式可以理解和更好工作的秘密訊息! 1. **Python腳本(app.py)中的環境變數:** - 假設您有一個用 Python 寫的程式 (app.py)。您可能想要在不更改程式碼的情況下自訂它。您可以使用環境變數。 - 範例程式碼(app.py): ``` import os app_color = os.getenv("APP_COLOR", "default_color") print(f"The app color is {app_color}") ``` - 正常運作腳本:`python app.py` - 以特定顏色執行:`export APP_COLOR=blue; python 應用程式.py` 2. **在 Docker 中使用 ENV 變數:** - Docker 容器也可以使用環境變數。這就像是向容器內的程式發出指令。 - 範例程式碼: - `docker run -e APP_COLOR=green simple-webapp-color` - 這會執行 Docker 容器(`simple-webapp-color`)並將環境變數 `APP_COLOR` 設為「綠色」。 3. **檢查環境變數:** - 有時,您會想要檢查正在執行的容器正在使用哪些環境變數。 - 範例程式碼:`docker檢查blissful_hopper` - 此命令提供有關名為“blissful_hopper”的容器的詳細訊息,包括其環境變數。 簡單來說,環境變數就像程式(或 Docker 容器)可以讀取以了解如何行為的小註釋。您可以在執行程式之前設定這些註釋,程式將使用它們來自訂自身。第二個範例中的「export」指令就像在執行程式之前寫一條註釋,告訴它如何運作。 “docker Inspect”指令就像是在容器內部查看它有什麼註解。 ## Docker 映像 **Docker 檔案:** Dockerfile 就像是 Docker 建立映像的一組指令。這就像是烤蛋糕的食譜。 ``` # Use the Ubuntu base image FROM Ubuntu # Update apt repository RUN apt-get update # Install dependencies using apt RUN apt-get install -y python # Install Python dependencies using pip RUN pip install flask RUN pip install flask-mysql # Copy source code to /opt folder COPY . /opt/source-code # Set the working directory WORKDIR /opt/source-code # Specify entry point to run the web server ENTRYPOINT ["flask", "run"] ``` **建立自己的圖像的步驟:** 1. 使用上述內容建立一個名為「Dockerfile」的檔案。 2. 將其保存在與原始碼相同的目錄中。 **建置 Docker 映像:** 在終端機中執行以下命令: ``` docker build -t your-image-name . ``` 此命令告訴 Docker 使用目前目錄中的 Dockerfile (`.`) 建置映像,並使用您選擇的名稱對其進行標記 (`-t your-image-name`)。 **分層架構:** ![分層架構](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9i91e79dg61wnbbfp62m.png) - 將 Docker 映像視為一個分層蛋糕。 Dockerfile 中的每個指令都會在映像上新增一層。 - 圖層可重複使用。如果您變更程式碼中的某些內容,Docker 只會重建受影響的層,從而提高效率。 **Docker 建置輸出:** - 當您建置映像檔時,Docker 會顯示流程中的每個步驟。如果發生故障,它會給您錯誤訊息。 **你可以容器化什麼?** - 幾乎所有東西!應用程式、服務、資料庫、網站,基本上任何軟體都可以容器化。 - 這就像將您的軟體放入一個盒子中,以便它可以在任何地方執行而不會造成麻煩。 ## 什麼是 Docker CMD 與 ENTRYPOINT **Docker 中的`CMD`:** - 將 CMD 視為啟動容器時程式執行的預設操作。 - 這就像說,“嘿,當你執行這個容器時,默認執行此操作。” - 範例:`CMD ["flask", "run"]` 表示當容器啟動時,它會自動執行 Flask Web 伺服器。 **CMD 範例:** ``` FROM alpine CMD ["sleep", "5"] ``` 在此範例中,當您使用此映像執行容器時,它會自動休眠 5 秒。 **Docker 中的`ENTRYPOINT`:** - 將 ENTRYPOINT 視為容器所做的主要事情。就好像boss的命令一樣。 - 它設定一個預設應用程式在容器啟動時執行,但您仍然可以根據需要覆蓋它。 - 範例:`ENTRYPOINT ["flask", "run"]` 表示容器主要用於執行 Flask Web 伺服器,但如果需要,您仍可新增更多指令。 **入口點範例:** ``` FROM alpine ENTRYPOINT ["sleep"] CMD ["5"] ``` 在這裡,主要目的是睡眠,如果您願意,您仍然可以覆蓋睡眠持續時間。 在這兩種情況下,容器在啟動時只會休眠幾秒鐘。主要區別在於如何提供參數以及它們是否可以輕鬆覆蓋。 CMD 就像在說,“這是默認要做的事情”,而 ENTRYPOINT 就像在說,“這是主要要做的事情,但如果你願意,你可以稍微調整一下。”它們都有助於定義容器啟動時執行的操作。 ## Docker 中的網路: Docker 網路幫助容器(程式)相互通信,確保它們可以順利地協同工作。 **預設網路:** - Docker 建立預設網路供容器通訊。 - 範例程式碼:`docker run ubuntu --network=host` - 這使用主機網路執行 Ubuntu 容器,這意味著它與主機共享網路命名空間。 **使用者定義的網路:** - 您可以建立自己的網路以更好地組織和控制。 - 範例程式碼: ``` docker network create --driver=bridge --subnet=182.18.0.0/16 custom-isolated-network ``` - 這將建立一個名為「custom-isolated-network」的使用者定義的橋接網絡,具有特定的子網。 **上市網路:** - 您可以查看您擁有的所有網路。 - 範例程式碼:`docker network ls` **檢查網路:** - 您可以檢查特定網路的詳細資訊。 - 範例程式碼:`docker網路檢查blissful_hopper` - 這顯示有關名為「blissful_hopper」的網路的詳細資訊。 **嵌入式 DNS:** - Docker 有一個內建的 DNS 系統,供容器透過名稱相互查找。 - 範例程式碼:`mysql.connect(mysql)` - 這可能是程式碼中的一行,其中名為「mysql」的服務使用 Docker 的 DNS 連接到另一個名為「mysql」的服務。 ## Docker 儲存: ![Docker 儲存](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7i54a6m0o1tb0812xbjk.jpg) Docker 儲存就像使用容器時決定將資料保存在哪裡一樣。您可以將它們保留在容器內,使用磁碟區在容器之間共用它們,或將它們儲存在容器外部以妥善保管。 **Docker中的檔案系統:** - Docker 使用分層架構來建立映像。 Dockerfile 中的每個指令都會在檔案系統中新增一個新圖層。 ``` # Dockerfile FROM Ubuntu RUN apt-get update && apt-get install -y python RUN pip install flask flask-mysql COPY . /opt/source-code WORKDIR /opt/source-code ENTRYPOINT ["flask", "run"] ``` - Dockerfile 中的層: - 第 1 層:Ubuntu 基礎層 - 第 2 層:apt 軟體包的更改 - 第 3 層:pip 套件的變化 - 第 4 層:原始碼 - 第 5 層:使用「flask」指令更新入口點 - 第 6 層:容器層 **影像圖層:** - 當您建立 Docker 映像時,它由唯讀層組成。每一層代表影像的變化或加入。 - 第 1 層:Ubuntu 基礎層 - 第 2 層:apt 軟體包的更改 - 第 3 層:pip 套件的變化 - 第 4 層:原始碼 - 第 5 層:使用「flask」指令更新入口點 ``` # Build the Docker image docker build -t mmumshad/my-custom-app . ``` **容器層:** - 當您執行 Docker 容器時,會在唯讀映像層上方新增一個讀寫層。該層特定於正在執行的容器。 - 第 6 層. 容器層 ``` # Run the Docker container docker run mmumshad/my-custom-app ``` **數量:** - 卷是一種在容器外部保存資料的方法。它們就像外部記憶體。 ``` # Create a Docker volume docker volume create data_volume # Use the volume in a container docker run -v data_volume:/var/mysql mysql ``` - 您也可以使用「-v」將特定目錄從主機掛載到容器: ``` # Mount a host directory to a container directory docker run -v /path/on/host:/var/mysql/mysql -d mysql ``` - docker run --mount 指令用於將主機上的特定目錄或檔案掛載到正在執行的 Docker 容器中。 ``` docker run --mount type=bind,source=/mysql,target=/var/mysql mysql ``` **儲存驅動程式:** - Docker 使用儲存驅動程式來管理資料的儲存和存取方式。一些常見的儲存驅動程式包括 AUFS、ZFS、BTRFS、Device Mapper、Overlay 和 Overlay2。 [在 Docker 管理資料](https://docs.docker.com/storage/) [關於儲存驅動程式](https://docs.docker.com/storage/storagedriver/) [卷](https://docs.docker.com/storage/volumes/) ## Docker 組合 ![Docker Compose](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjyro6o2844s2or1b83c.jpeg) Docker Compose 是一個方便的工具,可幫助您輕鬆執行和連接不同的軟體服務,就好像它們都是同一事件的一部分一樣。 **Docker Compose 基礎:** 1. **執行單一容器:** - 通常,您可以像這樣執行單獨的 Docker 容器: ``` docker run mmumshad/simple-webapp docker run mongodb docker run redis:alpine docker run ansible ``` 2. **Docker 撰寫文件(`docker-compose.yml`):** - Docker Compose 允許您在一個簡單的檔案中定義所有這些服務: ``` # docker-compose.yml version: '3' services: web: image: 'mmumshad/simple-webapp' database: image: 'mongodb' messaging: image: 'redis:alpine' orchestration: image: 'ansible' ``` - 此檔案描述您要執行的服務(「web」、「database」、「messaging」、「orchestration」)、它們各自的映像以及任何其他配置。 3. **使用 Docker Compose 執行:** - 要一起啟動所有這些服務: ``` docker-compose up ``` - Docker Compose 負責啟動「docker-compose.yml」檔案中定義的所有容器。 4. **使用 Docker Compose 建置:** - 您也可以使用 Docker Compose 建置映像: ``` docker-compose build ``` - 此指令建置「docker-compose.yml」檔案中指定的映像。 **執行連結容器:** - 如果您要透過連結執行單一容器: ``` docker run -d --name redis redis docker run --name voting-app -p 5000:80 --link redis:redis voting-app docker run --name result-app -p 5001:80 --link db:db result-app docker run -d --name worker --link db:db --link redis:redis worker ``` - 在 Docker 中撰寫: ``` # docker-compose.yml version: '3' services: vote: image: 'voting-app' ports: - '5000:80' links: - 'redis:redis' result: image: 'result-app' ports: - '5001:80' links: - 'db:db' worker: image: 'worker' links: - 'db:db' - 'redis:redis' db: image: 'db' redis: image: 'redis' ``` Docker Compose 可讓您在單一檔案中描述整個應用程式堆疊,從而輕鬆管理、執行和連接不同的服務。這就像在一份計劃中寫下活動的所有任務,然後 Docker Compose 為您處理設定。 [Docker Compose 概述](https://docs.docker.com/compose/) [Docker 撰寫文件](https://docs.docker.com/engine/reference/commandline/compose/) ## Docker 註冊表 ![Docker 註冊表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bzflp82qyg36y8fcf8k8.png) Docker 註冊表是人們儲存和分享 Docker 映像的地方,使其他人可以輕鬆使用和執行他們的軟體。它就像一個大型線上程式庫,可以輕鬆下載並在不同電腦上使用。 **Docker 註冊表基礎知識:** 1. **公共登記處:** - Docker 映像可以在 Docker Hub 等公共註冊表中儲存和共用。 - 例: ``` docker pull nginx ``` 2. **私人登記處:** - 有時,您可能希望將圖像保存在您自己的私人註冊表中。 - 例: - 登入私人註冊表: ``` bash docker login private-registry.io ``` - 從私有註冊表中的映像執行容器: ``` docker run private-registry.io/apps/internal-app ``` 3. **部署您自己的私有註冊表:** - 您可以為您的團隊或公司部署自己的私人註冊表。 - 例: - 在您的電腦上執行私有註冊表: ``` docker run -d -p 5000:5000 --name registry registry:2 ``` - 為私人註冊表標記您的圖像: ``` bash docker image tag my-image localhost:5000/my-image ``` - 將映像推送到您的私人註冊表: ``` bash docker push localhost:5000/my-image ``` - 從您的私人註冊表中提取映像: ``` bash docker pull localhost:5000/my-image ``` 4. **從遠端私有註冊表中提取:** - 您也可以使用 IP 位址或網域從遠端私有註冊表中提取映像。 - 例: ``` docker pull 192.168.56.100:5000/my-image ``` Docker 註冊表就像一個儲存空間,人們在其中保存和共享 Docker 映像。您可以將公用註冊表用於廣泛使用的映像,也可以根據您的特定需求設定自己的私人註冊表。它就像一個用於共享和儲存軟體藍圖(圖像)的特殊庫。 ## Docker 引擎 ![Docker 引擎](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hc6r4dvo9kg9xqgwsrbb.jpg) 想像一下,你有一個魔盒(Docker Engine),可以為你執行和管理各種程式(容器)。 Docker Engine 就像是這個魔盒的大腦。 1. **Docker 守護程式:** - 守護程式就像魔法盒的看門人。它始終在那裡,隨時準備接受指示並確保一切順利進行。 2. **REST API:** - 將 REST API 視為一組允許您與魔盒對話的規則。它就像你和守護程式用來溝通的語言。你告訴守護程式要做什麼,它會理解,因為你們說的是同一種語言。 3. **Docker CLI(命令列介面):** - Docker CLI 就像是用來命令守護程式的魔杖。您輸入指令,守護程式就會按照您的指示進行操作。這就像說「Abracadabra」就能讓事情發生。 **連線到遠端 Docker 引擎:** 連接到遠端 Docker 引擎可讓您控制另一台機器上的容器,且設定約束可確保容器僅使用指定的資源。 1. **Docker主機IP:** - 您可以使用 IP 位址和連接埠連接到不同電腦上的 Docker 引擎。 - 例: ``` docker -H=remote-docker-engine:2375 run nginx ``` - 這告訴您的本機 Docker CLI 與遠端 Docker 引擎進行通訊。 2. **有約束地執行容器:** - Docker 允許您設定容器的資源限制,例如 CPU 和記憶體限制。 - 例: ``` docker run --cpus=0.5 ubuntu docker run --memory=100m ubuntu ``` - 這些指令限制容器僅使用半個 CPU 核心和 100 MB 記憶體。 當然,讓我們簡化一下PID命名空間的概念: **命名空間PID:** PID 命名空間可讓您為容器中的進程(如程式或任務)建立單獨的區域,因此它們有自己的一組「票號」(進程 ID),不會與容器外的進程發生衝突。 **範例程式碼:** 1. **使用主機 PID 命名空間執行容器:** - 這表示容器與主機共用相同的「票號」。 ``` docker run --pid=host ubuntu ``` 2. **執行具有隔離 PID 命名空間的容器:** - 這表示容器有自己的一組獨立於主機的「票號」。 ``` docker run --pid=container ubuntu ``` 在第一個範例中,容器與進程交互,就好像它與主機位於同一空間中一樣。在第二個範例中,容器有自己的進程隔離空間。這就像在大型活動中擁有一個私人區域,您的團隊有自己的一套票號,讓您可以獨立於活動的其餘部分進行操作。 **容器化概念:** 1. **進程 ID 命名空間:** - 容器有自己獨立的流程 ID (PID) 空間,因此容器內的流程與容器外的流程是分開的。 - 例: ``` docker run --pid=host ubuntu ``` - 此指令使用主機的 PID 命名空間來執行容器,因此它共用相同的程序。 2. **網路命名空間:** - 容器也有自己獨立的網路命名空間,這意味著它們可以有自己的網路配置。 - 例: ``` docker run --net=host nginx ``` - 此指令使用主機的網路命名空間來執行容器。 3. **Unix分時命名空間:** - 此命名空間允許容器擁有自己的時間視圖,與主機和其他容器分開。 - 例: ``` docker run --uts=host ubuntu ``` - 此指令使用主機的 Unix 時間共用命名空間來執行容器。 4. **進程間掛載命名空間:** - Mount命名空間隔離檔案系統,讓容器擁有自己的檔案系統視圖。 - 例: ``` docker run --mount=type=bind,source=/host/folder,target=/container/folder ubuntu ``` - 此指令將主機中的資料夾安裝到容器中。 當然!我們來簡化一下cgroup的概念: **C組:** cgroup(控制組的縮寫)可協助在不同進程或容器之間管理和分配系統資源,例如 CPU 和記憶體。它們確保沒有任何一個進程或容器耗盡所有可用資源,從而保持一切平衡。 **範例程式碼:** 1. **使用 Cgroup 設定 CPU 限制:** - 這就像說聚會上的每位客人只能吃一定數量的食物。 ``` docker run --cpus=0.5 ubuntu ``` - 這限制容器僅使用一半的 CPU 核心。 2. **使用 Cgroup 設定記憶體限制:** - 這就像說每位客人只能在舞池上佔據一定的空間。 ``` docker run --memory=100m ubuntu ``` - 這限制容器僅使用 100 MB 記憶體。 [Docker 引擎概述](https://docs.docker.com/engine/) [使用 Docker Engine API 進行開發](https://docs.docker.com/engine/api/) [執行時指標](https://docs.docker.com/config/containers/runmetrics/#control-groups) ## Linux容器與Windows容器的概念: **Linux 容器(預設):** Linux 容器是一種打包和執行軟體及其所需一切的方法,它們最適合執行 Linux 的電腦。 **Windows 容器:** Windows 容器是一種打包和執行軟體的方式,就像 Linux 容器一樣,但它們設計用於執行 Windows 的電腦。 **Windows 容器基礎:** 1. **集裝箱類型:** - Windows 容器有兩種主要類型:Windows Server Core 和 Nano Server。 - **Windows Server Core:** 將其視為功能更齊全的容器,適合各種應用程式。 - **Nano Server:** 將其視為一個輕量級容器,專為特定的、簡約的用例而設計。 2. **基礎鏡像:** - 基礎映像就像是建立容器時開始使用的空白畫布。 - 例: ``` docker pull mcr.microsoft.com/windows/servercore:ltsc2019 ``` - 此指令擷取 Windows Server Core 基礎映像。 - 例: ``` docker pull mcr.microsoft.com/windows/nanoserver:ltsc2019 ``` - 此命令提取 Nano Server 基礎映像。 3. **支援的環境:** - Windows 容器可以在特定版本的 Windows 作業系統上運作。 - 例: - 您可以在 Windows Server 2016 上執行 Windows 容器。 - 例: - 您可以在 Windows 10 專業版和企業版上執行 Windows 容器,並使用 Hyper-V 隔離容器進行額外隔離。 ## 容器編排 ![容器編排](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lyleybojw3xmr2dgfep.png) 容器編排是一種管理和協調多個容器的方法,確保它們無縫協作來執行應用程式,就像一個超級智能的管理器確保所有機器人一起工作來建置完美的塔一樣。 **為什麼要編曲?** 1. **多項任務,一名經理:** - 想像一下您有許多機器人(容器)執行不同的工作。編排就像有一位超級聰明的經理(編排者),他告訴每個機器人該做什麼,並確保一切順利進行。 2. **一致性:** - 編排確保所有任務每次都以相同的方式完成。這就像為您的機器人提供了一套要遵循的指令,以確保其行為的一致性。 3. **效率:** - 編排有助於優化任務,確保資源(如時間和材料)有效利用。這就像經理確保所有機器人一起工作而不浪費能源。 4. **縮放比例:** - 當您需要完成更多工作時,編排可以輕鬆建立額外的機器人(容器)。這就像當有很多事情需要完成時神奇地召喚更多機器人來提供幫助。 5. **可靠性:** - 編排確保任務可靠地完成,即使機器人(容器)出現故障。這就像製定備份計劃來確保無論如何都能完成工作。 6. **協調:** - 編排協調任務,確保機器人無縫協作。這就像經理確保每個機器人都知道自己的角色並協作以實現總體目標。 **容器編排程式碼:** ``` # Create a Docker service with 100 replicas (instances) of a Node.js application docker service create --replicas 100 --name my-nodejs-app nodejs ``` 在這個例子中: - `docker service create`:該指令告訴 Docker 建立一個服務,該服務是一組正在執行的容器。 - `--replicas 100`:此標誌指定您需要 100 個服務實例(副本)。 - `--name my-nodejs-app`:此標誌為您的服務提供名稱,在本例中為「my-nodejs-app」。 - `nodejs`:這是 Node.js 應用程式的圖片或配方。這就像是烘焙紙杯蛋糕的藍圖。 因此,這段簡單的程式碼就像告訴您神奇的廚師助手 (Docker Swarm) 建立 Node.js 應用程式的 100 個副本,確保您有大量容器正在執行並準備好提供服務。 ## Docker 群 ![Docker Swarm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z5noonjo2ikyrp90kc38.png) Docker Swarm 是一個工具,可以幫助協調和管理一組電腦(節點)作為一個機器人團隊一起工作,使它們能夠以協調的方式部署和執行多個容器。這就像有一個首席機器人經理,確保所有單一機器人一起建造出偉大而令人驚嘆的東西。 **設定 Docker Swarm:** 1. **群組管理器:** - 想像你有一個首席機器人(Swarm Manager)來領導團隊。主機器人決定需要做什麼,並指導其他機器人(節點)如何協同工作。 ``` # Initiate Docker Swarm on the Swarm Manager docker swarm init ``` 2. **節點工作人員:** - 現在,您的工作機器人(節點工作人員)已準備好加入團隊。 Swarm Manager 共享一個特殊的程式碼(令牌)來邀請他們一起工作。 ``` # Join a Node Worker to the Docker Swarm docker swarm join --token <token> <Swarm Manager IP> ``` **Docker Swarm 服務:** 現在您已經有了一個協調的團隊,您想要建立一項服務,例如與您的機器人團隊一起建造塔: ``` # Create a Docker service (a group of containers) with 3 replicas (instances) docker service create --replicas 3 --network frontend --name my-web-server my-web-image ``` - `--replicas 3`:此標誌告訴 Docker 建立服務的三個實例(副本)。 - `--network frontend`:此標誌指定您的服務屬於名為「frontend」的網路。 - `--name my-web-server`:這會為您的服務命名,在本例中為「my-web-server」。 - `my-web-image`:這是您的網頁伺服器的圖片或藍圖。這就像建造塔樓的配方。 您建立了一個由隊長(Swarm Manager)和工作機器人(Node Workers)組成的機器人團隊。然後,您指示他們建立一個執行您的 Web 伺服器應用程式的服務(容器群組)。主機器人確保建立 Web 伺服器的三個副本並將其連接到「前端」網路。這就像有一個首席機器人經理在工作機器人的幫助下監督多個塔(貨櫃)的建造。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytitz2wt4jsufejox9yx.gif) **好的,這就是本文的內容。** 另外,如果您對此或其他任何問題有任何疑問,請隨時在下面的評論中或在 [Instagram](https://www.instagram.com/_abhixsh/) 、[Facebook](https://www.facebook.com/abhi.haththakage/) 或[Twitter](https://twitter.com/abhixsh)。 感謝您閱讀這篇文章,我們下一篇再見! ❤️ --- 原文出處:https://dev.to/abhixsh/docker-for-the-absolute-beginner-3h1p