Full Code of vbenjs/vite-plugin-html for AI

main 4a32df2b416b cached
60 files
56.1 KB
17.5k tokens
26 symbols
1 requests
Download .txt
Repository: vbenjs/vite-plugin-html
Branch: main
Commit: 4a32df2b416b
Files: 60
Total size: 56.1 KB

Directory structure:
gitextract_p7e8ovn3/

├── .commitlintrc.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github/
│   └── workflows/
│       ├── publish.yml
│       ├── release.yml
│       └── test.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   ├── common.sh
│   └── pre-commit
├── .npmrc
├── .prettierrc.json
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh_CN.md
├── package.json
├── packages/
│   ├── core/
│   │   ├── build.config.ts
│   │   ├── package.json
│   │   └── src/
│   │       ├── __tests__/
│   │       │   ├── html.spec.ts
│   │       │   ├── minify.spec.ts
│   │       │   └── utils.spec.ts
│   │       ├── htmlPlugin.ts
│   │       ├── index.ts
│   │       ├── minifyHtml.ts
│   │       ├── typing.ts
│   │       └── utils/
│   │           ├── createHtmlFilter.ts
│   │           └── index.ts
│   └── playground/
│       ├── basic/
│       │   ├── basic.html
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── public/
│       │   │   └── inject.js
│       │   ├── server.js
│       │   ├── src/
│       │   │   ├── App.vue
│       │   │   ├── main.ts
│       │   │   └── test.vue
│       │   └── vite.config.ts
│       ├── custom-entry/
│       │   ├── package.json
│       │   ├── public/
│       │   │   └── inject.js
│       │   ├── src/
│       │   │   ├── App.vue
│       │   │   ├── main.ts
│       │   │   └── test.vue
│       │   ├── static/
│       │   │   └── index.html
│       │   └── vite.config.ts
│       └── mpa/
│           ├── index.html
│           ├── other.html
│           ├── package.json
│           ├── public/
│           │   └── inject.js
│           ├── src/
│           │   ├── App.vue
│           │   ├── main.ts
│           │   ├── other-app.vue
│           │   ├── other-main.ts
│           │   └── test.vue
│           └── vite.config.ts
├── pnpm-workspace.yaml
├── tsconfig.json
└── vitest.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .commitlintrc.json
================================================
{
  "extends": ["@commitlint/config-conventional"]
}


================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 2
indent_style = space
max_line_length = 100
quote_type = single

[*.md]
indent_size = 2
insert_final_newline = false
trim_trailing_whitespace = false

[*.py]
indent_size = 4

[Makefile]
indent_style = tab


================================================
FILE: .eslintignore
================================================
dist
node_modules


================================================
FILE: .eslintrc.json
================================================
{
  "root": true,
  "env": {
    "browser": true,
    "es2021": true,
    "es6": true,
    "node": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "rules": {
    "no-console": 1,
    "@typescript-eslint/no-non-null-assertion": "off",
    "@typescript-eslint/ban-ts-comment": "off",
    "@typescript-eslint/no-explicit-any": "off"
  }
}


================================================
FILE: .github/workflows/publish.yml
================================================
name: Npm Publish

on:
  push:
    branches:
      - main

jobs:
  publish-npm:
    if: "contains(github.event.head_commit.message, 'release')"
    runs-on: ${{matrix.os}}

    strategy:
      matrix:
        os: [ubuntu-latest]
        node-version: [16.x]
      fail-fast: false

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Install pnpm
        uses: pnpm/action-setup@v2.0.1
        with:
          version: 6.31.0

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}
          registry-url: https://registry.npmjs.org/
          cache: 'pnpm'

      - name: Install Dependencies
        run: pnpm install

      - name: Publish to NPM
        run: pnpm -r publish --access public --no-git-checks
        env:
          NODE_AUTH_TOKEN: ${{secrets.npm_token}}


================================================
FILE: .github/workflows/release.yml
================================================
name: Create Release

on:
  push:
    tags:
      - v*

jobs:
  build:
    name: Create Release
    runs-on: ${{matrix.os}}

    strategy:
      matrix:
        os: [ubuntu-latest]
      fail-fast: false

    steps:
      - name: Checkout code
        uses: actions/checkout@master

      - name: Create Release for Tag
        id: release_tag
        uses: yyx990803/release-tag@master
        env:
          GITHUB_TOKEN: ${{ secrets.OPER_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          body: |
            Please refer to [CHANGELOG.md](https://github.com/anncwb/vite-plugin-html/blob/main/CHANGELOG.md) for details.


================================================
FILE: .github/workflows/test.yml
================================================
name: Test

on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

jobs:
  build:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        node-version: [16.x]
        os: [ubuntu-latest]
      fail-fast: false

    steps:
      - uses: actions/checkout@v2

      - name: Install pnpm
        uses: pnpm/action-setup@v2.0.1
        with:
          version: 6.28.0

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}
          registry-url: https://registry.npmjs.org/
          cache: 'pnpm'

      - run: pnpm install

      - name: Test
        run: pnpm run test


================================================
FILE: .gitignore
================================================
node_modules
dist

================================================
FILE: .husky/commit-msg
================================================
#!/bin/sh

# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit "$1"


================================================
FILE: .husky/common.sh
================================================
#!/bin/sh
command_exists () {
  command -v "$1" >/dev/null 2>&1
}

# Workaround for Windows 10, Git Bash and Yarn
if command_exists winpty && test -t 1; then
  exec < /dev/tty
fi


================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"

[ -n "$CI" ] && exit 0

# Format and submit code according to lintstagedrc.js configuration
pnpm exec lint-staged --concurrent false


================================================
FILE: .npmrc
================================================
ignore-workspace-root-check=true
public-hoist-pattern[]=*


================================================
FILE: .prettierrc.json
================================================
{
  "semi": false,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 80,
  "trailingComma": "all"
}


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": [
    "octref.vetur",
    "dbaeumer.vscode-eslint",
    "stylelint.vscode-stylelint",
    "esbenp.prettier-vscode",
    "mrmlnc.vscode-less",
    "lokalise.i18n-ally",
    "antfu.iconify",
    "mikestead.dotenv",
    "heybourn.headwind"
  ]
}


================================================
FILE: .vscode/settings.json
================================================
{
  "typescript.tsdk": "./node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true,
  //===========================================
  //============= Editor ======================
  //===========================================
  "explorer.openEditors.visible": 0,
  "editor.tabSize": 2,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "diffEditor.ignoreTrimWhitespace": false,
  //===========================================
  //============= Other =======================
  //===========================================
  "breadcrumbs.enabled": true,
  "open-in-browser.default": "chrome",
  //===========================================
  //============= files =======================
  //===========================================
  "files.eol": "\n",
  "search.exclude": {
    "**/node_modules": true,
    "**/*.log": true,
    "**/*.log*": true,
    "**/bower_components": true,
    "**/dist": true,
    "**/elehukouben": true,
    "**/.git": true,
    "**/.gitignore": true,
    "**/.svn": true,
    "**/.DS_Store": true,
    "**/.idea": true,
    "**/.vscode": false,
    "**/yarn.lock": true,
    "**/tmp": true,
    "out": true,
    "dist": true,
    "node_modules": true,
    "CHANGELOG.md": true,
    "examples": true,
    "res": true,
    "screenshots": true,
    "yarn-error.log": true,
    "**/pnpm-lock.yaml": true,
    "**/.yarn": true
  },
  "files.exclude": {
    "**/.cache": true,
    "**/.editorconfig": true,
    "**/.eslintcache": true,
    "**/bower_components": true,
    "**/.idea": true,
    "**/tmp": true,
    "**/.git": true,
    "**/.svn": true,
    "**/.hg": true,
    "**/CVS": true,
    "**/.DS_Store": true
  },
  "files.watcherExclude": {
    "**/.git/objects/**": true,
    "**/.git/subtree-cache/**": true,
    "**/.vscode/**": true,
    "**/node_modules/**": true,
    "**/tmp/**": true,
    "**/bower_components/**": true,
    "**/dist/**": true,
    "**/yarn.lock": true
  },
  "stylelint.enable": true,
  "stylelint.packageManager": "yarn",
  "liveServer.settings.donotShowInfoMsg": true,
  "workbench.settings.enableNaturalLanguageSearch": false,
  "prettier.requireConfig": true,
  "workbench.sideBar.location": "left",
  "cSpell.words": [
    "vben",
    "windi",
    "browserslist",
    "tailwindcss",
    "esnext",
    "antv",
    "tinymce",
    "qrcode",
    "sider",
    "pinia",
    "sider",
    "nprogress",
    "INTLIFY",
    "stylelint",
    "esno",
    "vitejs",
    "sortablejs",
    "mockjs",
    "codemirror",
    "iconify",
    "commitlint",
    "vditor",
    "echarts",
    "cropperjs",
    "logicflow",
    "vueuse",
    "zxcvbn",
    "lintstagedrc",
    "brotli",
    "tailwindcss",
    "sider"
  ]
}


================================================
FILE: CHANGELOG.md
================================================
# [3.2.1](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.6...v3.2.1) (2023-12-26)

### Features

- support vite5.0

# [3.2.0](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.6...v3.2.0) (2022-03-15)

### Bug Fixes

- improve middleware logic ([36e143a](https://github.com/vbenjs/vite-plugin-html/commit/36e143a55b62710c7435ed0ca5ed4b035930c3af))

### Features

- support tags ([d07c9db](https://github.com/vbenjs/vite-plugin-html/commit/d07c9db4541432b94576e1fd4dce1b17098a60d0))

## [3.0.6](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.0...v3.0.6) (2022-02-10)

### Bug Fixes

- fix base configuration causing local development errors ([6deeead](https://github.com/vbenjs/vite-plugin-html/commit/6deeead53f02007effd42b013d0eb03390f0a9a2))
- fs-extra no longer exports existsSync ([#25](https://github.com/vbenjs/vite-plugin-html/issues/25)) ([d6614da](https://github.com/vbenjs/vite-plugin-html/commit/d6614dae2ab5d2f53d54ec480e1212613819186b))
- history mode support ([20a7c69](https://github.com/vbenjs/vite-plugin-html/commit/20a7c69ed7f8f355bda923dd9f84717727276c67))
- make sure template defaults are correct ([697626c](https://github.com/vbenjs/vite-plugin-html/commit/697626cb62db42c1853788ac4019a834822b19e5))

## [3.0.5](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.0...v3.0.5) (2022-02-09)

### Bug Fixes

- fix base configuration causing local development errors ([6deeead](https://github.com/vbenjs/vite-plugin-html/commit/6deeead53f02007effd42b013d0eb03390f0a9a2))
- fs-extra no longer exports existsSync ([#25](https://github.com/vbenjs/vite-plugin-html/issues/25)) ([d6614da](https://github.com/vbenjs/vite-plugin-html/commit/d6614dae2ab5d2f53d54ec480e1212613819186b))
- history mode support ([20a7c69](https://github.com/vbenjs/vite-plugin-html/commit/20a7c69ed7f8f355bda923dd9f84717727276c67))
- make sure template defaults are correct ([697626c](https://github.com/vbenjs/vite-plugin-html/commit/697626cb62db42c1853788ac4019a834822b19e5))

## [3.0.4](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.0...v3.0.4) (2022-02-07)

### Bug Fixes

- fix base configuration causing local development errors ([6deeead](https://github.com/vbenjs/vite-plugin-html/commit/6deeead53f02007effd42b013d0eb03390f0a9a2))
- fs-extra no longer exports existsSync ([#25](https://github.com/vbenjs/vite-plugin-html/issues/25)) ([d6614da](https://github.com/vbenjs/vite-plugin-html/commit/d6614dae2ab5d2f53d54ec480e1212613819186b))
- history mode support ([4b0a54f](https://github.com/vbenjs/vite-plugin-html/commit/4b0a54fd08dd3e065b239ef0587dc683263db343))
- make sure template defaults are correct ([697626c](https://github.com/vbenjs/vite-plugin-html/commit/697626cb62db42c1853788ac4019a834822b19e5))

## [3.0.2](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.0...v3.0.2) (2022-01-28)

### Bug Fixes

- fix base configuration causing local development errors ([6deeead](https://github.com/vbenjs/vite-plugin-html/commit/6deeead53f02007effd42b013d0eb03390f0a9a2))
- fs-extra no longer exports existsSync ([#25](https://github.com/vbenjs/vite-plugin-html/issues/25)) ([d6614da](https://github.com/vbenjs/vite-plugin-html/commit/d6614dae2ab5d2f53d54ec480e1212613819186b))
- make sure template defaults are correct ([697626c](https://github.com/vbenjs/vite-plugin-html/commit/697626cb62db42c1853788ac4019a834822b19e5))

## [3.0.2](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.0...v3.0.2) (2022-01-27)

### Bug Fixes

- fs-extra no longer exports existsSync ([#25](https://github.com/vbenjs/vite-plugin-html/issues/25)) ([d6614da](https://github.com/vbenjs/vite-plugin-html/commit/d6614dae2ab5d2f53d54ec480e1212613819186b))
- make sure template defaults are correct ([697626c](https://github.com/vbenjs/vite-plugin-html/commit/697626cb62db42c1853788ac4019a834822b19e5))

## [3.0.1](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.0...v3.0.1) (2022-01-27)

### Bug Fixes

- make sure template defaults are correct ([697626c](https://github.com/vbenjs/vite-plugin-html/commit/697626cb62db42c1853788ac4019a834822b19e5))

# [3.0.0-beta.1](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.0...v3.0.0-beta.1) (2022-01-27)

### Bug Fixes

- make sure template defaults are correct ([697626c](https://github.com/vbenjs/vite-plugin-html/commit/697626cb62db42c1853788ac4019a834822b19e5))

## [2.1.2](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.6...v2.1.2) (2021-12-27)

### Bug Fixes

- ssr error,close [#18](https://github.com/vbenjs/vite-plugin-html/issues/18) ([f799d98](https://github.com/vbenjs/vite-plugin-html/commit/f799d9821ec9b22bbbfd8b92ddcb4d25cc18219e))

### Features

- expose minifyFn ([c6409dc](https://github.com/vbenjs/vite-plugin-html/commit/c6409dc25e118b47adff250ab4dd0a239803258b))

## [2.1.1](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.6...v2.1.1) (2021-09-27)

### Features

- expose minifyFn ([c6409dc](https://github.com/vbenjs/vite-plugin-html/commit/c6409dc25e118b47adff250ab4dd0a239803258b))

# [2.1.0](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.6...v2.1.0) (2021-08-20)

### Features

- expose minifyFn ([c6409dc](https://github.com/vbenjs/vite-plugin-html/commit/c6409dc25e118b47adff250ab4dd0a239803258b))
- **inject:** inject the contents of the .env file into index.html ([5b52d7e](https://github.com/vbenjs/vite-plugin-html/commit/5b52d7e654c1056f6a368f4c7df0de8a63b61874))

## [2.0.7](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.6...v2.0.7) (2021-04-16)

### Features

- expose minifyFn ([c6409dc](https://github.com/vbenjs/vite-plugin-html/commit/c6409dc25e118b47adff250ab4dd0a239803258b))

## [2.0.4](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.2...v2.0.4) (2021-04-05)

## [2.0.3](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.2...v2.0.3) (2021-03-02)

## [2.0.2](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.1...v2.0.2) (2021-02-23)

### Features

- add gihub action ([3569c1c](https://github.com/vbenjs/vite-plugin-html/commit/3569c1c097be457fe91b5bb39c2bd56e61753fc9))

# [2.0.0-rc.1](https://github.com/vbenjs/vite-plugin-html/compare/v2.0.0-beta.2...v2.0.0-rc.1) (2021-01-29)

### Bug Fixes

- css build error ([12cd218](https://github.com/vbenjs/vite-plugin-html/commit/12cd218c3f02267022eed06eea18c8e67d4119ff))
- fix css compression failure [#1](https://github.com/vbenjs/vite-plugin-html/issues/1) ([b62e99c](https://github.com/vbenjs/vite-plugin-html/commit/b62e99cd809a0a581cbd1e1dae9260d0b35e9abb))

### Features

- inject title to viteHtmlPluginOptions ([3b34151](https://github.com/vbenjs/vite-plugin-html/commit/3b341516cc78c83619d672ab1c5316a4339a92ac))

# 2.0.0-beta.2 (2021-01-03)


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020-present, Vben

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# vite-plugin-html

**English** | [中文](./README.zh_CN.md)

## Features

- HTML compression capability
- EJS template capability
- Multi-page application support
- Support custom `entry`
- Support custom `template`

## Install (yarn or npm)

**node version:** >=12.0.0

**vite version:** >=2.0.0

```bash
yarn add vite-plugin-html -D
```

或

```bash
npm i vite-plugin-html -D
```

## Usage

- Add EJS tags to `index.html`, e.g.

```html
<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title><%- title %></title>
  <%- injectScript %>
</head>
```

- Configure in `vite.config.ts`, this method can introduce the required functions as needed

```ts
import { defineConfig, Plugin } from 'vite'
import vue from '@vitejs/plugin-vue'

import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  plugins: [
    vue(),
    createHtmlPlugin({
      minify: true,
      /**
       * After writing entry here, you will not need to add script tags in `index.html`, the original tags need to be deleted
       * @default src/main.ts
       */
      entry: 'src/main.ts',
      /**
       * If you want to store `index.html` in the specified folder, you can modify it, otherwise no configuration is required
       * @default index.html
       */
      template: 'public/index.html',

      /**
       * Data that needs to be injected into the index.html ejs template
       */
      inject: {
        data: {
          title: 'index',
          injectScript: `<script src="./inject.js"></script>`,
        },
        tags: [
          {
            injectTo: 'body-prepend',
            tag: 'div',
            attrs: {
              id: 'tag',
            },
          },
        ],
      },
    }),
  ],
})
```

Multi-page application configuration

```ts
import { defineConfig } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  plugins: [
    createHtmlPlugin({
      minify: true,
      pages: [
        {
          entry: 'src/main.ts',
          filename: 'index.html',
          template: 'public/index.html',
          injectOptions: {
            data: {
              title: 'index',
              injectScript: `<script src="./inject.js"></script>`,
            },
            tags: [
              {
                injectTo: 'body-prepend',
                tag: 'div',
                attrs: {
                  id: 'tag1',
                },
              },
            ],
          },
        },
        {
          entry: 'src/other-main.ts',
          filename: 'other.html',
          template: 'public/other.html',
          injectOptions: {
            data: {
              title: 'other page',
              injectScript: `<script src="./inject.js"></script>`,
            },
            tags: [
              {
                injectTo: 'body-prepend',
                tag: 'div',
                attrs: {
                  id: 'tag2',
                },
              },
            ],
          },
        },
      ],
    }),
  ],
})
```

## Parameter Description

`createHtmlPlugin(options: UserOptions)`

### UserOptions

| Parameter | Types                    | Default       | Description                                       |
| --------- | ------------------------ | ------------- | ------------------------------------------------- |
| entry     | `string`                 | `src/main.ts` | entry file path                                   |
| template  | `string`                 | `index.html`  | relative path to the template                     |
| inject    | `InjectOptions`          | -             | Data injected into HTML                           |
| minify    | `boolean|MinifyOptions` | -             | whether to compress html                          |
| pages     | `PageOption`             | -             | Multi-page configuration                          |

### InjectOptions

| Parameter  | Types                 | Default | Description                                                               |
| ---------- | --------------------- | ------- | ------------------------------------------------------------------------- |
| data       | `Record<string, any>` | -       | injected data                                                             |
| ejsOptions | `EJSOptions`          | -       | ejs configuration Options[EJSOptions](https://github.com/mde/ejs#options) |
| tags       | `HtmlTagDescriptor`   | -       | List of tags to inject                                                    |

`data` can be accessed in `html` using the `ejs` template syntax

#### Env inject

By default, the contents of the `.env` file will be injected into index.html, similar to vite's `loadEnv` function

### PageOption

| Parameter     | Types           | Default       | Description                   |
| ------------- | --------------- | ------------- | ----------------------------- |
| filename      | `string`        | -             | html file name                |
| template      | `string`        | `index.html`  | relative path to the template |
| entry         | `string`        | `src/main.ts` | entry file path               |
| injectOptions | `InjectOptions` | -             | Data injected into HTML       |

### MinifyOptions

Default compression configuration

```ts
    collapseWhitespace: true,
    keepClosingSlash: true,
    removeComments: true,
    removeRedundantAttributes: true,
    removeScriptTypeAttributes: true,
    removeStyleLinkTypeAttributes: true,
    useShortDoctype: true,
    minifyCSS: true,
```

### Run the playground

```bash
pnpm install

# spa
cd ./packages/playground/basic

pnpm run dev

# map
cd ./packages/playground/mpa

pnpm run dev

```

## Example project

[Vben Admin](https://github.com/anncwb/vue-vben-admin)

## License

MIT

[npm-img]: https://img.shields.io/npm/v/vite-plugin-html.svg
[npm-url]: https://npmjs.com/package/vite-plugin-html
[node-img]: https://img.shields.io/node/v/vite-plugin-html.svg
[node-url]: https://nodejs.org/en/about/releases/


================================================
FILE: README.zh_CN.md
================================================
# vite-plugin-html

**中文** | [English](./README.md)

[![npm][npm-img]][npm-url] [![node][node-img]][node-url]

## 功能

- HTML 压缩能力
- EJS 模版能力
- 多页应用支持
- 支持自定义`entry`
- 支持自定义`template`

## 安装 (yarn or npm)

**node version:** >=12.0.0

**vite version:** >=2.0.0

```bash
yarn add vite-plugin-html -D
```

或

```bash
npm i vite-plugin-html -D
```

## 使用

- 在 `index.html` 中增加 EJS 标签,例如

```html
<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title><%- title %></title>
  <%- injectScript %>
</head>
```

- 在 `vite.config.ts` 中配置,该方式可以按需引入需要的功能即可

```ts
import { defineConfig, Plugin } from 'vite'
import vue from '@vitejs/plugin-vue'

import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  plugins: [
    vue(),
    createHtmlPlugin({
      minify: true,
      /**
       * 在这里写entry后,你将不需要在`index.html`内添加 script 标签,原有标签需要删除
       * @default src/main.ts
       */
      entry: 'src/main.ts',
      /**
       * 如果你想将 `index.html`存放在指定文件夹,可以修改它,否则不需要配置
       * @default index.html
       */
      template: 'public/index.html',

      /**
       * 需要注入 index.html ejs 模版的数据
       */
      inject: {
        data: {
          title: 'index',
          injectScript: `<script src="./inject.js"></script>`,
        },
        tags: [
          {
            injectTo: 'body-prepend',
            tag: 'div',
            attrs: {
              id: 'tag',
            },
          },
        ],
      },
    }),
  ],
})
```

多页应用配置

```ts
import { defineConfig } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  plugins: [
    createHtmlPlugin({
      minify: true,
      pages: [
        {
          entry: 'src/main.ts',
          filename: 'index.html',
          template: 'public/index.html',
          injectOptions: {
            data: {
              title: 'index',
              injectScript: `<script src="./inject.js"></script>`,
            },
            tags: [
              {
                injectTo: 'body-prepend',
                tag: 'div',
                attrs: {
                  id: 'tag1',
                },
              },
            ],
          },
        },
        {
          entry: 'src/other-main.ts',
          filename: 'other.html',
          template: 'public/other.html',
          injectOptions: {
            data: {
              title: 'other page',
              injectScript: `<script src="./inject.js"></script>`,
            },
            tags: [
              {
                injectTo: 'body-prepend',
                tag: 'div',
                attrs: {
                  id: 'tag2',
                },
              },
            ],
          },
        },
      ],
    }),
  ],
})
```

## 参数说明

`createHtmlPlugin(options: UserOptions)`

### UserOptions

| 参数     | 类型                     | 默认值        | 说明                            |
| -------- | ------------------------ | ------------- | ------------------------------- |
| entry    | `string`                 | `src/main.ts` | 入口文件                        |
| template | `string`                 | `index.html`  | 模板的相对路径                  |
| inject   | `InjectOptions`          | -             | 注入 HTML 的数据                |
| minify   | `boolean|MinifyOptions` | -             | 是否压缩 html                   |
| pages    | `PageOption`             | -             | 多页配置                        |

### InjectOptions

| 参数       | 类型                  | 默认值 | 说明                                                       |
| ---------- | --------------------- | ------ | ---------------------------------------------------------- |
| data       | `Record<string, any>` | -      | 注入的数据                                                 |
| ejsOptions | `EJSOptions`          | -      | ejs 配置项[EJSOptions](https://github.com/mde/ejs#options) |
| tags       | `HtmlTagDescriptor`   | -      | 需要注入的标签列表                                         |

`data` 可以在 `html` 中使用 `ejs` 模版语法获取

#### env 注入

默认会向 index.html 注入 `.env` 文件的内容,类似 vite 的 `loadEnv`函数

### PageOption

| 参数          | 类型            | 默认值        | 说明             |
| ------------- | --------------- | ------------- | ---------------- |
| filename      | `string`        | -             | html 文件名      |
| template      | `string`        | `index.html`  | 模板的相对路径   |
| entry         | `string`        | `src/main.ts` | 入口文件         |
| injectOptions | `InjectOptions` | -             | 注入 HTML 的数据 |

### MinifyOptions

默认压缩配置

```ts
    collapseWhitespace: true,
    keepClosingSlash: true,
    removeComments: true,
    removeRedundantAttributes: true,
    removeScriptTypeAttributes: true,
    removeStyleLinkTypeAttributes: true,
    useShortDoctype: true,
    minifyCSS: true,
```

### 运行示例

```bash
pnpm install

# spa
cd ./packages/playground/basic

pnpm run dev

# map
cd ./packages/playground/mpa

pnpm run dev

```

## 示例项目

[Vben Admin](https://github.com/anncwb/vue-vben-admin)

## License

MIT

[npm-img]: https://img.shields.io/npm/v/vite-plugin-html.svg
[npm-url]: https://npmjs.com/package/vite-plugin-html
[node-img]: https://img.shields.io/node/v/vite-plugin-html.svg
[node-url]: https://nodejs.org/en/about/releases/


================================================
FILE: package.json
================================================
{
  "name": "vite-plugin-html-monorepo",
  "version": "3.2.1",
  "private": true,
  "scripts": {
    "stub": "pnpm run prepack --filter ./packages -- --stub",
    "postinstall": "pnpm run stub",
    "log": "conventional-changelog -p angular -i CHANGELOG.md -s",
    "lint:pretty": "pretty-quick --staged",
    "lint:eslint": "eslint \"packages/**/*.{ts,tsx}\" --fix",
    "prepare": "husky install",
    "preinstall": "npx only-allow pnpm",
    "test": "vitest"
  },
  "author": "Vben",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/vbenjs/vite-plugin-html"
  },
  "bugs": {
    "url": "https://github.com/vbenjs/vite-plugin-html/issues"
  },
  "homepage": "https://github.com/vbenjs/vite-plugin-html/tree/master/#readme",
  "devDependencies": {
    "@commitlint/cli": "^16.2.1",
    "@commitlint/config-conventional": "^16.2.1",
    "@types/html-minifier-terser": "^6.1.0",
    "@types/jsdom": "^16.2.14",
    "@types/node": "^17.0.21",
    "@typescript-eslint/eslint-plugin": "^5.14.0",
    "@typescript-eslint/parser": "^5.14.0",
    "commitizen": "^4.2.4",
    "conventional-changelog-cli": "^2.2.2",
    "cross-env": "^7.0.3",
    "eslint": "^8.11.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-html": "^6.2.0",
    "husky": "^7.0.4",
    "lint-staged": "^12.3.5",
    "prettier": "^2.5.1",
    "rimraf": "^3.0.2",
    "tsup": "^5.12.1",
    "typescript": "^4.6.2",
    "unbuild": "^0.7.0",
    "vite": "^2.8.6",
    "vitest": "^0.6.1"
  },
  "lint-staged": {
    "*": [
      "prettier --write --ignore-unknown"
    ],
    "packages/*/{src,types}/**/*.ts": [
      "eslint --ext .ts"
    ],
    "packages/**/*.d.ts": [
      "eslint --ext .ts"
    ]
  }
}


================================================
FILE: packages/core/build.config.ts
================================================
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
  clean: true,
  entries: ['./src/index'],
  declaration: true,
  rollup: {
    emitCJS: true,
  },
})


================================================
FILE: packages/core/package.json
================================================
{
  "name": "vite-plugin-html",
  "version": "3.2.2",
  "description": "A plugin for vite to Minimize index.html and use lodash.template template syntax in index.html",
  "main": "dist/index.cjs",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "require": "./dist/index.cjs",
      "import": "./dist/index.mjs",
      "types": "./dist/index.d.ts"
    }
  },
  "files": [
    "dist",
    "CHANGELOG.md",
    "README.md",
    "README.zh_CN.md"
  ],
  "scripts": {
    "dev": "pnpm unbuild --stub",
    "build": "pnpm unbuild",
    "prepublishOnly": "npm run build",
    "prepack": "pnpm unbuild"
  },
  "keywords": [
    "vite",
    "html",
    "minify",
    "vite-plugin"
  ],
  "author": "Vben",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/vbenjs/vite-plugin-html",
    "directory": "packages/core"
  },
  "bugs": {
    "url": "https://github.com/vbenjs/vite-plugin-html/issues"
  },
  "homepage": "https://github.com/vbenjs/vite-plugin-html/tree/master/#readme",
  "dependencies": {
    "@rollup/pluginutils": "^4.2.0",
    "colorette": "^2.0.16",
    "connect-history-api-fallback": "^1.6.0",
    "consola": "^2.15.3",
    "dotenv": "^16.0.0",
    "dotenv-expand": "^8.0.2",
    "ejs": "^3.1.6",
    "fast-glob": "^3.2.11",
    "fs-extra": "^10.0.1",
    "html-minifier-terser": "^6.1.0",
    "node-html-parser": "^5.3.3",
    "pathe": "^0.2.0"
  },
  "peerDependencies": {
    "vite": ">=2.0.0"
  },
  "devDependencies": {
    "@babel/types": "^7.17.0",
    "@types/ejs": "^3.1.0",
    "@types/fs-extra": "^9.0.13",
    "@types/html-minifier-terser": "^6.1.0",
    "@types/node": "^17.0.21",
    "typescript": "^4.6.2",
    "vite": "^2.8.6"
  }
}


================================================
FILE: packages/core/src/__tests__/html.spec.ts
================================================
import { createPlugin, createSpaPage, renderHtml } from '../htmlPlugin'
import { describe, test, expect } from 'vitest'

const createVitePlugin = () => {
  const { name } = createPlugin()
  return { name }
}

describe('html plugin test.', () => {
  test('make sure name.', async () => {
    const { name } = await createVitePlugin()
    expect(name).toEqual('vite:html')
  })
})

describe('function test.', () => {
  test('createSpaPage function test.', async () => {
    const page = createSpaPage('main.ts', 'public/index.html', {
      data: { a: '1' },
      ejsOptions: {},
    })
    expect(page).toEqual({
      filename: 'index.html',
      template: 'public/index.html',
      entry: 'main.ts',
      injectOptions: { data: { a: '1' }, ejsOptions: {} },
    })
  })

  test('renderHtml function test.', async () => {
    const content = await renderHtml(
      `
<!DOCTYPE html>
<html>
  <head>
    <title><%- title %></title>
    <title><%- ENV_TITLE %></title>
  </head>
</html>
`,
      {
        injectOptions: {
          data: { title: 'test-title' },
        },
        viteConfig: {} as any,
        env: {
          ENV_TITLE: 'env-title',
        },
      },
    )
    expect(content).toEqual(`
<!DOCTYPE html>
<html>
  <head>
    <title>test-title</title>
    <title>env-title</title>
  </head>
</html>
`)
  })
})


================================================
FILE: packages/core/src/__tests__/minify.spec.ts
================================================
import { createMinifyHtmlPlugin, minifyHtml } from '../minifyHtml'
import { describe, test, expect } from 'vitest'

const createVitePlugin = () => {
  const { name, generateBundle } = createMinifyHtmlPlugin()
  return { name, generateBundle }
}

describe('minify html plugin test.', () => {
  test('make sure name.', async () => {
    const { name } = await createVitePlugin()
    expect(name).toEqual('vite:minify-html')
  })

  test('make sure generateBundle.', async () => {
    const { generateBundle } = await createVitePlugin()
    const generate: any = generateBundle
    const testBundle = {
      test: {
        type: 'asset',
        fileName: 'index.html',
        source: `
        <!DOCTYPE html>
        <html>
        <style>
        div {
          color: red;
        }
        </style>
        </html>
        `,
      },
    }
    await generate(null, testBundle, false)
    expect(testBundle.test.source).toEqual(
      `<!doctype html><html><style>div{color:red}</style></html>`,
    )
  })

  test('minify is true.', async () => {
    const ret = await minifyHtml(
      `<!DOCTYPE html>
<html>
</html>
`,
      true,
    )
    expect(ret).toEqual(`<!doctype html><html></html>`)
  })

  test('minify is false.', async () => {
    const ret = await minifyHtml(
      `<!DOCTYPE html>
<html>
</html>
`,
      false,
    )
    expect(ret).toEqual(
      `<!DOCTYPE html>
<html>
</html>
`,
    )
  })

  test('minify css.', async () => {
    const ret = await minifyHtml(
      `<!DOCTYPE html>
<html>
<style>
div {
  color: red;
}
</style>
</html>
`,
      true,
    )
    expect(ret).toEqual(
      `<!doctype html><html><style>div{color:red}</style></html>`,
    )
  })

  test('custom minify options.', async () => {
    const ret = await minifyHtml(
      `<!DOCTYPE html>
<html>
<style>
div {
  color: red;
}
</style>
</html>
`,
      { minifyCSS: true },
    )
    expect(ret).toEqual(`<!DOCTYPE html>
<html>
<style>div{color:red}</style>
</html>
`)
  })
})


================================================
FILE: packages/core/src/__tests__/utils.spec.ts
================================================
import { describe, test, expect } from 'vitest'
import { htmlFilter } from '../utils/createHtmlFilter'

describe('utils test.', () => {
  test('createHtmlFilter > htmlFilter.', async () => {
    expect(htmlFilter('index.html')).toBe(true)
    expect(htmlFilter('index.html.html')).toBe(true)
    expect(htmlFilter('/index.html')).toBe(true)
    expect(htmlFilter('/index.html/index.html')).toBe(true)
    expect(htmlFilter('users/index.html')).toBe(true)

    expect(htmlFilter('index.htm')).toBe(false)
    expect(htmlFilter('index.css')).toBe(false)
    expect(htmlFilter('index.js')).toBe(false)
    expect(htmlFilter('index.ts')).toBe(false)
    expect(htmlFilter('./index.html')).toBe(false)
  })
})


================================================
FILE: packages/core/src/htmlPlugin.ts
================================================
import type { ResolvedConfig, PluginOption } from 'vite'
import type { InjectOptions, PageOption, Pages, UserOptions } from './typing'
import { render } from 'ejs'
import { isDirEmpty, loadEnv } from './utils'
import { normalizePath } from 'vite'
import { parse } from 'node-html-parser'
import fs from 'fs-extra'
import path from 'pathe'
import fg from 'fast-glob'
import consola from 'consola'
import { dim } from 'colorette'
import history from 'connect-history-api-fallback'
import * as vite from 'vite'

const DEFAULT_TEMPLATE = 'index.html'
const ignoreDirs = ['.', '', '/']

const bodyInjectRE = /<\/body>/

function getViteMajorVersion() {
  return vite?.version ? Number(vite.version.split('.')[0]) : 2
}

export function createPlugin(userOptions: UserOptions = {}): PluginOption {
  const {
    entry,
    template = DEFAULT_TEMPLATE,
    pages = [],
    verbose = false,
  } = userOptions

  let viteConfig: ResolvedConfig
  let env: Record<string, any> = {}
  const transformIndexHtmlHandler = async (html, ctx) => {
    const url = ctx.filename
    const base = viteConfig.base
    const excludeBaseUrl = url.replace(base, '/')
    const htmlName = path.relative(process.cwd(), excludeBaseUrl)

    const page = getPage(userOptions, htmlName, viteConfig)
    const { injectOptions = {} } = page
    const _html = await renderHtml(html, {
      injectOptions,
      viteConfig,
      env,
      entry: page.entry || entry,
      verbose,
    })
    const { tags = [] } = injectOptions
    return {
      html: _html,
      tags: tags,
    }
  }

  return {
    name: 'vite:html',
    enforce: 'pre',
    configResolved(resolvedConfig) {
      viteConfig = resolvedConfig
      env = loadEnv(viteConfig.mode, viteConfig.root, '')
    },
    config(conf) {
      const input = createInput(userOptions, conf as unknown as ResolvedConfig)

      if (input) {
        return {
          build: {
            rollupOptions: {
              input,
            },
          },
        }
      }
    },

    configureServer(server) {
      let _pages: { filename: string; template: string }[] = []
      const rewrites: { from: RegExp; to: any }[] = []
      if (!isMpa(viteConfig)) {
        const template = userOptions.template || DEFAULT_TEMPLATE
        const filename = DEFAULT_TEMPLATE
        _pages.push({
          filename,
          template,
        })
      } else {
        _pages = pages.map((page) => {
          return {
            filename: page.filename || DEFAULT_TEMPLATE,
            template: page.template || DEFAULT_TEMPLATE,
          }
        })
      }
      const proxy = viteConfig.server?.proxy ?? {}
      const baseUrl = viteConfig.base ?? '/'
      const keys = Object.keys(proxy)

      let indexPage: any = null
      for (const page of _pages) {
        if (page.filename !== 'index.html') {
          rewrites.push(createRewire(page.template, page, baseUrl, keys))
        } else {
          indexPage = page
        }
      }

      // ensure order
      if (indexPage) {
        rewrites.push(createRewire('', indexPage, baseUrl, keys))
      }

      server.middlewares.use(
        history({
          disableDotRule: undefined,
          htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
          rewrites: rewrites,
        }),
      )
    },

    transformIndexHtml:
      getViteMajorVersion() >= 5
        ? {
            // @ts-ignore
            order: 'pre',
            handler: transformIndexHtmlHandler,
          }
        : {
            enforce: 'pre',
            transform: transformIndexHtmlHandler,
          },
    async closeBundle() {
      const outputDirs: string[] = []

      if (isMpa(viteConfig) || pages.length) {
        for (const page of pages) {
          const dir = path.dirname(page.template)
          if (!ignoreDirs.includes(dir)) {
            outputDirs.push(dir)
          }
        }
      } else {
        const dir = path.dirname(template)
        if (!ignoreDirs.includes(dir)) {
          outputDirs.push(dir)
        }
      }
      const cwd = path.resolve(viteConfig.root, viteConfig.build.outDir)
      const htmlFiles = await fg(
        outputDirs.map((dir) => `${dir}/*.html`),
        { cwd: path.resolve(cwd), absolute: true },
      )

      await Promise.all(
        htmlFiles.map((file) =>
          fs.move(file, path.resolve(cwd, path.basename(file)), {
            overwrite: true,
          }),
        ),
      )

      const htmlDirs = await fg(
        outputDirs.map((dir) => dir),
        { cwd: path.resolve(cwd), onlyDirectories: true, absolute: true },
      )
      await Promise.all(
        htmlDirs.map(async (item) => {
          const isEmpty = await isDirEmpty(item)
          if (isEmpty) {
            return fs.remove(item)
          }
        }),
      )
    },
  }
}

export function createInput(
  { pages = [], template = DEFAULT_TEMPLATE }: UserOptions,
  viteConfig: ResolvedConfig,
) {
  const input: Record<string, string> = {}
  if (isMpa(viteConfig) || pages?.length) {
    const templates = pages.map((page) => page.template)
    templates.forEach((temp) => {
      let dirName = path.dirname(temp)
      const file = path.basename(temp)

      dirName = dirName.replace(/\s+/g, '').replace(/\//g, '-')

      const key =
        dirName === '.' || dirName === 'public' || !dirName
          ? file.replace(/\.html/, '')
          : dirName
      input[key] = path.resolve(viteConfig.root, temp)
    })

    return input
  } else {
    const dir = path.dirname(template)
    if (ignoreDirs.includes(dir)) {
      return undefined
    } else {
      const file = path.basename(template)
      const key = file.replace(/\.html/, '')
      return {
        [key]: path.resolve(viteConfig.root, template),
      }
    }
  }
}

export async function renderHtml(
  html: string,
  config: {
    injectOptions: InjectOptions
    viteConfig: ResolvedConfig
    env: Record<string, any>
    entry?: string
    verbose?: boolean
  },
) {
  const { injectOptions, viteConfig, env, entry, verbose } = config
  const { data, ejsOptions } = injectOptions

  const ejsData: Record<string, any> = {
    ...(viteConfig?.env ?? {}),
    ...(viteConfig?.define ?? {}),
    ...(env || {}),
    ...data,
  }
  let result = await render(html, ejsData, ejsOptions)

  if (entry) {
    result = removeEntryScript(result, verbose)
    result = result.replace(
      bodyInjectRE,
      `<script type="module" src="${normalizePath(
        `${entry}`,
      )}"></script>\n</body>`,
    )
  }
  return result
}

export function getPage(
  { pages = [], entry, template = DEFAULT_TEMPLATE, inject = {} }: UserOptions,
  name: string,
  viteConfig: ResolvedConfig,
) {
  let page: PageOption
  if (isMpa(viteConfig) || pages?.length) {
    page = getPageConfig(name, pages, DEFAULT_TEMPLATE)
  } else {
    page = createSpaPage(entry, template, inject)
  }
  return page
}

function isMpa(viteConfig: ResolvedConfig) {
  const input = viteConfig?.build?.rollupOptions?.input ?? undefined
  return typeof input !== 'string' && Object.keys(input || {}).length > 1
}

export function removeEntryScript(html: string, verbose = false) {
  if (!html) {
    return html
  }

  const root = parse(html)
  const scriptNodes = root.querySelectorAll('script[type=module]') || []
  const removedNode: string[] = []
  scriptNodes.forEach((item) => {
    removedNode.push(item.toString())
    item.parentNode.removeChild(item)
  })
  verbose &&
    removedNode.length &&
    consola.warn(`vite-plugin-html: Since you have already configured entry, ${dim(
      removedNode.toString(),
    )} is deleted. You may also delete it from the index.html.
        `)
  return root.toString()
}

export function createSpaPage(
  entry: string | undefined,
  template: string,
  inject: InjectOptions = {},
): PageOption {
  return {
    entry,
    filename: 'index.html',
    template: template,
    injectOptions: inject,
  }
}

export function getPageConfig(
  htmlName: string,
  pages: Pages,
  defaultPage: string,
): PageOption {
  const defaultPageOption: PageOption = {
    filename: defaultPage,
    template: `./${defaultPage}`,
  }

  const page = pages.filter((page) => {
    return path.resolve('/' + page.template) === path.resolve('/' + htmlName)
  })?.[0]
  return page ?? defaultPageOption ?? undefined
}

export function getHtmlInPages(page: PageOption, root: string) {
  const htmlPath = getHtmlPath(page, root)

  return readHtml(htmlPath)
}

export function getHtmlPath(page: PageOption, root: string) {
  const { template } = page
  const templatePath = template.startsWith('.') ? template : `./${template}`
  return path.resolve(root, templatePath)
}

export async function readHtml(path: string) {
  if (!fs.pathExistsSync(path)) {
    throw new Error(`html is not exist in ${path}`)
  }
  return await fs.readFile(path).then((buffer) => buffer.toString())
}

function createRewire(
  reg: string,
  page: any,
  baseUrl: string,
  proxyUrlKeys: string[],
) {
  return {
    from: new RegExp(`^/${reg}*`),
    to({ parsedUrl }: any) {
      const pathname: string = parsedUrl.path

      const excludeBaseUrl = pathname.replace(baseUrl, '/')

      const template = path.resolve(baseUrl, page.template)

      if (excludeBaseUrl.startsWith("/static")) {
        return excludeBaseUrl;
      }

      if (excludeBaseUrl === '/') {
        return template
      }
      const isApiUrl = proxyUrlKeys.some((item) =>
        pathname.startsWith(path.resolve(baseUrl, item)),
      )
      return isApiUrl ? parsedUrl.path : template
    },
  }
}


================================================
FILE: packages/core/src/index.ts
================================================
import type { PluginOption } from 'vite'
import type { UserOptions } from './typing'
import { createPlugin } from './htmlPlugin'
import { createMinifyHtmlPlugin } from './minifyHtml'
import consola from 'consola'

consola.wrapConsole()

export function createHtmlPlugin(
  userOptions: UserOptions = {},
): PluginOption[] {
  return [createPlugin(userOptions), createMinifyHtmlPlugin(userOptions)]
}


================================================
FILE: packages/core/src/minifyHtml.ts
================================================
import type { PluginOption } from 'vite'
import type { UserOptions } from './typing'
import type { Options as MinifyOptions } from 'html-minifier-terser'
import { minify as minifyFn } from 'html-minifier-terser'
import { htmlFilter } from './utils/createHtmlFilter'

function getOptions(minify: boolean): MinifyOptions {
  return {
    collapseWhitespace: minify,
    keepClosingSlash: minify,
    removeComments: minify,
    removeRedundantAttributes: minify,
    removeScriptTypeAttributes: minify,
    removeStyleLinkTypeAttributes: minify,
    useShortDoctype: minify,
    minifyCSS: minify,
  }
}

export async function minifyHtml(
  html: string,
  minify: boolean | MinifyOptions,
) {
  if (typeof minify === 'boolean' && !minify) {
    return html
  }

  let minifyOptions: boolean | MinifyOptions = minify

  if (typeof minify === 'boolean' && minify) {
    minifyOptions = getOptions(minify)
  }

  return await minifyFn(html, minifyOptions as MinifyOptions)
}

export function createMinifyHtmlPlugin({
  minify = true,
}: UserOptions = {}): PluginOption {
  return {
    name: 'vite:minify-html',
    // apply: 'build',
    enforce: 'post',
    async generateBundle(_, outBundle) {
      if (minify) {
        for (const bundle of Object.values(outBundle)) {
          if (
            bundle.type === 'asset' &&
            htmlFilter(bundle.fileName) &&
            typeof bundle.source === 'string'
          ) {
            bundle.source = await minifyHtml(bundle.source, minify)
          }
        }
      }
    },
  }
}


================================================
FILE: packages/core/src/typing.ts
================================================
import type { Options as EJSOptions } from 'ejs'
import type { Options as MinifyOptions } from 'html-minifier-terser'
import type { HtmlTagDescriptor } from 'vite'

export type Entry = string | Record<string, string>

export interface InjectOptions {
  /**
   *  @description Data injected into the html template
   */
  data?: Record<string, any>

  tags?: HtmlTagDescriptor[]

  /**
   * @description ejs options configuration
   */
  ejsOptions?: EJSOptions
}

export interface PageOption {
  filename: string
  template: string
  entry?: string
  injectOptions?: InjectOptions
}

export type Pages = PageOption[]

export interface UserOptions {
  /**
   * @description Page options
   */
  pages?: Pages

  /**
   * @description Minimize options
   */
  minify?: MinifyOptions | boolean

  /**
   * page entry
   */
  entry?: string

  /**
   * template path
   */
  template?: string

  /**
   * @description inject options
   */
  inject?: InjectOptions

  /**
   * output warning log
   * @default false
   */
  verbose?: boolean
}


================================================
FILE: packages/core/src/utils/createHtmlFilter.ts
================================================
import { createFilter } from '@rollup/pluginutils'

export const htmlFilter = createFilter(['**/*.html'])


================================================
FILE: packages/core/src/utils/index.ts
================================================
import { expand } from 'dotenv-expand'
import dotenv from 'dotenv'
import { join, dirname } from 'pathe'
import fse from 'fs-extra'

export function loadEnv(
  mode: string,
  envDir: string,
  prefix = '',
): Record<string, string> {
  if (mode === 'local') {
    throw new Error(
      `"local" cannot be used as a mode name because it conflicts with ` +
        `the .local postfix for .env files.`,
    )
  }

  const env: Record<string, string> = {}
  const envFiles = [
    /** mode local file */ `.env.${mode}.local`,
    /** mode file */ `.env.${mode}`,
    /** local file */ `.env.local`,
    /** default file */ `.env`,
  ]

  for (const file of envFiles) {
    const path = lookupFile(envDir, [file], true)
    if (path) {
      const parsed = dotenv.parse(fse.readFileSync(path))

      // let environment variables use each other
      expand({
        parsed,
        // prevent process.env mutation
        ignoreProcessEnv: true,
      })

      // only keys that start with prefix are exposed to client
      for (const [key, value] of Object.entries(parsed)) {
        if (key.startsWith(prefix) && env[key] === undefined) {
          env[key] = value
        } else if (key === 'NODE_ENV') {
          // NODE_ENV override in .env file
          process.env.VITE_USER_NODE_ENV = value
        }
      }
    }
  }

  return env
}

export function lookupFile(
  dir: string,
  formats: string[],
  pathOnly = false,
): string | undefined {
  for (const format of formats) {
    const fullPath = join(dir, format)
    if (fse.pathExistsSync(fullPath) && fse.statSync(fullPath).isFile()) {
      return pathOnly ? fullPath : fse.readFileSync(fullPath, 'utf-8')
    }
  }
  const parentDir = dirname(dir)
  if (parentDir !== dir) {
    return lookupFile(parentDir, formats, pathOnly)
  }
}

export async function isDirEmpty(dir: string) {
  return fse.readdir(dir).then((files) => {
    return files.length === 0
  })
}


================================================
FILE: packages/playground/basic/basic.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>test-<%- title %></title>
  </head>

  <body>
    <div><%- ENV %></div>
    <div><%- NODE_ENV %></div>
    <div id="app"></div>
    basic-html
    <script type="module" src="/src/main.ts"></script>
    <%- injectScript %>
  </body>
</html>


================================================
FILE: packages/playground/basic/index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>test-<%- title %></title>
  </head>

  <body>
    <div><%- ENV %></div>
    <div><%- NODE_ENV %></div>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
    <%- injectScript %>
  </body>
</html>


================================================
FILE: packages/playground/basic/package.json
================================================
{
  "name": "playground-basic",
  "version": "0.0.1",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "axios": "^0.26.1",
    "vite-plugin-html": "workspace:*",
    "vue": "^3.2.31",
    "vue-router": "^4.0.14"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.2.4",
    "@vue/compiler-sfc": "^3.2.31",
    "vite": "^2.8.6"
  }
}


================================================
FILE: packages/playground/basic/public/inject.js
================================================
console.log('inject successfully!')


================================================
FILE: packages/playground/basic/server.js
================================================
const http = require('http')
const { URL } = require('url')

const port = 8080

const server = http.createServer((req, res) => {
  const { pathname } = new URL(req.url)

  // api开头的是API请求
  if (pathname.startsWith('/api')) {
    // 再判断路由
    if (pathname === '/api/users') {
      // 获取HTTP动词
      const method = req.method
      if (method === 'GET') {
        // 写一个假数据
        const resData = [
          {
            id: 1,
            name: '小明',
            age: 18,
          },
          {
            id: 2,
            name: '小红',
            age: 19,
          },
        ]
        res.setHeader('Content-Type', 'application/json')
        res.end(JSON.stringify(resData))
        return
      }
    }
  }
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('Hello World')
})

server.listen(port, () => {
  console.log(`Server is running on http://127.0.0.1:${port}/`)
})


================================================
FILE: packages/playground/basic/src/App.vue
================================================
<template>
  <div>
    hello world
    <router-view></router-view>
  </div>
</template>


================================================
FILE: packages/playground/basic/src/main.ts
================================================
import { createApp } from 'vue'
import App from './App.vue'
import { createRouter, createWebHashHistory } from 'vue-router'
// import { createRouter, createWebHistory } from 'vue-router'
import axios from 'axios'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: '/test',
      component: () => import('./test.vue'),
    },
  ],
})

createApp(App).use(router).mount('#app')

axios.get('/api/users').then((res) => {
  console.log(res)
})


================================================
FILE: packages/playground/basic/src/test.vue
================================================
<template>test</template>


================================================
FILE: packages/playground/basic/vite.config.ts
================================================
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  // base: '/aaa/',
  server: {
    proxy: {
      '/api': 'http://localhost:8080',
    },
  },
  plugins: [
    vue(),
    createHtmlPlugin({
      minify: true,
      inject: {
        data: {
          title: 'index',
          injectScript: `<script src="./inject.js"></script>`,
        },
        tags: [
          {
            tag: 'div',
            attrs: { id: 'ddd' },
            injectTo: 'body-prepend',
          },
        ],
      },
    }),
  ],
})


================================================
FILE: packages/playground/custom-entry/package.json
================================================
{
  "name": "playground-entry",
  "version": "0.0.1",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "vite-plugin-html": "workspace:*",
    "vue": "^3.2.31",
    "vue-router": "^4.0.14"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.2.4",
    "@vue/compiler-sfc": "^3.2.31",
    "vite": "^2.8.6"
  }
}


================================================
FILE: packages/playground/custom-entry/public/inject.js
================================================
console.log('inject successfully!')


================================================
FILE: packages/playground/custom-entry/src/App.vue
================================================
<template>
  <div>
    hello world
    <router-view></router-view>
  </div>
</template>


================================================
FILE: packages/playground/custom-entry/src/main.ts
================================================
import { createApp } from 'vue'
import App from './App.vue'
import { createRouter, createWebHashHistory } from 'vue-router'
// import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: '/test',
      component: () => import('./test.vue'),
    },
  ],
})
createApp(App).use(router).mount('#app')


================================================
FILE: packages/playground/custom-entry/src/test.vue
================================================
<template>test-custom-entry</template>


================================================
FILE: packages/playground/custom-entry/static/index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>test-<%- title %></title>
  </head>

  <body>
    <div><%- ENV %></div>
    <div><%- NODE_ENV %></div>
    <div id="app"></div>
    <%- injectScript %>
  </body>
</html>


================================================
FILE: packages/playground/custom-entry/vite.config.ts
================================================
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  server: {
    proxy: {
      '/api': 'http://localhost:8080',
    },
  },
  plugins: [
    vue(),
    createHtmlPlugin({
      minify: true,
      entry: 'src/main.ts',
      /**
       * @default index.html
       */
      template: 'static/index.html',
      inject: {
        data: {
          title: 'index',
          injectScript: `<script src="./inject.js"></script>`,
        },
      },
    }),
  ],
})


================================================
FILE: packages/playground/mpa/index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>test-<%- title %></title>
  </head>

  <body>
    <div id="app"></div>
    <div>index app</div>
    <div><%- ENV %></div>
    <div><%- NODE_ENV %></div>
  </body>
</html>


================================================
FILE: packages/playground/mpa/other.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><%- title %></title>
  </head>

  <body>
    <div><%- ENV %></div>
    <div><%- NODE_ENV %></div>
    <div id="app"></div>
    <div>other page</div>
  </body>
</html>


================================================
FILE: packages/playground/mpa/package.json
================================================
{
  "name": "playground-map",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "vite-plugin-html": "workspace:*",
    "vue": "^3.2.31",
    "vue-router": "^4.0.14"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.2.4",
    "@vue/compiler-sfc": "^3.2.31",
    "vite": "^2.8.6"
  }
}


================================================
FILE: packages/playground/mpa/public/inject.js
================================================
console.log('inject successfully!')


================================================
FILE: packages/playground/mpa/src/App.vue
================================================
<template>
  <div>hello world</div>

  <router-view></router-view>
</template>


================================================
FILE: packages/playground/mpa/src/main.ts
================================================
import { createApp } from 'vue'
import App from './App.vue'
import { createRouter, createWebHistory } from 'vue-router'
// import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/test',
      component: () => import('./test.vue'),
    },
  ],
})

createApp(App).use(router).mount('#app')


================================================
FILE: packages/playground/mpa/src/other-app.vue
================================================
<template>
  <div>
    <div>hello world app</div>
    <router-view></router-view>
  </div>
</template>


================================================
FILE: packages/playground/mpa/src/other-main.ts
================================================
import { createApp } from 'vue'
import App from './other-app.vue'
import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: '/test',
      component: () => import('./test.vue'),
    },
  ],
})

createApp(App).use(router).mount('#app')


================================================
FILE: packages/playground/mpa/src/test.vue
================================================
<template>test</template>


================================================
FILE: packages/playground/mpa/vite.config.ts
================================================
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  server: {
    proxy: {
      '/api': 'http://localhost:8080',
    },
  },
  plugins: [
    vue(),
    createHtmlPlugin({
      minify: true,
      pages: [
        {
          entry: 'src/main.ts',
          filename: 'index.html',
          template: 'index.html',
          injectOptions: {
            data: {
              title: 'index',
              injectScript: `<script src="./inject.js"></script>`,
            },
            tags: [
              {
                injectTo: 'body-prepend',
                tag: 'div',
                attrs: {
                  id: 'tag1',
                },
              },
            ],
          },
        },
        {
          entry: 'src/other-main.ts',
          filename: 'other.html',
          template: 'other.html',
          injectOptions: {
            data: {
              title: 'other page',
              injectScript: `<script src="./inject.js"></script>`,
            },
            tags: [
              {
                injectTo: 'body-prepend',
                tag: 'div',
                attrs: {
                  id: 'tag2',
                },
              },
            ],
          },
        },
      ],
    }),
  ],
})


================================================
FILE: pnpm-workspace.yaml
================================================
packages:
  - packages/*
  - packages/playground/*


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "module": "ESNext",
    "target": "es2017",
    "moduleResolution": "node",
    "strict": true,
    "declaration": true,
    "noUnusedLocals": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "lib": ["ESNext"],
    "sourceMap": false,
    "noEmitOnError": true,
    "noImplicitAny": false
  },
  "include": ["./packages"],
  "exclude": ["**/dist", "**/node_modules", "**/test"]
}


================================================
FILE: vitest.config.ts
================================================
/// <reference types="vitest" />

import { defineConfig } from 'vite'

export default defineConfig({})
Download .txt
gitextract_p7e8ovn3/

├── .commitlintrc.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github/
│   └── workflows/
│       ├── publish.yml
│       ├── release.yml
│       └── test.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   ├── common.sh
│   └── pre-commit
├── .npmrc
├── .prettierrc.json
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh_CN.md
├── package.json
├── packages/
│   ├── core/
│   │   ├── build.config.ts
│   │   ├── package.json
│   │   └── src/
│   │       ├── __tests__/
│   │       │   ├── html.spec.ts
│   │       │   ├── minify.spec.ts
│   │       │   └── utils.spec.ts
│   │       ├── htmlPlugin.ts
│   │       ├── index.ts
│   │       ├── minifyHtml.ts
│   │       ├── typing.ts
│   │       └── utils/
│   │           ├── createHtmlFilter.ts
│   │           └── index.ts
│   └── playground/
│       ├── basic/
│       │   ├── basic.html
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── public/
│       │   │   └── inject.js
│       │   ├── server.js
│       │   ├── src/
│       │   │   ├── App.vue
│       │   │   ├── main.ts
│       │   │   └── test.vue
│       │   └── vite.config.ts
│       ├── custom-entry/
│       │   ├── package.json
│       │   ├── public/
│       │   │   └── inject.js
│       │   ├── src/
│       │   │   ├── App.vue
│       │   │   ├── main.ts
│       │   │   └── test.vue
│       │   ├── static/
│       │   │   └── index.html
│       │   └── vite.config.ts
│       └── mpa/
│           ├── index.html
│           ├── other.html
│           ├── package.json
│           ├── public/
│           │   └── inject.js
│           ├── src/
│           │   ├── App.vue
│           │   ├── main.ts
│           │   ├── other-app.vue
│           │   ├── other-main.ts
│           │   └── test.vue
│           └── vite.config.ts
├── pnpm-workspace.yaml
├── tsconfig.json
└── vitest.config.ts
Download .txt
SYMBOL INDEX (26 symbols across 5 files)

FILE: packages/core/src/htmlPlugin.ts
  constant DEFAULT_TEMPLATE (line 15) | const DEFAULT_TEMPLATE = 'index.html'
  function getViteMajorVersion (line 20) | function getViteMajorVersion() {
  function createPlugin (line 24) | function createPlugin(userOptions: UserOptions = {}): PluginOption {
  function createInput (line 179) | function createInput(
  function renderHtml (line 214) | async function renderHtml(
  function getPage (line 247) | function getPage(
  function isMpa (line 261) | function isMpa(viteConfig: ResolvedConfig) {
  function removeEntryScript (line 266) | function removeEntryScript(html: string, verbose = false) {
  function createSpaPage (line 287) | function createSpaPage(
  function getPageConfig (line 300) | function getPageConfig(
  function getHtmlInPages (line 316) | function getHtmlInPages(page: PageOption, root: string) {
  function getHtmlPath (line 322) | function getHtmlPath(page: PageOption, root: string) {
  function readHtml (line 328) | async function readHtml(path: string) {
  function createRewire (line 335) | function createRewire(

FILE: packages/core/src/index.ts
  function createHtmlPlugin (line 9) | function createHtmlPlugin(

FILE: packages/core/src/minifyHtml.ts
  function getOptions (line 7) | function getOptions(minify: boolean): MinifyOptions {
  function minifyHtml (line 20) | async function minifyHtml(
  function createMinifyHtmlPlugin (line 37) | function createMinifyHtmlPlugin({

FILE: packages/core/src/typing.ts
  type Entry (line 5) | type Entry = string | Record<string, string>
  type InjectOptions (line 7) | interface InjectOptions {
  type PageOption (line 21) | interface PageOption {
  type Pages (line 28) | type Pages = PageOption[]
  type UserOptions (line 30) | interface UserOptions {

FILE: packages/core/src/utils/index.ts
  function loadEnv (line 6) | function loadEnv(
  function lookupFile (line 53) | function lookupFile(
  function isDirEmpty (line 70) | async function isDirEmpty(dir: string) {
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (65K chars).
[
  {
    "path": ".commitlintrc.json",
    "chars": 53,
    "preview": "{\n  \"extends\": [\"@commitlint/config-conventional\"]\n}\n"
  },
  {
    "path": ".editorconfig",
    "chars": 330,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_siz"
  },
  {
    "path": ".eslintignore",
    "chars": 18,
    "preview": "dist\nnode_modules\n"
  },
  {
    "path": ".eslintrc.json",
    "chars": 523,
    "preview": "{\n  \"root\": true,\n  \"env\": {\n    \"browser\": true,\n    \"es2021\": true,\n    \"es6\": true,\n    \"node\": true\n  },\n  \"extends\""
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 904,
    "preview": "name: Npm Publish\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  publish-npm:\n    if: \"contains(github.event.head_comm"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 643,
    "preview": "name: Create Release\n\non:\n  push:\n    tags:\n      - v*\n\njobs:\n  build:\n    name: Create Release\n    runs-on: ${{matrix.o"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 708,
    "preview": "name: Test\n\non:\n  push:\n    branches:\n      - main\n\n  pull_request:\n    branches:\n      - main\n\njobs:\n  build:\n    runs-"
  },
  {
    "path": ".gitignore",
    "chars": 17,
    "preview": "node_modules\ndist"
  },
  {
    "path": ".husky/commit-msg",
    "chars": 116,
    "preview": "#!/bin/sh\n\n# shellcheck source=./_/husky.sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx --no-install commitlint --edit \"$1\"\n"
  },
  {
    "path": ".husky/common.sh",
    "chars": 179,
    "preview": "#!/bin/sh\ncommand_exists () {\n  command -v \"$1\" >/dev/null 2>&1\n}\n\n# Workaround for Windows 10, Git Bash and Yarn\nif com"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 205,
    "preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n. \"$(dirname \"$0\")/common.sh\"\n\n[ -n \"$CI\" ] && exit 0\n\n# Format and submit code"
  },
  {
    "path": ".npmrc",
    "chars": 58,
    "preview": "ignore-workspace-root-check=true\npublic-hoist-pattern[]=*\n"
  },
  {
    "path": ".prettierrc.json",
    "chars": 106,
    "preview": "{\n  \"semi\": false,\n  \"tabWidth\": 2,\n  \"singleQuote\": true,\n  \"printWidth\": 80,\n  \"trailingComma\": \"all\"\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 266,
    "preview": "{\n  \"recommendations\": [\n    \"octref.vetur\",\n    \"dbaeumer.vscode-eslint\",\n    \"stylelint.vscode-stylelint\",\n    \"esbenp"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 2696,
    "preview": "{\n  \"typescript.tsdk\": \"./node_modules/typescript/lib\",\n  \"typescript.enablePromptUseWorkspaceTsdk\": true,\n  //========="
  },
  {
    "path": "CHANGELOG.md",
    "chars": 6686,
    "preview": "# [3.2.1](https://github.com/vbenjs/vite-plugin-html/compare/v3.0.6...v3.2.1) (2023-12-26)\n\n### Features\n\n- support vite"
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2020-present, Vben\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
  },
  {
    "path": "README.md",
    "chars": 6129,
    "preview": "# vite-plugin-html\n\n**English** | [中文](./README.zh_CN.md)\n\n## Features\n\n- HTML compression capability\n- EJS template cap"
  },
  {
    "path": "README.zh_CN.md",
    "chars": 5283,
    "preview": "# vite-plugin-html\n\n**中文** | [English](./README.md)\n\n[![npm][npm-img]][npm-url] [![node][node-img]][node-url]\n\n## 功能\n\n- "
  },
  {
    "path": "package.json",
    "chars": 1720,
    "preview": "{\n  \"name\": \"vite-plugin-html-monorepo\",\n  \"version\": \"3.2.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"stub\": \"pnpm run p"
  },
  {
    "path": "packages/core/build.config.ts",
    "chars": 183,
    "preview": "import { defineBuildConfig } from 'unbuild'\n\nexport default defineBuildConfig({\n  clean: true,\n  entries: ['./src/index'"
  },
  {
    "path": "packages/core/package.json",
    "chars": 1738,
    "preview": "{\n  \"name\": \"vite-plugin-html\",\n  \"version\": \"3.2.2\",\n  \"description\": \"A plugin for vite to Minimize index.html and use"
  },
  {
    "path": "packages/core/src/__tests__/html.spec.ts",
    "chars": 1334,
    "preview": "import { createPlugin, createSpaPage, renderHtml } from '../htmlPlugin'\nimport { describe, test, expect } from 'vitest'\n"
  },
  {
    "path": "packages/core/src/__tests__/minify.spec.ts",
    "chars": 1985,
    "preview": "import { createMinifyHtmlPlugin, minifyHtml } from '../minifyHtml'\nimport { describe, test, expect } from 'vitest'\n\ncons"
  },
  {
    "path": "packages/core/src/__tests__/utils.spec.ts",
    "chars": 705,
    "preview": "import { describe, test, expect } from 'vitest'\nimport { htmlFilter } from '../utils/createHtmlFilter'\n\ndescribe('utils "
  },
  {
    "path": "packages/core/src/htmlPlugin.ts",
    "chars": 9565,
    "preview": "import type { ResolvedConfig, PluginOption } from 'vite'\nimport type { InjectOptions, PageOption, Pages, UserOptions } f"
  },
  {
    "path": "packages/core/src/index.ts",
    "chars": 400,
    "preview": "import type { PluginOption } from 'vite'\nimport type { UserOptions } from './typing'\nimport { createPlugin } from './htm"
  },
  {
    "path": "packages/core/src/minifyHtml.ts",
    "chars": 1538,
    "preview": "import type { PluginOption } from 'vite'\nimport type { UserOptions } from './typing'\nimport type { Options as MinifyOpti"
  },
  {
    "path": "packages/core/src/typing.ts",
    "chars": 1039,
    "preview": "import type { Options as EJSOptions } from 'ejs'\nimport type { Options as MinifyOptions } from 'html-minifier-terser'\nim"
  },
  {
    "path": "packages/core/src/utils/createHtmlFilter.ts",
    "chars": 106,
    "preview": "import { createFilter } from '@rollup/pluginutils'\n\nexport const htmlFilter = createFilter(['**/*.html'])\n"
  },
  {
    "path": "packages/core/src/utils/index.ts",
    "chars": 1934,
    "preview": "import { expand } from 'dotenv-expand'\nimport dotenv from 'dotenv'\nimport { join, dirname } from 'pathe'\nimport fse from"
  },
  {
    "path": "packages/playground/basic/basic.html",
    "chars": 433,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <meta name="
  },
  {
    "path": "packages/playground/basic/index.html",
    "chars": 418,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <meta name="
  },
  {
    "path": "packages/playground/basic/package.json",
    "chars": 379,
    "preview": "{\n  \"name\": \"playground-basic\",\n  \"version\": \"0.0.1\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\"\n  },\n "
  },
  {
    "path": "packages/playground/basic/public/inject.js",
    "chars": 36,
    "preview": "console.log('inject successfully!')\n"
  },
  {
    "path": "packages/playground/basic/server.js",
    "chars": 912,
    "preview": "const http = require('http')\nconst { URL } = require('url')\n\nconst port = 8080\n\nconst server = http.createServer((req, r"
  },
  {
    "path": "packages/playground/basic/src/App.vue",
    "chars": 88,
    "preview": "<template>\n  <div>\n    hello world\n    <router-view></router-view>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/playground/basic/src/main.ts",
    "chars": 483,
    "preview": "import { createApp } from 'vue'\nimport App from './App.vue'\nimport { createRouter, createWebHashHistory } from 'vue-rout"
  },
  {
    "path": "packages/playground/basic/src/test.vue",
    "chars": 26,
    "preview": "<template>test</template>\n"
  },
  {
    "path": "packages/playground/basic/vite.config.ts",
    "chars": 624,
    "preview": "import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport { createHtmlPlugin } from 'vite-plugin-h"
  },
  {
    "path": "packages/playground/custom-entry/package.json",
    "chars": 355,
    "preview": "{\n  \"name\": \"playground-entry\",\n  \"version\": \"0.0.1\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\"\n  },\n "
  },
  {
    "path": "packages/playground/custom-entry/public/inject.js",
    "chars": 36,
    "preview": "console.log('inject successfully!')\n"
  },
  {
    "path": "packages/playground/custom-entry/src/App.vue",
    "chars": 88,
    "preview": "<template>\n  <div>\n    hello world\n    <router-view></router-view>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/playground/custom-entry/src/main.ts",
    "chars": 393,
    "preview": "import { createApp } from 'vue'\nimport App from './App.vue'\nimport { createRouter, createWebHashHistory } from 'vue-rout"
  },
  {
    "path": "packages/playground/custom-entry/src/test.vue",
    "chars": 39,
    "preview": "<template>test-custom-entry</template>\n"
  },
  {
    "path": "packages/playground/custom-entry/static/index.html",
    "chars": 363,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <meta name="
  },
  {
    "path": "packages/playground/custom-entry/vite.config.ts",
    "chars": 570,
    "preview": "import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport { createHtmlPlugin } from 'vite-plugin-h"
  },
  {
    "path": "packages/playground/mpa/index.html",
    "chars": 364,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <meta name="
  },
  {
    "path": "packages/playground/mpa/other.html",
    "chars": 360,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <meta name="
  },
  {
    "path": "packages/playground/mpa/package.json",
    "chars": 372,
    "preview": "{\n  \"name\": \"playground-map\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"v"
  },
  {
    "path": "packages/playground/mpa/public/inject.js",
    "chars": 36,
    "preview": "console.log('inject successfully!')\n"
  },
  {
    "path": "packages/playground/mpa/src/App.vue",
    "chars": 79,
    "preview": "<template>\n  <div>hello world</div>\n\n  <router-view></router-view>\n</template>\n"
  },
  {
    "path": "packages/playground/mpa/src/main.ts",
    "chars": 390,
    "preview": "import { createApp } from 'vue'\nimport App from './App.vue'\nimport { createRouter, createWebHistory } from 'vue-router'\n"
  },
  {
    "path": "packages/playground/mpa/src/other-app.vue",
    "chars": 103,
    "preview": "<template>\n  <div>\n    <div>hello world app</div>\n    <router-view></router-view>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/playground/mpa/src/other-main.ts",
    "chars": 337,
    "preview": "import { createApp } from 'vue'\nimport App from './other-app.vue'\nimport { createRouter, createWebHashHistory } from 'vu"
  },
  {
    "path": "packages/playground/mpa/src/test.vue",
    "chars": 26,
    "preview": "<template>test</template>\n"
  },
  {
    "path": "packages/playground/mpa/vite.config.ts",
    "chars": 1360,
    "preview": "import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport { createHtmlPlugin } from 'vite-plugin-h"
  },
  {
    "path": "pnpm-workspace.yaml",
    "chars": 51,
    "preview": "packages:\n  - packages/*\n  - packages/playground/*\n"
  },
  {
    "path": "tsconfig.json",
    "chars": 421,
    "preview": "{\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"target\": \"es2017\",\n    \"moduleResolution\": \"node\",\n    \"strict\": t"
  },
  {
    "path": "vitest.config.ts",
    "chars": 103,
    "preview": "/// <reference types=\"vitest\" />\n\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({})\n"
  }
]

About this extraction

This page contains the full source code of the vbenjs/vite-plugin-html GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (56.1 KB), approximately 17.5k tokens, and a symbol index with 26 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!