# core/plugins/site.plugin.ts

> 96 lines of code and 15 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-plugins-site-plugin-ts
Source text: https://banes-lab.com/source/build-scripts/core/plugins/site.plugin.ts.txt

Listed in [core/plugins](https://banes-lab.com/api/source/build-scripts/core/plugins.md), after [core/plugins/server.plugin.ts](https://banes-lab.com/source/build-scripts/core/plugins/server.plugin.ts.md).

## Definitions

- `current` (lexical_declaration, line 76, exported)
- `phase` (lexical_declaration, line 38, exported)
- `write` (lexical_declaration, line 26)
- `initialState` (lexical_declaration, line 16)
- `relink` (lexical_declaration, line 68, exported)
- `configureServer` (method_definition, line 65, exported)
- `handler` (method_definition, line 54, exported)
- `configResolved` (method_definition, line 61, exported)
- `discovery` (lexical_declaration, line 80, exported)
- `BUILD_COMMAND` (lexical_declaration, line 14)
- `Held` (interface_declaration, line 30)
- `sitePlugin` (lexical_declaration, line 36, exported)
- `held` (lexical_declaration, line 37, exported)
- `state` (lexical_declaration, line 66, exported)
- `catalog` (lexical_declaration, line 67, exported)

## Contained in

- [core/plugins](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-plugins.md)

## Uses

- [core/converters/site.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/site.converter.ts.md)
- [core/coordinators/catalog.coordinator.ts](https://banes-lab.com/source/build-scripts/core/coordinators/catalog.coordinator.ts.md)
- [core/coordinators/ontology.coordinator.ts](https://banes-lab.com/source/build-scripts/core/coordinators/ontology.coordinator.ts.md)
- [core/coordinators/payload.coordinator.ts](https://banes-lab.com/source/build-scripts/core/coordinators/payload.coordinator.ts.md)
- [core/loaders/site.loader.ts](https://banes-lab.com/source/build-scripts/core/loaders/site.loader.ts.md)
- [core/pipelines/site.pipeline.ts](https://banes-lab.com/source/build-scripts/core/pipelines/site.pipeline.ts.md)

## Used by

- [core/adapters/document.adapter.ts](https://banes-lab.com/source/build-scripts/core/adapters/document.adapter.ts.md)
- [core/pipelines/site.pipeline.ts](https://banes-lab.com/source/build-scripts/core/pipelines/site.pipeline.ts.md)

## Linked from

- [core/adapters](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-adapters.md)
- [core/converters](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-converters.md)
- [core/coordinators](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-coordinators.md)
- [core/loaders](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-loaders.md)
- [core/pipelines](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-pipelines.md)
- [core/plugins](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-plugins.md)

## Source

```typescript
import type { Discovery, SitePhase, SiteState, SiteStep } from "#types/site.types";
import type { Plugin, ResolvedConfig } from "vite";
import { catalogMiddleware, payloadMiddleware } from "#core/coordinators/payload.coordinator";
import { discoverSteps, runPhase } from "#core/pipelines/site.pipeline";
import type { DevState } from "#types/page.types";
import type { DiagramWalk } from "#types/diagram.types";
import { buildCatalog } from "#core/coordinators/catalog.coordinator";
import { composeOntology } from "#core/coordinators/ontology.coordinator";
import { createRelinker } from "#core/coordinators/link.coordinator";
import { discover } from "#core/converters/site.converter";
import { loadFrom } from "#core/loaders/site.loader";
import process from "node:process";

const BUILD_COMMAND = "build";

const initialState = function initialState(config: ResolvedConfig, diagrams: DiagramWalk): SiteState {
    return {
        diagrams,
        mode: config.command === BUILD_COMMAND ? "build" : "serve",
        ontology: null,
        outDir: config.build.outDir,
        root: config.root,
    };
};

const write = function write(line: string): void {
    process.stdout.write(line);
};

interface Held {
    config: ResolvedConfig | null;
    state: SiteState | null;
    steps: readonly SiteStep[];
}

export const sitePlugin = function sitePlugin(diagrams: DiagramWalk): Plugin {
    const held: Held = { config: null, state: null, steps: [] };
    const phase = async function phase(name: SitePhase, state: SiteState): Promise<void> {
        await runPhase(held.steps, name, state, write).then((next) => {
            held.state = next;
        });
    };
    return {
        buildStart: {
            async handler() {
                if (held.config !== null) {
                    await phase("start", initialState(held.config, diagrams));
                }
            },
            order: "pre",
            sequential: true,
        },
        closeBundle: {
            async handler() {
                if (held.state !== null) {
                    await phase("close", held.state);
                }
            },
            sequential: true,
        },
        async configResolved(config) {
            held.config = config;
            held.steps = await discoverSteps();
        },
        configureServer(server) {
            let state: Promise<DevState> | null = null;
            let catalog: Promise<ReadonlyMap<string, string>> | null = null;
            const relink = createRelinker(server.config.root, (error) => {
                server.config.logger.error(String(error));
            });
            server.watcher.on("change", (file) => {
                state = null;
                catalog = null;
                relink(file);
            });
            const current = async (): Promise<DevState> => {
                state ??= loadFrom(server).then(async (loaded) => ({ discovery: await discover(loaded), loaded }));
                return state;
            };
            const discovery = async (): Promise<Discovery> => (await current()).discovery;
            server.middlewares.use(
                catalogMiddleware(discovery, async () => {
                    catalog ??= current().then(
                        async (loaded) =>
                            (
                                await buildCatalog(
                                    loaded.loaded.runner,
                                    loaded.discovery,
                                    loaded.loaded.exportSections,
                                    composeOntology(),
                                )
                            ).files,
                    );
                    return catalog;
                }),
            );
            server.middlewares.use(payloadMiddleware(discovery));
        },
        name: "site",
    };
};
```
