1
+ import * as path from 'path' ;
2
+ import { promises as fs } from "fs" ;
3
+
4
+ function getMimeType ( ext : string ) : string {
5
+ switch ( ext ) {
6
+ case 'jpg' :
7
+ case 'jpeg' :
8
+ return 'image/jpeg' ;
9
+ case 'svg' :
10
+ return 'image/svg+xml' ;
11
+ case 'gif' :
12
+ case 'png' :
13
+ case 'webp' :
14
+ return `image/${ ext } ` ;
15
+ default :
16
+ return 'application/octet-stream' ;
17
+ }
18
+ } ;
19
+
20
+ export async function inlineImages ( html : string , htmlDir : string ) : Promise < string > {
21
+ const imgTagRegex = / < i m g ( .* ) ? s r c = " ( [ \w . \- \/ ] + ) " ( .* ) > / ;
22
+ let matches = html . match ( new RegExp ( imgTagRegex , 'g' ) ) ;
23
+ if ( ! matches )
24
+ return html ;
25
+ let imgPromises = matches
26
+ . map ( imgTag => imgTag . match ( imgTagRegex ) [ 2 ] )
27
+ . map ( relImgPath => path . resolve ( htmlDir , relImgPath ) )
28
+ . map ( imgPath => fs . readFile ( imgPath ) ) ;
29
+ let i = 0 ;
30
+ return Promise . all ( imgPromises ) . then ( images =>
31
+ html . replace ( new RegExp ( imgTagRegex , 'g' ) , ( _match , p1 , p2 , p3 ) =>
32
+ `<img ${ p1 || '' } src="data:${ getMimeType ( p2 . split ( '.' ) . pop ( ) ) } ;base64, ${ images [ i ++ ] . toString ( 'base64' ) } "${ p3 } >`
33
+ ) ) ;
34
+ }
35
+
36
+ export async function inlineHtmlScripts ( html : string , htmlDir : string ) : Promise < string > {
37
+ const scriptTagRegex = / < s c r i p t (?: .* ) ? s r c = " ( [ \w . \- \/ ] + ) " .* > < \/ s c r i p t > / ;
38
+ let matches = html . match ( new RegExp ( scriptTagRegex , 'g' ) ) ;
39
+ if ( ! matches )
40
+ return html ;
41
+ let scriptPromises = matches
42
+ . map ( scriptTag => scriptTag . match ( scriptTagRegex ) [ 1 ] )
43
+ . map ( relScriptPath => path . resolve ( htmlDir , relScriptPath ) )
44
+ . map ( scriptPath => fs . readFile ( scriptPath , 'utf8' ) ) ;
45
+ let i = 0 ;
46
+ return Promise . all ( scriptPromises ) . then ( scripts =>
47
+ html . replace ( new RegExp ( scriptTagRegex , 'g' ) , ( ) =>
48
+ `<script>${ scripts [ i ++ ] . replace ( / < \/ s c r i p t > / g, '<\\/script>' ) } </script>` ) ) ;
49
+ }
50
+
51
+ export async function inlineHtmlStyles ( html : string , htmlDir : string ) : Promise < string > {
52
+ const linkTagRegex = / < l i n k (?: .* ) ? r e l = " s t y l e s h e e t " (?: .* ) ? h r e f = " ( [ \w . \- \/ ] + ) " .* > | < l i n k (?: .* ) ? h r e f = " ( [ \w . \- \/ ] + ) " (?: .* ) ? r e l = " s t y l e s h e e t " .* > / ;
53
+ let matches = html . match ( new RegExp ( linkTagRegex , 'g' ) ) ;
54
+ if ( ! matches )
55
+ return html ;
56
+ let stylesheetPromises = matches
57
+ . map ( linkTag => {
58
+ let m = linkTag . match ( linkTagRegex ) ;
59
+ return m [ 1 ] || m [ 2 ] ;
60
+ } )
61
+ . map ( relPath => path . resolve ( htmlDir , relPath ) )
62
+ . map ( stylesheetPath => fs . readFile ( stylesheetPath , 'utf8' ) ) ;
63
+ let i = 0 ;
64
+ return Promise . all ( stylesheetPromises ) . then ( stylesheets =>
65
+ html . replace ( new RegExp ( linkTagRegex , 'g' ) , ( ) =>
66
+ `<style>${ stylesheets [ i ++ ] } </style>` ) ) ;
67
+ }
68
+
69
+ export async function inlineAll ( html : string , htmlDir : string ) : Promise < string > {
70
+ return await inlineHtmlStyles (
71
+ await inlineImages (
72
+ await inlineHtmlScripts ( html , htmlDir ) ,
73
+ htmlDir ) ,
74
+ htmlDir )
75
+ }
0 commit comments