Mobile devices have many different screen sizes, and building the app to be pixel perfect on all different sizes can be time-consuming. Running live update on multiple devices would speed up this time considerably.
Live update relies on a port and replacing the code at runtime with reflection. Currently, there is no way to change the port.
The live update tool already supports specifying the port to send the code too --webhook:http://localhost:9868/update https://github.com/fsprojects/FSharp.Compiler.PortaCode/blob/7bc5e17b32d848024e4635553eda3fc0afbb5156/src/ProcessCommandLine.fs#L70
The app simply needs a way to override the port. This could be done by override the port for each build:
do runner.EnableLiveUpdate(port = 9868)
I have done this and tested locally and it works.
Steps:
Build and deploy to the device with the default port.
stop the app and manually start on the device
Set a new port number in code; build and deploy
start live update with default port
open another terminal, start live update with new port ie
fabulous --watch --send --define:LIVE_UPDATE --webhook:http://localhost:9868/update
make a code change and watch both devices update.
I had the code working for this against version 0.36 ie before the refactor. The code changes are very small.
After checking out master (0.40.x) my changes did not work, and given a little more investigation (file new project with 0.40.4 via nuget) live update is not working.
The main issue is this:
System.Exception: NYI: extension of generic type, needs FCS support: ProgramRunner`3::member EnableLiveUpdate
at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1647.Invoke(String message)
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convMemberRef(FSharpMemberOrFunctionOrValue memb, range range) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 246
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convExpr(FSharpExpr expr) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 39
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convExpr(FSharpExpr expr) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 110
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convExpr(FSharpExpr expr) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 110
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convExpr(FSharpExpr expr) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 77
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convExpr(FSharpExpr expr) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 110
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convExpr(FSharpExpr expr) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 110
at FSharp.Compiler.PortaCode.FromCompilerService.Convert.convExpr(FSharpExpr expr) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 77
at FSharp.Compiler.PortaCode.FromCompilerService.clo@340-33.GenerateNext(IEnumerable`1& next) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 357
at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1647.Invoke(String message)
at FSharp.Compiler.PortaCode.FromCompilerService.clo@340-33.GenerateNext(IEnumerable`1& next) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 357
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1.MoveNextImpl()
at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source)
at Microsoft.FSharp.Collections.ArrayModule.Collect[T,TResult](FSharpFunc`2 mapping, T[] array)
at FSharp.Compiler.PortaCode.FromCompilerService.clo@340-33.GenerateNext(IEnumerable`1& next) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\FromCompilerService.fs:line 343
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1.MoveNextImpl()
at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source)
at Microsoft.FSharp.Collections.ArrayModule.Collect[T,TResult](FSharpFunc`2 mapping, T[] array)
at [email protected](FSharpImplementationFileContents i) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\ProcessCommandLine.fs:line 188
at FSharp.Compiler.PortaCode.ProcessCommandLine.jsonFiles@213.Invoke(FSharpImplementationFileContents[] impls) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\ProcessCommandLine.fs:line 213
at FSharp.Compiler.PortaCode.ProcessCommandLine.sendToWebHook@218.Invoke(String hook, FSharpList`1 fileContents) in D:\a\1\s\paket-files\neutral\fsprojects\FSharp.Compiler.PortaCode\src\ProcessCommandLine.fs:line 219"
Another minor issue is the template is wrong:
#if DEBUG
open LiveUpdate
#endif
is required or EnableLiveUpdate is not found for this line: runner.EnableLiveUpdate()
@TimLariviere should this issue be addressed in a separate issue?
Yes, please open a separate issue for the template
Quick check in FSharp.Compiler.PortaCode confirmed my intuition.
We changed from ProgramRunner<'model, 'msg> to ProgramRunner<'arg, 'model, 'msg> to match what Elmish does, and FCS doesn't like that.
Hopefully it should be easy enough to do a quick fix in FCS
// TODO: extensions of generic type
if memb.IsExtensionMember && memb.ApparentEnclosingEntity.GenericParameters.Count > 0 && not (memb.CompiledName = "ProgramRunner`2.EnableLiveUpdate") then
failwithf "NYI: extension of generic type, needs FCS support: %A::%A" memb.ApparentEnclosingEntity memb
@willsam100 The issue has been fixed in 0.41.0
Most helpful comment
Yes, please open a separate issue for the template
Quick check in FSharp.Compiler.PortaCode confirmed my intuition.
We changed from
ProgramRunner<'model, 'msg>toProgramRunner<'arg, 'model, 'msg>to match what Elmish does, and FCS doesn't like that.Hopefully it should be easy enough to do a quick fix in FCS
https://github.com/fsprojects/FSharp.Compiler.PortaCode/blob/0d254ac8b1ad333de453e98fb1f274b37564467a/src/FromCompilerService.fs#L242-L244