Jekyll2024-03-18T07:47:11+09:00https://deku.posstree.com/feed.xmlDeku『Programming Artist, DeKu』dev.yakuza@gmail.com[GitHub Actions] Reivewers自動設定2024-02-03T00:00:00+09:002024-02-23T11:35:27+09:00https://deku.posstree.com/share/github-actions/github-actions-set-reviewers-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#github-actions">GitHub Actions</a></li> <li><a href="#dependabot-%E7%94%A8-github-actions">Dependabot 用 GitHub Actions</a></li> <li><a href="#actionsgithub-script">actions/github-script</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p><code class="language-plaintext highlighter-rouge">GitHub</code>で<code class="language-plaintext highlighter-rouge">Pull request</code>を生成すると、次のように<code class="language-plaintext highlighter-rouge">Reviewers</code>に手動でレビュアーを設定していました。</p> <picture> <source srcset="/assets/images/category/share/2024/set-reviewers/pull_request_reviewers.avif" type="image/avif" /> <source srcset="/assets/images/category/share/2024/set-reviewers/pull_request_reviewers.webp" type="image/webp" /> <img src="/assets/images/category/share/2024/set-reviewers/pull_request_reviewers.png" alt="GitHub Actions - Set reviewers" /> </picture> <p>今回のブログポストでは<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を使って<code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Reiewers</code>にレビュアーを自動で設定する方法について説明します。</p> <h2 id="github-actions">GitHub Actions</h2> <p><code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Reviewers</code>にレビュアーを自動で設定するためには、<code class="language-plaintext highlighter-rouge">.github/workflows/set_reviewers.yml</code>ファイルを生成して次のように修正します。</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">on</span><span class="pi">:</span> <span class="na">pull_request</span><span class="pi">:</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">set-reviewers</span><span class="pi">:</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span> <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">1</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">actor="$"</span> <span class="s">reviewers=("USER_1" "USER_2" "USER_3")</span> <span class="s">reviewers=($(printf "%s\n" "${reviewers[@]}" | grep -v "$actor" | shuf -n 2))</span> <span class="s">reviewers=$(printf '%s\n' "${reviewers[@]}" | jq -R . | jq -s .)</span> <span class="s">curl -X POST \</span> <span class="s">-H "Content-Type: application/json" \</span> <span class="s">-H "Authorization: token $" \</span> <span class="s">-d "{ \"reviewers\": $reviewers }" \</span> <span class="s">"https://api.github.com/repos/$/pulls/$/requested_reviewers"</span> </code></pre></div></div> <p>この<code class="language-plaintext highlighter-rouge">GitHub Actions</code>は<code class="language-plaintext highlighter-rouge">USER_1</code>、<code class="language-plaintext highlighter-rouge">USER_2</code>、<code class="language-plaintext highlighter-rouge">USER_3</code>の中から<code class="language-plaintext highlighter-rouge">Pull request</code>を生成した人を除外してランダムに 2 人を<code class="language-plaintext highlighter-rouge">Reviewers</code>に設定するように作りました。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">actor</span><span class="o">=</span><span class="s2">"$"</span> <span class="nv">reviewers</span><span class="o">=(</span><span class="s2">"USER_1"</span> <span class="s2">"USER_2"</span> <span class="s2">"USER_3"</span><span class="o">)</span> <span class="nv">reviewers</span><span class="o">=(</span><span class="si">$(</span><span class="nb">printf</span> <span class="s2">"%s</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">reviewers</span><span class="p">[@]</span><span class="k">}</span><span class="s2">"</span> | <span class="nb">grep</span> <span class="nt">-v</span> <span class="s2">"</span><span class="nv">$actor</span><span class="s2">"</span> | <span class="nb">shuf</span> <span class="nt">-n</span> 2<span class="si">)</span><span class="o">)</span> </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Reviewers</code>には基本的に<code class="language-plaintext highlighter-rouge">Pull request</code>を生成した人は設定できません。</p> <p>この<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を使うと<code class="language-plaintext highlighter-rouge">Pull request</code>を生成するたびにランダムにレビュアーを設定してレビュアーを選ぶ時間を短縮することができます。</p> <div class="in-feed-ads ads-container"> <div class="ads-block ads-left"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="2718813593"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="ads-block ads-center"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="6492035359"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <h2 id="dependabot-用-github-actions">Dependabot 用 GitHub Actions</h2> <p>先ほど作成した<code class="language-plaintext highlighter-rouge">GitHub Actions</code>は<code class="language-plaintext highlighter-rouge">Dependabot</code>が作った<code class="language-plaintext highlighter-rouge">Pull request</code>では動かないです。この<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を<code class="language-plaintext highlighter-rouge">Dependabot</code>でも動作するようにするためには<code class="language-plaintext highlighter-rouge">pull_request</code>部分を<code class="language-plaintext highlighter-rouge">pull_request_target</code>に修正する必要があります。<code class="language-plaintext highlighter-rouge">.github/workflows/set_reviewers.yml</code>ファイルを開いて次のように修正します。</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">on</span><span class="pi">:</span> <span class="na">pull_request_target</span><span class="pi">:</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">set-reviewers</span><span class="pi">:</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span> <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">1</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">actor="$"</span> <span class="s">reviewers=("USER_1" "USER_2" "USER_3")</span> <span class="s">reviewers=($(printf "%s\n" "${reviewers[@]}" | grep -v "$actor" | shuf -n 2))</span> <span class="s">reviewers=$(printf '%s\n' "${reviewers[@]}" | jq -R . | jq -s .)</span> <span class="s">curl -X POST \</span> <span class="s">-H "Content-Type: application/json" \</span> <span class="s">-H "Authorization: token $" \</span> <span class="s">-d "{ \"reviewers\": $reviewers }" \</span> <span class="s">"https://api.github.com/repos/$/pulls/$/requested_reviewers"</span> </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">Dependabot</code>が作った<code class="language-plaintext highlighter-rouge">Pull request</code>ではセキュリティ上の理由でどのような<code class="language-plaintext highlighter-rouge">sercrets</code>も使うことができず、<code class="language-plaintext highlighter-rouge">Readonly</code>動作のみが可能なためエラーが発生します。</p> <ul> <li><a href="https://github.blog/changelog/2021-02-19-github-actions-workflows-triggered-by-dependabot-prs-will-run-with-read-only-permissions/" rel="nofollow noreferrer" target="\_blank">GitHub Actions: Workflows triggered by Dependabot PRs will run with read-only permissions</a></li> <li><a href="https://securitylab.github.com/research/github-actions-preventing-pwn-requests/" rel="nofollow noreferrer" target="\_blank">Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests</a></li> </ul> <p>これを修正するためには<code class="language-plaintext highlighter-rouge">on</code>の部分を<code class="language-plaintext highlighter-rouge">pull_request</code>から<code class="language-plaintext highlighter-rouge">pull_request_target</code>に修正する必要があります。</p> <h2 id="actionsgithub-script">actions/github-script</h2> <p><code class="language-plaintext highlighter-rouge">GitHub</code>が提供している<code class="language-plaintext highlighter-rouge">actions/github-script</code>を使うともっと読みやすいコードを書くことができます。</p> <ul> <li><a href="https://github.com/actions/github-script" rel="nofollow noreferrer" target="\_blank">actions/github-script</a></li> </ul> <p><code class="language-plaintext highlighter-rouge">actions/github-script</code>を使うと次のように修正することができます。</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">on</span><span class="pi">:</span> <span class="na">pull_request_target</span><span class="pi">:</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">set-reviewers</span><span class="pi">:</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span> <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">1</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set reviewers</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v5</span> <span class="na">with</span><span class="pi">:</span> <span class="na">github-token</span><span class="pi">:</span> <span class="s">$</span> <span class="na">script</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">const reviewers = ["USER_1", "USER_2", "USER_3"];</span> <span class="s">const actor = context.payload.pull_request.user.login;</span> <span class="s">const { owner, repo } = context.repo;</span> <span class="s">const prNumber = context.payload.pull_request.number;</span> <span class="s">const { data: assignedReviewers } = await github.rest.pulls.listRequestedReviewers({</span> <span class="s">owner,</span> <span class="s">repo,</span> <span class="s">pull_number: prNumber,</span> <span class="s">});</span> <span class="s">if (assignedReviewers.length === 0) {</span> <span class="s">const filteredReviewers = reviewers.filter(reviewer => reviewer !== actor);</span> <span class="s">const selectedReviewers = filteredReviewers.sort(() => Math.random() - 0.5).slice(0, 2);</span> <span class="s">const prNumber = context.payload.pull_request.number;</span> <span class="s">await github.rest.pulls.requestReviewers({</span> <span class="s">owner,</span> <span class="s">repo,</span> <span class="s">pull_number: prNumber,</span> <span class="s">reviewers: selectedReviewers</span> <span class="s">});</span> <span class="s">}</span> </code></pre></div></div> <h2 id="完了">完了</h2> <p>これで<code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Reviewers</code>を自動で設定する<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を作成することができました。この<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を使うと<code class="language-plaintext highlighter-rouge">Pull request</code>に<code class="language-plaintext highlighter-rouge">Reviewers</code>を設定する時間を減らすことができるし、特定のユーザーにレビューリクエストが集中させることを防ぐことができます。</p>dev.yakuza@gmail.com[GitHub Actions] Assignees 自動設定2024-02-03T00:00:00+09:002024-02-20T19:51:52+09:00https://deku.posstree.com/share/github-actions/github-actions-set-assignees-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#github-actions-%E4%BD%9C%E6%88%90">GitHub Actions 作成</a></li> <li><a href="#dependabot-%E7%94%A8-github-actions">Dependabot 用 GitHub Actions</a></li> <li><a href="#actionsgithub-script">actions/github-script</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p><code class="language-plaintext highlighter-rouge">GitHub</code>で<code class="language-plaintext highlighter-rouge">Pull request</code>を作成する際、次のように<code class="language-plaintext highlighter-rouge">Assignees</code>を手動で<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人を設定していました。</p> <picture> <source srcset="/assets/images/category/share/2024/set-assignees/pull_request_assignees.avif" type="image/avif" /> <source srcset="/assets/images/category/share/2024/set-assignees/pull_request_assignees.webp" type="image/webp" /> <img src="/assets/images/category/share/2024/set-assignees/pull_request_assignees.png" alt="GitHub Actions - Set assignees" /> </picture> <p><code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Assignees</code>は結局<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人なので、<code class="language-plaintext highlighter-rouge">Pull request</code>を作成するたびに<code class="language-plaintext highlighter-rouge">Assignees</code>に<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人を自動で設定したいと思いました。</p> <p>今回のブログポストでは、<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を使って<code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Assignees</code>に<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人を自動で設定する方法について説明します。</p> <h2 id="github-actions-作成">GitHub Actions 作成</h2> <p>それでは<code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Assignees</code>に<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人を自動で設定する<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を作ってみましょう。<code class="language-plaintext highlighter-rouge">.github/workflows/set_assignees.yml</code>ファイルを作成し、次のように修正します。</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Set assigness</span> <span class="na">on</span><span class="pi">:</span> <span class="na">pull_request</span><span class="pi">:</span> <span class="na">types</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">opened</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">set-assignees</span><span class="pi">:</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set assignees</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span> <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">1</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set assignees</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">OWNER="$"</span> <span class="s">REPOSITORY="$"</span> <span class="s">TOKEN="$"</span> <span class="s">PULL_REQUEST_NUMBER="$"</span> <span class="s">ASSIGNEES=$(curl -s \</span> <span class="s">"https://api.github.com/repos/$OWNER/$REPOSITORY/issues/$PULL_REQUEST_NUMBER" | \</span> <span class="s">jq --raw-output '.assignees // [] | .[].login')</span> <span class="s">if [ -z "$ASSIGNEES" ]; then</span> <span class="s">ASSIGNEE=$</span> <span class="s">curl -X POST \</span> <span class="s">-H "Content-Type: application/json" \</span> <span class="s">-H "Authorization: token $TOKEN" \</span> <span class="s">-d "{ \"assignees\": \"${ASSIGNEE}\" }" \</span> <span class="s">https://api.github.com/repos/$REPOSITORY/issues/$PULL_REQUEST_NUMBER/assignees</span> <span class="s">fi</span> </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">GitHub</code>が提供する<code class="language-plaintext highlighter-rouge">API</code>を使って<code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Assignees</code>に<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人(<code class="language-plaintext highlighter-rouge">github.actor</code>)を設定するようにしました。</p> <ul> <li>公式ドキュメント: <a href="https://docs.github.com/en/rest/issues/assignees?apiVersion=2022-11-28#list-assignees" rel="nofollow noreferrer" target="\_blank">List assignees</a></li> <li>公式ドキュメント: <a href="https://docs.github.com/en/rest/issues/assignees?apiVersion=2022-11-28#add-assignees-to-an-issue" rel="nofollow noreferrer" target="\_blank">Add assignees to an issue</a></li> </ul> <div class="in-feed-ads ads-container"> <div class="ads-block ads-left"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="2718813593"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="ads-block ads-center"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="6492035359"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <h2 id="dependabot-用-github-actions">Dependabot 用 GitHub Actions</h2> <p>私は個人プロジェクトで<a href="https://docs.github.com/en/code-security/dependabot/working-with-dependabot" rel="nofollow noreferrer" target="\_blank">Dependabot</a>を使ってます。<code class="language-plaintext highlighter-rouge">Dependabot</code>が作った<code class="language-plaintext highlighter-rouge">Pull request</code>にプロジェクト<code class="language-plaintext highlighter-rouge">Owner</code>を<code class="language-plaintext highlighter-rouge">Assignees</code>に設定したかったです。</p> <p>このために<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を次のように修正しました。</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Set assigness</span> <span class="na">on</span><span class="pi">:</span> <span class="na">pull_request</span><span class="pi">:</span> <span class="na">types</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">opened</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">set-assignees</span><span class="pi">:</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set assignees</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span> <span class="na">timeout-minutes</span><span class="pi">:</span> <span class="m">1</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set assignees</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">OWNER="$"</span> <span class="s">REPOSITORY="$"</span> <span class="s">TOKEN="$"</span> <span class="s">PULL_REQUEST_NUMBER="$"</span> <span class="s">ASSIGNEES=$(curl -s \</span> <span class="s">"https://api.github.com/repos/$OWNER/$REPOSITORY/issues/$PULL_REQUEST_NUMBER" | \</span> <span class="s">jq --raw-output '.assignees // [] | .[].login')</span> <span class="s">if [ -z "$ASSIGNEES" ]; then</span> <span class="s">ASSIGNEE=$</span> <span class="s">BRANCH_NAME=$</span> <span class="s">if [[ "${BRANCH_NAME}" == "dependabot/"* ]]; then</span> <span class="s">ASSIGNEE=$OWNER</span> <span class="s">fi</span> <span class="s">curl -X POST \</span> <span class="s">-H "Content-Type: application/json" \</span> <span class="s">-H "Authorization: token $TOKEN" \</span> <span class="s">-d "{ \"assignees\": \"${ASSIGNEE}\" }" \</span> <span class="s">https://api.github.com/repos/$REPOSITORY/issues/$PULL_REQUEST_NUMBER/assignees</span> <span class="s">fi</span> </code></pre></div></div> <p>追加した内容は次のように<code class="language-plaintext highlighter-rouge">branch</code>名が<code class="language-plaintext highlighter-rouge">dependabot/</code>で始まる場合、<code class="language-plaintext highlighter-rouge">Assignees</code>に<code class="language-plaintext highlighter-rouge">github.repository_owner</code>を設定するようにしました。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">BRANCH_NAME</span><span class="o">=</span><span class="err">$</span> <span class="k">if</span> <span class="o">[[</span> <span class="s2">"</span><span class="k">${</span><span class="nv">BRANCH_NAME</span><span class="k">}</span><span class="s2">"</span> <span class="o">==</span> <span class="s2">"dependabot/"</span><span class="k">*</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then </span><span class="nv">ASSIGNEE</span><span class="o">=</span><span class="nv">$OWNER</span> <span class="k">fi</span> </code></pre></div></div> <p>しかし、この<code class="language-plaintext highlighter-rouge">GitHub Actions</code>は<code class="language-plaintext highlighter-rouge">Dependabot</code>の<code class="language-plaintext highlighter-rouge">Pull request</code>で正常に動作しませんでした。セキュリティーの理由で、<code class="language-plaintext highlighter-rouge">Dependabot</code>の<code class="language-plaintext highlighter-rouge">Pull request</code>ではどの<code class="language-plaintext highlighter-rouge">sercrets</code>も使用できないし、<code class="language-plaintext highlighter-rouge">Readonly</code>の動作しかできないためエラーが発生しました。</p> <p>これを修正するためには<code class="language-plaintext highlighter-rouge">on</code>に<code class="language-plaintext highlighter-rouge">pull_request</code>ではなく<code class="language-plaintext highlighter-rouge">pull_request_target</code>を使用するように修正する必要があります。</p> <ul> <li><a href="https://github.blog/changelog/2021-02-19-github-actions-workflows-triggered-by-dependabot-prs-will-run-with-read-only-permissions/" rel="nofollow noreferrer" target="\_blank">GitHub Actions: Workflows triggered by Dependabot PRs will run with read-only permissions</a></li> <li><a href="https://securitylab.github.com/research/github-actions-preventing-pwn-requests/" rel="nofollow noreferrer" target="\_blank">Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests</a></li> </ul> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Set assigness</span> <span class="na">on</span><span class="pi">:</span> <span class="na">pull_request_target</span><span class="pi">:</span> <span class="na">types</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">opened</span> </code></pre></div></div> <h2 id="actionsgithub-script">actions/github-script</h2> <p><code class="language-plaintext highlighter-rouge">GitHub</code>が提供する<code class="language-plaintext highlighter-rouge">actions/github-script</code>を使うともっと読みやすいコードを作成することができます。</p> <ul> <li><a href="https://github.com/actions/github-script" rel="nofollow noreferrer" target="\_blank">actions/github-script</a></li> </ul> <p><code class="language-plaintext highlighter-rouge">actions/github-script</code>を使うと次のように修正することができます。</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Set</span><span class="nv"> </span><span class="s">assignees'</span> <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Set</span><span class="nv"> </span><span class="s">assignees</span><span class="nv"> </span><span class="s">automatically</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">pull</span><span class="nv"> </span><span class="s">request.'</span> <span class="na">inputs</span><span class="pi">:</span> <span class="na">token</span><span class="pi">:</span> <span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">GitHub</span><span class="nv"> </span><span class="s">token'</span> <span class="na">required</span><span class="pi">:</span> <span class="no">true</span> <span class="na">runs</span><span class="pi">:</span> <span class="na">using</span><span class="pi">:</span> <span class="s1">'</span><span class="s">composite'</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set assignees</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/github-script@v6</span> <span class="na">with</span><span class="pi">:</span> <span class="na">github-token</span><span class="pi">:</span> <span class="s">$</span> <span class="na">script</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">const { owner, repo } = context.repo;</span> <span class="s">const prNumber = context.payload.pull_request.number;</span> <span class="s">const response = await github.request(`GET /repos/${owner}/${repo}/issues/${prNumber}`);</span> <span class="s">const assignees = response.data.assignees.map(assignee => assignee.login);</span> <span class="s">if (assignees.length === 0) {</span> <span class="s">let assignee = context.actor;</span> <span class="s">const branchName = context.payload.pull_request.head.ref;</span> <span class="s">if (branchName.startsWith('dependabot/')) {</span> <span class="s">assignee = owner;</span> <span class="s">}</span> <span class="s">await github.rest.issues.addAssignees({</span> <span class="s">owner: owner,</span> <span class="s">repo: repo,</span> <span class="s">issue_number: prNumber,</span> <span class="s">assignees: [assignee]</span> <span class="s">});</span> <span class="s">}</span> </code></pre></div></div> <h2 id="完了">完了</h2> <p>これで<code class="language-plaintext highlighter-rouge">Pull request</code>の<code class="language-plaintext highlighter-rouge">Assignees</code>に<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人を自動で設定する<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を作成しました。<code class="language-plaintext highlighter-rouge">Pull request</code>を作成するたびに<code class="language-plaintext highlighter-rouge">Assignees</code>に<code class="language-plaintext highlighter-rouge">Pull request</code>を作成した人を手動で設定してる場合、この<code class="language-plaintext highlighter-rouge">GitHub Actions</code>を使用して自動化してみてください。</p>dev.yakuza@gmail.com[macOS] スリープモードを防ぐコマンド2024-01-31T00:00:00+09:002024-02-02T21:52:29+09:00https://deku.posstree.com/share/macos/caffeinate-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#caffeinate">Caffeinate</a></li> <li><a href="#caffeinate-%E7%B5%82%E4%BA%86">Caffeinate 終了</a></li> <li><a href="#caffeinate-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1">Caffeinate を使用する理由</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p><code class="language-plaintext highlighter-rouge">macOS</code> はデフォルトで省エネモードが設定されています。省エネモードは一定時間が経過すると自動的に画面を消したり、スリープモードに切り替えることで、電力消費を抑えたりノートパソコンのバッテリー寿命を延ばしたり、デスクトップのエネルギー効率を高めるのに役立ちます。</p> <p>このブログポストでは <code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを使って省エネモードが自動的に切り替わるのを防ぐ方法について説明します。</p> <h2 id="caffeinate">Caffeinate</h2> <p><code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドは macOS で省エネモードが自動的に切り替わるのを防ぐコマンドです。このコマンドはシステムがアクティブな状態を維持することで、画面が消えたりコンピュータが自動的に省エネモードに入らないようにします。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>caffeinate <span class="o">[</span>options] </code></pre></div></div> <p>コンピュータで何も操作をしないとき、省エネモードに切り替わるのを防ぎたい場合は、次のようにコマンドを実行します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>caffeinate <span class="nt">-d</span> <span class="nt">-t</span> 3600 </code></pre></div></div> <ul> <li><code class="language-plaintext highlighter-rouge">-d</code>: 画面が消えるのを防ぎます。</li> <li><code class="language-plaintext highlighter-rouge">-t</code>: 何秒間アクティブな状態を維持するか設定します。上記のコマンドは 1 時間アクティブな状態を維持します。</li> </ul> <p>ターミナルで <code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを実行した後、別のターミナルで時間がかかる作業を実行するとコンピュータが省エネモードに切り替わらずにアクティブな状態を維持することを確認できます。</p> <h2 id="caffeinate-終了">Caffeinate 終了</h2> <p>時間がかかる作業が終わったら、<code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを終了しなければなりません。<code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを実行したターミナルで <code class="language-plaintext highlighter-rouge">Ctrl + C</code> を押して <code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを終了するか、<code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドが実行されたターミナルを終了することで <code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを終了できます。</p> <h2 id="caffeinate-を使用する理由">Caffeinate を使用する理由</h2> <p>設定で省エネモードを無効にする方法もありますが、省エネモードを無効にすると電力消費が増加し、バッテリー寿命が短くなる可能性があるため、基本的には有効にしておくのが良いです。設定で省エネモードを無効にした後、これを忘れてしまうと省エネモードが継続的に無効になった状態でコンピュータを使用することになり、バッテリー寿命が短くなるなどの問題が発生する可能性があります。</p> <p>また、会社のコンピュータの場合、セキュリティ上の理由で席を空ける間に自動的に画面が消えるなどの設定を強制しています。</p> <p>このとき、一時的に時間がかかる作業(コマンド)を実行しなければならない場合、<code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを使用して省エネモードが自動的に切り替わるのを防ぎ、作業が終わった後にコマンドを終了することで、基本設定を維持しながらも省エネモードが自動的に切り替わるのを防ぐことができます。</p> <h2 id="完了">完了</h2> <p>これで <code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを使って <code class="language-plaintext highlighter-rouge">macOS</code> で省エネモードが自動的に切り替わるのを防ぐ方法について説明しました。皆さんも基本設定を維持しながらも省エネモードが自動的に切り替わるのを防ぎたい場合は <code class="language-plaintext highlighter-rouge">Caffeinate</code> コマンドを使用してみてください。</p>dev.yakuza@gmail.com[Flutter] Lexical or Preprocessor Issue (Xcode): *.h file not found エラー修正2024-01-26T00:00:00+09:002024-02-01T11:50:51+09:00https://deku.posstree.com/flutter/error/test-concurrency-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E5%8E%9F%E5%9B%A0">エラーの原因</a></li> <li><a href="#%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E8%A7%A3%E6%B1%BA">エラーの解決</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p>Flutter プロジェクトを進行中、突然次のようなエラーが発生しました。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flutter Lexical or Preprocessor Issue <span class="o">(</span>Xcode<span class="o">)</span>: <span class="s1">'FirebaseABTesting/FirebaseABTesting.h'</span> file not found </code></pre></div></div> <p>特に修正した内容がないため、エラーが発生する理由がなかったが、このようなエラーが発生して iOS でプロジェクトをビルドできませんでした。今回のブログポストでは、Flutter で突然発生する <code class="language-plaintext highlighter-rouge">flutter Lexical or Preprocessor Issue (Xcode): *.h file not found</code> エラーを解決する方法について説明します。</p> <h2 id="エラーの原因">エラーの原因</h2> <p>Flutter でプロジェクトを開発中、<code class="language-plaintext highlighter-rouge">flutter Lexical or Preprocessor Issue (Xcode): *.h file not found</code> エラーが発生した場合、<code class="language-plaintext highlighter-rouge">Xcode</code> のアップデートによる問題である可能性が高いです。</p> <p>この場合は、ほとんどが <code class="language-plaintext highlighter-rouge">Xcode</code> のアップデートにより <code class="language-plaintext highlighter-rouge">CocoaPods</code> のバージョンが低くなって発生する問題です。したがって、正常にビルドされていたプロジェクトも <code class="language-plaintext highlighter-rouge">Xcode</code> のアップデートにより <code class="language-plaintext highlighter-rouge">CocoaPods</code> のバージョンが低くなって <code class="language-plaintext highlighter-rouge">flutter Lexical or Preprocessor Issue (Xcode): *.h file not found</code> エラーが発生することがあります。</p> <h2 id="エラーの解決">エラーの解決</h2> <p>この場合は <code class="language-plaintext highlighter-rouge">CocoaPods</code> のバージョンを更新して解決することができます。私は <code class="language-plaintext highlighter-rouge">Homebrew</code> で <code class="language-plaintext highlighter-rouge">CocoaPods</code> をインストールしたため、次のように <code class="language-plaintext highlighter-rouge">Homebrew</code> を使って <code class="language-plaintext highlighter-rouge">CocoaPods</code> のバージョンを更新しました。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew upgrade cocoapods </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">CocoaPods</code> を更新した後、問題があるプロジェクトに移動した後、次のコマンドを実行して <code class="language-plaintext highlighter-rouge">Pod</code> を再インストールします。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pod <span class="nb">install</span> </code></pre></div></div> <p>必要であれば <code class="language-plaintext highlighter-rouge">Pods</code> フォルダと <code class="language-plaintext highlighter-rouge">Podfile.lock</code> ファイルを削除した後、再度 <code class="language-plaintext highlighter-rouge">pod install</code> コマンドを実行して <code class="language-plaintext highlighter-rouge">Pod</code> を再インストールします。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">rm</span> <span class="nt">-rf</span> Pods Podfile.lock pod <span class="nb">install</span> </code></pre></div></div> <p>これでプロジェクトを再ビルドすると正常にビルドされることを確認できます。</p> <h2 id="完了">完了</h2> <p>これで Flutter で突然発生する <code class="language-plaintext highlighter-rouge">flutter Lexical or Preprocessor Issue (Xcode): *.h file not found</code> エラーを解決する方法について説明しました。皆さんも Flutter プロジェクトを進行中、<code class="language-plaintext highlighter-rouge">flutter Lexical or Preprocessor Issue (Xcode): *.h file not found</code> エラーが発生した場合は、<code class="language-plaintext highlighter-rouge">CocoaPods</code> のバージョンを更新して解決してみてください。</p>dev.yakuza@gmail.com[Flutter] concurrencyオプションを使ってテストの実行速度を改善する2024-01-26T00:00:00+09:002024-01-28T20:31:50+09:00https://deku.posstree.com/flutter/test/test-concurrency-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#concurency-%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3">concurency オプション</a></li> <li><a href="#%E3%82%B3%E3%82%A2%E6%95%B0%E7%A2%BA%E8%AA%8D">コア数確認</a></li> <li><a href="#%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%9F%E8%A1%8C%E9%80%9F%E5%BA%A6%E6%AF%94%E8%BC%83">テストの実行速度比較</a></li> <li><a href="#github-actions-%E3%81%A7%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%9F%E8%A1%8C%E9%80%9F%E5%BA%A6%E6%AF%94%E8%BC%83">GitHub Actions でテストの実行速度比較</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p>Flutter でアプリを開発する時、テストコードを作成してこれを実行してサービスの安定性を高めます。しかし、プロジェクトの規模が大きくなるとテストコードの量も増え、それに伴ってテストコードを実行するのにかかる時間も増えてしまいます。</p> <p>今回のブログポストでは、<code class="language-plaintext highlighter-rouge">concurrency</code>オプションを使ってテストコードを並列で実行してテストの実行速度を改善する方法について説明します。</p> <h2 id="concurency-オプション">concurency オプション</h2> <p>Flutter で test を実行する時、<code class="language-plaintext highlighter-rouge">concurrency</code>オプションを使ってテストコードを並列で実行することができます。これによってテストコードを実行するのにかかる時間を短縮することができます。</p> <p>次のコマンドを実行すると Flutter の test コマンドで使えるオプションを確認することができます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flutter <span class="nb">test</span> <span class="nt">-h</span> </code></pre></div></div> <p>色んなオプションの中で次のように <code class="language-plaintext highlighter-rouge">concurrency</code> オプションを確認することができます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-j</span>, <span class="nt">--concurrency</span><span class="o">=</span><<span class="nb">jobs</span><span class="o">></span> The number of concurrent <span class="nb">test </span>processes to run. This will be ignored when running integration tests. </code></pre></div></div> <p>公式ドキュメントでも <code class="language-plaintext highlighter-rouge">concurrency</code> オプションを確認することができます。</p> <ul> <li>公式ドキュメント: <a href="https://pub.dev/packages/test#test-concurrency" rel="nofollow noreferrer" target="\_blank">Test concurrency</a></li> </ul> <h2 id="コア数確認">コア数確認</h2> <p>Flutter の Test コマンドはデフォルトでホスト CPU コアの半分を使うように設定されています。.</p> <blockquote> <p>Test suites run concurrently by default, using half of the host’s CPU cores.</p> </blockquote> <p>そのため、マシンのコア数の半分以下を <code class="language-plaintext highlighter-rouge">concurrency</code> オプションに設定すると、<code class="language-plaintext highlighter-rouge">concurrency</code> オプションを設定しないで実行する時よりも性能が落ちることがあります。</p> <p>なので、現在のマシンのコア数を確認して、適切なコア数を設定する必要があります。次のコマンドを実行するとマシンのコア数を確認することができます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">nproc</span> <span class="nt">--all</span> </code></pre></div></div> <h2 id="テストの実行速度比較">テストの実行速度比較</h2> <p><code class="language-plaintext highlighter-rouge">concurrency</code> オプションを使ってどの程度テストコードの実行速度が向上するのか確認してみましょう。Flutter プロジェクトで次のコマンドを使ってテストコードを実行してみます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flutter <span class="nb">test</span> </code></pre></div></div> <p>そしたら次のようにテストコードが実行された後、テストコードを実行するのにかかった時間を確認することができます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>02:10 +657: All tests passed! </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">concurrency</code> オプションを使わずにテストコードを実行すると <code class="language-plaintext highlighter-rouge">2分10秒</code> かかることが確認できます。次に次のように <code class="language-plaintext highlighter-rouge">concurrency</code> オプションを使ってテストコードを実行してみます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flutter <span class="nb">test</span> <span class="nt">--concurrency</span><span class="o">=</span><span class="si">$(</span><span class="nb">nproc</span> <span class="nt">--all</span><span class="si">)</span> </code></pre></div></div> <p>そしたら次のようにテストコードが実行された後、テストコードを実行するのにかかった時間を確認することができます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>02:02 +657: All tests passed! </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">concurrency</code> オプションを使うと <code class="language-plaintext highlighter-rouge">8秒</code> 程度テストコードの実行速度が向上することが確認できます。</p> <h2 id="github-actions-でテストの実行速度比較">GitHub Actions でテストの実行速度比較</h2> <p>私の場合ロカルマシンの性能(12 cores)が良いため、大きな効果を確認することができませんでしたが、<code class="language-plaintext highlighter-rouge">CI/CD</code> 環境ではもっと大きな効果を確認することができます。<code class="language-plaintext highlighter-rouge">GitHub Actions</code> で <code class="language-plaintext highlighter-rouge">concurrency</code> オプションを使わずにテストコードを実行した場合、次のように <code class="language-plaintext highlighter-rouge">7分</code> 程度かかることが確認できます。</p> <picture> <source srcset="/assets/images/category/flutter/2024/test-concurrency/time_without_concurrency_option.avif" type="image/avif" /> <source srcset="/assets/images/category/flutter/2024/test-concurrency/time_without_concurrency_option.webp" type="image/webp" /> <img src="/assets/images/category/flutter/2024/test-concurrency/time_without_concurrency_option.png" alt="Flutter - test without concurrency option" /> </picture> <p><code class="language-plaintext highlighter-rouge">GitHub Actions</code> で <code class="language-plaintext highlighter-rouge">concurrency</code> オプションを使ってテストコードを実行した場合、次のように <code class="language-plaintext highlighter-rouge">4分</code> 程度かかることが確認できます。</p> <picture> <source srcset="/assets/images/category/flutter/2024/test-concurrency/time_with_concurrency_option.avif" type="image/avif" /> <source srcset="/assets/images/category/flutter/2024/test-concurrency/time_with_concurrency_option.webp" type="image/webp" /> <img src="/assets/images/category/flutter/2024/test-concurrency/time_with_concurrency_option.png" alt="Flutter - test with concurrency option" /> </picture> <h2 id="完了">完了</h2> <p>今回のブログポストでは<code class="language-plaintext highlighter-rouge">Flutter</code>のテストで<code class="language-plaintext highlighter-rouge">concurrency</code>オプションを使ってテストの実行速度を改善する方法について説明しました。まだ<code class="language-plaintext highlighter-rouge">concurrency</code>オプションを使っていない場合、<code class="language-plaintext highlighter-rouge">concurrency</code>オプションを追加してテストの実行速度を改善してみてください。</p>dev.yakuza@gmail.com[Monoepo] Yarn Workspaces2024-01-18T00:00:00+09:002024-03-10T11:36:58+09:00https://deku.posstree.com/environment/monorepo/monorepo-yarn_workspaces-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E7%9B%AE%E6%AC%A1">目次</a></li> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#%E3%83%96%E3%83%AD%E3%82%B0%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA">ブログシリーズ</a></li> <li><a href="#yarn-workspaces">Yarn Workspaces</a></li> <li><a href="#%E4%BE%8B%E9%A1%8C">例題</a></li> <li><a href="#yarn-workspaces-%E3%81%AE%E8%A8%AD%E5%AE%9A">Yarn Workspaces の設定</a></li> <li><a href="#yarn-workspaces-%E7%A2%BA%E8%AA%8D">Yarn Workspaces 確認</a></li> <li><a href="#gitignore">gitignore</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p>このブログポストでは<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を使ってモノレポを構成する方法について紹介します。</p> <h2 id="ブログシリーズ">ブログシリーズ</h2> <p>このブログはシリーズで作成されました。次のリンクを通じて他のブログポストも確認してください。</p> <ul> <li><a href="https://deku.posstree.com/environment/repository_strategy/" target="\_blank">[プロジェクト管理] リポジトリ戦略</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/tools/" target="\_blank">[JavaScript] モノレポ(Monorepo)のためのツール</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/module-resolutions/" target="\_blank">[Monorepo] NodeJS のモジュールの読み込み</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/symlink/" target="\_blank">[Monorepo] Symlink</a></li> <li>[Monorepo] Yarn Workspaces</li> </ul> <h2 id="yarn-workspaces">Yarn Workspaces</h2> <p>前回のブログポストである<code class="language-plaintext highlighter-rouge">モノレポを使うためのツール</code>で JavaScript パッケージマネージャである<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を紹介しました。</p> <ul> <li><a href="https://deku.posstree.com/environment/monorepo/tools/" target="\_blank">[JavaScript] モノレポ(Monorepo)のためのツール</a></li> </ul> <p>今回のブログポストでは実際に<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>機能を使ってモノレポを構成する方法について紹介します。</p> <ul> <li>公式ドキュメント: <a href="https://yarnpkg.com/features/workspaces" rel="nofollow noreferrer" target="\_blank">Workspaces</a></li> </ul> <p><code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>は前回のブログポストで紹介した<code class="language-plaintext highlighter-rouge">Symlink</code>を使って複数のプロジェクトを単一のコードベースで管理できるようにしてくれる機能です。この機能を使えば簡単にモノレポを構成できます。</p> <ul> <li><a href="https://deku.posstree.com/environment/monorepo/symlink/" target="\_blank">[Monorepo] Symlink</a></li> </ul> <h2 id="例題">例題</h2> <p><code class="language-plaintext highlighter-rouge">Yarn</code>が提供する<code class="language-plaintext highlighter-rouge">Workspace</code>機能を確認するための例題を作成してみましょう。まず、次のようにフォルダとファイル構造を作成します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> └── src/ ├── module-a/ │ ├── index.js │ └── package.json └── module-b/ ├── index.js └── package.json </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">module-a</code>の<code class="language-plaintext highlighter-rouge">package.json</code>は次のようです。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">src/module-a/package.json</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"module-a"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">module-b</code>の<code class="language-plaintext highlighter-rouge">package.json</code>は次のようです。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">src/module-b/package.json</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"module-b"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>そして、<code class="language-plaintext highlighter-rouge">module-b</code>の<code class="language-plaintext highlighter-rouge">index.js</code>は次のようです。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// src/module-b/index.js</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-b</span><span class="dl">'</span><span class="p">);</span> </code></pre></div></div> <p>最後に<code class="language-plaintext highlighter-rouge">module-a</code>の<code class="language-plaintext highlighter-rouge">index.js</code>は次のようです。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// src/module-a/index.js</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-a</span><span class="dl">'</span><span class="p">);</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-b</span><span class="dl">'</span><span class="p">);</span> </code></pre></div></div> <p>このようにファイルを構成した後、次のコマンドを実行してモジュールを正しく読み込めるか確認します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node src/module-a/index.js </code></pre></div></div> <p>そしたら次のようにエラーが発生することを確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module-a node:internal/modules/cjs/loader:1073 throw err<span class="p">;</span> ^ Error: Cannot find module <span class="s1">'module-b'</span> Require stack: - /Users/deku/temp/temp/src/module-a/index.js at Module._resolveFilename <span class="o">(</span>node:internal/modules/cjs/loader:1070:15<span class="o">)</span> at Module._load <span class="o">(</span>node:internal/modules/cjs/loader:923:27<span class="o">)</span> at Module.require <span class="o">(</span>node:internal/modules/cjs/loader:1137:19<span class="o">)</span> at require <span class="o">(</span>node:internal/modules/helpers:121:18<span class="o">)</span> at Object.<anonymous> <span class="o">(</span>/Users/deku/temp/temp/src/module-a/index.js:3:1<span class="o">)</span> at Module._compile <span class="o">(</span>node:internal/modules/cjs/loader:1255:14<span class="o">)</span> at Module._extensions..js <span class="o">(</span>node:internal/modules/cjs/loader:1309:10<span class="o">)</span> at Module.load <span class="o">(</span>node:internal/modules/cjs/loader:1113:32<span class="o">)</span> at Module._load <span class="o">(</span>node:internal/modules/cjs/loader:960:12<span class="o">)</span> at Function.executeUserEntryPoint <span class="o">[</span>as runMain] <span class="o">(</span>node:internal/modules/run_main:83:12<span class="o">)</span> <span class="o">{</span> code: <span class="s1">'MODULE_NOT_FOUND'</span>, requireStack: <span class="o">[</span> <span class="s1">'/Users/deku/temp/temp/src/module-a/index.js'</span> <span class="o">]</span> <span class="o">}</span> </code></pre></div></div> <div class="in-feed-ads ads-container"> <div class="ads-block ads-left"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="2718813593"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="ads-block ads-center"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="6492035359"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <h2 id="yarn-workspaces-の設定">Yarn Workspaces の設定</h2> <p>次は<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を使って<code class="language-plaintext highlighter-rouge">module-a</code>で<code class="language-plaintext highlighter-rouge">module-b</code>を使えるようにしてみます。まずルートフォルダ(<code class="language-plaintext highlighter-rouge">/</code>)で次のコマンドを使って<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を使えるようにします。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn init <span class="nt">-y</span> </code></pre></div></div> <p>そうするとルートフォルダに次のような内容を含んだ<code class="language-plaintext highlighter-rouge">package.json</code>が作成されることを確認できます。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"monorepo"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="p">,</span><span class="w"> </span><span class="nl">"license"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MIT"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を使うためにはこの<code class="language-plaintext highlighter-rouge">package.json</code>ファイルを次のように修正する必要があります。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"monorepo"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="p">,</span><span class="w"> </span><span class="nl">"license"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MIT"</span><span class="p">,</span><span class="w"> </span><span class="nl">"private"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"> </span><span class="nl">"workspaces"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"packages"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"src/module-a"</span><span class="p">,</span><span class="w"> </span><span class="s2">"src/module-b"</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>モノレポは複数のプロジェクトを持っている単一のコードベースであるため、<code class="language-plaintext highlighter-rouge">npm</code>レジストリなどにデプロイする必要はありません。そのため<code class="language-plaintext highlighter-rouge">private</code>を<code class="language-plaintext highlighter-rouge">true</code>に設定してモノレポがデプロイされないようにします。<code class="language-plaintext highlighter-rouge">Yarn V1</code>では必須ですが、<code class="language-plaintext highlighter-rouge">Yarn V2</code>からは設定する必要はありません。安全に管理するために<code class="language-plaintext highlighter-rouge">private</code>を<code class="language-plaintext highlighter-rouge">true</code>に設定することをお勧めします。もちろん、モノレポ内の個々のプロジェクトはデプロイできるため、それぞれのプロジェクトは<code class="language-plaintext highlighter-rouge">private</code>を設定する必要はありません。</p> <p><code class="language-plaintext highlighter-rouge">Workspaces</code>は配列(<code class="language-plaintext highlighter-rouge">[]</code>)またはオブジェクト(<code class="language-plaintext highlighter-rouge">{}</code>)を設定できます。<code class="language-plaintext highlighter-rouge">Yarn</code>ではオブジェクト形式で作成することを推奨しています。<code class="language-plaintext highlighter-rouge">Workspaces</code>の中に<code class="language-plaintext highlighter-rouge">packages</code>というキーで配列を作成し、それぞれのモジュールを追加しました。このようにそれぞれ指定してもよいですが、次のように<code class="language-plaintext highlighter-rouge">*</code>を使って簡単にすべてのモジュールを指定することもできます。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"monorepo"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="p">,</span><span class="w"> </span><span class="nl">"license"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MIT"</span><span class="p">,</span><span class="w"> </span><span class="nl">"private"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"> </span><span class="nl">"workspaces"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"packages"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"src/*"</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h2 id="yarn-workspaces-確認">Yarn Workspaces 確認</h2> <p>これで<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を使う準備が整いました。次のコマンドを実行してパッケージをインストールします。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn <span class="nb">install</span> </code></pre></div></div> <p>すると<code class="language-plaintext highlighter-rouge">node_modules</code>フォルダがルートフォルダに作成され、<code class="language-plaintext highlighter-rouge">Symlink</code>を使ってそれぞれのモジュールが接続されていることを確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> ├── node_modules │ ├── module-a -> ../src/module-a │ └── module-b -> ../src/module-b ├── package.json ├── src │ ├── module-a │ │ ├── index.js │ │ └── package.json │ └── module-b │ ├── index.js │ └── package.json └── yarn.lock </code></pre></div></div> <p>これで<code class="language-plaintext highlighter-rouge">module-a</code>から<code class="language-plaintext highlighter-rouge">module-b</code>を使えるようになりました。次のコマンドを実行して<code class="language-plaintext highlighter-rouge">module-a</code>が正しく動作するか確認してみましょう。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node src/module-a/index.js </code></pre></div></div> <p>すると次のように問題なく<code class="language-plaintext highlighter-rouge">module-a</code>が実行されることを確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module-a module-b </code></pre></div></div> <p>もちろん<code class="language-plaintext highlighter-rouge">Symlink</code>で接続されているため、<code class="language-plaintext highlighter-rouge">module-b</code>のコードを修正すると<code class="language-plaintext highlighter-rouge">module-a</code>でも修正されたコードを使うことができます。<code class="language-plaintext highlighter-rouge">src/module-b/index.js</code>ファイルを開いて次のように修正します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>console.log<span class="o">(</span><span class="s1">'module-b!!!'</span><span class="o">)</span><span class="p">;</span> </code></pre></div></div> <p>そして次のコマンドを実行して修正された内容が正しく表示されるか確認してみましょう。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node src/module-a/index.js </code></pre></div></div> <p>すると次のように修正された内容が正しく表示されることを確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module-a module-b!!! </code></pre></div></div> <h2 id="gitignore">.gitignore</h2> <p><code class="language-plaintext highlighter-rouge">Git</code>でソースコードを管理している場合、<code class="language-plaintext highlighter-rouge">.gitignore</code>ファイルを作成して次のように修正して<code class="language-plaintext highlighter-rouge">node_modules</code>フォルダを<code class="language-plaintext highlighter-rouge">Git</code>から除外するようにします。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># .gitignore</span> node_modules </code></pre></div></div> <h2 id="完了">完了</h2> <p>これでモノレポを使うため<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を使う方法についてみてみました。<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>は基本的に<code class="language-plaintext highlighter-rouge">Symlink</code>で動作するため、<code class="language-plaintext highlighter-rouge">Symlink</code>について理解するとよいでしょう。<code class="language-plaintext highlighter-rouge">Symlink</code>について詳しく知りたい場合は前回のブログポストを参照してください。</p> <ul> <li><a href="https://deku.posstree.com/environment/monorepo/symlink/" target="\_blank">[Monorepo] Symlink</a></li> </ul> <p>皆さんも<code class="language-plaintext highlighter-rouge">Yarn</code>の<code class="language-plaintext highlighter-rouge">Workspaces</code>を使ってモノレポを構成してみてください。</p>dev.yakuza@gmail.com[Monoepo] Symlink2024-01-17T00:00:00+09:002024-03-10T11:36:58+09:00https://deku.posstree.com/environment/monorepo/monorepo-symlink-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E7%9B%AE%E6%AC%A1">目次</a></li> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#%E3%83%96%E3%83%AD%E3%82%B0%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA">ブログシリーズ</a></li> <li><a href="#symlink">Symlink</a></li> <li><a href="#%E4%BE%8B%E9%A1%8C">例題</a></li> <li><a href="#symlink-%E7%94%9F%E6%88%90">Symlink 生成</a></li> <li><a href="#symlink-%E7%A2%BA%E8%AA%8D">Symlink 確認</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p>モノレポで色んなモジュールの依存関係を連結する時、<code class="language-plaintext highlighter-rouge">Symlink</code>を活用します。今回のブログポストではモノレポを理解するための基本知識である<code class="language-plaintext highlighter-rouge">Symlink(Symbolic Link)</code>について説明します。</p> <h2 id="ブログシリーズ">ブログシリーズ</h2> <p>このブログはシリーズで制作されています。次のリンクを通じて他のブログポストも確認してください。</p> <ul> <li><a href="https://deku.posstree.com/environment/repository_strategy/" target="\_blank">[プロジェクト管理] リポジトリ戦略</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/tools/" target="\_blank">[JavaScript] モノレポ(Monorepo)のためのツール</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/module-resolutions/" target="\_blank">[Monorepo] NodeJS のモジュールの読み込み</a></li> <li>[Monorepo] Symlink</li> <li><a href="https://deku.posstree.com/environment/monorepo/yarn_workspaces/" target="\_blank">[Monorepo] Yarn Workspaces</a></li> </ul> <h2 id="symlink">Symlink</h2> <p><code class="language-plaintext highlighter-rouge">Symlink</code>は<code class="language-plaintext highlighter-rouge">Symbolic Link</code>の略で、<code class="language-plaintext highlighter-rouge">ファイル</code>または<code class="language-plaintext highlighter-rouge">ディレクトリ</code>に対する<code class="language-plaintext highlighter-rouge">ショートカット(System shortcut)</code>と考えれば良いです。</p> <p>Symlink は主要 OS(macOS, Windows, Linux)でサポートする基本機能です。また、<code class="language-plaintext highlighter-rouge">NodeJS</code>のパッケージマネージャーである<code class="language-plaintext highlighter-rouge">npm</code>と<code class="language-plaintext highlighter-rouge">yarn</code>でもサポートしています。</p> <h2 id="例題">例題</h2> <p><code class="language-plaintext highlighter-rouge">npm</code>と<code class="language-plaintext highlighter-rouge">yarn</code>が提供する<code class="language-plaintext highlighter-rouge">Symlink</code>機能を確認するための例題を作ってみましょう。まず、次のようなフォルダとファイル構造を作成します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> └── src/ ├── module-a/ │ ├── index.js │ └── package.json └── module-b/ ├── index.js └── package.json </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">module-a</code>の<code class="language-plaintext highlighter-rouge">package.json</code>は次のようです。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">src/module-a/package.json</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"module-a"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">module-b</code>の<code class="language-plaintext highlighter-rouge">package.json</code>は次のようです。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">src/module-b/package.json</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"module-b"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>そして、<code class="language-plaintext highlighter-rouge">module-b</code>の<code class="language-plaintext highlighter-rouge">index.js</code>は次のようです。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// src/module-b/index.js</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-b</span><span class="dl">'</span><span class="p">);</span> </code></pre></div></div> <p>最後に<code class="language-plaintext highlighter-rouge">module-a</code>の<code class="language-plaintext highlighter-rouge">index.js</code>は次のようです。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// src/module-a/index.js</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-a</span><span class="dl">'</span><span class="p">);</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-b</span><span class="dl">'</span><span class="p">);</span> </code></pre></div></div> <p>このようにファイルを構成した後、次のコマンドを実行してモジュールを読み込めるか確認します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node src/module-a/index.js </code></pre></div></div> <p>すると、次のようにエラーが発生することが確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module-a node:internal/modules/cjs/loader:1073 throw err<span class="p">;</span> ^ Error: Cannot find module <span class="s1">'module-b'</span> Require stack: - /Users/deku/temp/temp/src/module-a/index.js at Module._resolveFilename <span class="o">(</span>node:internal/modules/cjs/loader:1070:15<span class="o">)</span> at Module._load <span class="o">(</span>node:internal/modules/cjs/loader:923:27<span class="o">)</span> at Module.require <span class="o">(</span>node:internal/modules/cjs/loader:1137:19<span class="o">)</span> at require <span class="o">(</span>node:internal/modules/helpers:121:18<span class="o">)</span> at Object.<anonymous> <span class="o">(</span>/Users/deku/temp/temp/src/module-a/index.js:3:1<span class="o">)</span> at Module._compile <span class="o">(</span>node:internal/modules/cjs/loader:1255:14<span class="o">)</span> at Module._extensions..js <span class="o">(</span>node:internal/modules/cjs/loader:1309:10<span class="o">)</span> at Module.load <span class="o">(</span>node:internal/modules/cjs/loader:1113:32<span class="o">)</span> at Module._load <span class="o">(</span>node:internal/modules/cjs/loader:960:12<span class="o">)</span> at Function.executeUserEntryPoint <span class="o">[</span>as runMain] <span class="o">(</span>node:internal/modules/run_main:83:12<span class="o">)</span> <span class="o">{</span> code: <span class="s1">'MODULE_NOT_FOUND'</span>, requireStack: <span class="o">[</span> <span class="s1">'/Users/deku/temp/temp/src/module-a/index.js'</span> <span class="o">]</span> <span class="o">}</span> </code></pre></div></div> <div class="in-feed-ads ads-container"> <div class="ads-block ads-left"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="2718813593"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="ads-block ads-center"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="6492035359"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <h2 id="symlink-生成">Symlink 生成</h2> <p><code class="language-plaintext highlighter-rouge">Symlink</code>機能を確認するため<code class="language-plaintext highlighter-rouge">module-b</code>フォルダに移動します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>src/module-b </code></pre></div></div> <p>移動した後、次のコマンドを実行して<code class="language-plaintext highlighter-rouge">Symlink</code>を使う準備をします。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">link</span> <span class="c"># yarn link</span> </code></pre></div></div> <p>その後、<code class="language-plaintext highlighter-rouge">module-b</code>を使ってる<code class="language-plaintext highlighter-rouge">module-a</code>フォルダに移動します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> .. <span class="nb">cd </span>module-a </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">module-a</code>フォルダに移動したら、次のコマンドを実行して<code class="language-plaintext highlighter-rouge">Symlink</code>を作成します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">link </span>module-b </code></pre></div></div> <p>このように<code class="language-plaintext highlighter-rouge">link</code>コマンドを実行すると次のように<code class="language-plaintext highlighter-rouge">module-a</code>フォルダの<code class="language-plaintext highlighter-rouge">node_modules</code>フォルダが生成され、<code class="language-plaintext highlighter-rouge">modules-b</code>の<code class="language-plaintext highlighter-rouge">Symlink</code>が生成されたことが確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> ├── index.js ├── node_modules │ └── module-b -> ../../module-b └── package.json </code></pre></div></div> <p>この<code class="language-plaintext highlighter-rouge">Symlink</code>フォルダは<code class="language-plaintext highlighter-rouge">module-b</code>をコピーしたのではなく、<code class="language-plaintext highlighter-rouge">module-b</code>自体と連動しています。そのため、<code class="language-plaintext highlighter-rouge">src/module-b/index.js</code>ファイルを修正すると<code class="language-plaintext highlighter-rouge">src/module-a/node_modules/module-b/index.js</code>ファイルも同時に修正され、逆に<code class="language-plaintext highlighter-rouge">src/module-a/node_modules/module-b/index.js</code>ファイルを修正すると<code class="language-plaintext highlighter-rouge">src/module-b/index.js</code>ファイルも同時に修正されます。</p> <h2 id="symlink-確認">Symlink 確認</h2> <p>次はプロジェクトのルートフォルダ(<code class="language-plaintext highlighter-rouge">/</code>)に移動した後、次のコマンドを実行してモジュールを読み込めるか確認します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># cd ../..</span> node src/module-a/index.js </code></pre></div></div> <p>すると、次のように問題なく実行されることが確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module-a module-b </code></pre></div></div> <p>次は<code class="language-plaintext highlighter-rouge">src/module-b/index.js</code>ファイルの内容を次のように修正します。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-b!!!!</span><span class="dl">'</span><span class="p">);</span> </code></pre></div></div> <p>修正した後、<code class="language-plaintext highlighter-rouge">src/module-a/node_modules/module-b/index.js</code>ファイルを開いてみると修正した内容が反映されていることが確認できます。もちろん、次のコマンドを実行すると修正した内容が表示されることが確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node src/module-a/index.js module-a module-b!!!! </code></pre></div></div> <h2 id="完了">完了</h2> <p>これでモノレポを使うための基本知識である<code class="language-plaintext highlighter-rouge">Symlink</code>について説明しました。モノレポで色んなモジュールの依存関係を連結する時、<code class="language-plaintext highlighter-rouge">Symlink</code>を活用するので今回のブログポストを通して<code class="language-plaintext highlighter-rouge">Symlink</code>を理解しておくとモノレポを使うのに役に立つと思います。</p>dev.yakuza@gmail.com[Monorepo] NodeJSのモジュールの読み込み2024-01-16T00:00:00+09:002024-03-10T11:36:58+09:00https://deku.posstree.com/environment/monorepo/monorepo-resolution-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#%E3%83%96%E3%83%AD%E3%82%B0%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA">ブログシリーズ</a></li> <li><a href="#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB">モジュール</a></li> <li><a href="#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF">モジュールの読み込み</a> <ul> <li><a href="#file-path">File path</a></li> <li><a href="#package-name">Package name</a></li> </ul> </li> <li><a href="#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF%E5%84%AA%E5%85%88%E9%A0%86%E4%BD%8D">モジュールの読み込み優先順位</a></li> <li><a href="#%E4%BE%8B%E9%A1%8C">例題</a></li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p>今回のブログポストではモノレポを理解するための基本知識として、<code class="language-plaintext highlighter-rouge">NodeJS</code>がモジュールを読み込む方法について説明します。</p> <h2 id="ブログシリーズ">ブログシリーズ</h2> <p>このブログはシリーズで制作されています。次のリンクを通じて他のブログポストも確認してください。</p> <ul> <li><a href="https://deku.posstree.com/environment/repository_strategy/" target="\_blank">[プロジェクト管理] リポジトリ戦略</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/tools/" target="\_blank">[JavaScript] モノレポ(Monorepo)のためのツール</a></li> <li>[Monorepo] NodeJS のモジュールの読み込み</li> <li><a href="https://deku.posstree.com/environment/monorepo/symlink/" target="\_blank">[Monorepo] Symlink</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/yarn_workspaces/" target="\_blank">[Monorepo] Yarn Workspaces</a></li> </ul> <h2 id="モジュール">モジュール</h2> <p>JavaScript でモジュールはコードを構成し、再利用可能な単位に分離するために使用される機能です。モジュールを使用するとコードをより簡単にメンテナンスすることができるし、拡張することができます。ECMAScript 2015(ES6)から JavaScript に元々なかったモジュールシステムが導入されました。</p> <p>モジュールはファイルレベルでコードをカプセル化し、必要な機能を他のファイルから取り込んで使用することができます。モジュールを使用するとグローバルスコープのコンフリクトを防ぐことができ、コードの依存関係を明確に管理することができます。</p> <p>JavaScript でモジュールを使用するためには、次のキーワードを使用します。</p> <ul> <li><code class="language-plaintext highlighter-rouge">import</code>: 他のモジュールからエクスポートされた機能を現在のモジュールに取り込みます。</li> <li><code class="language-plaintext highlighter-rouge">export</code>: 現在のモジュールから外部にエクスポートする関数、変数、クラスなどを指定します。</li> </ul> <p>JavaScript で次のようにモジュールを作成することができます。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// math.js</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">add</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">a</span> <span class="o">+</span> <span class="nx">b</span><span class="p">;</span> <span class="p">}</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">subtract</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">a</span> <span class="o">-</span> <span class="nx">b</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>このように作成したモジュールは次のように使用することができます。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// main.js</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">add</span><span class="p">,</span> <span class="nx">subtract</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./math</span><span class="dl">'</span><span class="p">;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">add</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span> <span class="c1">// 8</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">subtract</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span> <span class="c1">// 5</span> </code></pre></div></div> <h2 id="モジュールの読み込み">モジュールの読み込み</h2> <p>JavaScript でモジュールを読み込む方法は大きく分けて次の 2 つがあります。</p> <ul> <li><code class="language-plaintext highlighter-rouge">File path</code>を使用する方法</li> <li><code class="language-plaintext highlighter-rouge">Package name</code>を使用する方法</li> </ul> <h3 id="file-path">File path</h3> <p><code class="language-plaintext highlighter-rouge">File path</code>を使用してモジュールを読み込む場合、相対パス(Relative path)と絶対パス(Absolute path)の両方を使用することができます。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Relative path</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">add</span><span class="p">,</span> <span class="nx">subtract</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../some/file/path/math</span><span class="dl">'</span><span class="p">;</span> <span class="c1">// Absolute path</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">add</span><span class="p">,</span> <span class="nx">subtract</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">/src/math</span><span class="dl">'</span><span class="p">;</span> </code></pre></div></div> <h3 id="package-name">Package name</h3> <p><code class="language-plaintext highlighter-rouge">node_modules</code>フォルダーにあるモジュールは<code class="language-plaintext highlighter-rouge">Package name</code>を使用して読み込むことができます。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// react module exists in node_modules</span> <span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span> </code></pre></div></div> <div class="in-feed-ads ads-container"> <div class="ads-block ads-left"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="2718813593"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="ads-block ads-center"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="6492035359"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <h2 id="モジュールの読み込み優先順位">モジュールの読み込み優先順位</h2> <p><code class="language-plaintext highlighter-rouge">NodeJS</code>はモジュールを読み込む際に、まずは同じフォルダーにモジュールが存在するか、同じフォルダーの<code class="language-plaintext highlighter-rouge">node_modules</code>にモジュールが存在するかを確認します。もし同じフォルダーにモジュールが存在しない場合、親フォルダーの<code class="language-plaintext highlighter-rouge">node_modules</code>フォルダーを確認し、親フォルダーの<code class="language-plaintext highlighter-rouge">node_modules</code>にも存在しない場合、親フォルダーの親フォルダーの<code class="language-plaintext highlighter-rouge">node_modules</code>からモジュールを探します。</p> <h2 id="例題">例題</h2> <p><code class="language-plaintext highlighter-rouge">NodeJS</code>がモジュールを読み込む方法を確認するために、次のようなフォルダー構造を作成してみます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> └── src/ ├── module-a/ │ ├── index.js │ └── package.json └── module-b/ ├── index.js └── package.json </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">module-a</code>の<code class="language-plaintext highlighter-rouge">package.json</code>は次のようです。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">src/module-a/package.json</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"module-a"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">module-b</code>の<code class="language-plaintext highlighter-rouge">package.json</code>は次のようです。</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">src/module-b/package.json</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"module-b"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w"> </span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"index.js"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>そして<code class="language-plaintext highlighter-rouge">module-b</code>の<code class="language-plaintext highlighter-rouge">index.js</code>は次のようです。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// src/module-b/index.js</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-b</span><span class="dl">'</span><span class="p">);</span> </code></pre></div></div> <p>最後に<code class="language-plaintext highlighter-rouge">module-a</code>の<code class="language-plaintext highlighter-rouge">index.js</code>は次のようです。</p> <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// src/module-a/index.js</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-a</span><span class="dl">'</span><span class="p">);</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">module-b</span><span class="dl">'</span><span class="p">);</span> </code></pre></div></div> <p>このようにファイルを構成した後、次のコマンドを実行してモジュールを読み込むことができるか確認します。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node src/module-a/index.js </code></pre></div></div> <p>そしたら次のようなエラーが発生することが確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module-a node:internal/modules/cjs/loader:1073 throw err<span class="p">;</span> ^ Error: Cannot find module <span class="s1">'module-b'</span> Require stack: - /Users/deku/temp/temp/src/module-a/index.js at Module._resolveFilename <span class="o">(</span>node:internal/modules/cjs/loader:1070:15<span class="o">)</span> at Module._load <span class="o">(</span>node:internal/modules/cjs/loader:923:27<span class="o">)</span> at Module.require <span class="o">(</span>node:internal/modules/cjs/loader:1137:19<span class="o">)</span> at require <span class="o">(</span>node:internal/modules/helpers:121:18<span class="o">)</span> at Object.<anonymous> <span class="o">(</span>/Users/deku/temp/temp/src/module-a/index.js:3:1<span class="o">)</span> at Module._compile <span class="o">(</span>node:internal/modules/cjs/loader:1255:14<span class="o">)</span> at Module._extensions..js <span class="o">(</span>node:internal/modules/cjs/loader:1309:10<span class="o">)</span> at Module.load <span class="o">(</span>node:internal/modules/cjs/loader:1113:32<span class="o">)</span> at Module._load <span class="o">(</span>node:internal/modules/cjs/loader:960:12<span class="o">)</span> at Function.executeUserEntryPoint <span class="o">[</span>as runMain] <span class="o">(</span>node:internal/modules/run_main:83:12<span class="o">)</span> <span class="o">{</span> code: <span class="s1">'MODULE_NOT_FOUND'</span>, requireStack: <span class="o">[</span> <span class="s1">'/Users/deku/temp/temp/src/module-a/index.js'</span> <span class="o">]</span> <span class="o">}</span> </code></pre></div></div> <p>次は<code class="language-plaintext highlighter-rouge">src</code>フォルダ名を<code class="language-plaintext highlighter-rouge">node_modules</code>で変更して次のコマンドを実行してみます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node node_modules/module-a/index.js </code></pre></div></div> <p>そしたら次のように問題なく実行されることが確認できます。</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module-a module-b </code></pre></div></div> <p>フォルダー名が<code class="language-plaintext highlighter-rouge">src</code>の場合、<code class="language-plaintext highlighter-rouge">module-a</code>から<code class="language-plaintext highlighter-rouge">require('module-b');</code>を通じて<code class="language-plaintext highlighter-rouge">module-b</code>を読み込むと、ファイルパスではないため、同じフォルダーの<code class="language-plaintext highlighter-rouge">node_modules</code>から<code class="language-plaintext highlighter-rouge">module-b</code>を探すことになります。<code class="language-plaintext highlighter-rouge">node_modules</code>が現在のフォルダーに存在しないため、親フォルダーの<code class="language-plaintext highlighter-rouge">node_modules</code>を確認します。親フォルダーにも<code class="language-plaintext highlighter-rouge">node_modules</code>が存在しないため、<code class="language-plaintext highlighter-rouge">MODULE_NOT_FOUND</code>エラーが発生することが確認できます。</p> <p>フォルダー名を<code class="language-plaintext highlighter-rouge">node_modules</code>に変更した後、同じコードを実行すると、<code class="language-plaintext highlighter-rouge">module-a</code>フォルダーに<code class="language-plaintext highlighter-rouge">node_modules</code>が存在しないため、親フォルダーから<code class="language-plaintext highlighter-rouge">node_modules</code>を探すことになります。親フォルダーにはフォルダー名を変更した<code class="language-plaintext highlighter-rouge">node_modules</code>が存在し、そのフォルダーに<code class="language-plaintext highlighter-rouge">module-b</code>が存在するため、問題なく実行されることが確認できます。</p> <h2 id="完了">完了</h2> <p>これで<code class="language-plaintext highlighter-rouge">NodeJS</code>がモジュールを読み込む方法について説明しました。<code class="language-plaintext highlighter-rouge">NodeJS</code>がモジュールを読み込む方法はモノレポでプロジェクトを構成するのに役立つ知識なので、今回のブログポストで紹介しました。皆さんもこの機会に<code class="language-plaintext highlighter-rouge">NodeJS</code>がモジュールを読み込む方法についてもう一度理解してみてください。</p>dev.yakuza@gmail.com[JavaScript] モノレポ(Monorepo)のためのツール2024-01-11T00:00:00+09:002024-03-10T11:36:58+09:00https://deku.posstree.com/environment/monorepo/monorepo_tools-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#%E3%83%96%E3%83%AD%E3%82%B0%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA">ブログシリーズ</a></li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AC%E3%83%9D%E3%82%92%E5%A7%8B%E3%82%81%E3%82%8B%E6%96%B9%E6%B3%95">モノレポを始める方法</a></li> <li><a href="#%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%BC">パッケージマネージャー</a></li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AC%E3%83%9D%E7%94%A8%E3%83%84%E3%83%BC%E3%83%AB">モノレポ用ツール</a> <ul> <li><a href="#lerna">Lerna</a></li> <li><a href="#nx">Nx</a></li> <li><a href="#turborepo">Turborepo</a></li> </ul> </li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p>今回のブログポストでは、JavaScript で開発するプロジェクトでモノレポ(Monorepo)を使用するために必要なツールを紹介します。</p> <h2 id="ブログシリーズ">ブログシリーズ</h2> <p>このブログはシリーズで制作されました。次のリンクを通じて他のブログポストも確認してください。</p> <ul> <li><a href="https://deku.posstree.com/environment/repository_strategy/" target="\_blank">[プロジェクト管理] リポジトリ戦略</a></li> <li>[JavaScript] モノレポ(Monorepo)のためのツール</li> <li><a href="https://deku.posstree.com/environment/monorepo/module-resolutions/" target="\_blank">[Monorepo] NodeJS のモジュールの読み込み</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/symlink/" target="\_blank">[Monorepo] Symlink</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/yarn_workspaces/" target="\_blank">[Monorepo] Yarn Workspaces</a></li> </ul> <h2 id="モノレポを始める方法">モノレポを始める方法</h2> <p>モノレポを始める方法は大きく 2 つあります。</p> <ul> <li>パッケージマネージャーを利用する方法</li> <li>モノレポ用ツールを利用する方法</li> </ul> <p>今回のブログポストでは、JavaScript プロジェクトでモノレポをサポートするパッケージマネージャーとモノレポツールについて紹介します。</p> <h2 id="パッケージマネージャー">パッケージマネージャー</h2> <p>JavaScript プロジェクトでモノレポを構成するためには、モノレポをサポートするパッケージマネージャーを使用することができます。モノレポをサポートするパッケージマネージャーは、<code class="language-plaintext highlighter-rouge">pnpm</code>、<code class="language-plaintext highlighter-rouge">yarn</code>、<code class="language-plaintext highlighter-rouge">npm</code>があります。</p> <p>モノレポをサポートするパッケージマネージャーである<code class="language-plaintext highlighter-rouge">pnpm</code>、<code class="language-plaintext highlighter-rouge">yarn</code>、<code class="language-plaintext highlighter-rouge">npm</code>は次のような特性を持っています。</p> <table> <thead> <tr> <th>機能</th> <th>pnpm</th> <th>yarn</th> <th>npm</th> </tr> </thead> <tbody> <tr> <td>workspace 提供</td> <td>✅</td> <td>✅</td> <td>✅</td> </tr> <tr> <td>孤立した node_modules</td> <td>✅(default)</td> <td>✅</td> <td>✅</td> </tr> <tr> <td>ホイスティングされた node_modules</td> <td>✅</td> <td>✅</td> <td>✅(default)</td> </tr> <tr> <td>ピア自動インストール</td> <td>✅</td> <td>❌</td> <td>✅</td> </tr> <tr> <td>Plug’n’Play</td> <td>✅</td> <td>✅(default)</td> <td>✅</td> </tr> <tr> <td>Zero-Installs</td> <td>❌</td> <td>✅</td> <td>❌</td> </tr> <tr> <td>依存パッチ</td> <td>✅</td> <td>✅</td> <td>❌</td> </tr> <tr> <td>NodeJS バージョン管理</td> <td>✅</td> <td>❌</td> <td>❌</td> </tr> <tr> <td>Lockfile</td> <td>✅(pnpm-lock.yaml)</td> <td>✅(yarn.lock)</td> <td>✅(package-lock.json)</td> </tr> <tr> <td>上書きサポート</td> <td>✅</td> <td>✅(resolution 使用)</td> <td>✅</td> </tr> <tr> <td>Content-addressable リポジトリ</td> <td>✅</td> <td>❌</td> <td>❌</td> </tr> <tr> <td>動的パッケージ実行</td> <td>✅(pnpm dlx)</td> <td>✅(yarn dlx)</td> <td>✅(npx)</td> </tr> <tr> <td>Listing licenses</td> <td>✅(pnpm licenses list)</td> <td>✅(Via a plugin)</td> <td>❌</td> </tr> </tbody> </table> <div class="in-feed-ads ads-container"> <div class="ads-block ads-left"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="2718813593"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="ads-block ads-center"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="6492035359"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <h2 id="モノレポ用ツール">モノレポ用ツール</h2> <p>パッケージマネージャーが提供する<code class="language-plaintext highlighter-rouge">Workspace</code>機能だけでも十分にモノレポを構成することができますが、モノレポ用ツールを使用するとより簡単にモノレポを構成することができます。また、モノレポ用ツールが提供する<code class="language-plaintext highlighter-rouge">Cache</code>機能を使用すると<code class="language-plaintext highlighter-rouge">Build</code>や<code class="language-plaintext highlighter-rouge">CI</code>などをより高速に実行することができます。</p> <p>JavaScript プロジェクトのためのモノレポ用ツールには<code class="language-plaintext highlighter-rouge">Lerna</code>、<code class="language-plaintext highlighter-rouge">Nx</code>、<code class="language-plaintext highlighter-rouge">Turborepo</code>があります。</p> <h3 id="lerna">Lerna</h3> <p><code class="language-plaintext highlighter-rouge">Lerna</code>はオープンソースで開発、管理されています。オープンソースコミュニティだけでは管理が難しく、<code class="language-plaintext highlighter-rouge">Nx</code>に引き継がれました。</p> <ul> <li>Lerna: <a href="https://lerna.js.org/" rel="nofollow noreferrer" target="\_blank">https://lerna.js.org/</a></li> </ul> <p>現在も<code class="language-plaintext highlighter-rouge">Lerna</code>を使用することはできますが、<code class="language-plaintext highlighter-rouge">Nx</code>に引き継がれたため、<code class="language-plaintext highlighter-rouge">Nx</code>が自分たちのツールほど<code class="language-plaintext highlighter-rouge">Lerna</code>をサポートするかは確実ではないため、<code class="language-plaintext highlighter-rouge">Lerna</code>を使用するのであれば<code class="language-plaintext highlighter-rouge">Nx</code>を使用するか、もう少し動向を見守ることをお勧めします。</p> <h3 id="nx">Nx</h3> <p><code class="language-plaintext highlighter-rouge">Nx</code>は<code class="language-plaintext highlighter-rouge">Narwhal Technologies Inc.</code>という会社で開発、提供しています。この会社は<code class="language-plaintext highlighter-rouge">Angular</code>フレームワークに関連するツールやサービスを提供する会社です。<code class="language-plaintext highlighter-rouge">Angular</code>フレームワークに関連するツールを開発する会社が作った<code class="language-plaintext highlighter-rouge">Nx</code>であるため、<code class="language-plaintext highlighter-rouge">Nx</code>は<code class="language-plaintext highlighter-rouge">Angular</code>アプリケーションをサポートするモノレポ管理ツールとして始まりました。現在は<code class="language-plaintext highlighter-rouge">React</code>など他のフレームワークもサポートしています。</p> <ul> <li>Nx: <a href="https://nx.dev/" rel="nofollow noreferrer" target="\_blank">https://nx.dev/</a></li> </ul> <p>もし<code class="language-plaintext highlighter-rouge">Angular</code>フレームワークでプロジェクトを開発する予定であれば、<code class="language-plaintext highlighter-rouge">Nx</code>は優れた選択肢になると思います。もちろん、他のフレームワークでも<code class="language-plaintext highlighter-rouge">Nx</code>は良い選択肢になるかもしれませんが、<code class="language-plaintext highlighter-rouge">Angular</code>フレームワークを中心に開発された<code class="language-plaintext highlighter-rouge">Nx</code>と<code class="language-plaintext highlighter-rouge">Angular</code>中心のツールを開発する会社が作った<code class="language-plaintext highlighter-rouge">Nx</code>は<code class="language-plaintext highlighter-rouge">Angular</code>フレームワークでより良いパフォーマンスを発揮すると思います。</p> <p><code class="language-plaintext highlighter-rouge">Nx</code>がサポートするフレームワークは次のリンクから確認できます。</p> <ul> <li>Recipes: <a href="https://nx.dev/recipes" rel="nofollow noreferrer" target="\_blank">https://nx.dev/recipes</a></li> </ul> <h3 id="turborepo">Turborepo</h3> <p><code class="language-plaintext highlighter-rouge">Turborepo</code>は<code class="language-plaintext highlighter-rouge">Jared Palmer</code>が開発しましたが、2021 年に<code class="language-plaintext highlighter-rouge">NextJS</code>を作って運営している<code class="language-plaintext highlighter-rouge">Vercel</code>が買収し、開発、管理しています。</p> <ul> <li>Turbo: <a href="https://turbo.build/" rel="nofollow noreferrer" target="\_blank">https://turbo.build/</a></li> </ul> <p>もし、<code class="language-plaintext highlighter-rouge">NextJS</code>、<code class="language-plaintext highlighter-rouge">React</code>でプロジェクトを開発する予定であれば、<code class="language-plaintext highlighter-rouge">Turborepo</code>は優れた選択肢になると思います。もちろん、他のフレームワークでも<code class="language-plaintext highlighter-rouge">Turborepo</code>は良い選択肢になるかもしれませんが、<code class="language-plaintext highlighter-rouge">NextJS</code>を作って運営している<code class="language-plaintext highlighter-rouge">Vercel</code>が買収した<code class="language-plaintext highlighter-rouge">Turborepo</code>は<code class="language-plaintext highlighter-rouge">NextJS</code>でより良いパフォーマンスを発揮すると思います。</p> <p><code class="language-plaintext highlighter-rouge">Turborepo</code>がサポートするフレームワークは次のリンクから確認できます。</p> <ul> <li>Turborepo Examples: <a href="https://turbo.build/repo/docs/getting-started/from-example" rel="nofollow noreferrer" target="\_blank">https://turbo.build/repo/docs/getting-started/from-example</a></li> </ul> <h2 id="完了">完了</h2> <p>今回のブログポストでは、JavaScript で開発するプロジェクトでモノレポ(Monorepo)を使用するために必要なツールを紹介しました。パッケージマネージャーが提供する機能だけで十分にモノレポを構成することができますが、モノレポ用ツールを使用するとより簡単にモノレポを構成することができます。</p> <p>モノレポでプロジェクトを構成する予定であれば、パッケージマネージャーの機能だけでなく、モノレポ用ツールの導入も検討してみてください。</p>dev.yakuza@gmail.com[プロジェクト管理] リポジトリ戦略2024-01-04T00:00:00+09:002024-03-10T11:36:58+09:00https://deku.posstree.com/environment/repository_strategy-ja<div id="contents_list"> <h2 id="section">目次</h2> <ul> <li><a href="#%E6%A6%82%E8%A6%81">概要</a></li> <li><a href="#%E3%83%96%E3%83%AD%E3%82%B0%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA">ブログシリーズ</a></li> <li><a href="#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E6%88%A6%E7%95%A5">リポジトリ戦略</a></li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AA%E3%82%B9monolith">モノリス Monolith</a> <ul> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AA%E3%82%B9%E3%81%AE%E5%88%A9%E7%82%B9">モノリスの利点</a></li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AA%E3%82%B9%E3%81%AE%E6%AC%A0%E7%82%B9">モノリスの欠点</a></li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AA%E3%82%B9%E5%B0%8E%E5%85%A5%E6%99%82%E3%81%AE%E8%80%83%E6%85%AE%E4%BA%8B%E9%A0%85">モノリス導入時の考慮事項</a></li> </ul> </li> <li><a href="#%E3%83%9E%E3%83%AB%E3%83%81%E3%83%AC%E3%83%9Dmulti-repo">マルチレポ Multi Repo</a> <ul> <li><a href="#%E3%83%9E%E3%83%AB%E3%83%81%E3%83%AC%E3%83%9D%E3%81%AE%E5%88%A9%E7%82%B9">マルチレポの利点</a></li> <li><a href="#%E3%83%9E%E3%83%AB%E3%83%81%E3%83%AC%E3%83%9D%E3%81%AE%E6%AC%A0%E7%82%B9">マルチレポの欠点</a></li> <li><a href="#%E3%83%9E%E3%83%AB%E3%83%81%E3%83%AC%E3%83%9D%E5%B0%8E%E5%85%A5%E6%99%82%E3%81%AE%E8%80%83%E6%85%AE%E4%BA%8B%E9%A0%85">マルチレポ導入時の考慮事項</a></li> </ul> </li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AC%E3%83%9Dmonorepo">モノレポ Monorepo</a> <ul> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AC%E3%83%9D%E3%81%AE%E5%88%A9%E7%82%B9">モノレポの利点</a></li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AC%E3%83%9D%E3%81%AE%E6%AC%A0%E7%82%B9">モノレポの欠点</a></li> <li><a href="#%E3%83%A2%E3%83%8E%E3%83%AC%E3%83%9D%E5%B0%8E%E5%85%A5%E6%99%82%E3%81%AE%E8%80%83%E6%85%AE%E4%BA%8B%E9%A0%85">モノレポ導入時の考慮事項</a></li> </ul> </li> <li><a href="#%E5%AE%8C%E4%BA%86">完了</a></li> </ul> </div> <h2 id="概要">概要</h2> <p>プロジェクトを開発する時、1 つのリポジトリで構成した方がいいのか、マルチレポで構成した方がいいのかリポジトリの戦略を決めます。今回のブログポストでは、プロジェクトを管理するためのリポジトリ戦略である<code class="language-plaintext highlighter-rouge">モノリス(Monolith)</code>、<code class="language-plaintext highlighter-rouge">マルチレポ(Multi Repo)</code>、<code class="language-plaintext highlighter-rouge">モノレポ(Monorepo)</code>について説明します。</p> <h2 id="ブログシリーズ">ブログシリーズ</h2> <p>このブログはシリーズで制作されました。次のリンクを通じて他のブログポストも確認してください。</p> <ul> <li>[プロジェクト管理] リポジトリ戦略</li> <li><a href="https://deku.posstree.com/environment/monorepo/tools/" target="\_blank">[JavaScript] モノレポ(Monorepo)のためのツール</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/module-resolutions/" target="\_blank">[Monorepo] NodeJS のモジュールの読み込み</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/symlink/" target="\_blank">[Monorepo] Symlink</a></li> <li><a href="https://deku.posstree.com/environment/monorepo/yarn_workspaces/" target="\_blank">[Monorepo] Yarn Workspaces</a></li> </ul> <h2 id="リポジトリ戦略">リポジトリ戦略</h2> <p>リポジトリ戦略は次のように<code class="language-plaintext highlighter-rouge">モノリス(Monolith)</code>、<code class="language-plaintext highlighter-rouge">マルチレポ(Multi Repo)</code>、<code class="language-plaintext highlighter-rouge">モノレポ(Monorepo)</code>があります。</p> <picture> <source srcset="/assets/images/category/environment/2024/repository_strategy/repository_strategy.avif" type="image/avif" /> <source srcset="/assets/images/category/environment/2024/repository_strategy/repository_strategy.webp" type="image/webp" /> <img src="/assets/images/category/environment/2024/repository_strategy/repository_strategy.jpg" alt="Repository strategy" /> </picture> <ul> <li>モノリス: モノリスは 1 つのサービスを 1 つのプロジェクトにして 1 つのリポジトリで管理します。</li> <li>マルチレポ: マルチレポは 1 つのサービスを複数のプロジェクトに分けて複数のリポジトリで管理します。</li> <li>モノレポ: モノレポは 1 つのサービスを複数のプロジェクトに分けて 1 つのリポジトリで管理します。</li> </ul> <h2 id="モノリスmonolith">モノリス(Monolith)</h2> <p>モノリス(Monolith)はソフトウェアプロジェクトを単一のコードベースで構成された単一のアプリケーションに設計するプロジェクト管理技法です。モノリスアーキテクチャでは、アプリケーションのすべてのコンポーネントが 1 つのコードベースに統合されて開発、デプロイ、運用が行われます。</p> <h3 id="モノリスの利点">モノリスの利点</h3> <ul> <li>管理とメンテナンスが簡単: 単一のコードベースで構成されているため、全体的な管理とメンテナンスが比較的簡単です。</li> <li>統合テストの容易性: 全体システムが単一のアプリケーションで構成されているため、統合テストが容易です。</li> <li>初期開発速度の向上: 最初はすべてが 1 つの場所にあるため、開発が迅速に進むことができます。</li> </ul> <h3 id="モノリスの欠点">モノリスの欠点</h3> <ul> <li>拡張性の制約: アプリケーションのサイズが大きくなると、拡張が難しくなる可能性があります。</li> <li>技術スタックの依存: 単一の技術スタックに依存するため、さまざまな技術の導入が難しくなる可能性があります。</li> <li>デプロイの難しさ: 全体アプリケーションを修正してデプロイする必要があるため、小さな変更のデプロイが難しい可能性があります。</li> </ul> <h3 id="モノリス導入時の考慮事項">モノリス導入時の考慮事項</h3> <p>次のような場合、モノリス導入を検討することができると思います。</p> <ul> <li>小規模プロジェクト: 小規模プロジェクトであれば、初期開発速度を高めることができます。</li> <li>簡単なメンテナンスが必要な場合: 簡単なアプリケーションでは、メンテナンスが容易になる場合があります。</li> <li>技術スタックが明らかになっている場合: 特定の技術スタックについてしっかりと決めた場合は、モノリスが役に立つ可能性があります。</li> <li>チーム規模が小さい場合: 小さなチームが協力して開発する場合、モノリスが効果的になる場合があります。</li> </ul> <p>しかし、プロジェクトの規模や要件が増えるにつれて、分散アーキテクチャやマイクロサービスアーキテクチャなど他のアーキテクチャも検討する必要があります。これは、アプリケーションの拡張性、柔軟性、独立性などを高めることができます。</p> <div class="in-feed-ads ads-container"> <div class="ads-block ads-left"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="2718813593"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="ads-block ads-center"> <ins class="adsbygoogle" style="display: block; text-align: center" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-7987914246691031" data-ad-slot="6492035359"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <h2 id="マルチレポmulti-repo">マルチレポ(Multi Repo)</h2> <p>マルチレポ(Multi Repo)はソフトウェアプロジェクトを複数の独立したリポジトリで開発するプロジェクト管理技法です。各リポジトリは特定の機能、モジュール、またはサービスに対応し、開発、デプロイ、運用が分離されています。</p> <h3 id="マルチレポの利点">マルチレポの利点</h3> <ul> <li>独立した開発とデプロイ: 各リポジトリは独立して開発、テスト、デプロイされるため、迅速な開発サイクルが可能です。</li> <li>スケーラビリティ: 特定のモジュールやサービスの負荷が増加すると、そのリポジトリだけを拡張してシステム全体のパフォーマンスを向上させることができます。</li> <li>技術スタックの多様性: 各リポジトリは独自の技術スタックを選択できるため、特定の技術に依存せず、複数の技術を組み合わせて使用できます。</li> <li>分離されたコードベース: 各リポジトリは特定の機能や業務領域に集中しているため、コードの可読性とメンテナンス性が向上する可能性があります。</li> </ul> <h3 id="マルチレポの欠点">マルチレポの欠点</h3> <ul> <li>依存関係の管理の難しさ: 多くのリポジトリ間の依存関係を管理することは複雑になる可能性があります。</li> <li>システム全体の統合の難しさ: 各リポジトリが独立して開発されているため、統合する際に競合が発生する可能性があり、解決に時間がかかる場合があります。</li> <li>総合的なビジョンの欠如: システム全体を理解して管理することが難しく、特に総合的なビジョンが必要な場合には難しい場合があります。</li> </ul> <h3 id="マルチレポ導入時の考慮事項">マルチレポ導入時の考慮事項</h3> <p>次のような場合、マルチレポ導入を検討することができると思います。</p> <ul> <li>大規模プロジェクト: プロジェクトが大きく、多くの機能やモジュールを含む場合、それぞれを独立して管理する必要がある場合に使用できます。</li> <li>チーム間の協力: 複数のチームが同時に作業し、互いに独立して開発したい場合、マルチレポが有効になる場合があります。</li> <li>サービス指向アーキテクチャ(SOA)またはマイクロサービスアーキテクチャ: マルチレポは各サービスを独立して管理するのに役立ち、SOA またはマイクロサービスアーキテクチャとよくマッチします。</li> </ul> <p>マルチレポは分散環境でチームの協力と迅速な開発サイクルをサポートするのに適しており、特にサービス指向アーキテクチャでは各サービスを個別に管理することが重要です。</p> <p>しかし、チームの規模が小さく、プロジェクトの規模が小さい場合、多くの技術スタックとリポジトリの管理の難しさが発生する可能性があります。</p> <h2 id="モノレポmonorepo">モノレポ(Monorepo)</h2> <p>モノレポ(Mono-repo)はソフトウェアプロジェクトを 1 つの大規模なコードベース(リポジトリ)として構成して開発するプロジェクト管理技法です。この方法では、すべてのソースコード、ライブラリ、モジュールが 1 つの中央位置に格納され、管理されます。</p> <h3 id="モノレポの利点">モノレポの利点</h3> <ul> <li>依存関係の管理が容易: 1 つのコードベースですべての依存関係を管理するため、依存関係の競合やバージョン管理が容易です。</li> <li>全体システムの理解が容易: プロジェクトの全体的な構造と動作を理解しやすくなります。全体システムを一目で把握できます。</li> <li>コードの再利用性: すべてのモジュールとライブラリが 1 つのコードベースにあるため、コードの再利用が容易です。</li> <li>統合テストの容易性: 全体システムが 1 つのコードベースで構成されているため、全体システムの統合テストが容易です。</li> </ul> <h3 id="モノレポの欠点">モノレポの欠点</h3> <ul> <li>大規模プロジェクトの管理の難しさ: プロジェクトの規模が大きくなると、ビルド時間が長くなり、すべてのコードに対するチーム間の協力が難しくなる可能性があります。</li> <li>技術スタックの制約: 1 つのコードベースで作業するため、特定の技術スタックに制約を受ける可能性があります。</li> <li>CI/CD 性能の低下: 大規模モノレポでは、継続的な統合とデプロイのパフォーマンスが低下する可能性があります。</li> </ul> <h3 id="モノレポ導入時の考慮事項">モノレポ導入時の考慮事項</h3> <p>次のような場合、モノレポ導入を検討することができると思います。</p> <ul> <li>中小規模プロジェクト: プロジェクトが小規模であれば、1 つのリポジトリで管理することが便利になります。</li> <li>チーム間の協力: すべてのチームが 1 つのリポジトリで作業する場合、コード共有と協力が容易になります。</li> <li>依存関係の管理が重要な場合: プロジェクト内の依存関係が複雑に絡み合っている場合、モノレポで管理することが便利になります。</li> <li>単一の技術スタックの使用が必要な場合: 特定の技術スタックを一貫して使用する必要がある場合、モノレポが適している場合があります。</li> </ul> <p>モノレポは、プロジェクトの規模が小さく、チーム間の協力が必要な場合に有効になります。また、依存関係の管理が重要な場合や、特定の技術スタックを使用する必要がある場合にも有効になります。しかし、プロジェクトの規模が大きくなると、ビルド時間が長くなり、チーム間の協力が難しくなる可能性があります。</p> <h2 id="完了">完了</h2> <p>今回のブログポストではプロジェクト管理技法であるリポジトリ戦略について説明しました。特定の戦略が良いか悪いかはありません。プロジェクトの規模と要件に応じて、適切な戦略を選択してください。</p>dev.yakuza@gmail.com