vite-split-config
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published
logo

vite-split-config

Split monolithic config file into dedicated chunks.

Motivation

Config files tend to grow.

Eventually there appears more and more specialized settings, more plugin imports and options for them, more local helpers and variables used once somewhere 300 lines below, more comments, and so on.

Left like that, config turns into leviathan, taking forever to figure it out and update something. Especially when the issue you want to address requires updating multiple config sections.

It's not hard at all to split config apart and merge that chunks. But anyway it's some extra complexity to care about – which nobody likes to bring.

This solution takes away that low-level logic from your sources.

Table of Contents

Installation

npm install -D vite-split-config
yarn add -D vite-split-config

Usage

Define chunks dedicated to certain configuration aspects:

// my-chunk.ts
import { defineChunk } from 'vite-split-config'
import checker from 'vite-plugin-checker'

export const useLint = defineChunk({
  plugins: [
    checker({
      typescript: true,
      eslint: { 
        lintCommand: '...' 
      },
      stylelint: { 
        lintCommand: '...' 
      },
    })
  ]
})
// my-other-chunk.ts
import { defineChunk } from 'vite-split-config'
import criticalCSS from 'rollup-plugin-critical'
import customSelectors from 'postcss-custom-selectors'

export const useStyles = defineChunk({
  css: {
    devSourcemap: true,
    postcss: {
      plugins: [
        customSelectors({
          /*...*/
        }),
      ]
    }
  },
  plugins: [
    criticalCSS({
      /*...*/
    }),
  ]
})

Then combine them together, and provide a basic config:

// vite.config.ts
import { useChunks } from 'vite-split-config'

import { useLint } from './my-chunk'
import { useStyles } from './my-other-chunk'

const defineConfig = useChunks([ useLint, useStyles ])

export default defineConfig({
  resolve: {
    alias: {/*...*/}
  },
  base: '/',
  /* other basic settings */
})

Chunks will be merged recursively, in order you specified in useChunks, starting with the basic config.

API

type ViteConfig = Vite.UserConfig | Promise<Vite.UserConfig>

type ExtendConfig<R> = (base: Vite.UserConfig, cfg: { env: NodeJS.ProcessEnv, vite: Vite.ConfigEnv }) => R

type Chunk = ExtendConfig<Promise<Vite.UserConfig>>

defineChunk

function defineChunk(config: ViteConfig): Chunk

function defineChunk(config: ExtendConfig<ViteConfig>): Chunk

function defineChunk(config: ExtendConfig<void | Promise<void>>): Chunk

// basic usage:
defineChunk({ /* Vite.UserConfig options here */ })

// async usage:
import { UserConfig } from 'vite'
import detectPort from 'detect-port'
defineChunk(new Promise<UserConfig>((resolve, reject) => {
    detectPort(3000, (err, freePort) => {
        if (err) reject(err)
        else resolve({
          server: { port: freePort },
        })
    })
}))

// depending on base config (can also return a promise):
defineChunk(base => ({
    define: { __APP_TYPE__: JSON.stringify(base.appType) }
}))

// depending on Vite env or process.env:
defineChunk((base, { env, vite }) => ({
    logLevel: vite.mode === 'test' ? 'silent' : 'info',
    appType: env.APP_TYPE,
}))

// imperative update:
defineChunk(base => {
    base.plugins.push(myPlugin())
    // don't need to return value explicitly
})

useChunks

function useChunks(chunks: Chunk[]): (base: Vite.UserConfigExport) => Vite.UserConfigFn

// vite.config.ts
const defineConfig = useChunks([ chunk1, chunk2, /* ... */ ])
export default defineConfig({ /* basic config */ })

Return value of useChunks is basically equivalent to vite.defineConfig function, so you may use it as drop-in replacement, with all the same features – defining conditional or async basic config.

The only difference is that it always returns a function – so that Vite will feed it with its env params, which then will be passed to every chunk.

mergeConfig

Re-export of Vite's mergeConfig helper.

Hints

merging strategy

Configs are merged with Vite's mergeConfig helper.

It has one specific feature: if one of merged values is an array, then other value is added to that array. Like this:

mergeConfig({ a: [1] }, { a: 2 }) // => { a: [1, 2] }

Thus, you can't declaratively override a value in this case. But, the purpose of this tool is extension, not overriding. If some of your chunks are trying to specify different value for the same option, you're probably doing something wrong.

However, if you absolutely need to do override, you may use chunk callback definition and imperatively mutate parent config. See example in defineChunk section.

importing chunk modules

When importing local modules into vite.config, you may face complaints from your editor: Screenshot 2023-02-24 at 22 45 17 It doesn't affect build in any way, but is annoying to see.

How to fix it is explained in warning itself: just include your files in tsconfig.node.json.

LICENSE

MIT

Package Sidebar

Install

npm i vite-split-config

Weekly Downloads

0

Version

1.0.0

License

MIT

Unpacked Size

9.82 kB

Total Files

5

Last publish

Collaborators

  • jeron-diovis