@@ -22,16 +22,76 @@ function attachHMRServer({httpServer, path, packagerServer}) {
2222 client = null ;
2323 }
2424
25+ // Returns a promise with the full list of dependencies and the shallow
26+ // dependencies each file on the dependency list has for the give platform
27+ // and entry file.
28+ function getDependencies ( platform , bundleEntry ) {
29+ return packagerServer . getDependencies ( {
30+ platform : platform ,
31+ dev : true ,
32+ entryFile : bundleEntry ,
33+ } ) . then ( response => {
34+ // for each dependency builds the object:
35+ // `{path: '/a/b/c.js', deps: ['modA', 'modB', ...]}`
36+ return Promise . all ( Object . values ( response . dependencies ) . map ( dep => {
37+ if ( dep . isAsset ( ) || dep . isAsset_DEPRECATED ( ) || dep . isJSON ( ) ) {
38+ return Promise . resolve ( { path : dep . path , deps : [ ] } ) ;
39+ }
40+ return packagerServer . getShallowDependencies ( dep . path )
41+ . then ( deps => {
42+ return {
43+ path : dep . path ,
44+ deps,
45+ } ;
46+ } ) ;
47+ } ) )
48+ . then ( deps => {
49+ // list with all the dependencies the bundle entry has
50+ const dependenciesCache = response . dependencies . map ( dep => dep . path ) ;
51+
52+ // map that indicates the shallow dependency each file included on the
53+ // bundle has
54+ const shallowDependencies = { } ;
55+ deps . forEach ( dep => shallowDependencies [ dep . path ] = dep . deps ) ;
56+
57+ return { dependenciesCache, shallowDependencies} ;
58+ } ) ;
59+ } ) ;
60+ }
61+
2562 packagerServer . addFileChangeListener ( filename => {
2663 if ( ! client ) {
2764 return ;
2865 }
2966
30- packagerServer . buildBundleForHMR ( {
31- entryFile : filename ,
32- platform : client . platform ,
33- } )
34- . then ( bundle => client . ws . send ( bundle ) ) ;
67+ packagerServer . getShallowDependencies ( filename )
68+ . then ( deps => {
69+ // if the file dependencies have change we need to invalidate the
70+ // dependencies caches because the list of files we need to send to the
71+ // client may have changed
72+ if ( arrayEquals ( deps , client . shallowDependencies [ filename ] ) ) {
73+ return Promise . resolve ( ) ;
74+ }
75+ return getDependencies ( client . platform , client . bundleEntry )
76+ . then ( ( { dependenciesCache, shallowDependencies} ) => {
77+ // invalidate caches
78+ client . dependenciesCache = dependenciesCache ;
79+ client . shallowDependencies = shallowDependencies ;
80+ } ) ;
81+ } )
82+ . then ( ( ) => {
83+ // make sure the file was modified is part of the bundle
84+ if ( ! client . shallowDependencies [ filename ] ) {
85+ return ;
86+ }
87+
88+ return packagerServer . buildBundleForHMR ( {
89+ platform : client . platform ,
90+ entryFile : filename ,
91+ } )
92+ . then ( bundle => client . ws . send ( bundle ) ) ;
93+ } )
94+ . done ( ) ;
3595 } ) ;
3696
3797 const WebSocketServer = require ( 'ws' ) . Server ;
@@ -44,19 +104,37 @@ function attachHMRServer({httpServer, path, packagerServer}) {
44104 wss . on ( 'connection' , ws => {
45105 console . log ( '[Hot Module Replacement] Client connected' ) ;
46106 const params = querystring . parse ( url . parse ( ws . upgradeReq . url ) . query ) ;
47- client = {
48- ws,
49- platform : params . platform ,
50- bundleEntry : params . bundleEntry ,
51- } ;
52-
53- client . ws . on ( 'error' , e => {
54- console . error ( '[Hot Module Replacement] Unexpected error' , e ) ;
55- disconnect ( ) ;
56- } ) ;
57107
58- client . ws . on ( 'close' , ( ) => disconnect ( ) ) ;
108+ getDependencies ( params . platform , params . bundleEntry )
109+ . then ( ( { dependenciesCache, shallowDependencies} ) => {
110+ client = {
111+ ws,
112+ platform : params . platform ,
113+ bundleEntry : params . bundleEntry ,
114+ dependenciesCache,
115+ shallowDependencies,
116+ } ;
117+
118+ client . ws . on ( 'error' , e => {
119+ console . error ( '[Hot Module Replacement] Unexpected error' , e ) ;
120+ disconnect ( ) ;
121+ } ) ;
122+
123+ client . ws . on ( 'close' , ( ) => disconnect ( ) ) ;
124+ } )
125+ . done ( ) ;
59126 } ) ;
60127}
61128
129+ function arrayEquals ( arrayA , arrayB ) {
130+ arrayA = arrayA || [ ] ;
131+ arrayB = arrayB || [ ] ;
132+ return (
133+ arrayA . length === arrayB . length &&
134+ arrayA . every ( ( element , index ) => {
135+ return element === arrayB [ index ] ;
136+ } )
137+ ) ;
138+ }
139+
62140module . exports = attachHMRServer ;
0 commit comments