Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7ec46d5

Browse files
committed
hot reload added/removed pages
1 parent301cd26 commit7ec46d5

File tree

5 files changed

+254
-8
lines changed

5 files changed

+254
-8
lines changed

‎client/next-dev.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import'react-hot-loader/patch'
2-
import'webpack-dev-server/client?http://localhost:3030'
2+
import'./webpack-dev-client?http://localhost:3030'
33
import*asnextfrom'./next'
44

55
module.exports=next

‎client/webpack-dev-client/index.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/* global __resourceQuery, next */
2+
3+
// Based on 'webpack-dev-server/client'
4+
5+
importurlfrom'url'
6+
importstripAnsifrom'strip-ansi'
7+
importsocketfrom'./socket'
8+
9+
functiongetCurrentScriptSource(){
10+
// `document.currentScript` is the most accurate way to find the current script,
11+
// but is not supported in all browsers.
12+
if(document.currentScript){
13+
returndocument.currentScript.getAttribute('src')
14+
}
15+
// Fall back to getting all scripts in the document.
16+
constscriptElements=document.scripts||[]
17+
constcurrentScript=scriptElements[scriptElements.length-1]
18+
if(currentScript){
19+
returncurrentScript.getAttribute('src')
20+
}
21+
// Fail as there was no script to use.
22+
thrownewError('[WDS] Failed to get current script source')
23+
}
24+
25+
leturlParts
26+
if(typeof__resourceQuery==='string'&&__resourceQuery){
27+
// If this bundle is inlined, use the resource query to get the correct url.
28+
urlParts=url.parse(__resourceQuery.substr(1))
29+
}else{
30+
// Else, get the url from the <script> this file was called with.
31+
letscriptHost=getCurrentScriptSource()
32+
scriptHost=scriptHost.replace(/\/[^\/]+$/,'')
33+
urlParts=url.parse(scriptHost||'/',false,true)
34+
}
35+
36+
lethot=false
37+
letinitial=true
38+
letcurrentHash=''
39+
letlogLevel='info'
40+
41+
functionlog(level,msg){
42+
if(logLevel==='info'&&level==='info'){
43+
returnconsole.log(msg)
44+
}
45+
if(['info','warning'].indexOf(logLevel)>=0&&level==='warning'){
46+
returnconsole.warn(msg)
47+
}
48+
if(['info','warning','error'].indexOf(logLevel)>=0&&level==='error'){
49+
returnconsole.error(msg)
50+
}
51+
}
52+
53+
constonSocketMsg={
54+
hot(){
55+
hot=true
56+
log('info','[WDS] Hot Module Replacement enabled.')
57+
},
58+
invalid(){
59+
log('info','[WDS] App updated. Recompiling...')
60+
},
61+
hash(hash){
62+
currentHash=hash
63+
},
64+
'still-ok':()=>{
65+
log('info','[WDS] Nothing changed.')
66+
},
67+
'log-level':(level)=>{
68+
logLevel=level
69+
},
70+
ok(){
71+
if(initial){
72+
initial=false
73+
return
74+
}
75+
reloadApp()
76+
},
77+
warnings(warnings){
78+
log('info','[WDS] Warnings while compiling.')
79+
for(leti=0;i<warnings.length;i++){
80+
console.warn(stripAnsi(warnings[i]))
81+
}
82+
if(initial){
83+
initial=false
84+
return
85+
}
86+
reloadApp()
87+
},
88+
errors(errors){
89+
log('info','[WDS] Errors while compiling.')
90+
for(leti=0;i<errors.length;i++){
91+
console.error(stripAnsi(errors[i]))
92+
}
93+
if(initial){
94+
initial=false
95+
return
96+
}
97+
reloadApp()
98+
},
99+
'proxy-error':(errors)=>{
100+
log('info','[WDS] Proxy error.')
101+
for(leti=0;i<errors.length;i++){
102+
log('error',stripAnsi(errors[i]))
103+
}
104+
if(initial){
105+
initial=false
106+
return
107+
}
108+
},
109+
reload(route){
110+
next.router.reload(route)
111+
},
112+
close(){
113+
log('error','[WDS] Disconnected!')
114+
}
115+
}
116+
117+
lethostname=urlParts.hostname
118+
letprotocol=urlParts.protocol
119+
120+
if(urlParts.hostname==='0.0.0.0'){
121+
// why do we need this check?
122+
// hostname n/a for file protocol (example, when using electron, ionic)
123+
// see: https://github.com/webpack/webpack-dev-server/pull/384
124+
if(window.location.hostname&&!!~window.location.protocol.indexOf('http')){
125+
hostname=window.location.hostname
126+
}
127+
}
128+
129+
// `hostname` can be empty when the script path is relative. In that case, specifying
130+
// a protocol would result in an invalid URL.
131+
// When https is used in the app, secure websockets are always necessary
132+
// because the browser doesn't accept non-secure websockets.
133+
if(hostname&&(window.location.protocol==='https:'||urlParts.hostname==='0.0.0.0')){
134+
protocol=window.location.protocol
135+
}
136+
137+
constsocketUrl=url.format({
138+
protocol,
139+
auth:urlParts.auth,
140+
hostname,
141+
port:(urlParts.port==='0') ?window.location.port :urlParts.port,
142+
pathname:urlParts.path==null||urlParts.path==='/' ?'/sockjs-node' :urlParts.path
143+
})
144+
145+
socket(socketUrl,onSocketMsg)
146+
147+
functionreloadApp(){
148+
if(hot){
149+
log('info','[WDS] App hot update...')
150+
window.postMessage('webpackHotUpdate'+currentHash,'*')
151+
}else{
152+
log('info','[WDS] App updated. Reloading...')
153+
window.location.reload()
154+
}
155+
}

‎client/webpack-dev-client/socket.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
importSockJSfrom'sockjs-client'
2+
3+
letretries=0
4+
letsock=null
5+
6+
exportdefaultfunctionsocket(url,handlers){
7+
sock=newSockJS(url)
8+
9+
sock.onopen=()=>{
10+
retries=0
11+
}
12+
13+
sock.onclose=()=>{
14+
if(retries===0)handlers.close()
15+
16+
// Try to reconnect.
17+
sock=null
18+
19+
// After 10 retries stop trying, to prevent logspam.
20+
if(retries<=10){
21+
// Exponentially increase timeout to reconnect.
22+
// Respectfully copied from the package `got`.
23+
constretryInMs=1000*Math.pow(2,retries)+Math.random()*100
24+
retries+=1
25+
26+
setTimeout(()=>{
27+
socket(url,handlers)
28+
},retryInMs)
29+
}
30+
}
31+
32+
sock.onmessage=(e)=>{
33+
// This assumes that all data sent via the websocket is JSON.
34+
constmsg=JSON.parse(e.data)
35+
if(handlers[msg.type]){
36+
handlers[msg.type](msg.data)
37+
}
38+
}
39+
}

‎lib/router.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,26 @@ export default class Router {
5959
}
6060
}
6161

62+
asyncreload(route){
63+
deletethis.components[route]
64+
65+
if(route!==this.route)return
66+
67+
letdata
68+
letprops
69+
try{
70+
data=awaitthis.fetchComponent(route)
71+
if(route!==this.route){
72+
props=awaitthis.getInitialProps(data.Component,data.ctx)
73+
}
74+
}catch(err){
75+
if(err.cancelled)returnfalse
76+
throwerr
77+
}
78+
79+
this.notify({ ...data, props})
80+
}
81+
6282
back(){
6383
window.history.back()
6484
}

‎server/hot-reloader.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export default class HotReloader {
99
this.server=null
1010
this.stats=null
1111
this.compilationErrors=null
12-
this.prevAssets={}
12+
this.prevAssets=null
13+
this.prevEntryChunkNames=null
1314
}
1415

1516
asyncstart(){
@@ -23,21 +24,44 @@ export default class HotReloader {
2324

2425
compiler.plugin('after-emit',(compilation,callback)=>{
2526
const{ assets}=compilation
26-
for(constfofObject.keys(assets)){
27-
deleteCache(assets[f].existsAt)
28-
}
29-
for(constfofObject.keys(this.prevAssets)){
30-
if(!assets[f]){
31-
deleteCache(this.prevAssets[f].existsAt)
27+
28+
if(this.prevAssets){
29+
for(constfofObject.keys(assets)){
30+
deleteCache(assets[f].existsAt)
31+
}
32+
for(constfofObject.keys(this.prevAssets)){
33+
if(!assets[f]){
34+
deleteCache(this.prevAssets[f].existsAt)
35+
}
3236
}
3337
}
3438
this.prevAssets=assets
39+
3540
callback()
3641
})
3742

3843
compiler.plugin('done',(stats)=>{
3944
this.stats=stats
4045
this.compilationErrors=null
46+
47+
constentryChunkNames=newSet(stats.compilation.chunks
48+
.filter((c)=>c.entry)
49+
.map((c)=>c.name))
50+
51+
if(this.prevEntryChunkNames){
52+
constadded=diff(entryChunkNames,this.prevEntryChunkNames)
53+
constremoved=diff(this.prevEntryChunkNames,entryChunkNames)
54+
55+
for(constnofnewSet([...added, ...removed])){
56+
constm=n.match(/^bundles\/pages(\/.+?)(?:\/index)?\.js$/)
57+
if(!m){
58+
console.error('Unexpected chunk name: '+n)
59+
continue
60+
}
61+
this.send('reload',m[1])
62+
}
63+
}
64+
this.prevEntryChunkNames=entryChunkNames
4165
})
4266

4367
this.server=newWebpackDevServer(compiler,{
@@ -98,6 +122,10 @@ export default class HotReloader {
98122
returnthis.compilationErrors
99123
}
100124

125+
send(type,data){
126+
this.server.sockWrite(this.server.sockets,type,data)
127+
}
128+
101129
getfileSystem(){
102130
returnthis.server.middleware.fileSystem
103131
}
@@ -107,3 +135,7 @@ function deleteCache (path) {
107135
deleterequire.cache[path]
108136
deleteread.cache[path]
109137
}
138+
139+
functiondiff(a,b){
140+
returnnewSet([...a].filter((v)=>!b.has(v)))
141+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp