import type { Plugin , ViteDevServer , ResolvedConfig } from 'vite' ; import type { UserOptions } from './lib/options' ; import path from 'path' ; import shell from 'shelljs' ; import { last } from 'lodash' ; import { getHtmlContent } from './lib/utils' ; import { name } from '../package.json' ; const resolve = ( p ) => path . resolve ( process . cwd ( ) , p ) ; const PREFIX = 'src' ; export default function htmlTemplate ( userOptions = { } ) { const options = { pagesDir : 'src/pages' , pages : { } , data : { } , ... userOptions , } ; let config ; return { name , configResolved ( resolvedConfig ) { config = resolvedConfig ; } , /**
         * for dev
         * if SPA, just use template and write script main.{js,ts} for /{entry}.html
         * if MPA, check pageName(default is index) and write /${pagesDir}/{pageName}/${entry}.html
         */ configureServer ( server ) { return ( ) => { server . middlewares . use ( async ( req , res , next ) => { if ( ! req . url ?. endsWith ( '.html' ) && req . url !== '/' ) { return next ( ) ; } let url = req . url ; const pageName = ( ( ) => { if ( url === '/' ) { return 'index' ; } return url . match ( new RegExp ( `${ options . pagesDir }/(.*)/` ) ) ?. [ 1 ] || 'index' ; } ) ( ) ; const page = options . pages [ pageName ] || { } ; const templateOption = page . template ; const templatePath = templateOption ? resolve ( templateOption ) : resolve ( 'public/index.html' ) ; const isMPA = typeof config . build . rollupOptions . input !== 'string' && Object . keys ( config . build . rollupOptions . input || { } ) . length > 0 ; let content = await getHtmlContent ( { pagesDir : options . pagesDir , pageName , templatePath , pageEntry : page . entry || 'main' , pageTitle : page . title || 'Home Page' , isMPA , data : options . data , entry : options . entry || '/src/main' , extraData : { base : config . base , url , } , } ) ; content = await server . transformIndexHtml ?. ( url , content , req . originalUrl ) ; res . end ( content ) ; } ) ; } ; } , see https resolveId ( id ) { if ( id . endsWith ( '.html' ) ) { const isMPA = typeof config . build . rollupOptions . input !== 'string' && Object . keys ( config . build . rollupOptions . input || { } ) . length > 0 ; if ( ! isMPA ) { return `${ PREFIX }/${ path . basename ( id ) }` ; } else { const pageName = last ( path . dirname ( id ) . split ( '/' ) ) || '' ; if ( pageName in ( config . build . rollupOptions . input as any ) ) { return `${ PREFIX }/${ options . pagesDir . replace ( 'src/' , '' ) }/${ pageName }/index.html` ; } } } return null ; } , /** for dev */ load ( id ) { if ( id . startsWith ( PREFIX ) ) { const idNoPrefix = id . slice ( PREFIX . length ) ; const pageName = path . basename ( id ) . replace ( '.html' , '' ) ; const page = options . pages [ pageName ] || { } ; const templateOption = page . template ; const templatePath = templateOption ? resolve ( templateOption ) : resolve ( 'public/index.html' ) ; const isMPA = typeof config . build ?. rollupOptions . input !== 'string' && Object . keys ( config . build ?. rollupOptions . input || { } ) . length > 0 ; return getHtmlContent ( { pagesDir : options . pagesDir , pageName , templatePath , pageEntry : page . entry || 'main' , pageTitle : page . title || 'Home Page' , isMPA , extraData : { base : config . base , url : isMPA ? idNoPrefix : '/' , } , data : options . data , entry : options . entry || '/src/main' , } ) ; } return null ; } , /** for build */ closeBundle ( ) { const isMPA = typeof config . build ?. rollupOptions . input !== 'string' && Object . keys ( config . build ?. rollupOptions . input || { } ) . length > 0 ; if ( ! isMPA ) { const root = config . root || process . cwd ( ) ; const dest = ( config . build && config . build . outDir ) || 'dist' ; const resolve = ( p ) => path . resolve ( root , p ) ; shell . mv ( resolve ( `${ dest }/${ PREFIX }/*.html` ) , resolve ( dest ) ) ; shell . rm ( '-rf' , resolve ( `${ dest }/${ PREFIX }` ) ) ; } } , } ; } export type { UserOptions as HtmlTemplateOptions } ;