├── .gitignore ├── LICENSE.md ├── README.md ├── WebSharper.Warp.Test ├── App.config ├── Program.fs └── WebSharper.Warp.Test.fsproj ├── WebSharper.Warp.sln ├── WebSharper.Warp ├── Warp.fs ├── Warp.fsi ├── WebSharper.Warp.fsproj ├── reference-nover.fsx └── reference.fsx ├── build.cmd ├── build.fsx ├── build.sh ├── getting-started.md ├── ivy.xml ├── readme.txt.in └── tools ├── NuGet └── NuGet.exe └── includes.fsx /.gitignore: -------------------------------------------------------------------------------- 1 | tools/packages/ 2 | packages/ 3 | build/ 4 | bin/ 5 | obj/ 6 | *.suo 7 | */Scripts/WebSharper/ 8 | */Content/WebSharper/ 9 | readme.txt 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | ## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | ## END OF TERMS AND CONDITIONS 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # websharper.warp 2 | 3 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/intellifactory/websharper.warp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | WebSharper Warp is a friction-less web development library for building **scripted** and **standalone** **full-stack** F# client-server applications. Warp is built on top of WebSharper and is designed to help you become more productive in these scenarios by providing an API for on-the-fly compilation and an OWIN compliant server middleware for self-hosting or embedding sitelets in various compatible web servers. 6 | 7 | **Update**: Note that many Warp shorthands have been integrated into WebSharper now. To use these new shorthands, you don't need Warp, but be sure to open `WebSharper.Sitelets` instead. (You can find the old getting started guide that uses Warp [here](getting-started.md)). 8 | 9 | * `Warp.Page` -> `Content.Page` 10 | * `Warp.Text` -> `Content.Text` 11 | * `Warp.Json` -> `Content.Json` 12 | * `Warp.CreateSPA` -> `Application.SinglePage` 13 | * `Warp.CreateApplication` -> `Application.MultiPage` 14 | 15 | # Installing 16 | 17 | To get started with Warp is super-easy, all you need is to open a new F# Console Application (or any other F# project type if you want to script applications), and add `WebSharper.Warp` to it: 18 | 19 | ``` 20 | Install-Package WebSharper.Warp 21 | ``` 22 | 23 | Or if you use [Paket](http://fsprojects.github.io/Paket/): 24 | 25 | ``` 26 | paket init 27 | paket add nuget WebSharper.Warp 28 | ``` 29 | 30 | # Scripting with Warp 31 | 32 | When you add the `WebSharper.Warp` NuGet package to your project in Visual Studio, a new document tab will open giving the necessary boilerplate for using Warp in scripted applications. 33 | 34 | For instance, the SPA example above can be written as an F# script and executed in F# Interative: 35 | 36 | ```fsharp 37 | #I "../packages/Owin.1.0/lib/net40" 38 | #I "../packages/Microsoft.Owin.3.0.1/lib/net45" 39 | #I "../packages/Microsoft.Owin.Host.HttpListener.3.0.1/lib/net45" 40 | #I "../packages/Microsoft.Owin.Hosting.3.0.1/lib/net45" 41 | #I "../packages/Microsoft.Owin.FileSystems.3.0.1/lib/net45" 42 | #I "../packages/Microsoft.Owin.StaticFiles.3.0.1/lib/net45" 43 | #I "../packages/WebSharper.3.2.8.170/lib/net40" 44 | #I "../packages/WebSharper.Compiler.3.2.4.170/lib/net40" 45 | #I "../packages/WebSharper.Owin.3.2.6.83/lib/net45" 46 | #load "../packages/WebSharper.Warp.3.2.10.13/tools/reference.fsx" 47 | 48 | open WebSharper 49 | open WebSharper.Html.Server 50 | 51 | let MySite = 52 | Warp.CreateSPA (fun ctx -> 53 | [H1 [Text "Hello world!"]]) 54 | 55 | do Warp.RunAndWaitForInput(MySite) |> ignore 56 | ``` 57 | 58 | If you use Paket, then you should replace the `#`-lines above with this one: 59 | 60 | ```fsharp 61 | #load "../packages/WebSharper.Warp/tools/reference-nover.fsx" 62 | ``` 63 | 64 | In FSI, you should see: 65 | 66 | ``` 67 | --> Added 'c:\sandbox\test\Library1\HelloWorld\../packages/Owin.1.0/lib/net40' to library include path 68 | [... more lines ...] 69 | 70 | [Loading c:\sandbox\test\Library1\packages\WebSharper.Warp.3.2.10.13\tools\reference.fsx] 71 | 72 | namespace FSI_0004 73 | 74 | Serving http://localhost:9000/, press Enter to stop. 75 | ``` 76 | 77 | You can then test this application as before: 78 | 79 | ![](http://i.imgur.com/xYITvCql.png) 80 | -------------------------------------------------------------------------------- /WebSharper.Warp.Test/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WebSharper.Warp.Test/Program.fs: -------------------------------------------------------------------------------- 1 | namespace WebSharper.Warp.Test 2 | 3 | open WebSharper 4 | open WebSharper.Sitelets 5 | 6 | type EndPoints = 7 | | [] Index 8 | 9 | [] 10 | module Client = 11 | 12 | open WebSharper.Html.Client 13 | open WebSharper.JavaScript 14 | 15 | let Content () = 16 | Button [Text "Click me!"] 17 | |>! OnClick (fun _ _ -> 18 | JS.Alert "Clicked!") 19 | 20 | module Server = 21 | 22 | open WebSharper.Html.Server 23 | 24 | let app = 25 | Application.MultiPage(fun ctx endpoint -> 26 | match endpoint with 27 | | EndPoints.Index -> 28 | Content.Page( 29 | Title = "Welcome to my site!", 30 | Body = [ 31 | Div [Text (System.DateTime.UtcNow.ToString())] 32 | Div [ClientSide <@ Client.Content () @>] 33 | ] 34 | ) 35 | ) 36 | 37 | [] 38 | let main argv = 39 | Warp.RunAndWaitForInput(app, urls = ["http://localhost:9000"; "http://127.0.0.1:9000"]) 40 | -------------------------------------------------------------------------------- /WebSharper.Warp.Test/WebSharper.Warp.Test.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 1208759e-f34b-40c2-9900-73c370a0934a 9 | Exe 10 | WebSharper.Warp.Test 11 | WebSharper.Warp.Test 12 | v4.5 13 | true 14 | 4.3.1.0 15 | WebSharper.Warp.Test 16 | 17 | 18 | true 19 | full 20 | false 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | 3 25 | AnyCPU 26 | bin\Debug\WebSharper.Warp.Test.XML 27 | true 28 | 29 | 30 | pdbonly 31 | true 32 | true 33 | bin\Release\ 34 | TRACE 35 | 3 36 | AnyCPU 37 | bin\Release\WebSharper.Warp.Test.XML 38 | true 39 | 40 | 41 | 42 | 43 | 44 | 45 | 11 46 | 47 | 48 | 49 | 50 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 51 | 52 | 53 | 54 | 55 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /WebSharper.Warp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.Warp", "WebSharper.Warp\WebSharper.Warp.fsproj", "{4BD496F1-B318-4669-82C7-A45734F46A30}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.Warp.Test", "WebSharper.Warp.Test\WebSharper.Warp.Test.fsproj", "{1208759E-F34B-40C2-9900-73C370A0934A}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4BD496F1-B318-4669-82C7-A45734F46A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {4BD496F1-B318-4669-82C7-A45734F46A30}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {4BD496F1-B318-4669-82C7-A45734F46A30}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {4BD496F1-B318-4669-82C7-A45734F46A30}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {1208759E-F34B-40C2-9900-73C370A0934A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {1208759E-F34B-40C2-9900-73C370A0934A}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {1208759E-F34B-40C2-9900-73C370A0934A}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {1208759E-F34B-40C2-9900-73C370A0934A}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /WebSharper.Warp/Warp.fs: -------------------------------------------------------------------------------- 1 | namespace WebSharper 2 | 3 | open System 4 | open System.Collections.Generic 5 | open System.IO 6 | open System.Reflection 7 | open System.Runtime.CompilerServices 8 | open System.Threading.Tasks 9 | open WebSharper.Sitelets 10 | open global.Owin 11 | open Microsoft.Owin.Hosting 12 | open Microsoft.Owin.StaticFiles 13 | open Microsoft.Owin.FileSystems 14 | open WebSharper 15 | open WebSharper.Owin 16 | open WebSharper.Html.Server 17 | 18 | [] 19 | module Extensions = 20 | open WebSharper.Html.Server 21 | 22 | type Sitelets.Page with 23 | member this.WithStyleSheet (href: string) = 24 | let css = Link [Rel "stylesheet"; HRef href] 25 | { this with 26 | Head = Seq.append this.Head [css] 27 | } 28 | 29 | member this.WithJavaScript (href: string) = 30 | let css = Script [Type "text/javascript"; Src href] 31 | { this with 32 | Head = Seq.append this.Head [css] 33 | } 34 | 35 | module SPA = 36 | type EndPoint = 37 | | [] Home 38 | 39 | module internal Compilation = 40 | 41 | module PC = WebSharper.PathConventions 42 | 43 | open System.Reflection 44 | open IntelliFactory.Core 45 | module FE = WebSharper.Compiler.FrontEnd 46 | 47 | type CompiledAssembly = 48 | { 49 | ReadableJavaScript : string 50 | CompressedJavaScript : string 51 | Info : WebSharper.Core.Metadata.Info 52 | References : list 53 | } 54 | 55 | let websharperDir = lazy (Path.GetDirectoryName typeof>.Assembly.Location) 56 | 57 | let getRefs (loader: Compiler.Loader) = 58 | [ 59 | for dll in Directory.EnumerateFiles(websharperDir.Value, "*.dll") do 60 | if Path.GetFileName(dll) <> "FSharp.Core.dll" then 61 | yield dll 62 | let dontRef (n: string) = 63 | [ 64 | "FSharp.Compiler.Interactive.Settings," 65 | "FSharp.Compiler.Service," 66 | "FSharp.Core," 67 | "FSharp.Data.TypeProviders," 68 | "Mono.Cecil" 69 | "mscorlib," 70 | "System." 71 | "System," 72 | ] |> List.exists n.StartsWith 73 | let rec loadRefs (asms: Assembly[]) (loaded: Map) = 74 | let refs = 75 | asms 76 | |> Seq.collect (fun asm -> asm.GetReferencedAssemblies()) 77 | |> Seq.map (fun n -> n.FullName) 78 | |> Seq.distinct 79 | |> Seq.filter (fun n -> not (dontRef n || Map.containsKey n loaded)) 80 | |> Seq.choose (fun n -> 81 | try Some (AppDomain.CurrentDomain.Load n) 82 | with _ -> None) 83 | |> Array.ofSeq 84 | if Array.isEmpty refs then 85 | loaded 86 | else 87 | (loaded, refs) 88 | ||> Array.fold (fun loaded r -> Map.add r.FullName r loaded) 89 | |> loadRefs refs 90 | let asms = 91 | AppDomain.CurrentDomain.GetAssemblies() 92 | |> Array.append (AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()) 93 | |> Array.filter (fun a -> not (dontRef a.FullName)) 94 | yield! asms 95 | |> Array.map (fun asm -> asm.FullName, asm) 96 | |> Map.ofArray 97 | |> loadRefs asms 98 | |> Seq.choose (fun (KeyValue(n, asm)) -> 99 | try Some asm.Location 100 | with :? NotSupportedException -> 101 | // The dynamic assembly does not support `.Location`. 102 | // No problem, if it's from the dynamic assembly then 103 | // it doesn't incur a dependency anyway. 104 | None) 105 | ] 106 | |> Seq.distinctBy Path.GetFileName 107 | |> Seq.map loader.LoadFile 108 | |> Seq.toList 109 | 110 | let getLoader() = 111 | let localDir = Directory.GetCurrentDirectory() 112 | let fsharpDir = Path.GetDirectoryName typeof>.Assembly.Location 113 | let loadPaths = 114 | [ 115 | localDir 116 | websharperDir.Value 117 | fsharpDir 118 | ] 119 | let aR = 120 | AssemblyResolver.Create() 121 | .SearchDirectories(loadPaths) 122 | .WithBaseDirectory(fsharpDir) 123 | FE.Loader.Create aR stderr.WriteLine 124 | 125 | let compile (asm: System.Reflection.Assembly) = 126 | let loader = getLoader() 127 | let refs = getRefs loader 128 | let opts = { FE.Options.Default with References = refs } 129 | let compiler = FE.Prepare opts (eprintfn "%O") 130 | compiler.Compile(asm) 131 | |> Option.map (fun asm -> 132 | { 133 | ReadableJavaScript = asm.ReadableJavaScript 134 | CompressedJavaScript = asm.CompressedJavaScript 135 | Info = asm.Info 136 | References = refs 137 | } 138 | ) 139 | 140 | let getCompiled (asm: System.Reflection.Assembly) = 141 | let loader = getLoader() 142 | let refs = getRefs loader 143 | refs 144 | |> List.tryFind (fun r -> r.FullName = asm.FullName) 145 | |> Option.bind (fun r -> 146 | match r.ReadableJavaScript, r.CompressedJavaScript with 147 | | Some readable, Some compressed -> 148 | let opts = { FE.Options.Default with References = refs } 149 | let compiler = FE.Prepare opts (eprintfn "%O") 150 | Some { 151 | ReadableJavaScript = readable 152 | CompressedJavaScript = compressed 153 | Info = compiler.GetInfo() 154 | References = refs 155 | } 156 | | _ -> 157 | eprintfn "Assembly not compiled. When using Scripted = false, the application must be precompiled." 158 | None) 159 | 160 | let outputFiles root (refs: Compiler.Assembly list) = 161 | let pc = PC.PathUtility.FileSystem(root) 162 | let writeTextFile path contents = 163 | Directory.CreateDirectory (Path.GetDirectoryName path) |> ignore 164 | File.WriteAllText(path, contents) 165 | let writeBinaryFile path contents = 166 | Directory.CreateDirectory (Path.GetDirectoryName path) |> ignore 167 | File.WriteAllBytes(path, contents) 168 | let emit text path = 169 | match text with 170 | | Some text -> writeTextFile path text 171 | | None -> () 172 | let script = PC.ResourceKind.Script 173 | let content = PC.ResourceKind.Content 174 | for a in refs do 175 | let aid = PC.AssemblyId.Create(a.FullName) 176 | emit a.ReadableJavaScript (pc.JavaScriptPath aid) 177 | emit a.CompressedJavaScript (pc.MinifiedJavaScriptPath aid) 178 | let writeText k fn c = 179 | let p = pc.EmbeddedPath(PC.EmbeddedResource.Create(k, aid, fn)) 180 | writeTextFile p c 181 | let writeBinary k fn c = 182 | let p = pc.EmbeddedPath(PC.EmbeddedResource.Create(k, aid, fn)) 183 | writeBinaryFile p c 184 | for r in a.GetScripts() do 185 | writeText script r.FileName r.Content 186 | for r in a.GetContents() do 187 | writeBinary content r.FileName (r.GetContentData()) 188 | 189 | let (+/) x y = Path.Combine(x, y) 190 | 191 | let outputFile root (asm: CompiledAssembly) = 192 | let dir = root +/ "Scripts" +/ "WebSharper" 193 | Directory.CreateDirectory(dir) |> ignore 194 | File.WriteAllText(dir +/ "WebSharper.EntryPoint.js", asm.ReadableJavaScript) 195 | File.WriteAllText(dir +/ "WebSharper.EntryPoint.min.js", asm.CompressedJavaScript) 196 | 197 | type WarpApplication<'EndPoint when 'EndPoint : equality> = Sitelet<'EndPoint> 198 | 199 | [] 200 | module Owin = 201 | 202 | type WarpOptions<'EndPoint when 'EndPoint : equality>(assembly, ?debug, ?rootDir, ?scripted) = 203 | let debug = defaultArg debug false 204 | let rootDir = defaultArg rootDir (Directory.GetCurrentDirectory()) 205 | let scripted = defaultArg scripted true 206 | 207 | member this.Assembly = assembly 208 | member this.Debug = debug 209 | member this.RootDir = rootDir 210 | member this.Scripted = scripted 211 | 212 | type WarpMiddleware<'EndPoint when 'EndPoint : equality>(next: Owin.AppFunc, sitelet: WarpApplication<'EndPoint>, options: WarpOptions<'EndPoint>) = 213 | let exec = 214 | // Compile only when the app starts and not on every request. 215 | let compile = 216 | if options.Scripted then 217 | Compilation.compile 218 | else 219 | Compilation.getCompiled 220 | match compile options.Assembly with 221 | | None -> failwith "Failed to compile with WebSharper" 222 | | Some asm -> 223 | Compilation.outputFiles options.RootDir asm.References 224 | Compilation.outputFile options.RootDir asm 225 | // OWIN middleware form a Russian doll, innermost -> outermost 226 | let siteletMw = 227 | WebSharper.Owin.SiteletMiddleware( 228 | next, 229 | Options.Create(asm.Info) 230 | .WithServerRootDirectory(options.RootDir) 231 | .WithDebug(options.Debug), 232 | sitelet) 233 | let staticFilesMw = 234 | Microsoft.Owin.StaticFiles.StaticFileMiddleware( 235 | AppFunc siteletMw.Invoke, 236 | StaticFileOptions( 237 | FileSystem = PhysicalFileSystem(options.RootDir))) 238 | staticFilesMw.Invoke 239 | 240 | member this.Invoke(env: IDictionary) = exec env 241 | 242 | /// Adds the Warp middleware to an Owin.IAppBuilder pipeline. 243 | [] 244 | let UseWarp(appB: Owin.IAppBuilder, sitelet: WarpApplication<'EndPoint>, options) = 245 | Owin.MidFunc(fun next -> 246 | let mw = WarpMiddleware<_>(next, sitelet, options) 247 | Owin.AppFunc mw.Invoke) 248 | |> appB.Use 249 | 250 | #if NO_UINEXT 251 | #else 252 | open WebSharper.UI.Next 253 | open WebSharper.UI.Next.Server 254 | #endif 255 | 256 | [] 257 | type Warp internal (urls: list, stop: unit -> unit) = 258 | 259 | member this.Urls = urls 260 | 261 | member this.Stop() = stop() 262 | 263 | interface System.IDisposable with 264 | member this.Dispose() = stop() 265 | 266 | [] 267 | static member Run(sitelet: WarpApplication<'EndPoint>, ?debug, ?urls, ?rootDir, ?scripted, ?assembly) = 268 | let assembly = 269 | match assembly with 270 | | Some a -> a 271 | | None -> Assembly.GetCallingAssembly() 272 | let urls = defaultArg urls ["http://localhost:9000/"] 273 | let urls = urls |> List.map (fun url -> if not (url.EndsWith "/") then url + "/" else url) 274 | let options = Owin.WarpOptions<_>(assembly, ?debug = debug, ?rootDir = rootDir, ?scripted = scripted) 275 | try 276 | let startOptions = new StartOptions() 277 | urls |> List.iter startOptions.Urls.Add 278 | let server = WebApp.Start(startOptions, fun appB -> 279 | Owin.UseWarp(appB, sitelet, options) 280 | .Use(fun ctx next -> 281 | Task.Factory.StartNew(fun () -> 282 | let s : Stream = 283 | ctx .Set("owin.ResponseStatusCode", 404) 284 | .Set("owin.ResponseReasonPhrase", "Not Found") 285 | .Get("owin.ResponseBody") 286 | use w = new StreamWriter(s) 287 | w.Write("Page not found"))) 288 | |> ignore) 289 | new Warp(urls, server.Dispose) 290 | with e -> 291 | failwithf "Error starting website:\n%s" (e.ToString()) 292 | 293 | [] 294 | static member RunAndWaitForInput(app: WarpApplication<'EndPoint>, ?debug, ?urls, ?rootDir, ?scripted, ?assembly) = 295 | try 296 | let assembly = 297 | match assembly with 298 | | Some a -> a 299 | | None -> Assembly.GetCallingAssembly() 300 | let warp = Warp.Run(app, ?debug = debug, ?urls = urls, ?rootDir = rootDir, ?scripted = scripted, assembly = assembly) 301 | stdout.WriteLine("Serving {0}, press Enter to stop.", warp.Urls) 302 | stdin.ReadLine() |> ignore 303 | warp.Stop() 304 | 0 305 | with e -> 306 | eprintfn "%A" e 307 | 1 308 | 309 | static member Page (?Body: #seq, ?Head: #seq, ?Title: string, ?Doctype: string) = 310 | Content.Page(?Body = Body, ?Doctype = Doctype, ?Head = Head, ?Title = Title) 311 | 312 | #if NO_UINEXT 313 | #else 314 | static member Doc (doc: Doc) = Content.Page doc 315 | 316 | static member Doc (?Body: #seq, ?Head: #seq, ?Title: string, ?Doctype: string) = 317 | Content.Page(?Body = Body, ?Doctype = Doctype, ?Head = Head, ?Title = Title) 318 | #endif 319 | 320 | static member Json data = 321 | Content.Json data 322 | 323 | static member CreateApplication(f: Context<'EndPoints> -> 'EndPoints -> Async>) : WarpApplication<'EndPoints> = 324 | Sitelet.Infer f 325 | 326 | static member CreateSPA (f: Context -> #seq) = 327 | Warp.CreateApplication (fun ctx SPA.EndPoint.Home -> 328 | Warp.Page(Body = f ctx) 329 | ) 330 | 331 | static member CreateSPA (f: Context -> Async>) = 332 | Warp.CreateApplication (fun ctx SPA.EndPoint.Home -> 333 | f ctx 334 | ) 335 | 336 | static member Text out = 337 | Warp.CreateApplication (fun ctx SPA.EndPoint.Home -> 338 | Warp.Page(Body = [Text out]) 339 | ) 340 | 341 | 342 | type ClientAttribute = WebSharper.Pervasives.JavaScriptAttribute 343 | type ServerAttribute = WebSharper.Pervasives.RpcAttribute 344 | type EndPointAttribute = Sitelets.EndPointAttribute 345 | type MethodAttribute = Sitelets.MethodAttribute 346 | type JsonAttribute = Sitelets.JsonAttribute 347 | type QueryAttribute = Sitelets.QueryAttribute 348 | type FormDataAttribute = Sitelets.FormDataAttribute 349 | type WildCardAttribute = Sitelets.WildcardAttribute 350 | -------------------------------------------------------------------------------- /WebSharper.Warp/Warp.fsi: -------------------------------------------------------------------------------- 1 | namespace WebSharper 2 | 3 | open System 4 | open System.Collections.Generic 5 | open System.Reflection 6 | open System.Runtime.CompilerServices 7 | open System.Threading.Tasks 8 | open WebSharper.Html.Server 9 | open WebSharper.Sitelets 10 | 11 | [] 12 | module Extensions = 13 | 14 | type Page with 15 | /// Include the given stylesheet to the page. 16 | member WithStyleSheet : href: string -> Page 17 | /// Include the given JavaScript to the page. 18 | member WithJavaScript : href: string -> Page 19 | 20 | module SPA = 21 | type EndPoint = 22 | | [] Home 23 | 24 | /// A WebSharper application whose HTTP endpoints are matched to values of type 'EndPoint. 25 | type WarpApplication<'EndPoint when 'EndPoint : equality> = Sitelet<'EndPoint> 26 | 27 | [] 28 | module Owin = 29 | 30 | /// Warp OWIN middleware options. 31 | type WarpOptions<'EndPoint when 'EndPoint : equality> = 32 | 33 | /// Create options for a Warp application compiled from the given assembly. 34 | /// debug: true if the served JavaScript files should be readable, false for compressed. 35 | /// rootDir: the root directory of the application. 36 | new : Assembly 37 | * ?debug: bool 38 | * ?rootDir: string 39 | * ?scripted: bool 40 | -> WarpOptions<'EndPoint> 41 | 42 | /// Warp OWIN middleware. 43 | type WarpMiddleware<'EndPoint when 'EndPoint : equality> = 44 | 45 | /// next: The next OWIN middleware to run, if any. 46 | /// app: The Warp application to run. 47 | /// options: Options that instruct the middleware how to run and where to look for files. 48 | new : next: Owin.AppFunc 49 | * app: WarpApplication<'EndPoint> 50 | * options: WarpOptions<'EndPoint> 51 | -> WarpMiddleware<'EndPoint> 52 | 53 | /// Invokes the Warp middleware with the provided environment dictionary. 54 | member Invoke : env: IDictionary -> Task 55 | 56 | #if NO_UINEXT 57 | #else 58 | open WebSharper.UI.Next 59 | #endif 60 | 61 | /// Utilities to work with Warp applications. 62 | [] 63 | type Warp = 64 | 65 | interface IDisposable 66 | 67 | /// Get the list of URL prefixes on which the Warp application is listening. 68 | member Urls : list 69 | 70 | /// Stop the running Warp application. 71 | member Stop : unit -> unit 72 | 73 | /// Runs the Warp application. 74 | /// debug: true if the served JavaScript files should be readable, false for compressed. 75 | /// urls: a list of URL prefixes on which to listen; defaults to ["http://localhost:9000/"]. 76 | /// rootDir: the root directory of the application. 77 | /// assembly: the main assembly to compile to JavaScript; defaults to the calling assembly. 78 | static member Run 79 | : app: WarpApplication<'EndPoint> 80 | * ?debug: bool 81 | * ?urls: list 82 | * ?rootDir: string 83 | * ?scripted: bool 84 | * ?assembly: Assembly 85 | -> Warp 86 | 87 | /// Runs the Warp application and waits for standard input. 88 | /// debug: true if the served JavaScript files should be readable, false for compressed. 89 | /// urls: a list of URL prefixes on which to listen; defaults to ["http://localhost:9000/"]. 90 | /// rootDir: the root directory of the application. 91 | /// assembly: the main assembly to compile to JavaScript; defaults to the calling assembly. 92 | /// Returns: an error code suitable for returning from the application's entry point. 93 | static member RunAndWaitForInput 94 | : app: WarpApplication<'EndPoint> 95 | * ?debug: bool 96 | * ?urls: list 97 | * ?rootDir: string 98 | * ?scripted: bool 99 | * ?assembly: Assembly 100 | -> int 101 | 102 | /// Creates an HTML page response. 103 | [] 104 | static member Page 105 | : ?Body: #seq 106 | * ?Head: #seq 107 | * ?Title: string 108 | * ?Doctype: string 109 | -> Async> 110 | 111 | #if NO_UINEXT 112 | #else 113 | 114 | /// Creates an HTML page from an `Doc`. 115 | /// Equivalent to Content.Doc. 116 | [] 117 | static member Doc : Doc -> Async> 118 | 119 | /// Creates an HTML page response from `Doc`s. 120 | [] 121 | static member Doc 122 | : ?Body: #seq 123 | * ?Head: #seq 124 | * ?Title: string 125 | * ?Doctype: string 126 | -> Async> 127 | 128 | #endif 129 | 130 | /// Creates a JSON-encoded content. 131 | [] 132 | static member Json : 'Data -> Async> 133 | 134 | /// Creates a Warp application based on an `Action->Content` mapping. 135 | [] 136 | static member CreateApplication 137 | : (Context<'EndPoint> -> 'EndPoint -> Async>) 138 | -> WarpApplication<'EndPoint> 139 | 140 | /// Creates a Warp single page application (SPA) based on the body of that single page. 141 | static member CreateSPA 142 | : (Context -> #seq) 143 | -> WarpApplication 144 | 145 | /// Creates a Warp single page application (SPA). Use Warp.Page() to create the returned page. 146 | [] 147 | static member CreateSPA 148 | : (Context -> Async>) 149 | -> WarpApplication 150 | 151 | /// Creates a Warp single page application (SPA) that responds with the given text. 152 | [] 153 | static member Text : string -> WarpApplication 154 | 155 | type ClientAttribute = WebSharper.Pervasives.JavaScriptAttribute 156 | type ServerAttribute = WebSharper.Pervasives.RpcAttribute 157 | type EndPointAttribute = Sitelets.EndPointAttribute 158 | type MethodAttribute = Sitelets.MethodAttribute 159 | type JsonAttribute = Sitelets.JsonAttribute 160 | type QueryAttribute = Sitelets.QueryAttribute 161 | type FormDataAttribute = Sitelets.FormDataAttribute 162 | type WildCardAttribute = Sitelets.WildcardAttribute 163 | -------------------------------------------------------------------------------- /WebSharper.Warp/WebSharper.Warp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 4bd496f1-b318-4669-82c7-a45734f46a30 9 | Library 10 | WebSharper.Warp 11 | WebSharper.Warp 12 | v4.5 13 | 4.3.1.0 14 | WebSharper.Warp 15 | 16 | 17 | true 18 | full 19 | false 20 | false 21 | ../build/net45/ 22 | DEBUG;TRACE 23 | 3 24 | ../build/net45/WebSharper.Warp.XML 25 | 26 | 27 | pdbonly 28 | true 29 | true 30 | ../build/net45/ 31 | TRACE 32 | 3 33 | ../build/net45/WebSharper.Warp.XML 34 | 35 | 36 | 37 | 38 | 39 | 40 | 11 41 | 42 | 43 | 44 | 45 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 46 | 47 | 48 | 49 | 50 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /WebSharper.Warp/reference-nover.fsx: -------------------------------------------------------------------------------- 1 | #I "../../Owin/lib/net40" 2 | #I "../../Microsoft.Owin/lib/net45" 3 | #I "../../IntelliFactory.Xml/lib/net40" 4 | #I "../../Microsoft.Owin.Host.HttpListener/lib/net45" 5 | #I "../../Microsoft.Owin.Hosting/lib/net45" 6 | #I "../../Microsoft.Owin.FileSystems/lib/net45" 7 | #I "../../Microsoft.Owin.StaticFiles/lib/net45" 8 | #I "../../WebSharper/lib/net40" 9 | #I "../../WebSharper.Html/lib/net40" 10 | #I "../../WebSharper.UI.Next/lib/net40" 11 | #I "../../WebSharper.Compiler/lib/net40" 12 | #I "../../WebSharper.Owin/lib/net45" 13 | #I "../lib/net45" 14 | #r "WebSharper.Core.dll" 15 | #r "WebSharper.Core.JavaScript.dll" 16 | #r "WebSharper.JavaScript.dll" 17 | #r "WebSharper.JQuery.dll" 18 | #r "WebSharper.Collections.dll" 19 | #r "WebSharper.Control.dll" 20 | #r "WebSharper.Main.dll" 21 | #r "WebSharper.Web.dll" 22 | #r "WebSharper.Html.Server.dll" 23 | #r "WebSharper.Html.Client.dll" 24 | #r "WebSharper.UI.Next.dll" 25 | #r "WebSharper.UI.Next.Templating.dll" 26 | #r "WebSharper.Sitelets.dll" 27 | #r "IntelliFactory.Core.dll" 28 | #r "IntelliFactory.Xml.dll" 29 | #r "Mono.Cecil.dll" 30 | #r "WebSharper.Compiler.dll" 31 | #r "WebSharper.Warp.dll" 32 | -------------------------------------------------------------------------------- /WebSharper.Warp/reference.fsx: -------------------------------------------------------------------------------- 1 | #r "WebSharper.Core.dll" 2 | #r "WebSharper.Core.JavaScript.dll" 3 | #r "WebSharper.JavaScript.dll" 4 | #r "WebSharper.Collections.dll" 5 | #r "WebSharper.Control.dll" 6 | #r "WebSharper.Main.dll" 7 | #r "WebSharper.Web.dll" 8 | #r "WebSharper.Html.Server.dll" 9 | #r "WebSharper.Html.Client.dll" 10 | #r "WebSharper.UI.Next.dll" 11 | #r "WebSharper.Sitelets.dll" 12 | #r "IntelliFactory.Core.dll" 13 | #r "Mono.Cecil.dll" 14 | #r "WebSharper.Compiler.dll" 15 | #I "../lib/net45" 16 | #r "WebSharper.Warp.dll" 17 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | REM NOTE: This file was auto-generated with `IB.exe prepare` from `IntelliFactory.Build`. 3 | 4 | setlocal 5 | set PATH=%PATH%;tools\NuGet 6 | nuget install IntelliFactory.Build -nocache -pre -ExcludeVersion -o tools\packages 7 | nuget install FSharp.Compiler.Tools -nocache -version 4.0.1.21 -excludeVersion -o tools/packages 8 | tools\packages\FSharp.Compiler.Tools\tools\fsi.exe --exec build.fsx %* 9 | -------------------------------------------------------------------------------- /build.fsx: -------------------------------------------------------------------------------- 1 | #load "tools/includes.fsx" 2 | open IntelliFactory.Build 3 | 4 | let bt = 5 | BuildTool().PackageId("WebSharper.Warp") 6 | .VersionFrom("WebSharper") 7 | .WithFSharpVersion(FSharpVersion.FSharp30) 8 | .WithFramework(fun fw -> fw.Net45) 9 | 10 | let main = 11 | bt.FSharp.Library("WebSharper.Warp") 12 | .SourcesFromProject() 13 | .References(fun r -> 14 | [ 15 | r.NuGet("Owin").ForceFoundVersion().Reference() 16 | r.NuGet("Microsoft.Owin").ForceFoundVersion().Reference() 17 | r.NuGet("Microsoft.Owin.Diagnostics").ForceFoundVersion().Reference() 18 | r.NuGet("Microsoft.Owin.FileSystems").ForceFoundVersion().Reference() 19 | r.NuGet("Microsoft.Owin.Host.HttpListener").ForceFoundVersion().Reference() 20 | r.NuGet("Microsoft.Owin.Hosting").ForceFoundVersion().Reference() 21 | r.NuGet("Microsoft.Owin.SelfHost").ForceFoundVersion().Reference() 22 | r.NuGet("Microsoft.Owin.StaticFiles").ForceFoundVersion().Reference() 23 | r.Assembly("System.Web") 24 | r.NuGet("WebSharper").ForceFoundVersion().Reference() 25 | r.NuGet("WebSharper.Html").ForceFoundVersion().Reference() 26 | r.NuGet("WebSharper.UI.Next").ForceFoundVersion().Reference() 27 | r.NuGet("WebSharper.Compiler").ForceFoundVersion().Reference() 28 | r.NuGet("WebSharper.Owin").ForceFoundVersion().Reference() 29 | ]) 30 | 31 | let test = 32 | bt.FSharp.ConsoleExecutable("WebSharper.Warp.Test") 33 | .SourcesFromProject() 34 | .References(fun r -> 35 | [ 36 | r.Project(main) 37 | r.NuGet("Owin").Reference() 38 | r.NuGet("Microsoft.Owin").Reference() 39 | r.NuGet("Microsoft.Owin.Diagnostics").Reference() 40 | r.NuGet("Microsoft.Owin.FileSystems").Reference() 41 | r.NuGet("Microsoft.Owin.Host.HttpListener").Reference() 42 | r.NuGet("Microsoft.Owin.Hosting").Reference() 43 | r.NuGet("Microsoft.Owin.SelfHost").Reference() 44 | r.NuGet("Microsoft.Owin.StaticFiles").Reference() 45 | r.Assembly("System.Web") 46 | r.NuGet("WebSharper").Reference() 47 | r.NuGet("WebSharper.Html").Reference() 48 | r.NuGet("WebSharper.UI.Next").Reference() 49 | r.NuGet("WebSharper.Compiler").Reference() 50 | r.NuGet("WebSharper.Owin").Reference() 51 | ]) 52 | 53 | let package = bt.NuGet.CreatePackage() 54 | 55 | do 56 | let getVersion (pkg: string) = 57 | match bt.NuGetResolver.FindLatestVersion(pkg) with 58 | | None -> failwith "" 59 | | Some v -> v.ToString() 60 | let replaceVersion pkg (s: string) = 61 | s.Replace("${" + pkg + "}", pkg + "." + getVersion pkg) 62 | let readme = 63 | System.IO.File.ReadAllText("readme.txt.in") 64 | .Replace("${WarpVersion}", package.GetComputedVersion()) 65 | |> replaceVersion "WebSharper" 66 | |> replaceVersion "WebSharper.Compiler" 67 | |> replaceVersion "Owin" 68 | |> replaceVersion "Microsoft.Owin" 69 | |> replaceVersion "Microsoft.Owin.Host.HttpListener" 70 | |> replaceVersion "Microsoft.Owin.Hosting" 71 | |> replaceVersion "Microsoft.Owin.SelfHost" 72 | |> replaceVersion "Microsoft.Owin.FileSystems" 73 | |> replaceVersion "Microsoft.Owin.StaticFiles" 74 | |> replaceVersion "WebSharper.Owin" 75 | System.IO.File.WriteAllText("readme.txt", readme) 76 | 77 | bt.Solution [ 78 | main 79 | test 80 | 81 | package 82 | .Configure(fun c -> 83 | { c with 84 | Title = Some "WebSharper.Warp" 85 | LicenseUrl = Some "http://websharper.com/licensing" 86 | ProjectUrl = Some "https://github.com/intellifactory/websharper.warp" 87 | Description = "WebSharper Warp" 88 | Authors = ["IntelliFactory"] 89 | RequiresLicenseAcceptance = true }) 90 | .Add(main) 91 | .AddFile("readme.txt", "readme.txt") 92 | .AddFile("WebSharper.Warp/reference.fsx", "tools/reference.fsx") 93 | .AddFile("WebSharper.Warp/reference-nover.fsx", "tools/reference-nover.fsx") 94 | ] 95 | |> bt.Dispatch 96 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export EnableNuGetPackageRestore=true 3 | : ${MonoHome=/usr/lib/mono} 4 | : ${FSharpHome=$MonoHome/4.0} 5 | : ${NuGetHome=tools/NuGet} 6 | export FSharpHome 7 | export MonoHome 8 | export NuGetHome 9 | mono $NuGetHome/NuGet.exe install IntelliFactory.Build -pre -ExcludeVersion -o tools/packages 10 | mono $FSharpHome/fsi.exe --exec build.fsx %* -------------------------------------------------------------------------------- /getting-started.md: -------------------------------------------------------------------------------- 1 | # Hello world! 2 | 3 | The simplest Warp site just serves text and consist of a single endpoint (`/`), by default listening on `http://localhost:9000`. 4 | 5 | ```fsharp 6 | open WebSharper 7 | 8 | let MyApp = Warp.Text "Hello world!" 9 | 10 | [] 11 | do Warp.RunAndWaitForInput(MyApp) |> ignore 12 | ``` 13 | 14 | ![](http://i.imgur.com/fZgqeKjl.png) 15 | 16 | # Single Page Applications 17 | 18 | While serving text is fun and often useful, going beyond isn't any complicated. Warp also helps constructing HTML. In the most basic form, you can create single page applications (SPAs) using `Warp.CreateSPA` and WebSharper's server-side HTML combinators: 19 | 20 | ```fsharp 21 | open WebSharper.Html.Server 22 | 23 | let MySite = 24 | Warp.CreateSPA (fun ctx -> 25 | [H1 [Text "Hello world!"]]) 26 | 27 | [] 28 | do Warp.RunAndWaitForInput(MySite) |> ignore 29 | ``` 30 | 31 | ![](http://i.imgur.com/xYITvCql.png) 32 | 33 | # Multi-page applications 34 | 35 | Using multiple `EndPoints` and `Warp.CreateApplication`, you can define multi-page Warp applications. When constructing the actual pages, `Warp.Page` comes handy - allowing you to fill the `Title`, `Head`, and the `Body` parts on demand. `Warp.Page` pages are fully autonomous and will **automatically contain the dependencies of any client-side code used on the page**. 36 | 37 | ```fsharp 38 | type Endpoints = 39 | | [] Home 40 | | [] About 41 | 42 | let MySite = 43 | Warp.CreateApplication (fun ctx endpoint -> 44 | let (=>) label endpoint = A [HRef (ctx.Link endpoint)] -< [Text label] 45 | match endpoint with 46 | | Endpoints.Home -> 47 | Warp.Page( 48 | Body = 49 | [ 50 | H1 [Text "Hello world!"] 51 | "About" => Endpoints.About 52 | ] 53 | ) 54 | | Endpoints.About -> 55 | Warp.Page( 56 | Body = 57 | [ 58 | P [Text "This is a simple app"] 59 | "Home" => Endpoints.Home 60 | ] 61 | ) 62 | ) 63 | 64 | [] 65 | do Warp.RunAndWaitForInput(MySite) |> ignore 66 | ``` 67 | 68 | ![](http://i.imgur.com/WMnmzIPl.png) 69 | 70 | # Adding client-side functionality 71 | 72 | Warp applications can easily incorporate client-side content and functionality, giving an absolute edge over any web development library. The example below is reimplemented from [Deploying WebSharper apps to Azure via GitHub](http://websharper.com/blog-entry/4368), and although it omits the more advanced templating in that approach (which is straightforward to add to this implementation), it greatly simplifies constructing and running the application. 73 | 74 | ```fsharp 75 | module Server = 76 | [] 77 | let DoWork (s: string) = 78 | async { 79 | return System.String(List.ofSeq s |> List.rev |> Array.ofList) 80 | } 81 | 82 | [] 83 | module Client = 84 | open WebSharper.JavaScript 85 | open WebSharper.Html.Client 86 | 87 | let Main () = 88 | let input = Input [Attr.Value ""] 89 | let output = H1 [] 90 | Div [ 91 | input 92 | Button [Text "Send"] 93 | |>! OnClick (fun _ _ -> 94 | async { 95 | let! data = Server.DoWork input.Value 96 | output.Text <- data 97 | } 98 | |> Async.Start 99 | ) 100 | HR [] 101 | H4 [Class "text-muted"] -- Text "The server responded:" 102 | Div [Class "jumbotron"] -< [output] 103 | ] 104 | 105 | let MySite = 106 | Warp.CreateSPA (fun ctx -> 107 | [ 108 | H1 [Text "Say Hi to the server"] 109 | Div [ClientSide <@ Client.Main() @>] 110 | ]) 111 | 112 | [] 113 | do Warp.RunAndWaitForInput(MySite) |> ignore 114 | ``` 115 | 116 | ![](http://i.imgur.com/9sPa4lzl.png) 117 | 118 | # Taking things further 119 | 120 | Creating RESTful applications, using client-side visualizations is just as easy. For a quick example, here is a Chart.js-based visualization using the `WebSharper.ChartJs` WebSharper extension: 121 | 122 | ```fsharp 123 | [] 124 | module Client = 125 | open WebSharper.JavaScript 126 | open WebSharper.Html.Client 127 | open WebSharper.ChartJs 128 | 129 | let RadarChart () = 130 | Div [ 131 | H3 [Text "Activity Chart"] 132 | Canvas [Attr.Width "450"; Attr.Height "300"] 133 | |>! OnAfterRender (fun canvas -> 134 | let canvas = As canvas.Dom 135 | RadarChartData( 136 | Labels = [| "Eating"; "Drinking"; "Sleeping"; 137 | "Designing"; "Coding"; "Cycling"; "Running" |], 138 | Datasets = [| 139 | RadarChartDataset( 140 | FillColor = "rgba(151, 187, 205, 0.2)", 141 | StrokeColor = "rgba(151, 187, 205, 1)", 142 | PointColor = "rgba(151, 187, 205, 1)", 143 | Data = [|28.0; 48.0; 40.0; 19.0; 96.0; 27.0; 100.0|] 144 | ) 145 | RadarChartDataset( 146 | FillColor = "rgba(220, 220, 220, 0.2)", 147 | StrokeColor = "rgba(220, 220, 220, 1)", 148 | PointColor = "rgba(220,220,220,1)", 149 | Data = [|65.0; 59.0; 90.0; 81.0; 56.0; 55.0; 40.0|] 150 | ) 151 | |] 152 | ) 153 | |> Chart(canvas.GetContext "2d").Radar 154 | |> ignore 155 | ) 156 | ] 157 | 158 | let MySite = 159 | Warp.CreateSPA (fun ctx -> 160 | [ 161 | H1 [Text "Charts are easy with WebSharper Warp!"] 162 | Div [ClientSide <@ Client.RadarChart() @>] 163 | ]) 164 | 165 | [] 166 | do Warp.RunAndWaitForInput(MySite) |> ignore 167 | ``` 168 | 169 | ![](http://i.imgur.com/9o7x2b1l.png) 170 | 171 | -------------------------------------------------------------------------------- /ivy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /readme.txt.in: -------------------------------------------------------------------------------- 1 | To use Warp from an F# script, add the following lines at the top of your file: 2 | 3 | #I "packages/${Owin}/lib/net40" 4 | #I "packages/${Microsoft.Owin}/lib/net45" 5 | #I "packages/${Microsoft.Owin.Host.HttpListener}/lib/net45" 6 | #I "packages/${Microsoft.Owin.Hosting}/lib/net45" 7 | #I "packages/${Microsoft.Owin.FileSystems}/lib/net45" 8 | #I "packages/${Microsoft.Owin.StaticFiles}/lib/net45" 9 | #I "packages/${WebSharper}/lib/net40" 10 | #I "packages/${WebSharper.Compiler}/lib/net40" 11 | #I "packages/${WebSharper.Owin}/lib/net45" 12 | #load "packages/WebSharper.Warp.${WarpVersion}/tools/reference.fsx" 13 | 14 | If you install NuGet packages without version number in the path 15 | (for example if you use Paket), then you can simply add this instead: 16 | 17 | #load "packages/WebSharper.Warp/tools/reference-nover.fsx" 18 | -------------------------------------------------------------------------------- /tools/NuGet/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet-websharper/warp/820fa3a2b6300ebb6d8a4fa21b75a3446dee7c1f/tools/NuGet/NuGet.exe -------------------------------------------------------------------------------- /tools/includes.fsx: -------------------------------------------------------------------------------- 1 | #I "packages/NuGet.Core/lib/net40-Client" 2 | #I "packages/IntelliFactory.Core/lib/net40" 3 | #I "packages/IntelliFactory.Build/lib/net45" 4 | #r "NuGet.Core" 5 | #r "IntelliFactory.Core" 6 | #r "IntelliFactory.Build" --------------------------------------------------------------------------------