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
<%- title %>
<%- injectScript %>
```
- 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: ``,
},
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: ``,
},
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: ``,
},
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` | - | 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
<%- title %>
<%- injectScript %>
```
- 在 `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: ``,
},
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: ``,
},
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: ``,
},
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` | - | 注入的数据 |
| 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(
`
<%- title %>
<%- ENV_TITLE %>
`,
{
injectOptions: {
data: { title: 'test-title' },
},
viteConfig: {} as any,
env: {
ENV_TITLE: 'env-title',
},
},
)
expect(content).toEqual(`
test-title
env-title
`)
})
})
================================================
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: `
`,
},
}
await generate(null, testBundle, false)
expect(testBundle.test.source).toEqual(
``,
)
})
test('minify is true.', async () => {
const ret = await minifyHtml(
`
`,
true,
)
expect(ret).toEqual(``)
})
test('minify is false.', async () => {
const ret = await minifyHtml(
`
`,
false,
)
expect(ret).toEqual(
`
`,
)
})
test('minify css.', async () => {
const ret = await minifyHtml(
`
`,
true,
)
expect(ret).toEqual(
``,
)
})
test('custom minify options.', async () => {
const ret = await minifyHtml(
`
`,
{ minifyCSS: true },
)
expect(ret).toEqual(`
`)
})
})
================================================
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 = {}
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 = {}
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
entry?: string
verbose?: boolean
},
) {
const { injectOptions, viteConfig, env, entry, verbose } = config
const { data, ejsOptions } = injectOptions
const ejsData: Record = {
...(viteConfig?.env ?? {}),
...(viteConfig?.define ?? {}),
...(env || {}),
...data,
}
let result = await render(html, ejsData, ejsOptions)
if (entry) {
result = removeEntryScript(result, verbose)
result = result.replace(
bodyInjectRE,
`\n