1- import { Compiler , Configuration } from 'webpack'
1+ import { SyncHook } from 'tapable'
2+ import { Compiler } from 'webpack'
3+ import { escapeRegExp } from 'lodash'
24
35interface File {
46 [ key : string ] : string
@@ -13,6 +15,15 @@ interface Compilation {
1315 assets : { [ key : string ] : Asset }
1416}
1517
18+ interface HtmlWebpackPluginData {
19+ html : string
20+ outputName : string
21+ assets : {
22+ publicPath : string
23+ css : string [ ]
24+ }
25+ }
26+
1627interface ReplaceConfig {
1728 position ?: 'before' | 'after'
1829 removeTarget ?: boolean
@@ -59,10 +70,17 @@ export default class Plugin {
5970
6071 private css : File = { }
6172
62- private html : File = { }
63-
6473 constructor ( private readonly config : Config = { } ) { }
6574
75+ private getCSSFile ( cssLink : string , publicPath : string ) {
76+ // Link pattern: publicPath + fileName + '?' + hash
77+ const fileName = cssLink
78+ . replace ( new RegExp ( `^${ escapeRegExp ( publicPath ) } ` ) , '' )
79+ . replace ( / \? .+ $ / g, '' )
80+
81+ return this . css [ fileName ]
82+ }
83+
6684 private isCurrentFileNeedsToBeInlined ( fileName : string ) : boolean {
6785 if ( typeof this . config . filter === 'function' ) {
6886 return this . config . filter ( fileName )
@@ -73,55 +91,55 @@ export default class Plugin {
7391
7492 private prepare ( { assets } : Compilation ) {
7593 const isCSS = is ( 'css' )
76- const isHTML = is ( 'html' )
77- const { leaveCSSFile } = this . config
7894
7995 Object . keys ( assets ) . forEach ( ( fileName ) => {
8096 if ( isCSS ( fileName ) && this . isCurrentFileNeedsToBeInlined ( fileName ) ) {
8197 this . css [ fileName ] = assets [ fileName ] . source ( )
82- if ( ! leaveCSSFile ) {
98+ if ( ! this . config . leaveCSSFile ) {
8399 delete assets [ fileName ]
84100 }
85101 }
86-
87- if ( isHTML ( fileName ) && this . isCurrentFileNeedsToBeInlined ( fileName ) ) {
88- this . html [ fileName ] = assets [ fileName ] . source ( )
89- }
90102 } )
91103 }
92104
93- private process ( { assets } : Compilation , { output } : Configuration ) {
94- const publicPath = ( output && output . publicPath ) || ''
105+ private process ( data : HtmlWebpackPluginData ) {
95106 const { replace : replaceConfig = DEFAULT_REPLACE_CONFIG } = this . config
96107
97- Object . keys ( this . html ) . forEach ( ( htmlFileName ) => {
98- let html = this . html [ htmlFileName ]
99-
100- Object . keys ( this . css ) . forEach ( ( key ) => {
101- html = Plugin . addStyle ( html , this . css [ key ] , replaceConfig )
102- html = Plugin . removeLinkTag ( html , publicPath + key )
108+ // check if current html needs to be inlined
109+ if ( this . isCurrentFileNeedsToBeInlined ( data . outputName ) ) {
110+ data . assets . css . forEach ( ( cssLink ) => {
111+ data . html = Plugin . addStyle (
112+ data . html ,
113+ this . getCSSFile ( cssLink , data . assets . publicPath ) ,
114+ replaceConfig ,
115+ )
103116 } )
104117
105- html = Plugin . cleanUp ( html , replaceConfig )
106-
107- assets [ htmlFileName ] = {
108- source ( ) {
109- return html
110- } ,
111- size ( ) {
112- return html . length
113- } ,
114- }
115- } )
118+ data . html = Plugin . cleanUp ( data . html , replaceConfig )
119+ data . assets . css . length = 0 // prevent generate <link /> tag
120+ }
116121 }
117122
118123 apply ( compiler : Compiler ) {
119- compiler . hooks . emit . tapAsync (
124+ compiler . hooks . compilation . tap (
120125 'html-inline-css-webpack-plugin' ,
121- ( compilation : Compilation , callback : ( ) => void ) => {
122- this . prepare ( compilation )
123- this . process ( compilation , compiler . options )
124- callback ( )
126+ ( compilation ) => {
127+ if ( 'htmlWebpackPluginBeforeHtmlProcessing' in compilation . hooks ) {
128+ const hook : SyncHook < HtmlWebpackPluginData > =
129+ // @ts -ignore Error:(130, 27) TS2339: Property 'htmlWebpackPluginBeforeHtmlProcessing' does not exist on type 'CompilationHooks'.
130+ compilation . hooks . htmlWebpackPluginBeforeHtmlProcessing
131+ hook . tap (
132+ 'html-inline-css-webpack-plugin-html-webpack-plugin-before-html-processing' ,
133+ ( data : HtmlWebpackPluginData ) => {
134+ this . prepare ( compilation )
135+ this . process ( data )
136+ } ,
137+ )
138+ } else {
139+ throw new Error (
140+ '`html-webpack-plugin` should be ordered first before html-inline-css-webpack-plugin' ,
141+ )
142+ }
125143 } ,
126144 )
127145 }
0 commit comments