[Vite] CSSだけをビルドする方法

背景

Webpackのmini-css-extract-pluginのようにCSSファイルだけをViteで出力したい。

Vite をインストール

まずはVite周辺の環境を構築する。

npm i -D vite postcss postcss-preset-env

npm create vite@latest でも良いが、基本的にViteしか使わないので個別で入れる。PostCSSは任意。

package.jsonについては以下のような感じになる想定。

// package.json
{
  "name": "vite-build-css",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "build": "vite build"
  },
  "devDependencies": {
    "postcss": "^8.4.19",
    "postcss-preset-env": "^7.8.2",
    "vite": "^3.2.3"
  }
}

仕様

CSSをビルドするときの仕様は以下を想定。

  • CSSファイルは、srcディレクトリに配置
  • 出力ファイルは、distディレクトリに出力
    • ネスト階層も考慮
    • distはsrcのディレクトリ構造を維持する

vite.config.js

// vite.config.js
import fs from 'fs';
import path from 'path';

import { defineConfig } from 'vite';

const TARGET_DIRECTORY = 'src';

const readdirRecursively = (dir, files = []) => {
  const dirents = fs.readdirSync(dir, { withFileTypes: true });
  const dirs = [];

  for (const dirent of dirents) {
    if (dirent.isDirectory()) dirs.push(`${dir}/${dirent.name}`);
    if (dirent.isFile()) files.push(`${dir}/${dirent.name}`);
  }

  for (const d of dirs) {
    files = readdirRecursively(d, files);
  }

  return files;
};

const getInputFiles = (extension = '.css') => {
  const fileNames = readdirRecursively(TARGET_DIRECTORY).filter((file) => path.extname(file) === extension);
  const inputFiles = {};

  for (let i = 0; i < fileNames.length; i++) {
    const file = fileNames[i].replace(__dirname, '');
    const fileName = file.replace(extension, '').replace('..', '').replaceAll('/', '_');

    inputFiles[fileName] = `${file}`;
  }

  return inputFiles;
};

// https://vitejs.dev/config/
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        assetFileNames: ({ name }) => {
          return name.replace(`${TARGET_DIRECTORY}/`, '');
        },
      },
      input: getInputFiles(),
    },
  },
});

ViteがPostCSSをサポートしているので、PostCSSが必要な場合は入れておく。postcss.config.jsを追加しておけばよいので便利。

// postcss.config.js
module.exports = {
  plugin: {
    'postcss-preset-env': {
      stage: 3,
    },
  },
};