Send content.dat updates for hot reloading.

This commit is contained in:
Dillon Kearns 2022-02-03 11:51:17 -08:00
parent 82dea47a89
commit 159c075324
7 changed files with 68 additions and 35 deletions

View File

@ -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
}

View File

@ -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 {

View File

@ -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);
});
});
}

View File

@ -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

View File

@ -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);
});
});
}

View File

@ -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());

View File

@ -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