1
1
import { Compiler } from 'webpack' ;
2
2
3
- interface Module {
4
- type ?: string
5
- content : string
6
- }
3
+ type File = {
4
+ [ key : string ] : string
5
+ } ;
7
6
8
- interface Compilation {
9
- modules : Module [ ]
10
- }
7
+ type Asset = {
8
+ source ( ) : string
9
+ size ( ) : number
10
+ } ;
11
11
12
- interface PluginData {
13
- html : string
14
- assets : { css : string [ ] }
12
+ interface Compilation {
13
+ assets : { [ key : string ] : Asset }
15
14
}
16
15
17
16
export default class Plugin
18
17
{
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>` ) ;
22
20
}
23
21
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
+ ) ;
30
27
}
31
28
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 = { } ;
37
31
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
+ }
42
43
} ) ;
43
44
}
44
45
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
+ } ) ;
49
60
}
50
61
51
62
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 ( ) ;
58
67
} ) ;
59
68
}
69
+ }
70
+
71
+ function is ( filenameExtension : string ) {
72
+ const reg = new RegExp ( `\.${ filenameExtension } $` ) ;
73
+ return ( fileName : string ) => reg . test ( fileName ) ;
60
74
}
0 commit comments