npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vite-plugin-page-html

v2.2.0

Published

A simple and flexible Vite plugin for processing html, Support EJS and multi-page. 灵活处理html的Vite插件,支持EJS和多页应用。

Downloads

46

Readme

vite-plugin-page-html

English | 中文

A simple and flexible vite plugin for processing html. Support EJS template syntax and multi-page configuration, can specify html file directory and access URL, Similar to the pages option of vue-cli.

Examples: React 】 - 【 Vue@3 】 - 【 Vue@2 】 - 【 Svelte

Features

  • 📚 Multi-page/Single-page application support
  • 📡 Html entry alias (custom url)
  • 📊 Support custom template
  • 🔑 Support custom entry
  • 🗳 EJS template capability
  • 🔗 External library import (CDN)
  • 🗜 HTML compression capability

Why ?

Although Vite supports multi-page applications natively, it requires html as entry, which means there must be these html.

If you put html in other directory, you need to add useless directories when accessing. There are also useless directories after build.

Although there are plug-ins that can solve these problems, but after using it, it can not satisfy my project, so I developed this plug-in vite-plugin-page-html.

Added: The vite-plugin-html plugin was not found while developing.

Install

  • node >= 14.x
  • vite >= 2.x
npm install -D vite-plugin-page-html

Usage

Add EJS tags to html, such as index.html

Tip: If entry is configured in vite.config.js, you need to delete the script tag in the html.

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge,chrome=1">
    <meta name="renderer" content="webkit">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="format-detection" content="telphone=no">
    <title><%= pageHtmlVitePlugin.title %></title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link rel="shortcut icon" href="<%= BASE_URL %>favicon.ico" type="image/x-icon">
    <!-- injectStyle -->
    <%- pageHtmlVitePlugin.data.injectStyle %>
  </head>
  <body>
    <div id="app"></div>

    <% if(DEV) { %>
    <script src="/path/development-only-script.js"></script>
    <% } %>

    <% for (var i in pageHtmlVitePlugin.data.scripts) { %>
    <script src="<%= pageHtmlVitePlugin.data.scripts[i] %>"></script>
    <% } %>

    <!-- injectScript -->
    <%- pageHtmlVitePlugin.data.injectScript %>
  </body>
</html>

SPA

Single-page application configuration, in vite.config.js you can configure access url, entry and template.

// vite.config.js
import PageHtml from 'vite-plugin-page-html'

export default defineConfig({
  plugins: [
    // ... plugins
    PageHtml({
      /**
       * Visit URL. e.g. `page/about`
       * @default 'index'
       */
      page: 'index',
      /**
       * The entry file, after configuration, you will need to delete the script tag in index.html
       */
      entry: 'src/main.js',
      /**
       * Specify the folder path of the html file
       * @default index.html 
       */
      template: 'src/index.html',
      title: 'Vue App',
      minify: false,
      /**
       * Data injected into the index.html ejs template
       */
      inject: {
        data: {
          injectStyle: `<script src="./inject.css"></script>`,
          injectScript: `<script src="./inject.js"></script>`,
          scripts: ['https://cdnjs.com/lodash/index.js']
        },
        tags: [
          {
            injectTo: 'body-prepend',
            tag: 'div',
            attrs: {
              id: 'inject',
            }
          }
        ]
      }
    })
  ]
})

MPA

Multi-page application configuration, you can specify the access URL through the key of the page object, other configurations are the same as single page.

// vite.config.js
import PageHtml from 'vite-plugin-page-html'

export default defineConfig({
  plugins: [
    // ... plugins
    PageHtml({
      template: 'src/index.html',
      minify: true,
      inject: {
        data: {
          injectStyle: `<script src="./inject.css"></script>`
        }
        tags: [
          {
            injectTo: 'body-prepend',
            tag: 'div',
            attrs: {
              id: 'inject',
            }
          }
        ]
      },
      page: {
        index: 'src/main.js',
        about: {
          entry: 'src/about/main.js',
          title: 'About Page',
        },
        'product/list': {
          entry: 'src/product/main.js',
          template: 'src/product/index.html', 
          title: 'Product list',
          /**
           * Override global inject data
           */
          inject: {
            data: {
              injectStyle: `<script src="./product.css"></script>`
            },
            tags: []
          }
        }
      }
    })
  ]
})

After starting the dev server, browse:

  • http://localhost:3000/index.html
    Use src/index.html as the template and src/main.js as the entry.
  • http://localhost:3000/about.html
    Use src/index.html as the template and src/about/main.js as the entry.
  • http://localhost:3000/product/list.html
    Use src/product/index.html as the template and src/product/main.js as the entry.

The URL structure after the project is constructed is the same as that during development:

├── dist
│   ├── assets
│   ├── favicon.ico
│   ├── index.html
│   ├── about.html
│   ├── product
│   │   └── list.html
│   └──

Configuration

PageHtml(/* Options */)

Options

PageHtml({
  page: string | PageConfig;
  entry?: string;
  template?: string;
  title?: string;
  minify?: boolean | MinifyOptions;
  ejsOptions?: EjsOptions;
  inject?: InjectOptions;
})

| property | default | description | | ------------ | ------------- | --------------------------------------------------------------------------------------------------------------- | | page | index | requred page configuration. If string, the value is the page path.PageConfig @See。 | | entry | src/main.js | entry file path. WARNING: The entry entry will be automatically written to html. | | template | index.html | template file path.(global) | | title | - | page title(global) | | minify | false | Compressed file. MinifyOptions @See | | ejsOptions | - | ejs options, @See | | inject | - | Data injected into HTML. (global) InjectOptions @see |

🚨 WARNING: The entry file has been written to html, you don't need to write it again.

InjectOptions

interface InjectOptions {
  /**
   * @see https://cn.vitejs.dev/guide/api-plugin.html#vite-specific-hooks
   */
  tags?: HtmlTagDescriptor[],
  /**
   * page data. Rendering via `ejs` : `<%= pageHtmlVitePlugin.data %>`
   */
  data?: Record<string, any>
}

interface HtmlTagDescriptor {
  tag: string
  attrs?: Record<string, string>
  children?: string | HtmlTagDescriptor[]
  /**
   * 默认: 'head-prepend'
   */
  injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend'
}

| property | type | default | description | | -------- | --------------------- | ------- | -------------------------------------------------------------------- | | tags | HtmlTagDescriptor[] | [] | List of tags to inject. HtmlTagDescriptor | | data | object | - | page data Rendering via ejs : <%= pageHtmlVitePlugin.data %> |

PageConfig

{
  [path: string]: string | PageOptions;
}

| property | default | description | | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | path | - | Single page configuration.1. path as output. 2. If value is string, it is the entry file. 3. PageOptions @See。 |

PageOptions

{
  entry: string;
  template?: string;
  title?: string;
  inject?: InjectOptions;
}

| property | default | description | | ---------- | ------------ | --------------------------------------------------------------- | | entry | - | required entry file | | template | index.html | template. Defaults is global template | | title | - | title. Defaults is global title | | inject | - | Data injected into HTML. InjectOptions @see |

Externals

When we optimize the project build, we generally introduce commonly used external libraries through external links (CDN). This reduces build times and improves page load times in production.

Currently, output.globals is only used if format is iife or umd. If format is es and we want to map the external module to a global variable, we usually solve it with a third-party plugin.

I recommend rollup-plugin-external-globals and vite-plugin-externals .

Next, we combine rollup-plugin-external-globals to implement the production environment and import the cdn file.

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><%= pageHtmlVitePlugin.title %></title>
    
    <% for (var i in pageHtmlVitePlugin.data.styles) { %>
    <link rel="stylesheet" href="<%= pageHtmlVitePlugin.data.styles[i] %>">
    <% } %>
  </head>
  <body>
    <div id="app"></div>
    <% if(PROD) { %>
      <% for (var i in pageHtmlVitePlugin.data.scripts) { %>
      <script src="<%= pageHtmlVitePlugin.data.scripts[i] %>"></script>
      <% } %>
    <% } %>
  </body>
</html>
// vite.config.js

import { defineConfig } from 'vite'
import PageHtml from 'vite-plugin-page-html'
import externalGlobals from 'rollup-plugin-external-globals'

export default defineConfig(({ command, mode }) => {
  // ...
  plugins: [
    // ... plugins
    PageHtml({
      page: {
        'index': 'src/main.js',
        'about': {
          entry: 'src/about/main.js',
          title: 'about US'
        },
      },
      template: 'public/template.html',
      inject: {
        data: {
          styles: [
            'https://cdn.jsdelivr.net/npm/[email protected]/lib/theme-chalk/index.css'
          ],
          scripts: [
            'https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js',
            'https://cdn.jsdelivr.net/npm/[email protected]/lib/index.js',
            'https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js'
          ]
        }
      }
    })
  ],
  build: {
    rollupOptions: {
      plugins: [
        externalGlobals({
          'vue': 'Vue',
          'axios': 'axios',
          'element-ui': 'ELEMENT',
        })
      ]
    }
  }
})

Thanks

vite.jsejshtml-minifier-terser