From 159c075324b47ec3f3f75a57daaaa008130e6804 Mon Sep 17 00:00:00 2001 From: Dillon Kearns Date: Thu, 3 Feb 2022 11:51:17 -0800 Subject: [PATCH] Send content.dat updates for hot reloading. --- generator/src/Pages/Internal/Platform.elm | 63 +++++++++++++------ generator/src/dev-server.js | 10 +-- generator/src/elm-pages-js-minified.js | 4 +- .../src/generate-template-module-connector.js | 4 ++ generator/static-code/elm-pages.js | 4 +- generator/static-code/hmr.js | 16 ++--- src/Pages/ProgramConfig.elm | 2 + 7 files changed, 68 insertions(+), 35 deletions(-) diff --git a/generator/src/Pages/Internal/Platform.elm b/generator/src/Pages/Internal/Platform.elm index 06c25959..3580c93e 100644 --- a/generator/src/Pages/Internal/Platform.elm +++ b/generator/src/Pages/Internal/Platform.elm @@ -12,6 +12,7 @@ import Browser import Browser.Dom as Dom import Browser.Navigation import BuildError exposing (BuildError) +import Bytes exposing (Bytes) import Bytes.Decode import Html exposing (Html) import Html.Attributes as Attr @@ -297,6 +298,7 @@ type Msg userMsg pageData | UpdateCacheAndUrlNew Url (Result Http.Error pageData) | PageScrollComplete | HotReloadComplete ContentJson + | HotReloadCompleteNew Bytes | ReloadCurrentPageData | NoOp @@ -617,6 +619,41 @@ update config appMsg model = PageScrollComplete -> ( model, Cmd.none ) + HotReloadCompleteNew pageDataBytes -> + let + route : route + route = + model.url + |> config.urlToRoute + + newThing : Maybe pageData + newThing = + pageDataBytes + |> Bytes.Decode.decode + (config.byteDecodePageData route) + in + model.pageData + |> Result.map + (\pageData -> + let + updatedPageData : Result String { userModel : userModel, sharedData : sharedData, pageData : pageData } + updatedPageData = + Ok + { userModel = pageData.userModel + , sharedData = pageData.sharedData + , pageData = + newThing + |> Maybe.withDefault pageData.pageData + } + in + ( { model + | pageData = updatedPageData + } + , Cmd.none + ) + ) + |> Result.withDefault ( model, Cmd.none ) + HotReloadComplete contentJson -> let urls : { currentUrl : Url, basePath : List String } @@ -817,29 +854,17 @@ application config = |> Sub.map UserMsg , config.fromJsPort |> Sub.map - (\decodeValue -> - case decodeValue |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder) of - Ok contentJson -> - HotReloadComplete contentJson - - Err _ -> - -- TODO should be no message here - ReloadCurrentPageData + (\_ -> + -- TODO should be no message here + ReloadCurrentPageData ) + , config.hotReloadData + |> Sub.map HotReloadCompleteNew ] Err _ -> - config.fromJsPort - |> Sub.map - (\decodeValue -> - case decodeValue |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder) of - Ok contentJson -> - HotReloadComplete contentJson - - Err _ -> - -- TODO should be no message here - ReloadCurrentPageData - ) + config.hotReloadData + |> Sub.map HotReloadCompleteNew , onUrlChange = UrlChanged , onUrlRequest = LinkClicked } diff --git a/generator/src/dev-server.js b/generator/src/dev-server.js index b79a4c44..50727408 100644 --- a/generator/src/dev-server.js +++ b/generator/src/dev-server.js @@ -196,7 +196,7 @@ async function start(options) { elmMakeRunning = false; }); clients.forEach((client) => { - client.response.write(`data: content.json\n\n`); + client.response.write(`data: content.dat\n\n`); }); } } else { @@ -218,7 +218,7 @@ async function start(options) { // } // }); clients.forEach((client) => { - client.response.write(`data: content.json\n\n`); + client.response.write(`data: content.dat\n\n`); }); } }); @@ -324,7 +324,7 @@ async function start(options) { const reviewOutput = await runElmReview(); console.log(restoreColorSafe(reviewOutput)); - if (req.url.includes("content.json")) { + if (req.url.includes("content.dat")) { res.writeHead(500, { "Content-Type": "application/json" }); if (emptyReviewError(reviewOutput)) { res.end(error); @@ -337,7 +337,7 @@ async function start(options) { } } else { console.log(restoreColorSafe(error)); - if (req.url.includes("content.json")) { + if (req.url.includes("content.dat")) { res.writeHead(500, { "Content-Type": "application/json" }); res.end(error); } else { @@ -423,7 +423,7 @@ async function start(options) { function (error) { console.log(restoreColorSafe(error)); - if (req.url.includes("content.json")) { + if (req.url.includes("content.dat")) { res.writeHead(500, { "Content-Type": "application/json" }); res.end(JSON.stringify(error)); } else { diff --git a/generator/src/elm-pages-js-minified.js b/generator/src/elm-pages-js-minified.js index 04ceccc7..c636a6fe 100644 --- a/generator/src/elm-pages-js-minified.js +++ b/generator/src/elm-pages-js-minified.js @@ -67,9 +67,9 @@ const appPromise = new Promise(function (resolve, reject) { userInit.load(appPromise); if (typeof connect === "function") { - connect(function (newContentJson) { + connect(function (bytesData) { appPromise.then((app) => { - app.ports.fromJsPort.send({ contentJson: newContentJson }); + app.ports.hotReloadData.send(bytesData); }); }); } diff --git a/generator/src/generate-template-module-connector.js b/generator/src/generate-template-module-connector.js index 21674d82..f16558e7 100644 --- a/generator/src/generate-template-module-connector.js +++ b/generator/src/generate-template-module-connector.js @@ -470,9 +470,13 @@ main = , sendPageData = sendPageData , byteEncodePageData = byteEncodePageData , byteDecodePageData = byteDecodePageData + , hotReloadData = hotReloadData identity } +port hotReloadData : (Bytes -> msg) -> Sub msg + + byteEncodePageData : PageData -> Bytes.Encode.Encoder byteEncodePageData pageData = case pageData of diff --git a/generator/static-code/elm-pages.js b/generator/static-code/elm-pages.js index c8b2dded..9e7924fb 100644 --- a/generator/static-code/elm-pages.js +++ b/generator/static-code/elm-pages.js @@ -70,9 +70,9 @@ const appPromise = new Promise(function (resolve, reject) { userInit.load(appPromise); if (typeof connect === "function") { - connect(function (newContentJson) { + connect(function (bytesData) { appPromise.then((app) => { - app.ports.fromJsPort.send({ contentJson: newContentJson }); + app.ports.hotReloadData.send(bytesData); }); }); } diff --git a/generator/static-code/hmr.js b/generator/static-code/hmr.js index 79b0bd80..c49b990e 100644 --- a/generator/static-code/hmr.js +++ b/generator/static-code/hmr.js @@ -9,7 +9,7 @@ function connect(sendContentJsonPort, initialErrorPage) { eventSource = new EventSource("/stream"); window.reloadOnOk = initialErrorPage; if (initialErrorPage) { - handleEvent(sendContentJsonPort, { data: "content.json" }); + handleEvent(sendContentJsonPort, { data: "content.dat" }); } eventSource.onmessage = async function (evt) { handleEvent(sendContentJsonPort, evt); @@ -17,7 +17,7 @@ function connect(sendContentJsonPort, initialErrorPage) { } async function handleEvent(sendContentJsonPort, evt) { - if (evt.data === "content.json") { + if (evt.data === "content.dat") { showCompiling(""); const elmJsRequest = elmJsFetch(); const fetchContentJson = fetchContentJsonForCurrentPage(); @@ -32,7 +32,7 @@ async function handleEvent(sendContentJsonPort, evt) { thenApplyHmr(elmJsResponse); } catch (errorJson) { if (typeof errorJson === "string") { - errorJson = JSON.parse(errorJson) + errorJson = JSON.parse(errorJson); } if (errorJson.type) { showError(errorJson); @@ -42,7 +42,7 @@ async function handleEvent(sendContentJsonPort, evt) { errors: errorJson, }); } else { - showError(JSON.parse(errorJson.errorsJson.errors)); + showError(JSON.parse(errorJson.errorsJson.errors)); } } } else if (evt.data === "elm.js") { @@ -84,7 +84,7 @@ async function updateContentJsonWith( } catch (errorJson) { if (errorJson.type) { showError(errorJson); - } else if (typeof errorJson === 'string') { + } else if (typeof errorJson === "string") { showError(JSON.parse(errorJson)); } else { showError(errorJson); @@ -98,10 +98,12 @@ function fetchContentJsonForCurrentPage() { let currentPath = window.location.pathname.replace(/(\w)$/, "$1/"); const contentJsonForPage = await fetch( - `${window.location.origin}${currentPath}content.json` + `${window.location.origin}${currentPath}content.dat` ); if (contentJsonForPage.ok || contentJsonForPage.status === 404) { - resolve(await contentJsonForPage.json()); + resolve( + new DataView(await (await contentJsonForPage.blob()).arrayBuffer()) + ); } else { try { reject(await contentJsonForPage.json()); diff --git a/src/Pages/ProgramConfig.elm b/src/Pages/ProgramConfig.elm index 2e487064..6258d8de 100644 --- a/src/Pages/ProgramConfig.elm +++ b/src/Pages/ProgramConfig.elm @@ -2,6 +2,7 @@ module Pages.ProgramConfig exposing (ProgramConfig) import ApiRoute import Browser.Navigation +import Bytes exposing (Bytes) import Bytes.Decode import Bytes.Encode import DataSource @@ -61,6 +62,7 @@ type alias ProgramConfig userMsg userModel route siteData pageData sharedData = , site : Maybe (SiteConfig siteData) , toJsPort : Json.Encode.Value -> Cmd Never , fromJsPort : Sub Decode.Value + , hotReloadData : Sub Bytes , onPageChange : { protocol : Url.Protocol , host : String