Skip to content

machour/vite-plugin-app-boundaries

Repository files navigation

vite-plugin-app-boundaries

Enforce strict architectural boundaries between application folders in Vite.

This plugin prevents one app (e.g. Front) from importing code from another app (e.g. Pro) at build time and dev time, not just via linting.

If a boundary is violated, Vite errors immediately.


Why this exists

Lint rules are easy to bypass. Aliases hide real paths. Large multi-front apps rot over time.

This plugin makes architecture non-negotiable by enforcing rules directly in Vite's module resolution graph.


Features

  • ✅ Enforce boundaries between any number of apps
  • ✅ Errors in dev AND build
  • ✅ Alias-aware (uses Vite's resolver)
  • ✅ Configurable allowlists
  • ✅ Zero runtime cost
  • ✅ Works with Vite 5 / 6 / 7

Example use case

resources/js/Apps/
├── Front/
├── Pro/
└── Shared/

Rules:

  • Front cannot import from Pro
  • Pro cannot import from Front
  • ✅ Both can import from Shared

Installation

npm install -D vite-plugin-app-boundaries

or

pnpm add -D vite-plugin-app-boundaries

Basic usage

vite.config.ts

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { enforceAppBoundaries } from "vite-plugin-app-boundaries";

export default defineConfig({
  plugins: [
    enforceAppBoundaries({
      root: "resources/js/Apps",

      apps: {
        Front: {
          path: "Front",
          allowImportsFrom: ["Shared"],
        },

        Pro: {
          path: "Pro",
          allowImportsFrom: ["Shared"],
        },

        Shared: {
          path: "Shared",
        },
      },
    }),

    react(),
  ],
});

What happens on violation

// Apps/Front/pages/welcome.tsx
import Editor from "@/Apps/Pro/components/editorjs";

⬇️

🚫 App boundary violation

Importer:
.../Apps/Front/pages/welcome.tsx
(app: Front)

Imported:
.../Apps/Pro/components/editorjs.tsx
(app: Pro)

Allowed imports for Front:
Shared

Vite stops immediately.


Configuration reference

root

Root directory that contains all apps.

root: "resources/js/Apps"

apps

Each app has:

  • path: folder name under root
  • allowImportsFrom: optional list of app names it may import from
apps: {
  Front: {
    path: "Front",
    allowImportsFrom: ["Shared"],
  },

  Admin: {
    path: "Admin",
    allowImportsFrom: ["Shared", "Pro"],
  },
}

debug (optional)

Enable verbose logging to see exactly how Vite resolves imports.

enforceAppBoundaries({
  debug: true,
  ...
});

Useful when diagnosing aliases or unexpected resolution.


ESLint mirror rules (recommended)

This plugin enforces boundaries at build time.
For editor errors, mirror the rules using ESLint.

Install

npm install -D eslint-plugin-boundaries

Example .eslintrc.cjs

module.exports = {
  plugins: ["boundaries"],

  settings: {
    "boundaries/include": ["resources/js/**/*"],

    "boundaries/elements": [
      { type: "front", pattern: "resources/js/Apps/Front/**" },
      { type: "pro", pattern: "resources/js/Apps/Pro/**" },
      { type: "shared", pattern: "resources/js/Apps/Shared/**" },
    ],
  },

  rules: {
    "boundaries/element-types": [
      "error",
      {
        default: "disallow",
        rules: [
          { from: "front", allow: ["shared"] },
          { from: "pro", allow: ["shared"] },
          { from: "shared", allow: ["shared"] },
        ],
      },
    ],
  },
};

What this plugin does NOT do

  • ❌ It does not replace ESLint
  • ❌ It does not rewrite imports
  • ❌ It does not enforce runtime isolation

Recommended setup:

  • This plugin → build-time enforcement
  • ESLint boundaries rules → editor feedback

License

MIT

About

Enforce architectural boundaries between app folders in Vite

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published