Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sitelets create root.js when non-prebundled #1409

Merged
merged 4 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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