11import { Compiler } from 'webpack' ;
22
3- interface Module {
4- type ?: string
5- content : string
6- }
3+ type File = {
4+ [ key : string ] : string
5+ } ;
76
8- interface Compilation {
9- modules : Module [ ]
10- }
7+ type Asset = {
8+ source ( ) : string
9+ size ( ) : number
10+ } ;
1111
12- interface PluginData {
13- html : string
14- assets : { css : string [ ] }
12+ interface Compilation {
13+ assets : { [ key : string ] : Asset }
1514}
1615
1716export default class Plugin
1817{
19-
20- static makeReg ( fileName : string ) {
21- return new RegExp ( `<link[^>]+href=['"]${ fileName } ['"][^>]+(>|\/>|><\/link>)` ) ;
18+ static addStyle ( html : string , style : string ) {
19+ return html . replace ( '</head>' , `<style>${ style } </style></head>` ) ;
2220 }
2321
24- static getStyleString ( modules : Module [ ] ) : string {
25- return modules
26- . filter ( ( { type = '' } ) => type . includes ( 'mini-css-extract-plugin' ) )
27- . reduce ( ( result , { content = '' } ) => {
28- return result + content ;
29- } , '' ) ;
22+ static removeLinkTag ( html : string , cssFileName : string ) {
23+ return html . replace (
24+ new RegExp ( `<link[^>]+href=['"]${ cssFileName } ['"][^>]+(>|\/>|><\/link>)` ) ,
25+ '' ,
26+ ) ;
3027 }
3128
32- static addStyleInToHTML ( compilation : Compilation , pluginData : PluginData ) {
33- const style = this . getStyleString ( compilation . modules ) ;
34- pluginData . html = pluginData . html
35- . replace ( '</head>' , `<style>\n${ style } \n</style></head>` ) ;
36- }
29+ private css : File = { } ;
30+ private html : File = { } ;
3731
38- static removeLinkTag ( pluginData : PluginData ) {
39- pluginData . assets . css . forEach ( ( fileName : string ) => {
40- pluginData . html = pluginData . html
41- . replace ( this . makeReg ( fileName ) , '' ) ;
32+ private prepare ( { assets } : Compilation ) {
33+ const isCSS = is ( 'css' ) ;
34+ const isHTML = is ( 'html' ) ;
35+
36+ Object . keys ( assets ) . forEach ( ( fileName ) => {
37+ if ( isCSS ( fileName ) ) {
38+ this . css [ fileName ] = assets [ fileName ] . source ( ) ;
39+ delete assets [ fileName ] ;
40+ } else if ( isHTML ( fileName ) ) {
41+ this . html [ fileName ] = assets [ fileName ] . source ( ) ;
42+ }
4243 } ) ;
4344 }
4445
45- static replace ( compilation : Compilation , pluginData : PluginData , callback : ( ...args : any [ ] ) => void ) {
46- Plugin . removeLinkTag ( pluginData ) ;
47- Plugin . addStyleInToHTML ( compilation , pluginData ) ;
48- callback ( null , pluginData ) ;
46+ private process ( { assets } : Compilation ) {
47+ Object . keys ( this . html ) . forEach ( ( htmlFileName ) => {
48+ let html = this . html [ htmlFileName ] ;
49+
50+ Object . keys ( this . css ) . forEach ( ( key ) => {
51+ html = Plugin . addStyle ( html , this . css [ key ] ) ;
52+ html = Plugin . removeLinkTag ( html , key ) ;
53+ } ) ;
54+
55+ assets [ htmlFileName ] = {
56+ source ( ) { return html } ,
57+ size ( ) { return html . length } ,
58+ } ;
59+ } ) ;
4960 }
5061
5162 apply ( compiler : Compiler ) {
52- compiler . hooks . compilation . tap ( 'HtmlReplaceWebpackPlugin' , ( compilation : any ) => {
53- compilation . hooks . htmlWebpackPluginAfterHtmlProcessing
54- . tapAsync (
55- 'html-webpack-plugin-before-html-processing' ,
56- Plugin . replace . bind ( Plugin , compilation )
57- ) ;
63+ compiler . hooks . emit . tapAsync ( 'html-inline-css-webpack-plugin' , ( compilation : Compilation , callback : ( ) => void ) => {
64+ this . prepare ( compilation ) ;
65+ this . process ( compilation ) ;
66+ callback ( ) ;
5867 } ) ;
5968 }
69+ }
70+
71+ function is ( filenameExtension : string ) {
72+ const reg = new RegExp ( `\.${ filenameExtension } $` ) ;
73+ return ( fileName : string ) => reg . test ( fileName ) ;
6074}
0 commit comments