import type * as d from '../declarations' ; import type { ServerResponse } from 'http' ; import * as util from './dev-server-utils' ; import { version } from '../version' ; import path from 'path' ; import fs from 'graceful-fs' ; import * as zlib from 'zlib' ; import { Buffer } from 'buffer' ; export async function serveFile ( devServerConfig , serverCtx , req , res ) { try { if ( util . isSimpleText ( req . filePath ) ) { let content = await serverCtx . sys . readFile ( req . filePath , 'utf8' ) ; if ( devServerConfig . websocket && util . isHtmlFile ( req . filePath ) && ! util . isDevServerClient ( req . pathname ) ) { content = appendDevServerClientScript ( devServerConfig , req , content ) ; } else if ( util . isCssFile ( req . filePath ) ) { content = updateStyleUrls ( req . url , content ) ; } if ( util . shouldCompress ( devServerConfig , req ) ) { res . writeHead ( 200 , util . responseHeaders ( { 'content-type' : util . getContentType ( req . filePath ) + '; charset=utf-8' , 'content-encoding' : 'gzip' , vary : 'Accept-Encoding' , } ) ) ; zlib . gzip ( content , { level : 9 } , ( _ , data ) => { res . end ( data ) ; } ) ; } else { res . writeHead ( 200 , util . responseHeaders ( { 'content-type' : util . getContentType ( req . filePath ) + '; charset=utf-8' , 'content-length' : Buffer . byteLength ( content , 'utf8' ) , } ) ) ; res . write ( content ) ; res . end ( ) ; } } else { res . writeHead ( 200 , util . responseHeaders ( { 'content-type' : util . getContentType ( req . filePath ) , 'content-length' : req . stats . size , } ) ) ; fs . createReadStream ( req . filePath ) . pipe ( res ) ; } serverCtx . logRequest ( req , 200 ) ; } catch ( e ) { serverCtx . serve500 ( req , res , e , 'serveFile' ) ; } } function updateStyleUrls ( url , oldCss ) { const versionId = url . searchParams . get ( 's-hmr' ) ; const hmrUrls = url . searchParams . get ( 's-hmr-urls' ) ; if ( versionId && hmrUrls ) { ( hmrUrls as string ) . split ( ',' ) . forEach ( ( hmrUrl ) => { urlVersionIds . set ( hmrUrl , versionId as string ) ; } ) ; } const reg = /url\((['"]?)(.*)\1\)/gi ; let result ; let newCss = oldCss ; while ( ( result = reg . exec ( oldCss ) ) !== null ) { const oldUrl = result [ 2 ] ; const parsedUrl = new URL ( oldUrl , url ) ; const fileName = path . basename ( parsedUrl . pathname ) ; const versionId = urlVersionIds . get ( fileName ) ; if ( ! versionId ) { continue ; } parsedUrl . searchParams . set ( 's-hmr' , versionId ) ; newCss = newCss . replace ( oldUrl , parsedUrl . pathname ) ; } return newCss ; } const urlVersionIds = new Map < string , string > ( ) ; export function appendDevServerClientScript ( devServerConfig , req , content ) { const devServerClientUrl = util . getDevServerClientUrl ( devServerConfig , req . headers ?. [ 'x-forwarded-host' ] ?? req . host , req . headers ?. [ 'x-forwarded-proto' ] ) ; const iframe = `<iframe title="Stencil Dev Server Connector ${ version } &#9889;" src="${ devServerClientUrl }" style="display:block;width:0;height:0;border:0;visibility:hidden" aria-hidden="true"></iframe>` ; return appendDevServerClientIframe ( content , iframe ) ; } export function appendDevServerClientIframe ( content , iframe ) { if ( content . includes ( '</body>' ) ) { return content . replace ( '</body>' , `${ iframe }</body>` ) ; } if ( content . includes ( '</html>' ) ) { return content . replace ( '</html>' , `${ iframe }</html>` ) ; } return `${ content }${ iframe }` ; }