cola

cola

Enjoy Coding Everywhere 👻

手取り足取り Vite エンジニアリングテンプレートを構築する

基本テンプレートの作成#

グローバルインストールスクリプトの作成#

yarn global add create-vite

プロジェクトの初期化#

vite-create <product-name>

git の追加#

git init

コードフォーマットの検証を追加#

ESLint の追加#

パッケージのインストール#

npm i eslint eslint-plugin-vue @vue/eslint-config-prettier @vue/eslint-config-typescript -D

eslint の設定#

.eslintrc

{
  "root": true,
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "extends": [
    "plugin:vue/vue3-recommended",
    "eslint:recommended",
    "@vue/typescript/recommended",
    "@vue/prettier"
  ],
  "plugins": ["vue"],
  "settings": {
    "import/resolver": {
      "node": { "extensions": [".js", ".mjs", ".ts", ".d.ts", ".tsx"] }
    }
  },
  "overrides": [
    {
      "files": ["*.json", "*.json5", "*.jsonc"],
      "parser": "jsonc-eslint-parser"
    },
    {
      "files": ["*.ts", "*.vue"],
      "rules": {
        "no-undef": "off"
      }
    },
    {
      "files": ["**/__tests__/**"],
      "rules": {
        "no-console": "off",
        "vue/one-component-per-file": "off"
      }
    },
    {
      "files": ["*.d.ts"],
      "rules": {
        "import/no-duplicates": "off"
      }
    },
    {
      "files": ["*.js"],
      "rules": {
        "@typescript-eslint/no-var-requires": "off"
      }
    },
    {
      "files": ["*.vue"],
      "parser": "vue-eslint-parser",
      "parserOptions": {
        "parser": "@typescript-eslint/parser",
        "extraFileExtensions": [".vue"],
        "ecmaVersion": "latest",
        "ecmaFeatures": {
          "jsx": true
        }
      },
      "rules": {
        "no-undef": "off"
      }
    }
  ],
  "rules": {
    "no-console": ["warn", { "allow": ["error"] }],
    "no-debugger": "warn"
  }
}

Prettier のインストール#

パッケージのインストール#

npm i prettier -D
正常であれば、prettier はこれだけでインストールできますが、[email protected]@vue/eslint-config-prettiereslint-plugin-prettier と互換性がないため、低バージョンの eslint-plugin-prettier をインストールする必要があります:npm i [email protected] -D

prettier のバージョンを下げることもできますが、推奨はしません。stylelint をインストールする際に、stylelint-prettier に影響を与える可能性があります。もちろん、低バージョンの stylelint-prettier をインストールすることもできますが、prettier とのフォーマットの衝突問題が発生します。この場合、stylelint-config-prettier を導入して解決しようとするかもしれませんが、それは stylelint のバージョンが 15.0.0 未満であることを要求します。そのため、stylelint のバージョンを下げる必要があり、依存関係の互換性の問題が徐々に発生します。

prettier の設定#

.prettierrc

{
  "singleQuote": true,
  "semi": false,
  "vueIndentScriptAndStyle": true
}

StyleLint の追加#

パッケージのインストール#

npm i stylelint stylelint-config-standard stylelint-config-standard-scss stylelint-config-standard-vue stylelint-order stylelint-prettier -D

stylelint の設定#

.stylelintrc

{
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-standard-scss",
    "stylelint-config-standard-vue/scss",
    "stylelint-prettier/recommended"
  ],
  "plugins": ["stylelint-order"],
  "customSyntax": "postcss-scss",
  "rules": {
    "order/order": ["custom-properties", "declarations"],
    "order/properties-order": [
      "position",
      "top",
      "right",
      "bottom",
      "left",
      "z-index",
      "display",
      "justify-content",
      "align-items",
      "float",
      "clear",
      "overflow",
      "overflow-x",
      "overflow-y",
      "margin",
      "margin-top",
      "margin-right",
      "margin-bottom",
      "margin-left",
      "border",
      "border-style",
      "border-width",
      "border-color",
      "border-top",
      "border-top-style",
      "border-top-width",
      "border-top-color",
      "border-right",
      "border-right-style",
      "border-right-width",
      "border-right-color",
      "border-bottom",
      "border-bottom-style",
      "border-bottom-width",
      "border-bottom-color",
      "border-left",
      "border-left-style",
      "border-left-width",
      "border-left-color",
      "border-radius",
      "padding",
      "padding-top",
      "padding-right",
      "padding-bottom",
      "padding-left",
      "width",
      "min-width",
      "max-width",
      "height",
      "min-height",
      "max-height",
      "font-size",
      "font-family",
      "font-weight",
      "text-align",
      "text-justify",
      "text-indent",
      "text-overflow",
      "text-decoration",
      "white-space",
      "color",
      "background",
      "background-position",
      "background-repeat",
      "background-size",
      "background-color",
      "background-clip",
      "opacity",
      "filter",
      "list-style",
      "outline",
      "visibility",
      "box-shadow",
      "text-shadow",
      "resize",
      "transition"
    ]
  },
  "ignoreFiles": ["node_modules/**", "dist/**", "build/**", ".git/**", "*.js"],
  "overrides": [
    {
      "files": ["*.(html|vue)", "**/*.(html|vue)"],
      "rules": {
        "unit-allowed-list": ["em", "rem", "px", "%", "s", "vw", "vh", "ms"]
      },
      "customSyntax": "postcss-html"
    }
  ]
}

VSCode の設定#

プラグインのインストール#

プロジェクトの設定が完了した後、ターミナルコマンドを使用してフォーマット操作を実行できるようになりますが、IDE のフォーマット操作には対応するプラグインをインストールする必要があります。VSCode では、ESlintPrettierStyleLintプラグインをインストールする必要があります。

プロジェクトの設定#

.vscode/settings.json

{
  "css.validate": true,
  "scss.validate": false,
  "less.validate": false,
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll": true,
    "source.fixAll.eslint": true
  },
  "eslint.probe": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact",
    "vue",
    "json",
    "jsonc"
  ],
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact",
    "vue",
    "json",
    "jsonc"
  ],
  "eslint.quiet": true, // 警告メッセージを表示しない
  "stylelint.validate": ["css", "less", "postcss", "scss", "sass", "vue"],
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[css]": {
    "editor.defaultFormatter": "stylelint.vscode-stylelint"
  },
  "[less]": {
    "editor.defaultFormatter": "stylelint.vscode-stylelint"
  },
  "[scss]": {
    "editor.defaultFormatter": "stylelint.vscode-stylelint"
  },
  "[sass]": {
    "editor.defaultFormatter": "stylelint.vscode-stylelint"
  }
}

editorconfig の追加#

異なるオペレーティングシステムでのエディタのフォーマットを一致させるために、一般的に EditorConfig for VS Code プラグインを追加します。

設定#

.editorconfig

# http://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

コミット検証#

パッケージのインストール#

npm i commitizen @commitlint/cli @commitlint/config-conventional @commitlint/cz-commitlint -D

コミットの設定#

.commitlintrc.json

{
  "extends": ["@commitlint/config-conventional"],
  "rules": {
    "type-empty": [2, "never"],
    "scope-enum": [2, "always", ["core", "style", "docs"]]
  },
  "prompt": {
    "settings": {
      "enableMultipleScopes": true,
      "scopeEnumSeparator": ","
    },
    "messages": {
      "skip": ":skip",
      "max": "upper %d chars",
      "min": "%d chars at least",
      "emptyWarning": "can not be empty",
      "upperLimitWarning": "over limit",
      "lowerLimitWarning": "below limit"
    },
    "questions": {
      "type": {
        "description": "Select the type of change that you're committing:",
        "enum": {
          "feat": {
            "description": "A new feature",
            "title": "Features",
            "emoji": "✨"
          },
          "fix": {
            "description": "A bug fix",
            "title": "Bug Fixes",
            "emoji": "🐛"
          },
          "docs": {
            "description": "Documentation only changes",
            "title": "Documentation",
            "emoji": "📚"
          },
          "style": {
            "description": "Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)",
            "title": "Styles",
            "emoji": "💎"
          },
          "refactor": {
            "description": "A code change that neither fixes a bug nor adds a feature",
            "title": "Code Refactoring",
            "emoji": "📦"
          },
          "perf": {
            "description": "A code change that improves performance",
            "title": "Performance Improvements",
            "emoji": "🚀"
          },
          "test": {
            "description": "Adding missing tests or correcting existing tests",
            "title": "Tests",
            "emoji": "🚨"
          },
          "build": {
            "description": "Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)",
            "title": "Builds",
            "emoji": "🛠"
          },
          "ci": {
            "description": "Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)",
            "title": "Continuous Integrations",
            "emoji": "⚙️"
          },
          "chore": {
            "description": "Other changes that don't modify src or test files",
            "title": "Chores",
            "emoji": "♻️"
          },
          "revert": {
            "description": "Reverts a previous commit",
            "title": "Reverts",
            "emoji": "🗑"
          }
        }
      },
      "scope": {
        "description": "scope"
      },
      "subject": {
        "description": "Write a short, imperative tense description of the change"
      },
      "body": {
        "description": "Provide a longer description of the change"
      },
      "isBreaking": {
        "description": "Are there any breaking changes?"
      },
      "breakingBody": {
        "description": "A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself"
      },
      "breaking": {
        "description": "Describe the breaking changes"
      },
      "isIssueAffected": {
        "description": "Does this change affect any open issues?"
      },
      "issuesBody": {
        "description": "If issues are closed, the commit requires a body. Please enter a longer description of the commit itself"
      },
      "issues": {
        "description": "Add issue references (e.g. \"fix #123\", \"re #123\".)"
      }
    }
  }
}

package.json に以下の設定を追加:

"config": {
  "commitizen": {
    "path": "@commitlint/cz-commitlint"
  }
}

scripts にコマンド "commit": "git-cz" を追加

プロセスの自動化#

パッケージのインストール#

npm i husky lint-staged -D

コマンドの追加#

package.jsonscripts に以下のコマンドを追加:

"prepare": "husky install",
"lint": "eslint --ext .ts,vue,tsx --ignore-path .gitignore .",
"style": "stylelint src/**/*.{css,scss,vue}",
"tslint": "vue-tsc --noEmit"

husky を使用して git hook を追加:

# commit 前にコードフォーマットを実行
npx husky add .husky/pre-commit "npx lint-staged"
# commit msg の検証
npx husky add .husky/commit-msg "npx commitlint --edit $1"
# commit 後、自動でリモートブランチにプッシュ
npx husky add .husky/post-commit "branch=$(git symbolic-ref --short -q HEAD)
git pull origin $branch
if [ "$?" == "0" ]; then
    git push origin $branch
    if [ "$?" == "0" ]; then
        echo "✨✨✨ プッシュ成功!"
    else
        echo 'プッシュに失敗しました!'
        exit 1
    fi
else
    echo 'コードのプルに失敗しました!'
    exit 1
fi"

TypeScript の設定#

パッケージのインストール#

npm i typescript vue-tsc -D

typescript の設定#

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "paths": {
      "@/*": ["src/*"]
    },
    "types": [
      "unplugin-vue-define-options",
      "vitest/importMeta",
      "unplugin-icons/types/vue",
      "element-plus/global"
    ],

    /* Bundler mode */
    "moduleResolution": "node",
    "allowImportingTsExtensions": true,
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": [
    "auto-imports.d.ts",
    "components.d.ts",
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue"
  ],
  "references": [{ "path": "./tsconfig.node.json" }]
}

tsconfig.node.json

{
  "compilerOptions": {
    "composite": true,
    "skipLibCheck": true,
    "module": "ESNext",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true
  },
  "include": ["vite.config.ts"]
}

types/env.d.ts

/// <reference types="vite/client" />
import Http from '@/utils/Http'
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
  const component: DefineComponent<{}, {}, any>
  export default component
}

declare module '@vue/runtime-core' {
  export interface ComponentCustomProperties {
    $http: typeof Http
  }
}

コンポーネント、API、アイコンの自動インポートを追加#

パッケージのインストール#

npm i unplugin-auto-import unplugin-vue-components unplugin-icons unplugin-vue-define-options -D

設定#

vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import DefineOptions from 'unplugin-vue-define-options/vite'
import Unocss from 'unocss/vite'
import Inspect from 'vite-plugin-inspect'
import VueJsx from '@vitejs/plugin-vue-jsx'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'

// https://vitejs.dev/config/
export default defineConfig({
  assetsInclude: ['**/*.JPG'],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
    },
    extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use '@/style/variables.scss' as *;`,
      },
    },
  },
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true,
      },
    },
  },
  plugins: [
    vue(),
    VueJsx(),
    DefineOptions(),
    Components({
      dirs: ['src/components', 'main.ts'],
      extensions: ['vue'],
      deep: true,
      dts: true,
      resolvers: [
        ElementPlusResolver(),
        IconsResolver({
          alias: {
            park: 'icon-park',
          },
          customCollections: ['custom'],
        }),
      ],
    }),
    AutoImport({
      resolvers: [ElementPlusResolver()],
      imports: ['vue', 'vue-router', '@vueuse/core', 'pinia', 'vitest'],
      include: [/\.[tj]sx?$/, /\.vue$/, /\.vue\?vue/, /\.md$/],
      dirs: ['./src/composables'],
      eslintrc: {
        enabled: true,
        globalsPropValue: true,
      },
    }),
    Unocss(),
    Icons({
      autoInstall: true,
      compiler: 'vue3',
      customCollections: {
        custom: FileSystemIconLoader('./src/icon/svg', (svg) =>
          svg
            .replace(/(width|height)=['"](\w+)['"]/g, '')
            .replace(/^<svg /, '<svg fill="currentColor"'),
        ),
      },
      iconCustomizer(collection, icon, props) {
        props.width = '1.2em'
        props.height = '1.2em'
      },
    }),
    Inspect(),
  ]
})

テストの追加#

パッケージのインストール#

npm i vitest @vitest/ui @vitest/coverage-c8 jsdom -D
VSCode に Vitest プラグインを追加

設定#

コマンドの追加#
"test": "vitest dev",
"ui": "vitest --ui",
"coverage": "vitest run --coverage"
vitest の設定#

vitest.config.ts

import { defineConfig, mergeConfig } from 'vitest/config'
import viteConfig from './vite.config'
export default mergeConfig(
  viteConfig,
  defineConfig({
    define: {
      'import.meta.vitest': 'undefined',
    },
    test: {
      globals: true,
      clearMocks: true,
      environment: 'jsdom',
      setupFiles: ['./vitest.setup.ts'],
      transformMode: {
        web: [/\.[jt]sx$/],
      },
      includeSource: ['src/**/*.{js,ts}'],
      coverage: {
        provider: 'c8',
        reporter: ['text', 'json', 'html'],
      },
    },
  }),
)

vitest.setup.ts

import { config } from '@vue/test-utils'

config.global.stubs = {}

完全なコード#

上記の設定プロセスを経て、エンジニアリングモジュールが構築されました。完全なコードは template-vite で確認できます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。