javascriptreactjsvite

Custom URL in Vite dev server (multi page app)


I'm building a multi page app with Vite (migrating from Webpack).

To open the login page in the dev server I have to go to: localhost:3010/login.html

Is it possible to tweak the Vite config to serve login.html with the URL as: localhost:3010/login (without .html)?

// vite.config.js excerpt

export default {
  build: {
    rollupOptions: {
      input: {
        index: new URL('./index.html', import.meta.url).pathname,
        login: new URL('./login.html', import.meta.url).pathname,
      }
    }
  },
  server: {
    port: 3010,
    proxy: {
      '/api': 'http://localhost:5000/',
    },
  },
};

Solution

  • Configure the Vite dev server with a Vite plugin's configureServer(server) API. That method's server argument is a ViteDevServer, whose middlewares property is the underlying Connect instance. Call middlewares.use() with a method that acts as a custom middleware.

    Here's a basic plugin that configures the dev server to replace /login with /login.html, added to the plugins array in the Vite config:

    import { defineConfig } from 'vite'
    
    const LoginHtmlFallbackPlugin = {
      name: 'login-html-fallback',
      configureServer(server) {
        server.middlewares.use('/login', (req, res, next) => {
          req.url += '.html'
          next()
        })
      }
    }
    
    export default defineConfig({
      plugins: [
        LoginHtmlFallbackPlugin
      ],
    })
    

    demo 1

    And a more dynamic plugin that falls back to a corresponding .html file (appending .html to extension-less URLs) only if it exists:

    // build/plugins/html-ext-fallback.js
    import path from 'path'
    import fs from 'fs'
    
    export default (options) => ({
      name: 'html-ext-fallback',
      configureServer(server) {
        server.middlewares.use((req, res, next) => {
          // Check extensionless URLs but ignore the `/` root path
          if (req.originalUrl.length > 1 && !path.extname(req.originalUrl)) {
            if (fs.existsSync(path.join(options.rootDir, `${req.originalUrl}.html`))) {
              req.url += '.html'
            }
          }
          next()
        })
      }
    })
    
    // vite.config.js
    import { defineConfig } from 'vite'
    import HtmlExtFallbackPlugin from './build/plugins/html-ext-fallback'
    
    export default defineConfig({
      plugins: [
        HtmlExtFallbackPlugin({ rootDir: __dirname })
      ],
    })
    

    demo 2