Out-of-the-box MPA plugin for Vite, with html template engine and virtual files support.

Overview

vite-plugin-virtual-mpa

Out-of-the-box MPA plugin for Vite, with html template engine and virtual files support, generate multiple files using only one template

English | 中文

Features

  • EJS template capability
  • Multi-page-application support, handle history fallback during development
  • Customize the path of generated files, generate multiple files using only one template

Motivation

When building MPA(multi-page-applications) with Vite, we usually need a plugin that:

  1. Has a template engine such as EJS, which can use one template to generate multiple files, and can customize the path of the generated files at build time.

  2. Auto configurations for rollupOptions.input and provide the ability to configure the development server's proxy (primarily the History Fallback API).

There are so many MPA plugins for vite on the market, but it seems no one can do both of above at the same time. I filtered the following plugins based on name matching and downloads:

  1. vite-plugin-mpa: It can automatically configure the entry and provide the DevServer proxy configuration (history fallback), but we must adjust the directory structure according to the convention, and does not support template engines and virtual entry, and cannot define the path to generate files.

  2. vite-plugin-html-template: The author of this plugin is the same as vite-plugin-mpa, which is recommended by the author. It is primarily used in combination with the MPA plugin to provide template engine functionality, and also doesn't support virtual entry.

  3. vite-plugin-html: It supports template engines only, but no virtual entry. You need to use multiple entry templates if you want to generate multiple files.

  4. vite-plugin-virtual-html: It supports virtual entry points, provides a rendering interface to customize template engines. But there's no built-in template engine, so it's a bit cumbersome to use.

Here, "virtual entry" means that multiple entry HTML files are rendered through only one template file.

They have their strengths, but they don't work very well. Either it needs to be used in conjunction or it is a significant change to the existing project structure. Sometimes I wonder if it is losing the advantage of template by implementing a template engine but requiring multiple template files.

This plugin is designed to solve these problems, and it has all of these capabilities at the same time. By combining virtual entry and template engine, users can generate different entry HTML with only one template, and can customize the output path of the entry file (no need to manually write scripts to move!). It also provides an interface to configure rewrite rules for the development server, so that the development can correctly request the entry file.

If your project is using Vite workflow and is an MPA application, you may want to give this plugin a try. It doesn't limit the technology stack, it doesn't matter if you use Vue or React or any other technologies.

Usage

pnpm add -D vite-plugin-virtual-mpa # or npm/yarn
// vite.config.ts
import { createMpaPlugin } from 'vite-plugin-virtual-mpa'

// @see https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    createMpaPlugin({
      pages: [
        // your configuration
      ]
    }),
  ],
})

Options

interface MpaOptions {
  /**
   * whether to print log
   * @default true
   */
  verbose?: boolean,
  /**
   * default template file
   * @default index.html
   */
  template?: `${string}.html`,
  /**
   * Configure your rewrite rules, only proceed html requests.
   * further: https://github.com/bripkens/connect-history-api-fallback
   */
  rewrites?: Rewrite[],
  /**
   * your MPA core configurations
   */
  pages: Array<{
    /**
     * Required page name.
     */
    name: string;
    /**
     * Relative path to the output directory, which should end with .html
     * @default `${name}.html`
     */
    filename?: `${string}.html`;
    /**
     * Higher priority template file, which will overwrite the default template.
     */
    template?: string;
    /**
     * Entry file that will append to body. which you should remove from the html template file.
     */
    entry?: string;
    /**
     * Data to inject with ejs.
     */
    data?: Record<string, any>,
  }>
}

Examples

// vite.config.ts
import { createMpaPlugin } from 'vite-plugin-virtual-mpa'

// @see https://vitejs.dev/config/
export default defineConfig({
  base: '/fruits/',
  build: {
    outDir: 'sites'
  },
  plugins: [
    createMpaPlugin({
      // Customize the history fallback rewrite rules
      rewrites: [
        {
          from: /\/fruits\/(apple|banana|strawberries)/, 
          to: ctx => `/fruits/${ctx.match[1]}.html`
        },
      ],
      pages: [
        {
          name: 'apple',
          // filename is optional, default is apple.html, which is relative path of `build.outDir`.
          filename: 'fruits/apple.html', // output into sites/fruits/apple.html at build time.
          data: {
            title: 'This is Apple page',
          },
        },
        {
          name: 'banana',
          filename: 'fruits/banana.html',
          data: {
            title: 'This is Banana page',
          },
        },
        {
          name: 'strawberries',
          filename: 'fruits/strawberries.html',
          data: {
            title: 'This is Strawberries page',
          },
        },
      ],
    }),
  ],
})
You might also like...

CLI utility that parses argv, loads your specified file, and passes the parsed argv into your file's exported function. Supports ESM/TypeScript/etc out of the box.

cleffa CLI tool that: Parses argv into an object (of command-line flags) and an array of positional arguments Loads a function from the specified file

Mar 6, 2022

Scaffold a full-stack SvelteKit application with tRPC and WindiCSS out of the box

create-sweet-app Interactive CLI to quickly set up an opinionated, full-stack, typesafe SvelteKit project. Inspired by the T3 Stack and create-t3-app

Dec 16, 2022

Cross provider map drawing library, supporting Mapbox, Google Maps and Leaflet out the box

Terra Draw Frictionless map drawing across mapping providers. TerraDraw centralises map drawing logic and provides a host of out the box drawing modes

Dec 31, 2022

FortuneSheet is an online spreedsheet component library that provides out-of-the-box features just like Excel

FortuneSheet FortuneSheet is an online spreedsheet component library that provides out-of-the-box features just like Excel English | 简体中文 Purpose The

Jan 3, 2023

Query for CSS brower support data, combined from caniuse and MDN, including version support started and global support percentages.

css-browser-support Query for CSS browser support data, combined from caniuse and MDN, including version support started and global support percentage

Nov 2, 2022

TS & JS Library for adaptive precision cursor for the web. Releases will come out soon! Meanwhile, check out the demo site:

Haha, cool cursor go brrrr... Table of Content What is this? Installation & Setup Installation Setup Usage Cursor controls Element settings Known issu

Nov 24, 2022

Small library for making box selections on HTML elements in JavaScript

Small library for making box selections on HTML elements in JavaScript

Box Selection Small JavaScript library for making box selections on HTML elements. Makes use of CSS transforms so there is no paint flashing. Installa

Oct 28, 2021

Turn an HTML input box to a duration picker, without jQuery

html-duration-picker.js html-duration-picker.js is a very tiny JS library used for transforming a native HTML text input into a duration picker. The a

Oct 19, 2022

The project integrates workflow engine, report engine and organization authority management background, which can be applied to the development of OA, HR, CRM, PM and other systems. With tlv8 IDE, business system development, testing and deployment can be realized quickly.

The project integrates workflow engine, report engine and organization authority management background, which can be applied to the development of OA, HR, CRM, PM and other systems. With tlv8 IDE, business system development, testing and deployment can be realized quickly.

介绍 项目集成了工作流引擎、报表引擎和组织机构权限管理后台,可以应用于OA、HR、CRM、PM等系统开发。配合使用tlv8 ide可以快速实现业务系统开发、测试、部署。 后台采用Spring MVC架构简单方便,前端使用流行的layui界面美观大方。 采用组件开发技术,提高系统的灵活性和可扩展性;采

Dec 27, 2022
Comments
  • hot reload pages

    hot reload pages

    First off- thank you for all of your work on this! Exactly what I needed.

    My use-case is pretty simple. I'm writing a static site and trigger a reload when a markdown file changes.

    When this happens, I need to reload the pages. Any ideas on how we might be able to either A) reload the plugin or B) reload the pages without restarting the whole server?

    Example code:

    import { resolve } from 'path';
    import { createMpaPlugin } from 'vite-plugin-virtual-mpa'
    import { defineConfig } from 'vite'
    import { buildBlogContentTree } from './gen'
    import shiki from 'shiki'
    import markdownIt from 'markdown-it';
    
    
    
    export default async () => {
      // load syntax highlighter
      const parser = await shiki.getHighlighter({
        theme: 'nord',
        langs: [
          'html', 'css', 'javascript', 'typescript',
          'go', 'ruby', 'lua',
          'vim',
        ]
      })
      // load markdown rendering engine
      let md = markdownIt({ html: true, highlight: (code, lang) => {
        return parser.codeToHtml(code, {lang})
      }})
    
      // build pages
      let pages = await buildBlogContentTree(md, 
        resolve(__dirname, 'content'),
        'blog.html'
      );
    
      return defineConfig({
        plugins: [
          //@ts-ignore
          HotReload(),
          createMpaPlugin({
            verbose: true,
            //@ts-ignore
            pages: pages,
            rewrites: [
              {
                from: /\/(.*.html)/,
                to: (ctx) => `/${!ctx.match[1] ? "index" : ctx.match[1]}.html`,
              },
            ],
          }),
        ]
      })
    }
    
    // determines if we should reload
    function HotReload() {
      return {
        name: 'custom-hmr',
        enforce: 'post',
    
        // HMR
        handleHotUpdate({ file, server }) {
          if (shouldReload(file)) {
            // restart the server is a page has changed
            if(file.endsWith(".md")) server.restart()
    
            server.ws.send({
              type: 'full-reload',          
              path: '*'
            });
          }
        },
      }
    }
    
    const shouldReload = (file: string): boolean => {
      return file.endsWith('.html') || 
        file.endsWith('.js') || 
        file.endsWith('.css') ||
        file.endsWith('.md')
    }
    
    opened by jalevin 10
  • How to create nested page?

    How to create nested page?

    image

    config

    import { defineConfig } from "vite";
    import { swcReactRefresh } from "vite-plugin-swc-react-refresh";
    import svgr from "vite-plugin-svgr";
    import { createMpaPlugin } from "vite-plugin-virtual-mpa";
    import { readdir } from "fs/promises";
    
    const pagesDir = "./pages";
    
    const getPages = async (path: string) => {
      const data = await readdir(path, { withFileTypes: true });
      const pages = [];
      for (const stats of data) {
        if (stats.isFile() && stats.name === "_entry.tsx") {
          pages.push({
            name: path.replace(pagesDir, "").replace("/", ""),
            entry: path + "/" + stats.name,
          });
        } else if (stats.isDirectory()) {
          const newPages = await getPages(path + "/" + stats.name);
          pages.push(...newPages);
        }
      }
      return pages;
    };
    
    export default defineConfig({
      plugins: [
        swcReactRefresh(),
        svgr(),
        createMpaPlugin({
          template: "public/index.html",
          rewrites: [
            {
              from: /\/(.*)/,
              to: (ctx) => `/${!ctx.match[1] ? "index" : ctx.match[1]}.html`,
            },
          ],
          pages: await getPages(pagesDir),
        }),
      ],
      esbuild: { jsx: "automatic" },
    });
    
    opened by fax1ty 4
  • 如何添加自定义的meta

    如何添加自定义的meta

    期望: createMpaPlugin({ pages: [ { name: 'lucky-draw', filename: 'lucky-draw/index.html', entry: /src/pages/lucky-draw/main.ts, data: { title: '抽奖活动123', meta: 'width=device-width,initial-scale=1.0,user-scalable=no,minimum-scale=1,maximum-scale=1', }, }, ], }) 通过添加meta标签注入到模版中

    opened by sendking 1
Zemi is data-driven and reverse-routing library for Express. It provides out-of-the-box OpenAPI support, allowing you to specify and autogenerate an OpenAPI spec.

zemi zemi is a data-driven routing library for Express, built with Typescript. Features: optional, out-of-the-box support for OpenAPI reverse-routing

Yoaquim Cintrón 5 Jul 23, 2022
Custom alert box using javaScript and css. This plugin will provide the functionality to customize the default JavaScript alert box.

customAlertBoxPlugin Custom Alert Box Plugin Using JavaScript and CSS Author: Suraj Aswal Must Include CSS Code/Default Custom Alert Box Class: /* mus

Suraj Aswal 17 Sep 10, 2022
Used for creating a out-of-the-box template without additional configuration.

ou Used for creating a out-of-the-box template without additional configuration. Templates Vue3 Lite Template Used for some simple web app Vue3 + Vite

Dewey Ou 6 Jul 17, 2022
Build forms from JSON Schema. Easily template-able. Compatible with Bootstrap 3 out of the box.

JSON Form The JSON Form library is a JavaScript client-side library that takes a structured data model defined using JSON Schema as input and returns

null 2.6k Dec 28, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Vite plugin to client bundle i18next locales composited from one to many json/yaml files from one to many libraries. Zero config HMR support included.

vite-plugin-i18next-loader yarn add -D vite-plugin-i18next-loader Vite plugin to client bundle i18next locales composited from one to many json/yaml f

AlienFast 4 Nov 30, 2022
mini vite, support static server, load ts files, pre-bundling.

Mini Vite 中文 Features Same structure with Vite. Support JS, TS, JSX, TSX, CSS, static files. Support public as public directory. Dependency Pre-Bundli

mysteryven 4 Sep 15, 2022
Add aliasing support to Vite from tsconfig.json or jsconfig.json files

Config to Alias Config to Alias adds aliasing support to Astro, JavaScript, TypeScript, and CSS files. Usage Install Config to Alias. npm install @ast

Astro Community 4 Mar 17, 2023