Skip to content

Commit

Permalink
Sitelets create root.js when non-prebundled (#1409)
Browse files Browse the repository at this point in the history
* #1408 write re-exports for non-bundled sitelet mode

* testing with FSharp proj

* fixes

* small fix for root.js addresses
  • Loading branch information
Jand42 committed Jun 6, 2024
1 parent 35e228e commit d027974
Show file tree
Hide file tree
Showing 18 changed files with 642 additions and 30 deletions.
12 changes: 11 additions & 1 deletion src/compiler/WebSharper.Compiler.CSharp/Compile.fs
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,18 @@ let Compile config (logger: LoggerBase) tryGetMetadata =
| Some (Bundle | Website | Service) -> Some (config.RuntimeMetadata, metas)
| _ -> None

let isSitelet =
match config.ProjectType with
| Some Html ->
true
| Some Website
| _ when Option.isSome config.OutputDir ->
true
| _ ->
false

let js, currentMeta, sources, res =
ModifyAssembly logger (Some comp) refMeta currentMeta config.SourceMap config.TypeScriptDeclaration config.TypeScriptOutput config.AnalyzeClosures runtimeMeta assem (config.ProjectType = None) config.PreBundle
ModifyAssembly logger (Some comp) refMeta currentMeta config.SourceMap config.TypeScriptDeclaration config.TypeScriptOutput config.AnalyzeClosures runtimeMeta assem (config.ProjectType = None) config.PreBundle isSitelet

match config.ProjectType with
| Some (Bundle | Website) ->
Expand Down
13 changes: 11 additions & 2 deletions src/compiler/WebSharper.Compiler.FSharp/Compile.fs
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,18 @@ let Compile (config : WsConfig) (warnSettings: WarnSettings) (logger: LoggerBase

let isLibrary = config.ProjectType = None

let js, currentMeta, sources, res =
ModifyAssembly logger (Some comp) (getRefMeta()) currentMeta config.SourceMap config.TypeScriptDeclaration config.TypeScriptOutput config.AnalyzeClosures runtimeMeta assem isLibrary config.PreBundle
let isSitelet =
match config.ProjectType with
| Some Html ->
true
| Some Website
| _ when Option.isSome config.OutputDir ->
true
| _ ->
false

let js, currentMeta, sources, res =
ModifyAssembly logger (Some comp) (getRefMeta()) currentMeta config.SourceMap config.TypeScriptDeclaration config.TypeScriptOutput config.AnalyzeClosures runtimeMeta assem isLibrary config.PreBundle isSitelet
match config.ProjectType with
| Some (Bundle | Website) ->
let wsRefs =
Expand Down
19 changes: 14 additions & 5 deletions src/compiler/WebSharper.Compiler/FrontEnd.fs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ let CreateBundleJSOutput (logger: LoggerBase) refMeta current entryPoint =

Some ("", "")

let CreateResources (logger: LoggerBase) (comp: Compilation option) (refMeta: M.Info) (current: M.Info) sourceMap dts ts closures (runtimeMeta: option<M.MetadataOptions * M.Info list>) (a: Mono.Cecil.AssemblyDefinition) isLibrary prebundle =
let CreateResources (logger: LoggerBase) (comp: Compilation option) (refMeta: M.Info) (current: M.Info) sourceMap dts ts closures (runtimeMeta: option<M.MetadataOptions * M.Info list>) (a: Mono.Cecil.AssemblyDefinition) isLibrary prebundle isSitelet =
let assemblyName = a.Name.Name
let sourceMap = false // TODO what about source mapping with all the small files
let currentPosFixed, sources =
Expand Down Expand Up @@ -214,6 +214,15 @@ let CreateResources (logger: LoggerBase) (comp: Compilation option) (refMeta: M.
bname, js, trAddrMap
)
|> Array.ofSeq |> Some
elif isSitelet then
let rootJS, addrMap = JavaScriptPackager.packageEntryPointReexport meta
let program, _, trAddrMap = rootJS |> WebSharper.Compiler.JavaScriptWriter.transformProgramAndAddrMap O.JavaScript WebSharper.Core.JavaScript.Readable addrMap
let js, _, _ = WebSharper.Compiler.JavaScriptPackager.programToString WebSharper.Core.JavaScript.Readable WebSharper.Core.JavaScript.Writer.CodeWriter program false
let trAddrMap = Dict.union [ trAddrMap; dict [ AST.Address.Global(), assemblyName ] ]
logger.TimedStage (sprintf "Writing reexports root.js")
Some [|
"root", js, trAddrMap
|]
else
None
let updated =
Expand Down Expand Up @@ -382,16 +391,16 @@ let CreateResources (logger: LoggerBase) (comp: Compilation option) (refMeta: M.
addMeta()
None, currentPosFixed, sources, res.ToArray()

let ModifyCecilAssembly (logger: LoggerBase) (comp: Compilation option) (refMeta: M.Info) (current: M.Info) sourceMap dts ts closures runtimeMeta (a: Mono.Cecil.AssemblyDefinition) isLibrary prebundle =
let jsOpt, currentPosFixed, sources, res = CreateResources logger comp refMeta current sourceMap dts ts closures runtimeMeta a isLibrary prebundle
let ModifyCecilAssembly (logger: LoggerBase) (comp: Compilation option) (refMeta: M.Info) (current: M.Info) sourceMap dts ts closures runtimeMeta (a: Mono.Cecil.AssemblyDefinition) isLibrary prebundle isSitelet =
let jsOpt, currentPosFixed, sources, res = CreateResources logger comp refMeta current sourceMap dts ts closures runtimeMeta a isLibrary prebundle isSitelet
let pub = Mono.Cecil.ManifestResourceAttributes.Public
for name, contents in res do
Mono.Cecil.EmbeddedResource(name, pub, contents)
|> a.MainModule.Resources.Add
jsOpt, currentPosFixed, sources, res

let ModifyAssembly (logger: LoggerBase) (comp: Compilation option) (refMeta: M.Info) (current: M.Info) sourceMap dts ts closures runtimeMeta (assembly : Assembly) isLibrary =
ModifyCecilAssembly logger comp refMeta current sourceMap dts ts closures runtimeMeta assembly.Raw isLibrary
let ModifyAssembly (logger: LoggerBase) (comp: Compilation option) (refMeta: M.Info) (current: M.Info) sourceMap dts ts closures runtimeMeta (assembly : Assembly) isLibrary prebundle isSitelet =
ModifyCecilAssembly logger comp refMeta current sourceMap dts ts closures runtimeMeta assembly.Raw isLibrary prebundle isSitelet

let AddExtraAssemblyReferences (wsrefs: Assembly seq) (assembly : Assembly) =
let a = assembly.Raw
Expand Down
84 changes: 75 additions & 9 deletions src/compiler/WebSharper.Compiler/JavaScriptPackager.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1378,16 +1378,82 @@ let programToString pref (getWriter: unit -> WebSharper.Core.JavaScript.Writer.C
WebSharper.Core.JavaScript.Writer.WriteProgram pref writer program
writer.GetCodeFile(), writer.GetMapFile(), isJSX

let packageEntryPoint (runtimeMeta: M.Info) (graph: DependencyGraph.Graph) asmName =
let packageEntryPointReexport (runtimeMeta: M.Info) =

let allBundleContent = ResizeArray()
let addresses = ResizeArray()

//let webControls =
// runtimeMeta.Classes |> Seq.choose (fun (KeyValue(td, (_, _, cls))) ->
// match cls with
// | Some cls when isWebControl cls ->
// Some td
// | _ -> None
// )
// |> Array.ofSeq
for qi in runtimeMeta.Quotations.Values do
allBundleContent.Add(qi.TypeDefinition, Some qi.Method)

for KeyValue((td, m), _) in runtimeMeta.QuotedMethods do
allBundleContent.Add(td, Some m)

for wc in runtimeMeta.WebControls do
allBundleContent.Add(wc.Key.TypeDefinition, None)

for td, m in allBundleContent do
match runtimeMeta.Classes.TryFind td with
| Some (addr, _, Some cls) ->
match m with
| Some m ->
match cls.Methods.TryFind m with
| Some mi ->
match mi.CompiledForm with
| M.Static (name, _, _) -> addresses.Add(addr)
| M.Func (name, _) -> addresses.Add(addr.Func(name))
| M.GlobalFunc (faddr, _) -> addresses.Add(faddr)
| _ -> ()
| _ -> ()
| _ ->
addresses.Add(addr)
| _ -> ()

let addressMap = Dictionary()

addressMap.Add("Runtime", Address.RuntimeAddr [ "default" ])

for a in Seq.distinct addresses do
addressMap |> Resolve.getRenamedInDict a.Address.Head a |> ignore

let revAddressMap = addressMap |> Dict.swap

let finalAddrMap = Dictionary()

let rootJs =
revAddressMap |> Seq.groupBy (fun kv -> kv.Key.Module)
|> Seq.map (fun (m, addrs) ->
let namedImports = ResizeArray()
for KeyValue(a, n) in addrs do
match a.Address |> List.rev |> List.head with
| "default" ->
let newName =
match m with
| JavaScriptModule m ->
m.Name.Replace('.', '_').Replace('`', '_')
| DotNetType m ->
(m.Name.Split([| '/'; '.' |]) |> Array.last).Split('`') |> Array.head
| _ -> "x"
let x = Id.New newName
namedImports.Add("default", x)
finalAddrMap.Add(a, x)
| i ->
let x = Id.New n
namedImports.Add(i, x)
finalAddrMap.Add(a, x)
let moduleName =
match m with
| JavaScriptModule m
| DotNetType m ->
"../" + m.Assembly + "/" + m.Name + ".js"
| _ -> ""
ExportDecl (false, Import(None, None, List.ofSeq namedImports, moduleName))
)
|> List.ofSeq

rootJs, finalAddrMap

let packageEntryPoint (runtimeMeta: M.Info) (graph: DependencyGraph.Graph) asmName =

let all = ResizeArray()
let bundles = Dictionary()
Expand Down
20 changes: 18 additions & 2 deletions src/compiler/WebSharper.Compiler/JavaScriptWriter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ type CollectVariables(env: Environment) =
override this.VisitAlias(a, _, _) =
defineId env a |> ignore

override this.VisitExportDecl(_, s) =
match s with
| Import(None, None, namedImports, _) ->
namedImports |> List.iter (snd >> defineId env >> ignore)
| _ ->
this.VisitStatement(s)

override this.VisitImport(d, f, n, m) =
if m = "" then
// global values used
Expand Down Expand Up @@ -549,6 +556,14 @@ and transformStatement (env: Environment) (statement: Statement) : J.Statement =
b |> Option.map (defineId env),
c |> List.map (fun (n, x) -> n, defineId env x),
d)
| ExportDecl (a, Import(None, None, b, c)) ->
J.Export (a,
J.Import(
None,
None,
b |> List.map (fun (n, x) -> n, transformId env x),
c)
)
| ExportDecl (a, b) ->
J.Export (a, trS b)
| Declare a ->
Expand Down Expand Up @@ -745,5 +760,6 @@ let transformProgramAndAddrMap output pref (addrMap: IDictionary<Address, Id>) s
let env = Environment.New(pref, output)
let cvars = CollectVariables(env)
statements |> List.iter cvars.VisitStatement
let trAddrMap = addrMap |> Dict.map (fun id -> (transformId env id).Name)
(statements |> List.map (transformStatement env) |> flattenJS), env.IsJSX.Value, trAddrMap
(statements |> List.map (transformStatement env) |> flattenJS),
env.IsJSX.Value,
(addrMap |> Dict.map (fun id -> (transformId env id).Name))
36 changes: 33 additions & 3 deletions src/sitelets/WebSharper.Sitelets/Content.fs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,13 @@ module Content =
|> Seq.collect importsOf
|> Array.ofSeq

let hasRoot =
ctx.Metadata.PreBundle.Count = 1 && ctx.Metadata.PreBundle.ContainsKey("root")

let bundleName =
if ctx.Metadata.PreBundle.Count > 0 && allImports.Length > 0 then
if hasRoot then
Some "root"
elif ctx.Metadata.PreBundle.Count > 0 && allImports.Length > 0 then
match requiredBundles with
| [||] ->
if ctx.Metadata.PreBundle.ContainsKey("all") then Some "all" else None
Expand Down Expand Up @@ -197,7 +202,32 @@ module Content =
| None -> None
| Some bundle ->
match bundle.TryFind a with
| Some b -> Some ("wsbundle." + b)
| Some b ->
if hasRoot then
match imported.TryGetValue(f) with
| true, i ->
Some i
| _ ->
let i = "i" + string (imported.Count + 1)
match f.Address |> List.rev with
| [] -> failwith "empty address"
| a :: r ->
let j =
match a with
| "default" ->
match r with
| [] ->
i :: r |> String.concat "."
| _ :: rr ->
i :: rr |> String.concat "."
| _ ->
i :: r |> String.concat "."
imported.Add(f, j)
let asmName = bundle[AST.Address.Global()]
scriptsTw.WriteLine($"""import {{ {b} as {i} }} from "{url}{asmName}/root.js";""")
Some j
else
Some ("wsbundle." + b)
| None ->
match a.Address with
| h :: t ->
Expand Down Expand Up @@ -272,7 +302,7 @@ module Content =
scriptsTw.WriteLine($"""{v}.$postinit("{i}");""")
| _ -> ()

Some activate, bundleName |> Option.map Array.singleton
Some activate, if hasRoot then None else bundleName |> Option.map Array.singleton
else
None, None

Expand Down
1 change: 1 addition & 0 deletions tests/Web.FSharp/Main.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
margin: 20px 0;
}
</style>
<script type="module" src="/@vite/client"></script>
</head>
<body>
<!-- Static navbar -->
Expand Down
8 changes: 8 additions & 0 deletions tests/Web.FSharp/Startup.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ type Startup () =
app.UseDeveloperExceptionPage() |> ignore

app.UseAuthentication()
.Use(fun context (next: RequestDelegate) ->
if context.Request.Path.StartsWithSegments("/Scripts") || context.Request.Path.StartsWithSegments("/@vite") then
let proxyRequest = context.Request.Path.Value
context.Response.Redirect($"http://localhost:5173{proxyRequest}")
Task.CompletedTask
else
next.Invoke(context)
)
.UseStaticFiles()
.UseWebSharper()
.Run(fun context ->
Expand Down
4 changes: 4 additions & 0 deletions tests/Web.FSharp/Web.FSharp.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<WebSharperTypeScriptOutput>False</WebSharperTypeScriptOutput>
</PropertyGroup>
<ItemGroup>
<None Include="vite.config.js" />
<Content Include="Main.html" CopyToPublishDirectory="Always" />
<Compile Include="Startup.fs" />
<None Include="wsconfig.json" />
Expand Down Expand Up @@ -37,6 +38,9 @@
<ProjectReference Include="..\WebSharper.Web.Tests\WebSharper.Web.Tests.fsproj" />
<ProjectReference Include="..\Website\Website.fsproj" />
</ItemGroup>
<Target Name="EnsureNodeModulesInstalled" BeforeTargets="Build">
<Exec Command="npm install" />
</Target>
<Import Project="..\..\msbuild\WebSharper.FSharp.Internal.targets" />
<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>
Loading

0 comments on commit d027974

Please sign in to comment.