11const path = require ( 'path' ) ;
2- const exec = require ( 'child_process' ) . execSync ;
32const fs = require ( 'fs' ) ;
43
54/**
6- * @typedef {{ versionFilename?: string } } Options
5+ * @typedef {import('./typings').Options } Options
76 */
87class VersinoCheckPlugin {
98 /**
109 *
1110 * @param {Options } options
1211 */
13- constructor ( options ) {
12+ constructor ( options = { } ) {
1413 this . updaterName = 'updater' ;
1514 this . updaterExtension = '.js' ;
16- this . name = 'VersionCheckPlugin' ;
1715 const defualtVersionFilename = 'version-hash.json' ;
18- const defualtUpdaterPath = 'cache-controller' ;
19- this . options = Object . assign ( { versionFilename : defualtVersionFilename , updaterPath : defualtUpdaterPath } ,
16+ this . updaterPath = 'cache-controller' ;
17+ this . options = Object . assign ( { versionFilename : defualtVersionFilename } ,
2018 options ) ;
19+
20+ this . options . entryNeedInjectedUpdater = [ 'main' ] ;
21+ if ( typeof options . entryNeedInjectedUpdater === 'string' ) {
22+ this . options . entryNeedInjectedUpdater = [ options . entryNeedInjectedUpdater ] ;
23+ } else if ( Array . isArray ( options . entryNeedInjectedUpdater ) ) {
24+ this . options . entryNeedInjectedUpdater = [ ...options . entryNeedInjectedUpdater ] ;
25+ }
2126 }
2227
2328 /**
2429 * Get updater file generate dirctory(unclude filename).
2530 * @returns {string }
2631 */
2732 getPrePath ( ) {
28- return this . options . updaterPath ;
33+ return this . updaterPath ;
2934 }
3035
3136 /**
3237 * Inject updater to frontend code as entry
3338 * @param {import('webpack').Compiler } compiler
3439 */
3540 generateFile ( compiler ) {
36- const { context } = compiler ;
37- this . options . updaterPath = path . join ( context , 'src' , this . options . updaterPath ) ;
41+ const { options } = compiler ;
3842 const prePath = this . getPrePath ( ) ;
39- let publicPath = compiler . options . output . publicPath ;
43+ let publicPath = options . output . publicPath ;
4044 publicPath = ( ! publicPath || publicPath === 'auto' ) ? '' : publicPath ;
4145 try {
4246 fs . mkdirSync ( prePath , { recursive : true } ) ;
@@ -55,39 +59,88 @@ class VersinoCheckPlugin {
5559 * Remove updater temp code in src dir.
5660 */
5761 removeFile ( ) {
58- const rmCommand = `rm -rf ${ this . getPrePath ( ) } ` ;
5962 try {
60- exec ( rmCommand ) ;
63+ fs . unlinkSync ( path . join ( this . getPrePath ( ) , this . updaterName + this . updaterExtension ) ) ;
64+ fs . rmdirSync ( this . getPrePath ( ) ) ;
6165 } catch ( e ) {
6266 throw e ;
6367 }
6468 }
6569
70+ /**
71+ *
72+ * @param {import('webpack').Compiler } compiler
73+ */
74+ getEntryEntries ( compiler ) {
75+ const originEntry = compiler . options . entry ;
76+ /** @type {import('./typings').EntryEntries } */
77+ const entryResult = { } ;
78+ if ( typeof originEntry === 'string' ) entryResult [ 'main' ] = originEntry ;
79+ else if ( Array . isArray ( originEntry ) ) entryResult [ 'main' ] = originEntry [ 0 ] ;
80+ else {
81+ const entryKeys = Object . keys ( originEntry ) ;
82+ entryKeys . forEach ( key => {
83+ const val = originEntry [ key ] ;
84+ if ( typeof val === 'string' ) entryResult [ key ] = val ;
85+ else if ( Array . isArray ( val ) ) entryResult [ key ] = val [ 0 ] ;
86+ else entryResult [ key ] = val [ 'import' ] [ 0 ] ;
87+ } ) ;
88+ }
89+ return entryResult ;
90+ }
91+
6692 /**
6793 * This plugin entry for webpack.
6894 * @param {import('webpack').Compiler } compiler
6995 */
7096 apply ( compiler ) {
71- compiler . hooks . afterEnvironment . tap ( this . name , ( ) => {
97+ const { outputFileSystem, options, context } = compiler ;
98+ this . updaterPath = path . join ( context , 'src' , this . updaterPath ) ;
99+ compiler . hooks . afterEnvironment . tap ( VersinoCheckPlugin . pluginName , ( ) => {
72100 this . generateFile ( compiler ) ;
73- const { outputFileSystem, options } = compiler ;
74- const firstEntry = Object . keys ( options . entry ) [ 0 ] ;
75- // Deal multiple versions of webpack.
76- const newEntryPath = path . join ( this . options . updaterPath , this . updaterName + this . updaterExtension ) ;
77- if ( typeof options . entry [ firstEntry ] === 'object' && options . entry [ firstEntry ] . import ) {
78- options . entry [ this . updaterName ] = { import : [ newEntryPath ] } ;
79- } else {
80- options . entry [ this . updaterName ] = newEntryPath ;
81- }
82- compiler . hooks . thisCompilation . tap ( this . name , compilation => {
83- compilation . hooks . afterChunks . tap ( this . name , chunks => {
84- compilation . hooks . afterHash . tap ( this . name , ( ) => {
101+ const entryEntries = this . getEntryEntries ( compiler ) ;
102+ const entryKeys = Object . keys ( entryEntries ) ;
103+ const entryNeedInjectedUpdaterResource = [ ] ;
104+ this . options . entryNeedInjectedUpdater . forEach ( entryName => {
105+ const val = entryEntries [ entryName ] ;
106+ if ( val ) entryNeedInjectedUpdaterResource . push ( val ) ;
107+ } ) ;
108+ compiler . hooks . thisCompilation . tap ( VersinoCheckPlugin . pluginName , compilation => {
109+ const originSources = { } ;
110+ const injectModulePath = path . join ( this . getPrePath ( ) , this . updaterName + this . updaterExtension ) ;
111+ compilation . hooks . buildModule . tap ( VersinoCheckPlugin . pluginName , moduleSource => {
112+ if ( entryNeedInjectedUpdaterResource . indexOf ( moduleSource . rawRequest ) >= 0 ) {
113+ try {
114+ const originSource = fs . readFileSync ( moduleSource . resource , { encoding : 'utf-8' } ) ;
115+ originSources [ moduleSource . rawRequest ] = originSource ;
116+
117+ const injectedSource =
118+ `\nimport '${ injectModulePath . replace ( / \\ / g, '/' ) } ';\n` + originSource ;
119+ fs . writeFileSync ( moduleSource . resource , injectedSource , { encoding : 'utf-8' } ) ;
120+ } catch ( e ) {
121+ throw e ;
122+ }
123+ }
124+ } ) ;
125+ compilation . hooks . succeedModule . tap ( VersinoCheckPlugin . pluginName , moduleSource => {
126+ if ( entryNeedInjectedUpdaterResource . indexOf ( moduleSource . rawRequest ) >= 0 ) {
127+ try {
128+ fs . writeFileSync ( moduleSource . resource , originSources [ moduleSource . rawRequest ] , {
129+ encoding : 'utf-8' ,
130+ } )
131+ } catch ( e ) {
132+ throw e ;
133+ }
134+ }
135+ } ) ;
136+ compilation . hooks . afterChunks . tap ( VersinoCheckPlugin . pluginName , chunks => {
137+ compilation . hooks . afterHash . tap ( VersinoCheckPlugin . pluginName , ( ) => {
85138 const { entry } = compiler . options ;
86139 const chunkHash = Array . from ( chunks ) ;
87140 /** @type {{ version: string } } */
88141 const versionHash = { version : '' } ;
89142 let versionVal = '' ;
90- Object . keys ( entry ) . map ( entryName => {
143+ entryKeys . map ( entryName => {
91144 versionVal += chunkHash . find ( ( { name} ) => name === entryName ) . renderedHash ;
92145 } ) ;
93146 versionHash . version = versionVal ;
@@ -112,4 +165,7 @@ class VersinoCheckPlugin {
112165 }
113166}
114167
168+ VersinoCheckPlugin . version = 1 ;
169+ VersinoCheckPlugin . pluginName = 'VersionCheckPlugin' ;
170+
115171module . exports = VersinoCheckPlugin ;
0 commit comments