1
- import { Compiler , Configuration } from 'webpack'
1
+ import { SyncHook } from 'tapable'
2
+ import { Compiler } from 'webpack'
3
+ import { escapeRegExp } from 'lodash'
2
4
3
5
interface File {
4
6
[ key : string ] : string
@@ -13,6 +15,15 @@ interface Compilation {
13
15
assets : { [ key : string ] : Asset }
14
16
}
15
17
18
+ interface HtmlWebpackPluginData {
19
+ html : string
20
+ outputName : string
21
+ assets : {
22
+ publicPath : string
23
+ css : string [ ]
24
+ }
25
+ }
26
+
16
27
interface ReplaceConfig {
17
28
position ?: 'before' | 'after'
18
29
removeTarget ?: boolean
@@ -59,10 +70,17 @@ export default class Plugin {
59
70
60
71
private css : File = { }
61
72
62
- private html : File = { }
63
-
64
73
constructor ( private readonly config : Config = { } ) { }
65
74
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
+
66
84
private isCurrentFileNeedsToBeInlined ( fileName : string ) : boolean {
67
85
if ( typeof this . config . filter === 'function' ) {
68
86
return this . config . filter ( fileName )
@@ -73,55 +91,55 @@ export default class Plugin {
73
91
74
92
private prepare ( { assets } : Compilation ) {
75
93
const isCSS = is ( 'css' )
76
- const isHTML = is ( 'html' )
77
- const { leaveCSSFile } = this . config
78
94
79
95
Object . keys ( assets ) . forEach ( ( fileName ) => {
80
96
if ( isCSS ( fileName ) && this . isCurrentFileNeedsToBeInlined ( fileName ) ) {
81
97
this . css [ fileName ] = assets [ fileName ] . source ( )
82
- if ( ! leaveCSSFile ) {
98
+ if ( ! this . config . leaveCSSFile ) {
83
99
delete assets [ fileName ]
84
100
}
85
101
}
86
-
87
- if ( isHTML ( fileName ) && this . isCurrentFileNeedsToBeInlined ( fileName ) ) {
88
- this . html [ fileName ] = assets [ fileName ] . source ( )
89
- }
90
102
} )
91
103
}
92
104
93
- private process ( { assets } : Compilation , { output } : Configuration ) {
94
- const publicPath = ( output && output . publicPath ) || ''
105
+ private process ( data : HtmlWebpackPluginData ) {
95
106
const { replace : replaceConfig = DEFAULT_REPLACE_CONFIG } = this . config
96
107
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
+ )
103
116
} )
104
117
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
+ }
116
121
}
117
122
118
123
apply ( compiler : Compiler ) {
119
- compiler . hooks . emit . tapAsync (
124
+ compiler . hooks . compilation . tap (
120
125
'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
+ }
125
143
} ,
126
144
)
127
145
}
0 commit comments