T-CREATOR

Yarn で社内テンプレート管理:dlx・create-* の私設スキャフォールド術

Yarn で社内テンプレート管理:dlx・create-* の私設スキャフォールド術

プロジェクトを新規立ち上げるたび、同じようなセットアップを繰り返していませんか。 社内で統一されたテンプレートがあれば、初期構成のブレや設定ミスを防ぎ、チーム全体の立ち上げスピードが劇的に向上します。 Yarn の dlxcreate-* の仕組みを組み合わせれば、npm に公開せず、社内限定のスキャフォールド環境を構築できます。

本記事では、Yarn を使った社内テンプレート管理の具体的な設計・実装手順を、初心者にもわかりやすく段階的に解説していきます。

背景

なぜ社内テンプレートが必要か

開発現場では、新しいプロジェクトを立ち上げる際に以下の作業が毎回発生します。

  • Next.js や React のボイラープレートをコピー
  • ESLint、Prettier、TypeScript の設定ファイルを整備
  • Docker、CI/CD、環境変数の初期設定
  • コーディング規約やディレクトリ構成の統一

これらを手作業で行うと、チームメンバーごとに微妙に設定が異なり、後からトラブルの元になりがちです。 統一されたテンプレートを用意すれば、プロジェクトの立ち上げが数分で完了し、品質のばらつきも抑えられるでしょう。

Yarn dlx とは

yarn dlx は、パッケージをグローバルにインストールせず、一時的に実行するためのコマンドです。 npx と似た役割を持ちますが、Yarn の PnP や依存解決戦略と親和性が高く、よりクリーンに動作します。

markdownyarn dlx create-next-app my-app

上記のコマンドでは、create-next-app を一時的にダウンロードし、テンプレートを展開してくれます。 グローバル環境を汚さず、常に最新のツールを利用できる点が大きなメリットです。

create-* パッケージの仕組み

create-react-appcreate-next-app など、create-* という名前のパッケージは、スキャフォールド専用ツールとして広く普及しています。 これらは内部的にテンプレートファイルをコピーし、必要な依存をインストールし、初期設定を自動で行うスクリプトです。

社内でも同じ仕組みを作れば、独自のベストプラクティスをコード化して配布できます。

以下の図で、Yarn dlx と create-* の関係を整理します。

mermaidflowchart LR
  user["開発者"] -->|"yarn dlx create-company-app"| dlx["Yarn dlx"]
  dlx -->|"一時インストール"| registry["npm or 社内レジストリ"]
  registry -->|"create-company-app 取得"| executor["実行スクリプト"]
  executor -->|"テンプレート展開"| template[("社内テンプレート")]
  template -->|"ファイルコピー"| newProject["新規プロジェクト"]
  executor -->|"yarn install"| newProject

この図のように、Yarn dlx がレジストリから create-* パッケージを取得し、テンプレートを展開して新規プロジェクトを生成します。 社内レジストリを使えば、外部に公開せずチーム内だけで利用可能です。

課題

社内テンプレート管理の課題

社内でテンプレートを運用しようとすると、以下のような課題が浮上します。

#課題影響
1テンプレートの配布方法が不明確Git clone や手動コピーに頼り、更新が追従しない
2バージョン管理が曖昧古いテンプレートが使われ続け、統一性が失われる
3npm に公開したくない社内専用のため、外部公開はセキュリティ・運用上のリスク
4カスタマイズ要件が多岐にわたるプロジェクトごとに微調整が必要で、テンプレート分岐が増える

これらを解決するには、社内限定のスキャフォールドツールを構築し、Yarn dlx で統一的に利用できる仕組みが必要です。

npm 公開 vs 社内レジストリ

npm に公開する場合、誰でもアクセス可能になりますが、社内のコーディング規約や秘匿情報を含むテンプレートには向きません。 一方、社内レジストリ(Verdaccio、GitHub Packages、npm Enterprise など)を使えば、アクセス制御しながら配布できます。

以下の図で、配布方法の選択肢を整理します。

mermaidflowchart TD
  start["テンプレート配布"] --> decision{"公開範囲"}
  decision -->|"全世界"| npm["npm 公開"]
  decision -->|"社内限定"| internal["社内レジストリ"]
  decision -->|"チーム限定"| git["Git リポジトリ + degit"]

  npm --> npmPros["メリット:<br/>- 手軽<br/>- メンテ不要"]
  npm --> npmCons["デメリット:<br/>- 機密情報リスク<br/>- 外部露出"]

  internal --> internalPros["メリット:<br/>- アクセス制御<br/>- バージョン管理"]
  internal --> internalCons["デメリット:<br/>- レジストリ運用コスト"]

  git --> gitPros["メリット:<br/>- 既存インフラ活用<br/>- 柔軟"]
  git --> gitCons["デメリット:<br/>- 認証・権限管理"]

社内レジストリを選ぶ場合、Verdaccio や GitHub Packages が低コストで導入しやすいでしょう。

解決策

社内スキャフォールドの全体設計

社内テンプレートを Yarn dlx で利用できるようにするには、以下の構成要素が必要です。

#要素役割
1create-* パッケージテンプレート展開とセットアップを実行するスクリプト
2テンプレートファイル群コピーするファイル(components、config、.env など)
3社内レジストリcreate-* パッケージをホスティング
4.yarnrc.yml 設定社内レジストリを参照するための設定

この構成により、yarn dlx create-company-app というコマンドだけで、統一されたプロジェクトが立ち上がります。

社内レジストリの選定と設定

社内レジストリには、以下の選択肢があります。

  • Verdaccio: 軽量で自前サーバーで動作、Docker で簡単にセットアップ可能
  • GitHub Packages: GitHub 組織アカウントで利用可能、CI/CD との統合が容易
  • npm Enterprise: 大規模組織向け、有料だが高機能

今回は Verdaccio を例に進めます。 Docker Compose で以下のように起動できます。

yamlversion: '3.8'
services:
  verdaccio:
    image: verdaccio/verdaccio:5
    ports:
      - '4873:4873'
    volumes:
      - ./verdaccio/storage:/verdaccio/storage
      - ./verdaccio/config:/verdaccio/conf

このファイルを docker-compose.yml として保存し、起動します。

bashdocker-compose up -d

Verdaccio が http:​/​​/​localhost:4873 で起動し、社内レジストリとして機能します。

次に、Yarn から社内レジストリを参照できるよう .yarnrc.yml を設定します。

yamlnpmRegistryServer: 'http://localhost:4873'

npmScopes:
  company:
    npmRegistryServer: 'http://localhost:4873'
    npmAlwaysAuth: true

この設定により、@company スコープのパッケージは社内レジストリから取得されます。 認証が必要な場合は、npmAlwaysAuth: true を追加し、別途 .npmrc や環境変数でトークンを設定しましょう。

create-* パッケージの作成

次に、スキャフォールド用の create-company-app パッケージを作成します。 このパッケージは、テンプレートをコピーし、依存をインストールする役割を担います。

ディレクトリ構成は以下のようにします。

csharpcreate-company-app/
├── bin/
│   └── cli.js         # エントリーポイント
├── templates/
│   └── default/       # デフォルトテンプレート
│       ├── package.json
│       ├── tsconfig.json
│       ├── .eslintrc.js
│       └── src/
├── package.json
└── README.md

この構成により、テンプレートファイルを整理し、CLI から呼び出せるようにします。

具体例

create-company-app の package.json

まず、create-company-app​/​package.json を作成します。

json{
  "name": "@company/create-company-app",
  "version": "1.0.0",
  "description": "社内プロジェクトテンプレート生成ツール",
  "bin": {
    "create-company-app": "./bin/cli.js"
  },
  "files": ["bin", "templates"],
  "dependencies": {
    "prompts": "^2.4.2",
    "fs-extra": "^11.1.0",
    "chalk": "^4.1.2"
  }
}

bin フィールドで CLI のエントリーポイントを指定します。 files フィールドで、パッケージに含めるファイルを限定しましょう。

次に、CLI スクリプト本体を作成します。

CLI スクリプトの実装(エントリーポイント)

bin​/​cli.js には、テンプレート展開のロジックを記述します。

javascript#!/usr/bin/env node

const fs = require('fs-extra');
const path = require('path');
const prompts = require('prompts');
const chalk = require('chalk');

このブロックでは、必要なライブラリをインポートしています。 #!​/​usr​/​bin​/​env node により、このファイルが Node.js スクリプトとして実行可能になります。

プロジェクト名の取得

続いて、ユーザーからプロジェクト名を取得します。

javascriptasync function main() {
  // コマンドライン引数からプロジェクト名を取得
  const args = process.argv.slice(2);
  let projectName = args[0];

  // 引数がない場合は対話的に取得
  if (!projectName) {
    const response = await prompts({
      type: 'text',
      name: 'projectName',
      message: 'プロジェクト名を入力してください',
      initial: 'my-company-app',
    });
    projectName = response.projectName;
  }

  if (!projectName) {
    console.log(
      chalk.red('プロジェクト名が指定されていません')
    );
    process.exit(1);
  }

  console.log(
    chalk.blue(
      `プロジェクト「${projectName}」を作成します...`
    )
  );
}

main().catch((err) => {
  console.error(chalk.red('エラーが発生しました:'), err);
  process.exit(1);
});

prompts ライブラリを使い、対話的にプロジェクト名を取得します。 引数で渡された場合はそのまま利用し、なければユーザーに入力を促すフローです。

テンプレートのコピー処理

次に、テンプレートファイルを新規プロジェクトディレクトリにコピーします。

javascriptasync function main() {
  // ... プロジェクト名取得部分(省略)

  const targetDir = path.join(process.cwd(), projectName);
  const templateDir = path.join(
    __dirname,
    '../templates/default'
  );

  // すでにディレクトリが存在する場合は確認
  if (fs.existsSync(targetDir)) {
    const response = await prompts({
      type: 'confirm',
      name: 'overwrite',
      message: `ディレクトリ「${projectName}」は既に存在します。上書きしますか?`,
      initial: false,
    });

    if (!response.overwrite) {
      console.log(chalk.yellow('処理を中断しました'));
      process.exit(0);
    }

    // 既存ディレクトリを削除
    await fs.remove(targetDir);
  }
}

このブロックでは、対象ディレクトリが既に存在する場合に上書き確認を行います。 ユーザーが拒否すれば処理を中断し、許可すれば既存ディレクトリを削除してから進めます。

ファイルのコピーと変数置換

テンプレートファイルをコピーし、プロジェクト名などの変数を置換します。

javascript// テンプレートをコピー
await fs.copy(templateDir, targetDir);
console.log(
  chalk.green('テンプレートファイルをコピーしました')
);

// package.json のプロジェクト名を置換
const pkgPath = path.join(targetDir, 'package.json');
const pkg = await fs.readJson(pkgPath);
pkg.name = projectName;
await fs.writeJson(pkgPath, pkg, { spaces: 2 });

console.log(chalk.green('package.json を更新しました'));

fs.copy でテンプレート全体をコピーし、その後 package.json のプロジェクト名を書き換えます。 他にも .env.exampleREADME.md など、必要に応じて置換処理を追加しましょう。

依存関係のインストール

最後に、Yarn を使って依存関係をインストールします。

javascript  const { execSync } = require('child_process');

  console.log(chalk.blue('依存関係をインストールしています...'));

  try {
    execSync('yarn install', {
      cwd: targetDir,
      stdio: 'inherit'
    });
    console.log(chalk.green('インストール完了!'));
  } catch (err) {
    console.log(chalk.yellow('yarn install に失敗しました。手動で実行してください。'));
  }

  console.log(chalk.green(`\n✨ プロジェクト「${projectName}」のセットアップが完了しました!`));
  console.log(chalk.blue(`\ncd ${projectName}`));
  console.log(chalk.blue('yarn dev\n'));
}

execSync を使い、新規ディレクトリ内で yarn install を実行します。 stdio: 'inherit' により、インストール進捗がそのままターミナルに表示されます。

テンプレートファイルの準備

templates​/​default​/​ ディレクトリに、実際のプロジェクトファイルを配置します。

luatemplates/
└── default/
    ├── package.json
    ├── tsconfig.json
    ├── .eslintrc.js
    ├── .prettierrc
    ├── next.config.js
    ├── .env.example
    └── src/
        ├── pages/
        │   └── index.tsx
        └── components/
            └── Layout.tsx

このディレクトリ構成が、新規プロジェクトのベースになります。 社内標準の設定をすべて含めておけば、プロジェクトごとの設定ミスを防げるでしょう。

社内レジストリへの発行

作成した create-company-app を社内レジストリに発行します。

bash# レジストリ URL を確認
yarn config get npmRegistryServer

# ログイン(Verdaccio の場合)
npm adduser --registry http://localhost:4873

# パッケージを発行
yarn publish --registry http://localhost:4873

発行後、他のメンバーは以下のコマンドでテンプレートを利用できます。

bashyarn dlx @company/create-company-app my-new-project

このコマンドを実行するだけで、統一されたプロジェクトが瞬時に立ち上がります。

実行フローの図解

実際の実行フローを図で整理します。

mermaidsequenceDiagram
  participant dev as 開発者
  participant dlx as yarn dlx
  participant registry as 社内レジストリ
  participant cli as create-company-app CLI
  participant fs as ファイルシステム

  dev->>dlx: yarn dlx @company/create-company-app my-app
  dlx->>registry: @company/create-company-app を取得
  registry-->>dlx: パッケージダウンロード
  dlx->>cli: bin/cli.js 実行
  cli->>dev: プロジェクト名確認(対話)
  dev-->>cli: 入力確定
  cli->>fs: templates/ をコピー
  fs-->>cli: コピー完了
  cli->>fs: package.json 書き換え
  cli->>dlx: yarn install 実行
  dlx->>fs: node_modules 構築
  fs-->>cli: インストール完了
  cli->>dev: セットアップ完了メッセージ

この図のように、Yarn dlx が社内レジストリから CLI を取得し、テンプレート展開とインストールを自動実行します。 開発者はコマンド一つで完結するため、学習コストも最小限です。

複数テンプレートの対応

プロジェクトの種類に応じて複数のテンプレートを用意したい場合、対話的に選択できるようにします。

javascriptconst response = await prompts({
  type: 'select',
  name: 'template',
  message: 'テンプレートを選択してください',
  choices: [
    { title: 'Next.js (TypeScript)', value: 'nextjs-ts' },
    { title: 'React (Vite)', value: 'react-vite' },
    { title: 'Express API', value: 'express-api' },
  ],
  initial: 0,
});

const templateDir = path.join(
  __dirname,
  `../templates/${response.template}`
);

このように、templates​/​ 配下に複数のテンプレートを配置し、ユーザーに選ばせる仕組みを追加できます。 チーム内で複数の技術スタックを扱う場合に有効でしょう。

CI/CD での利用

GitHub Actions などの CI/CD 環境でも、同じテンプレートを利用できます。

yamlname: Create New Project
on:
  workflow_dispatch:
    inputs:
      project_name:
        description: 'プロジェクト名'
        required: true

jobs:
  scaffold:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Enable Corepack
        run: corepack enable

      - name: Create project
        run: yarn dlx @company/create-company-app ${{ github.event.inputs.project_name }}
        env:
          YARN_NPM_REGISTRY_SERVER: http://your-registry:4873

      - name: Commit and push
        run: |
          git config user.name "Bot"
          git config user.email "bot@company.com"
          git add .
          git commit -m "chore: scaffold ${{ github.event.inputs.project_name }}"
          git push

このワークフローでは、手動トリガーでプロジェクトを生成し、自動でリポジトリにコミットします。 リモートワークやチーム分散時に、統一されたプロジェクトを迅速に展開できるでしょう。

まとめ

本記事では、Yarn の dlxcreate-* パッケージを活用した社内テンプレート管理の実践手法を解説しました。

以下のポイントを押さえれば、統一されたプロジェクトテンプレートをチーム全体で効率的に運用できます。

  • Yarn dlx を使い、グローバルインストール不要でスキャフォールドツールを実行
  • create-* パッケージ として社内専用の CLI を実装
  • 社内レジストリ(Verdaccio、GitHub Packages など)で配布し、アクセス制御
  • テンプレートファイル に社内標準の設定を集約し、バージョン管理
  • 複数テンプレート対応CI/CD 連携 で、多様なプロジェクト立ち上げに対応

この仕組みを導入すれば、新規プロジェクトの立ち上げ時間を大幅に短縮し、設定ミスや属人化を防げます。 また、テンプレート自体も Git で管理すれば、チーム全体でレビュー・改善を回せるでしょう。

社内のベストプラクティスをコード化し、誰でも簡単に最新の環境を再現できる状態を目指してみてください。

関連リンク