Use new lifecycle for HMR.

This commit is contained in:
Dillon Kearns 2020-05-03 11:40:47 -07:00
parent d2968fff89
commit 21c7588329
3 changed files with 211 additions and 36 deletions

View File

@ -38,3 +38,87 @@
display: none !important;
}
}
.lds-default {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
background-color: white;
}
.lds-default div {
position: absolute;
width: 6px;
height: 6px;
background: #000;
border-radius: 50%;
animation: lds-default 1.2s linear infinite;
}
.lds-default div:nth-child(1) {
animation-delay: 0s;
top: 37px;
left: 66px;
}
.lds-default div:nth-child(2) {
animation-delay: -0.1s;
top: 22px;
left: 62px;
}
.lds-default div:nth-child(3) {
animation-delay: -0.2s;
top: 11px;
left: 52px;
}
.lds-default div:nth-child(4) {
animation-delay: -0.3s;
top: 7px;
left: 37px;
}
.lds-default div:nth-child(5) {
animation-delay: -0.4s;
top: 11px;
left: 22px;
}
.lds-default div:nth-child(6) {
animation-delay: -0.5s;
top: 22px;
left: 11px;
}
.lds-default div:nth-child(7) {
animation-delay: -0.6s;
top: 37px;
left: 7px;
}
.lds-default div:nth-child(8) {
animation-delay: -0.7s;
top: 52px;
left: 11px;
}
.lds-default div:nth-child(9) {
animation-delay: -0.8s;
top: 62px;
left: 22px;
}
.lds-default div:nth-child(10) {
animation-delay: -0.9s;
top: 66px;
left: 37px;
}
.lds-default div:nth-child(11) {
animation-delay: -1s;
top: 62px;
left: 52px;
}
.lds-default div:nth-child(12) {
animation-delay: -1.1s;
top: 52px;
left: 62px;
}
@keyframes lds-default {
0%, 20%, 80%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
}

View File

@ -73,38 +73,80 @@ function loadContentAndInitializeApp(/** @type { init: any } */ mainElmModule)
if (module.hot) {
module.hot.addStatusHandler(function (status) {
console.log('HMR', status)
if (status === 'idle') {
// httpGet(`${window.location.origin}${path}content.json`).then(function (/** @type JSON */ contentJson) {
// // console.log('hot contentJson', contentJson);
// found this trick in the next.js source code
// https://github.com/zeit/next.js/blob/886037b1bac4bdbfeb689b032c1612750fb593f7/packages/next/client/dev/error-overlay/eventsource.js
// https://github.com/zeit/next.js/blob/886037b1bac4bdbfeb689b032c1612750fb593f7/packages/next/client/dev/dev-build-watcher.js
// more details about this API at https://www.html5rocks.com/en/tutorials/eventsource/basics/
let source = new window.EventSource('/__webpack_hmr')
// source.addEventListener('open', () => { console.log('open!!!!!') })
source.addEventListener('message', (e) => {
// console.log('message!!!!!', e)
// console.log(e.data.action)
// console.log('ACTION', e.data.action);
// if (e.data && e.data.action)
if (event.data === '\uD83D\uDC93') {
// heartbeat
} else {
const obj = JSON.parse(event.data)
console.log('obj.action', obj.action);
if (obj.action === 'building') {
app.ports.fromJsPort.send({ thingy: 'hmr-check' });
} else if (obj.action === 'built') {
// console.log('built -- fetching');
let currentPath = window.location.pathname.replace(/(\w)$/, "$1/")
httpGet(`${window.location.origin}${currentPath}content.json`).then(function (/** @type JSON */ contentJson) {
// console.log('httpGet response', contentJson);
app.ports.fromJsPort.send({ contentJson: contentJson });
// success()
});
}
// app.ports.fromJsPort.send({ contentJson: contentJson });
// });
// console.log('Reloaded!!!!!!!!!!', status)
}
});
})
// module.hot.addStatusHandler(function (status) {
// console.log('HMR', status)
// if (status === 'idle') {
// // httpGet(`${window.location.origin}${path}content.json`).then(function (/** @type JSON */ contentJson) {
// // // console.log('hot contentJson', contentJson);
// // app.ports.fromJsPort.send({ contentJson: contentJson });
// // });
// // console.log('Reloaded!!!!!!!!!!', status)
// } else if (status === 'check') {
// console.log('sending', { thingy: 'hmr-check' });
// app.ports.fromJsPort.send({ thingy: 'hmr-check' });
// }
// });
}
// found this trick from https://github.com/roots/sage/issues/1826
// module.hot.addStatusHandler(function (status) { /* handle status */}) works, but after several saves
// it stops working for some reason. So this is a workaround to work even when those updates stop coming through
const reporter = window.__webpack_hot_middleware_reporter__
const success = reporter.success
reporter.success = function () {
console.log('SUCCESS');
let currentPath = window.location.pathname.replace(/(\w)$/, "$1/")
httpGet(`${window.location.origin}${currentPath}content.json`).then(function (/** @type JSON */ contentJson) {
// console.log('hot contentJson', contentJson);
// const reporter = window.__webpack_hot_middleware_reporter__
// console.log('reporter keys', reporter);
setTimeout(() => {
app.ports.fromJsPort.send({ contentJson: contentJson });
}, 0)
success()
});
}
// const success = reporter.success
// reporter.success = function () {
// console.log('SUCCESS');
// let currentPath = window.location.pathname.replace(/(\w)$/, "$1/")
// httpGet(`${window.location.origin}${currentPath}content.json`).then(function (/** @type JSON */ contentJson) {
// // console.log('hot contentJson', contentJson);
// app.ports.fromJsPort.send({ contentJson: contentJson });
// success()
// });
// }
return app

View File

@ -197,10 +197,43 @@ view pathKey content viewFn model =
, body =
[ onViewChangeElement model.url
, body |> Html.map UserMsg |> Html.map AppMsg
, loadingView model.hmrStatus
]
}
loadingView : HmrStatus -> Html msg
loadingView hmrStatus =
Html.div
[ Html.Attributes.id "__elm-pages-loading"
, Html.Attributes.class "lds-default"
, Html.Attributes.style "position" "fixed"
, Html.Attributes.style "bottom" "10px"
, Html.Attributes.style "right" "10px"
, Html.Attributes.style "display"
(case hmrStatus of
HmrLoading ->
"block"
HmrLoaded ->
"none"
)
]
[ Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
]
onViewChangeElement currentUrl =
-- this is a hidden tag
-- it is used from the JS-side to reliably
@ -347,6 +380,7 @@ init pathKey canonicalSiteUrl document toJsPort viewFn content initUserModel fla
, userModel = userModel
, contentCache = contentCache
, phase = phase
, hmrStatus = HmrLoaded
}
, cmd
)
@ -362,6 +396,7 @@ init pathKey canonicalSiteUrl document toJsPort viewFn content initUserModel fla
, userModel = userModel
, contentCache = contentCache
, phase = Client
, hmrStatus = HmrLoaded
}
, Cmd.batch
[ userCmd |> Cmd.map UserMsg
@ -392,6 +427,7 @@ type AppMsg userMsg metadata view
| UpdateCacheForHotReload (Result Http.Error (ContentCache metadata view))
| PageScrollComplete
| HotReloadComplete ContentJson
| StartingHotReload
type Model userModel userMsg metadata view
@ -406,6 +442,7 @@ type alias ModelDetails userModel metadata view =
, contentCache : ContentCache metadata view
, userModel : userModel
, phase : Phase
, hmrStatus : HmrStatus
}
@ -594,11 +631,10 @@ update content allRoutes canonicalSiteUrl viewFunction pathKey onPageChangeMsg t
( model, Cmd.none )
HotReloadComplete contentJson ->
let
_ =
Debug.log "HotReloadComplete" { keys = Dict.keys contentJson.staticData, url = model.url.path }
in
( { model | contentCache = ContentCache.init document content (Just { contentJson = contentJson, initialUrl = model.url }) }
( { model
| contentCache = ContentCache.init document content (Just { contentJson = contentJson, initialUrl = model.url })
, hmrStatus = HmrLoaded
}
, Cmd.none
-- ContentCache.init document content (Maybe.map (\cj -> { contentJson = contentJson, initialUrl = model.url }) Nothing)
--|> ContentCache.lazyLoad document
@ -608,10 +644,22 @@ update content allRoutes canonicalSiteUrl viewFunction pathKey onPageChangeMsg t
--|> Task.attempt UpdateCacheForHotReload
)
StartingHotReload ->
let
_ =
Debug.log "starting..." ""
in
( { model | hmrStatus = HmrLoading }, Cmd.none )
CliMsg _ ->
( model, Cmd.none )
type HmrStatus
= HmrLoading
| HmrLoaded
application :
{ init :
Maybe
@ -718,16 +766,17 @@ application config =
, config.fromJsPort
|> Sub.map
(\decodeValue ->
--let
-- _ =
-- Debug.log "fromJsPort" (decodeValue |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder))
--in
case decodeValue |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder) of
Ok contentJson ->
AppMsg (HotReloadComplete contentJson)
case decodeValue |> Decode.decodeValue (Decode.field "thingy" Decode.string) |> Debug.log "thingy" of
Ok "hmr-check" ->
AppMsg StartingHotReload
Err error ->
Debug.todo ""
_ ->
case decodeValue |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder) of
Ok contentJson ->
AppMsg (HotReloadComplete contentJson)
Err error ->
Debug.todo ""
)
]