如何為Next.js/TypeScript應用設定開發容器

如何為Next.js/TypeScript應用設定開發容器

這是你新的軟體工程工作的第一天,你超級興奮地要向程式碼庫提出你的第一個拉動請求,但在這之前,你必須讓你的本地環境啟動和執行。這個艱苦的過程可能會花費你一整天或一週的時間。你將需要在多個雲提供商那裡建立賬戶,並訪問環境變數,你將花費相當多的時間編輯過時的文件。而現在,你已經失去了為團隊作出貢獻的火花。

或者

你正在尋找一個開源專案來做貢獻。你關注文件,但它已經過時了,難以理解,所以你放棄了對貢獻的追求。

或者

你想嘗試一個新的框架,瞭解它在幕後是如何工作的,但要做到這一點,你必須npm安裝500萬個不同的東西,而你並不那麼感興趣,所以你決定改為狂看HBO的《繼承》。

這是發生在所有級別的軟體工程師身上的三種非常常見的經歷,不管是剛參加工作還是剛參加一個開源專案。那麼,解決方案是什麼呢?

軟體工程行業承認,第一次拉取請求的時間或第一次貢獻的時間可能很費時和麻煩。因此,該行業創造了許多解決方案,如CodeSandbox和Replit的瀏覽器內沙盒解決方案。對於大型專案,基於雲的開發環境,如GitPod和GitHub Codespaces,可以簡化入職和協作。使用GitHub Codespaces或GitPod等工具的一個主要障礙是缺乏關於如何配置它們以自動執行你的專案的知識,這是可以理解的,因為這些概念在軟體工程行業還比較新。幸運的是,你有我,而且你找到了這篇博文。免責宣告:我在GitHub工作,是一名開發者倡導者。然而,有一部分的我對建立開發容器的過程感到有些畏懼。比如,什麼是開發容器?我應該只是複製和貼上一個嗎?在花了一些時間真正瞭解了開發容器之後,我覺得它們更容易接近了。

在這篇博文中,我將指導你為一個靜態的Next.js/TypeScript網路應用程式設定一個開發容器,以便它能自動在GitHub Codespace中執行。

我的新開源專案

與此相關的是,我很高興地告訴大家,我已經開始和Josh Goldberg一起維護我的第一個開源專案–開放貢獻專案。我們的目標是倡導和解釋企業對開源的貢獻。這是一個用Next.js和TypeScript建立的靜態文件網站。我們歡迎在設計、文件和程式碼方面的貢獻,特別是來自初學者的貢獻。請看下面的資料庫。

開放貢獻專案

我設定了一個開發容器,並啟用了GitHub Codespaces來簡化開放貢獻專案的開發過程。如果你在GitHub Codespaces中啟動Open Contributions專案,它將安裝所需的依賴項,執行專案,並啟動專案的瀏覽器預覽。你可以在這裡或通過點選下面的按鈕來試試!

在GitHub Codespaces中啟動Open Contributions專案

什麼是GitHub Codespaces?

GitHub Codespaces 是一個基於雲的開發環境。這有助於開發人員更快地上手,在任何裝置上進行編碼,並在一個一致的環境中進行編碼。GitHub Codespaces的使用者介面可以類似於你最喜歡的IDE–如Visual Studio Code、Visual Studio、Jupyter Notebook或JetBrains,但它在你的瀏覽器中開啟。你可以通過建立配置檔案來為GitHub Codespaces定製你的專案。這些配置檔案為你專案的所有使用者建立了一個可重複的Codespace配置。如果你不設定任何自定義配置,你的專案將使用預設的內建GitHub Codespaces配置。

你可以從以下資源中瞭解更多關於GitHub Codespaces的資訊:

什麼是開發容器?

GitHub Codespace是建立在利用開發容器的虛擬機器之上的,或稱 dev 容器,本質上是提供全面開發環境的 Docker 容器。你可以配置一個開發容器來提供統一的開發者體驗。你可以用這三個檔案配置一個開發容器: devcontainer.jsonDockerfiledocker-compose.yml 。對於像我們這樣的小型靜態Next.js/Typescript專案,我們只需要 devcontainer.json 檔案。

你可以從以下資源中瞭解更多關於開發容器的資訊:

瞭解Codespace生命週期屬性

在本指南中,我使用了一些Codespace生命週期屬性,所以我想我應該簡要介紹一下它們是什麼以及為什麼我們要使用它們。Codespace生命週期屬性是特殊的屬性,在建立和管理Codespace環境的特定點上自動執行。你可以使用它們在環境的生命週期中的特定點上執行定製任務。

下面是一些常用的Codespace生命週期屬性:

  • preCreateCommand:在建立Codespace之前執行,用於通過安裝任何必要的軟體或依賴性來設定環境。
  • onCreateCommand:在Codespace建立後立即執行,用於執行任何需要的額外設定任務。
  • postCreateCommand:在環境被建立後執行,用於執行任何最終的配置任務。
  • updateCommand:更新環境,通常用於安裝任何新的軟體或自上次建立環境以來被新增的依賴項。
  • updateContentCommand:更新環境的內容,通常用於更新環境中的檔案或資料。
  • postAttachCommand: 在這裡,”attach” 意味著連線到一個現有的和已經建立的Codespace。這個命令在使用者連線到Codespace之後執行,用於執行每次連線Codespace時應該執行的任何任務,例如啟動一個開發伺服器。

為Next.js/TypeScript程式碼庫構建開發容器的步驟

第1步:為你的專案建立一個Codespace

讓我們通過選擇 “Code”> “Codespaces”> “Create Codespace on [default branch].”,在GitHub Codespace中開啟我們的專案。

為你的專案建立一個Codespace

第2步:新增一個預製的開發容器

首先,開啟命令面板。我們可以使用這些選項中的任何一個訪問命令面板:

  • 按這個鍵盤快捷鍵組合Shift+Command+P(Mac)或Ctrl+Shift+P(Windows/Linux)。
  • 從應用程式選單中,點選 View > Command Palette
  • 按F1鍵

然後,在命令面板中,選擇 “Add dev container configuration files”。

新增一個預製的開發容器

第3步:建立一個新的配置

然後,我們將看到兩個選項:

  • 修改你的活動配置
  • 建立一個新的配置

由於我們還沒有一個配置好的開發容器,我們要選擇 “Create a new configuration”。

建立一個新的配置

第4步:選擇Node.js和TypeScript模板

接下來的步驟將引導我們進入預定義的開發容器列表,所以我們不必從頭開始! 目前,”Node.js & TypeScript” 開發容器是最適合Next.js/TypeScript專案的開始。

選擇Node.js和TypeScript模板

第5步:選擇你喜歡的Node.js版本

下一個螢幕將提示我們選擇我們喜歡的Node.js版本。我選擇了20,但你應該選擇最適合你的專案的任何版本。

選擇你喜歡的Node.js版本

第6步:跳過那些功能! 建立開發容器

下一步是新增功能。在我們的例子中,我們不需要任何功能,所以我們可以按 “OK”。按 “OK” 會給你的專案新增一個.devcontainer目錄,其中有一個devcontainer.json檔案,我們可以進一步定製。

建立開發容器

下面是我們最初的devcontainer.json檔案應該是什麼樣子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
​​// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-20"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
//"postCreateCommand": "yarn install",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
​​// For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node { "name": "Node.js & TypeScript", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/typescript-node:0-20" // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. //"postCreateCommand": "yarn install", // Configure tool-specific properties. // "customizations": {}, // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // "remoteUser": "root" }
​​// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-20"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
//"postCreateCommand": "yarn install",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

第7步:自動安裝專案的依賴項

作為本地設定的一部分,我執行 pnpm install 來安裝我的專案依賴。 pnpm 是一個Node.js包的包管理器。它被設計成快速、節省磁碟空間和功能豐富。它在磁碟上為每個包建立一個例項,並使用符號連結來連結到其他專案中安裝的包。

你的專案可能使用不同的命令和軟體包管理器來安裝專案依賴。也許,你的專案使用的是yarn或npm,所以你不想逐字逐句地複製我的這個步驟。相反,你可以把我在這一步的建議作為一個指導性的例子! 如果你使用 npm install 或 yarn install 來安裝你的專案依賴,用你的專案所需的命令替換 pnpm install 。

總之,我想把這個步驟自動化,這樣專案貢獻者就不必手動執行 pnpm install ,所以我用我的dev容器來自動完成。在我的 devcontainer.json 檔案中,我新增了一個名為的屬性:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"updateContentCommand": "pnpm install"
"updateContentCommand": "pnpm install"
"updateContentCommand": "pnpm install"

這將使我的Codespace能夠安裝最新的專案依賴。我考慮過將 pnpm install 命令委託給一個不同的 Codespace 生命週期屬性,但我想要 updateCommentCommand 的好處。使用這個生命週期屬性的最大好處是,它不會在每次建立環境時安裝所有的依賴項,而只會安裝自上次建立環境後新增的新依賴項。

第8步:自動執行本地開發伺服器

因為我的專案是靜態的,沒有太多複雜的東西,所以在安裝完所需的依賴項後,我需要用命令 pnpm dev 啟動我的本地環境。同樣,我不希望專案貢獻者手動輸入這個。我希望當他們在GitHub Codespaces中開啟我的專案時,專案就已經開始執行了,所以我在我的開發容器中通過在 devcontainer.json 檔案中新增以下幾行來實現這部分的自動化:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"postAttachCommand": "pnpm dev"
"postAttachCommand": "pnpm dev"
"postAttachCommand": "pnpm dev"

這句話是說在Codespace的所有東西都設定好後,使用者連線到Codespace,啟動開發伺服器。請記住,執行你的本地開發伺服器的命令可能有所不同。也許你需要使用npm run devyarn start 。在複製和貼上之前請仔細檢查!

第9步:選擇你的轉發埠

現在我們在上面的步驟中自動執行我們的本地開發伺服器,我們現在可以為Codespaces選擇一個特定的埠,將容器中的流量轉發到你本地機器上的一個埠。在下面的例子中,我選擇了3000埠。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"forwardPorts": [3000]
"forwardPorts": [3000]
    "forwardPorts": [3000]

因此,GitHub Codespaces 將生成一個遵循這一命名慣例的URL:

https://<your-github-handle>-<a-codespaces-id-which-combines-a-words-and-random-characters>-<your-port-number>.preview.app.github.dev/

對我來說,它生成了這個URL:

https://blackgirlbytes-ubiquitous-couscous-777759vgvpjcrv4q-3000.preview.app.github.dev/

你有能力改變你的埠的可見性! 要了解更多關於轉發埠的資訊,請檢視以下資源:

第10步: 獲取瀏覽器預覽

我最喜歡GitHub Codespace的部分是,只要在devcontainer.json檔案中加入以下幾行,就可以在Codespace中直接開啟瀏覽器預覽:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"portsAttributes": {
"3000": {
"label": "Application",
"onAutoForward": "openPreview"
}
}
"portsAttributes": { "3000": { "label": "Application", "onAutoForward": "openPreview" } }
"portsAttributes": {
"3000": {
"label": "Application",
"onAutoForward": "openPreview"
}
}

在Codespace中直接開啟瀏覽器預覽

第11步:自動新增擴充套件

我們可以配置一個專案來自動安裝GitHub Codespaces中的擴充套件。我們可以通過右鍵點選任何擴充套件,選擇 “Add to devcontainer.json” 來實現。

Add to devcontainer.json

我新增了以下擴充套件:

  • Code spell checker
  • ES Lint
  • Markdown-lint
  • Remote-containers

在這之後,它應該在我們的devcontainer.json檔案中新增以下物件:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"customizations": {
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"DavidAnson.vscode-markdownlint",
"ms-vscode-remote.remote-containers"
]
}
}
"customizations": { "vscode": { "extensions": [ "streetsidesoftware.code-spell-checker", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "DavidAnson.vscode-markdownlint", "ms-vscode-remote.remote-containers" ] } }
"customizations": {
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"DavidAnson.vscode-markdownlint",
"ms-vscode-remote.remote-containers"
]
}
}

第12步:使之成為同步的

使用 waitFor 屬性使我們能夠對Codespace的生命週期和特定命令的時間有更多的控制。例如,我在devcontainer.json檔案中使用了以下配置:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"waitFor": "onCreateCommand"
"waitFor": "onCreateCommand"
"waitFor": "onCreateCommand" 

這告訴Codespace建立過程等待onCreateCommand完成,然後再進入Codespace生命週期的下一個步驟。這確保了在執行其他命令之前環境已經設定好了。

注意事項

實際上,我的 devcontainer.json 檔案中根本就沒有onCreateCommand,所以我新增這一行並沒有意義。也許,如果我新增下面這一行,可能會更有意義:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"waitFor": "updateContentCommand"
"waitFor": "updateContentCommand"
"waitFor": "updateContentCommand"

我還在廣泛學習GitHub Codespaces,所以這是我犯的一個錯誤,我想糾正。

第13步:最後的devcontainer.json檔案

讓我們確認一下最終的結果吧! 在我的 .devcontainer 目錄中,我有一個 devcontainer.json ,內容如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18",
"waitFor": "onCreateCommand",
"updateContentCommand": "pnpm install",
"postAttachCommand": "pnpm dev",
"customizations": {
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"DavidAnson.vscode-markdownlint",
"ms-vscode-remote.remote-containers"
]
}
},
"portsAttributes": {
"3000": {
"label": "Application",
"onAutoForward": "openPreview"
}
},
"forwardPorts": [3000]
}
// For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node { "name": "Node.js & TypeScript", "image": "mcr.microsoft.com/devcontainers/typescript-node:0-18", "waitFor": "onCreateCommand", "updateContentCommand": "pnpm install", "postAttachCommand": "pnpm dev", "customizations": { "vscode": { "extensions": [ "streetsidesoftware.code-spell-checker", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "DavidAnson.vscode-markdownlint", "ms-vscode-remote.remote-containers" ] } }, "portsAttributes": { "3000": { "label": "Application", "onAutoForward": "openPreview" } }, "forwardPorts": [3000] }
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18",
"waitFor": "onCreateCommand",
"updateContentCommand": "pnpm install",
"postAttachCommand": "pnpm dev",
"customizations": {
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"DavidAnson.vscode-markdownlint",
"ms-vscode-remote.remote-containers"
]
}
},
"portsAttributes": {
"3000": {
"label": "Application",
"onAutoForward": "openPreview"
}
},
"forwardPorts": [3000]
}

第14步:試執行!

我們可以測試我們的改動,以確保GitHub Codespaces能夠安裝所需的依賴,安裝所需的擴充套件,執行我們的本地開發伺服器,並通過完全重建容器開啟瀏覽器預覽。

為了重建容器,我們需要訪問命令面板。我們可以使用這些選項中的任何一個來訪問命令面板:

  • 按這個鍵盤快捷鍵組合 Shift+Command+P (Mac) **OR **Ctrl+Shift+P (Windows/Linux)
  • 在應用程式選單中,點選View > Command Palette
  • 按下F1

然後,在命令面板中,選擇 “Codespaces: Full Rebuild Container”。

Codespaces:全面重建容器

視訊演練

我現場直播了自己通過建立一個開發容器的步驟和規劃這篇博文。請看!

分享你的學習成果

如果你嘗試過開發容器,或者掌握了使用GitHub Codespaces的任何很酷的技巧和竅門,請在下面發表評論!(via Rizèl Scarlett

評論留言