---
# System prepended metadata

title: Vite plugin tricks
tags: [web-tech, draft]

---

# Vite plugin tricks

* [**`resolveConfig`**](https://github.com/brillout/vite-plugin-ssr/blob/v0.4.131/vite-plugin-ssr/node/plugin/plugins/config/index.ts): In `configResolved` with `enforce: 'pre'`, add a promise to resolve config object with the plugin's own config. This allows queueing some async operations AFTER resolving the config. In any later `configResolved` stage, use `await` on that async func. to get and memoize the "grand final" config object
* [**buildConfig.ts**](https://github.com/brillout/vite-plugin-ssr/blob/v0.4.131/vite-plugin-ssr/node/plugin/plugins/buildConfig.ts): Normalize `rollupOptions.input` from `string | string []| { [entryName: string]: string }` to Object
  [**distFileNames.ts**](https://github.com/brillout/vite-plugin-ssr/blob/v0.4.131/vite-plugin-ssr/node/plugin/plugins/distFileNames.ts): Similar, but wrap single-element `output` to array
  ... for further tweaking; addition options can be attached with an Array.map
* [**packageJsonFile.ts**](https://github.com/brillout/vite-plugin-ssr/blob/v0.4.131/vite-plugin-ssr/node/plugin/plugins/packageJsonFile.ts): Add a `package.json` to out dir so that ESM can be correctly detected
* To discrimate between `build` and `dev`, let a variable `isDev = false` and set it to `true` in `configureServer` stage (only when a dev server is spinned up). It must be used in a later stage like `transform`.
  Seen in **extractExportNamesPlugin.ts**.
  > In `devConfig/index.ts` it is mentioned that ++"There doesn't seem to be a straightforward way to discriminate between `$ vite preview` and `$ vite dev`."++ The value of the `command` argument is "serve" in both cases.


# HTML transformations

> @ v4.4.7

**Hooks**: Default hooks are (where ... are collected through plugins in the resolved config):

1. Pre: `preImportMapHook` -> ... -> `htmlEnvHook`
2. Post: ... -> `postImportMapHook`

Hooks can be specified with `order` property being one of {pre/normal/post} to workaround that `enforce` property does not support the value "normal".

Import maps are `<script type="importmap">`.
HTML env is replacement of `%VITE_PREFIXED_ENV%`.

**[[html-proxy]]**: a reflection for adding/extracting some strings associated with the document, URL (matched against a regex!) being one form of
* #0 `foo.html?html-proxy&index=<index>.js`
* #1 `foo.html?html-proxy&inline-css&style-attr&index=<index>.css`
* #2 `foo.html?html-proxy&inline-css&index=<index>.css`

At the function `buildHtmlPlugin`, the working is tentatively described as following sections:

### To transform HTML 

* Pre-transform: apply pre hooks
* Traverse over HTML AST generated through `parse5`, handling the cases:
  * **A script tag**:
    * public file: prefix public path, leave it as-is
    * module: add the JS to entry point as an import statement
      if external, extract the src
      if inline, reference through [[html-proxy]] form #0
	  --> merge all modules to an equivalent single entry
    * (not module && external && not public file): bail out (Vite only accepts ES modules)
    * (not module && inline): collect inline import URLs through regex (*), stored as `scriptUrls`
      > regex? seriously? 
  * A tag that **has attrs that are meant to be URLs** (img src, link href, ...): These are the *only* "assets", besides JS, the HTML directly depends on. Others are indirectly through CSS.
    * For CSS, specifically `<link rel="stylesheet" src="...">`: Rewrite (eagerly) to JS import, stored in `styleUrls`.
    > Ineffective link tags are ignored (with attr `media` or `disabled`).
    > Original tag is not deleted. Which way to load it is determined later in (**-1).
    * For others, store them as `assetUrls` and rewrite that URL to public path *later* (**-2).
  * A tag **with "style" attr and inline style contains URL**: `url()` and `image-set()`: virtualize through [[html-proxy]] form #1, and add back a class.
    > Q: changes (demotes) specificity?
  * A **non-empty `<style>` tag**: Apply [[html-proxy]] form #2.
* Rewrite assets in (**-2) to built URLs if it is not empty and NOT referencing named output passed to rollup.
  > This is complicated to explain here. See code!
* Rewrite script URLs (*) to built URLs or public path.
* Try to resolve stylesheet URLs in (**-1).
success: Remove corresponding `<link>`
failure: Undo; Remove the import statement already inserted.
* Prepend module preload polyfill if the `build.modulePreload.polyfill` is set and there are async/deferred script tags.

### To generate a bundle:

* Get base of HTML. 
* "inject chunk asset links". (***)
An ES module can be inlined if it contains solely imports
* "inject css link when cssCodeSplit is false".
* Transform CSS stored through [[html-proxy]] of form #2.
* Apply normal and post hooks.
* "Resolve asset[/public] url references".
* Emit the HTML
* Remove all modules collected in (***) from bundle.

## Vite undocumented config:

`ssrEmitAssets: true`
https://github.com/vitejs/vite/blob/v4.3.9/packages/vite/src/node/build.ts#L228
