├── .gitattributes ├── .build ├── paket.references ├── build.fsproj └── build.fs ├── .gitignore ├── content └── application │ ├── src │ ├── Bolero.Template.1.Client │ │ ├── wwwroot │ │ │ ├── favicon.ico │ │ │ ├── icon-512.png │ │ │ ├── service-worker.js │ │ │ ├── css │ │ │ │ └── index.css │ │ │ ├── manifest.json │ │ │ ├── books.json │ │ │ ├── index.html │ │ │ ├── service-worker.published.js │ │ │ └── main.html │ │ ├── paket.references │ │ ├── MyApp.bolero.css │ │ ├── Main.minimal.fs │ │ ├── Startup.fs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Bolero.Template.1.Client.fsproj │ │ └── Main.fs │ └── Bolero.Template.1.Server │ │ ├── paket.references │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── Bolero.Template.1.Server.fsproj │ │ ├── Pages │ │ └── _Host.cshtml │ │ ├── BookService.fs │ │ ├── Index.fs │ │ └── Startup.fs │ ├── .config │ └── dotnet-tools.json │ ├── paket.dependencies │ ├── .template.config │ ├── dotnetcli.host.json │ └── template.json │ └── Bolero.Template.1.sln ├── paket.dependencies ├── .config └── dotnet-tools.json ├── paket.template ├── version.json ├── .editorconfig ├── .github └── workflows │ ├── publish.yml │ └── build.yml ├── Bolero.Template.sln ├── CHANGELOG.md ├── README.md ├── paket.lock └── .paket └── Paket.Restore.targets /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.build/paket.references: -------------------------------------------------------------------------------- 1 | Fake.Core.Target 2 | Fake.IO.FileSystem 3 | Fake.DotNet.Cli 4 | Fake.DotNet.Paket 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | paket-files/ 4 | /build/ 5 | .fake/ 6 | .vs/ 7 | *.user 8 | test-build/ 9 | .ionide/ 10 | content/*/.paket/ 11 | .idea/ 12 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsbolero/Template/HEAD/content/application/src/Bolero.Template.1.Client/wwwroot/favicon.ico -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsbolero/Template/HEAD/content/application/src/Bolero.Template.1.Client/wwwroot/icon-512.png -------------------------------------------------------------------------------- /content/application/.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "paket": { 6 | "version": "9.0.2", 7 | "commands": [ 8 | "paket" 9 | ], 10 | "rollForward": false 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /paket.dependencies: -------------------------------------------------------------------------------- 1 | source https://api.nuget.org/v3/index.json 2 | framework: net8.0 3 | storage: none 4 | 5 | github fsbolero/bolero .build/Utility.fs 6 | 7 | nuget Fake.Core.Target 8 | nuget Fake.IO.FileSystem 9 | nuget Fake.DotNet.Cli 10 | nuget Fake.DotNet.Paket 11 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Server/paket.references: -------------------------------------------------------------------------------- 1 | Bolero.Server 2 | //#if (hotreload_actual) 3 | Bolero.HotReload.Server 4 | //#endif 5 | Microsoft.AspNetCore.Components.WebAssembly.Server 6 | //#if (hostpage == "razor") 7 | Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 8 | //#endif 9 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/paket.references: -------------------------------------------------------------------------------- 1 | Bolero 2 | Bolero.Build 3 | //#if (hotreload_actual) 4 | Bolero.HotReload 5 | //#endif 6 | Microsoft.AspNetCore.Components.WebAssembly 7 | Microsoft.AspNetCore.Components.WebAssembly.DevServer 8 | //#if (!server) 9 | System.Net.Http.Json 10 | //#endif 11 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/service-worker.js: -------------------------------------------------------------------------------- 1 | // In development, always fetch from the network and do not enable offline support. 2 | // This is because caching would make development more difficult (changes would not 3 | // be reflected on the first load after each change). 4 | self.addEventListener('fetch', () => { }); 5 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/MyApp.bolero.css: -------------------------------------------------------------------------------- 1 | #counter { 2 | width: 80px; 3 | } 4 | 5 | #notification-area { 6 | position: fixed; 7 | bottom: 0; 8 | left: 0; 9 | right: 0; 10 | } 11 | 12 | #notification-area > div { 13 | max-width: 600px; 14 | margin-left: auto; 15 | margin-right: auto; 16 | margin-bottom: 5px; 17 | } 18 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/css/index.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | } 4 | 5 | body { 6 | display: flex; 7 | flex-direction: column; 8 | } 9 | 10 | #main { 11 | flex: 1; 12 | } 13 | 14 | #main > .columns { 15 | min-height: 100%; 16 | } 17 | 18 | .sidebar { 19 | width: 250px; 20 | background: whitesmoke; 21 | min-height: 100%; 22 | } 23 | -------------------------------------------------------------------------------- /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "paket": { 6 | "version": "9.0.2", 7 | "commands": [ 8 | "paket" 9 | ], 10 | "rollForward": false 11 | }, 12 | "nbgv": { 13 | "version": "3.6.133", 14 | "commands": [ 15 | "nbgv" 16 | ], 17 | "rollForward": false 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /paket.template: -------------------------------------------------------------------------------- 1 | type file 2 | id Bolero.Templates 3 | authors IntelliFactory 4 | projectUrl https://github.com/fsbolero/Template 5 | repositoryUrl https://github.com/fsbolero/Template 6 | repositoryType git 7 | description 8 | A set of tools and libraries to run F# applications in WebAssembly using Blazor. 9 | files 10 | content/**/*.* ==> content 11 | !**/paket-files/**/* 12 | !**/bin/**/* 13 | !**/obj/**/* 14 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fsharp_pwa3", 3 | "short_name": "fsharp_pwa3", 4 | "start_url": "./", 5 | "display": "standalone", 6 | "background_color": "#ffffff", 7 | "theme_color": "#03173d", 8 | "icons": [ 9 | { 10 | "src": "icon-512.png", 11 | "type": "image/png", 12 | "sizes": "512x512" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "0.25-alpha", 4 | "gitCommitIdShortAutoMinimum": 7, 5 | "nuGetPackageVersion": { 6 | "semVer": 2.0 7 | }, 8 | "publicReleaseRefSpec": [ 9 | "^refs/heads/master$", 10 | "^refs/heads/releases/v([\\d.]+)$" 11 | ], 12 | "release": { 13 | "branchName": "releases/v{version}" 14 | } 15 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | 9 | [*.{sln,fsproj,csproj,dependencies,lock,fs,fsi,fsx}] 10 | end_of_line = crlf 11 | 12 | [*.{fs,fsi,fsx,cs,dependencies,references,template,md}] 13 | indent_size = 4 14 | 15 | [.vscode/*.json] 16 | indent_size = 4 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | 21 | [*proj] 22 | insert_final_newline = false 23 | charset = utf-8-bom 24 | -------------------------------------------------------------------------------- /.build/build.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | exe 6 | --define:UTILITY_FROM_PAKET 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/books.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "The Fellowship of the Ring", 4 | "author": "J.R.R Tolkien", 5 | "publishDate": "1954-07-29", 6 | "isbn": "978-0345339706" 7 | }, 8 | { 9 | "title": "The Two Towers", 10 | "author": "J.R.R Tolkien", 11 | "publishDate": "1954-11-11", 12 | "isbn": "978-0345339713" 13 | }, 14 | { 15 | "title": "The Return of the King", 16 | "author": "J.R.R Tolkien", 17 | "publishDate": "1955-10-20", 18 | "isbn": "978-0345339737" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /content/application/paket.dependencies: -------------------------------------------------------------------------------- 1 | source https://api.nuget.org/v3/index.json 2 | //#if (nightly) 3 | source https://nuget.pkg.github.com/fsbolero/index.json 4 | //#endif 5 | framework: net8.0 6 | storage: none 7 | 8 | nuget FSharp.Core content: none 9 | nuget Bolero BOLERO_PAKET_VERSION 10 | nuget Bolero.Build BOLERO_PAKET_VERSION 11 | //#if (hotreload_actual) 12 | nuget Bolero.HotReload BOLERO_PAKET_VERSION 13 | nuget Bolero.HotReload.Server BOLERO_PAKET_VERSION 14 | //#endif 15 | //#if (server) 16 | nuget Bolero.Server BOLERO_PAKET_VERSION 17 | nuget Microsoft.AspNetCore.Components.WebAssembly.Server >= 8.0.0 18 | //#else 19 | nuget System.Net.Http.Json >= 8.0.0 20 | //#endif 21 | nuget Microsoft.AspNetCore.Components.WebAssembly >= 8.0.0 22 | nuget Microsoft.AspNetCore.Components.WebAssembly.DevServer >= 8.0.0 23 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/Main.minimal.fs: -------------------------------------------------------------------------------- 1 | module Bolero.Template._1.Client.Main 2 | 3 | open Elmish 4 | open Bolero 5 | open Bolero.Html 6 | //#if (hotreload_actual) 7 | open Bolero.Templating.Client 8 | //#endif 9 | 10 | type Model = 11 | { 12 | x: string 13 | } 14 | 15 | let initModel = 16 | { 17 | x = "" 18 | } 19 | 20 | type Message = 21 | | Ping 22 | 23 | let update message model = 24 | match message with 25 | | Ping -> model 26 | 27 | let view model dispatch = 28 | p { "Hello, world!" } 29 | 30 | type MyApp() = 31 | inherit ProgramComponent() 32 | 33 | override this.Program = 34 | Program.mkSimple (fun _ -> initModel) update view 35 | //#if (hotreload_actual) 36 | #if DEBUG 37 | |> Program.withHotReload 38 | #endif 39 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/Startup.fs: -------------------------------------------------------------------------------- 1 | namespace Bolero.Template._1.Client 2 | 3 | open Microsoft.AspNetCore.Components.WebAssembly.Hosting 4 | //#if (server) 5 | open Bolero.Remoting.Client 6 | //#else 7 | open Microsoft.Extensions.DependencyInjection 8 | open System 9 | open System.Net.Http 10 | //#endif 11 | 12 | module Program = 13 | 14 | [] 15 | let Main args = 16 | let builder = WebAssemblyHostBuilder.CreateDefault(args) 17 | //#if (!isInteractive) 18 | builder.RootComponents.Add("#main") 19 | //#endif 20 | //#if (server) 21 | builder.Services.AddBoleroRemoting(builder.HostEnvironment) |> ignore 22 | //#else 23 | builder.Services.AddScoped(fun _ -> 24 | new HttpClient(BaseAddress = Uri builder.HostEnvironment.BaseAddress)) |> ignore 25 | //#endif 26 | builder.Build().RunAsync() |> ignore 27 | 0 28 | -------------------------------------------------------------------------------- /content/application/.template.config/dotnetcli.host.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/dotnetcli.host", 3 | "symbolInfo": { 4 | "minimal": { 5 | "longName": "minimal", 6 | "shortName": "m" 7 | }, 8 | "server": { 9 | "longName": "server", 10 | "shortName": "s" 11 | }, 12 | "html": { 13 | "longName": "html", 14 | "shortName": "ht" 15 | }, 16 | "hotreload": { 17 | "longName": "hotreload", 18 | "shortName": "hr" 19 | }, 20 | "hostpage": { 21 | "longName": "hostpage", 22 | "shortName": "hp" 23 | }, 24 | "render": { 25 | "longName": "render", 26 | "shortName": "r" 27 | }, 28 | "pwa": { 29 | "longName": "pwa", 30 | "shortName": "pwa" 31 | }, 32 | "nightly": { 33 | "longName": "nightly", 34 | "shortName": "ni" 35 | }, 36 | "paket": { 37 | "longName": "paket", 38 | "shortName": "p" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:PORT_CLIENT_HTTP/", 7 | "sslPort": PORT_CLIENT_SSL 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Bolero.Template._1.Client": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 23 | "applicationUrl": "http://localhost:PORT_CLIENT_HTTP/", 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:PORT_SERVER_HTTP", 7 | "sslPort": PORT_SERVER_SSL 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Server": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 23 | "applicationUrl": "https://localhost:PORT_SERVER_SSL;http://localhost:PORT_SERVER_HTTP", 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Setup dotnet 12 | uses: actions/setup-dotnet@v1 13 | with: 14 | dotnet-version: '8.0.100' 15 | 16 | - name: Download nupkg 17 | uses: dawidd6/action-download-artifact@v6 18 | with: 19 | github_token: ${{secrets.GITHUB_TOKEN}} 20 | workflow: build.yml 21 | commit: ${{github.sha}} 22 | name: nuget 23 | 24 | - name: Push to GitHub release 25 | uses: svenstaro/upload-release-action@1.1.0 26 | with: 27 | tag: ${{github.ref}} 28 | repo_token: ${{secrets.GITHUB_TOKEN}} 29 | file_glob: 'true' 30 | file: ./*.nupkg 31 | 32 | - name: Push to GitHub feed 33 | run: dotnet nuget push *.nupkg 34 | --api-key "${{secrets.GITHUB_TOKEN}}" 35 | --source "https://nuget.pkg.github.com/${{github.repository_owner}}/" 36 | --skip-duplicate 37 | 38 | - name: Push to NuGet 39 | run: dotnet nuget push *.nupkg 40 | --api-key ${{secrets.NUGET_API_KEY}} 41 | --source https://api.nuget.org/v3/index.json 42 | --skip-duplicate 43 | -------------------------------------------------------------------------------- /Bolero.Template.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B50409CB-BB9C-469B-84D0-50BF0C7AE422}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "build", ".build\build.fsproj", "{91EEE882-892C-42B5-8F02-CFA65231E415}" 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(SolutionProperties) = preSolution 16 | HideSolutionNode = FALSE 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {91EEE882-892C-42B5-8F02-CFA65231E415}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {91EEE882-892C-42B5-8F02-CFA65231E415}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {91EEE882-892C-42B5-8F02-CFA65231E415}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {91EEE882-892C-42B5-8F02-CFA65231E415}.Release|Any CPU.Build.0 = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(NestedProjects) = preSolution 25 | {91EEE882-892C-42B5-8F02-CFA65231E415} = {B50409CB-BB9C-469B-84D0-50BF0C7AE422} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Server/Bolero.Template.1.Server.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/Bolero.Template.1.Client.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | service-worker-assets.js 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Bolero Application 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 |
Loading...
31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Server/Pages/_Host.cshtml: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @namespace Bolero.Template._1.Server 3 | @using Bolero.Server 4 | @inject IBoleroHostConfig BoleroHostConfig 5 | 6 | 7 | 8 | 9 | 10 | Bolero Application 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 33 | 34 |
@(await Html.RenderComponentAsync(BoleroHostConfig))
35 | @Html.RenderBoleroScript(BoleroHostConfig) 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Server/BookService.fs: -------------------------------------------------------------------------------- 1 | namespace Bolero.Template._1.Server 2 | 3 | open System 4 | open System.IO 5 | open System.Text.Json 6 | open System.Text.Json.Serialization 7 | open Microsoft.AspNetCore.Hosting 8 | open Bolero 9 | open Bolero.Remoting 10 | open Bolero.Remoting.Server 11 | open Bolero.Template._1 12 | 13 | type BookService(ctx: IRemoteContext, env: IWebHostEnvironment) = 14 | inherit RemoteHandler() 15 | 16 | let books = 17 | let json = Path.Combine(env.ContentRootPath, "data/books.json") |> File.ReadAllText 18 | JsonSerializer.Deserialize(json) 19 | |> ResizeArray 20 | 21 | override this.Handler = 22 | { 23 | getBooks = ctx.Authorize <| fun () -> async { 24 | return books.ToArray() 25 | } 26 | 27 | addBook = ctx.Authorize <| fun book -> async { 28 | books.Add(book) 29 | } 30 | 31 | removeBookByIsbn = ctx.Authorize <| fun isbn -> async { 32 | books.RemoveAll(fun b -> b.isbn = isbn) |> ignore 33 | } 34 | 35 | signIn = fun (username, password) -> async { 36 | if password = "password" then 37 | do! ctx.HttpContext.AsyncSignIn(username, TimeSpan.FromDays(365.)) 38 | return Some username 39 | else 40 | return None 41 | } 42 | 43 | signOut = fun () -> async { 44 | return! ctx.HttpContext.AsyncSignOut() 45 | } 46 | 47 | getUsername = ctx.Authorize <| fun () -> async { 48 | return ctx.HttpContext.User.Identity.Name 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.24 4 | 5 | * [#50](https://github.com/fsbolero/Template/issues/50) Replace option `--server` with `--render` to decide the render mode. Possible values are: 6 | * `LegacyServer` for classic server-side mode. 7 | * `LegacyWebAssembly` for classic client-side mode. 8 | * `WebAssembly` for client-only WebAssembly mode without a server project. 9 | * `InteractiveServer` for server-side interactive render mode (see https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-8.0). 10 | * `InteractiveWebAssembly` for client-side interactive render mode. 11 | * `InteractiveAuto` for automatic interactive render mode (client-side if available, otherwise server-side while downloading the client-side runtime in the background). 12 | * [#56](https://github.com/fsbolero/Template/issues/56) Update to paket 9.0.2 13 | * [#57](https://github.com/fsbolero/Template/issues/57) Remove call to RootComponents.Add when using InteractiveRenderMode 14 | 15 | ## 0.23 16 | 17 | * [#41](https://github.com/fsbolero/Template/issues/41) Fix issue where, when creating a project containing a dash, the solution file uses an underscore in the project path. 18 | * [#45](https://github.com/fsbolero/Template/issues/45) Add launchSettings that enable WebAssembly debugging. 19 | * [#52](https://github.com/fsbolero/Template/issues/52) Fix namespace used in Razor host page. 20 | 21 | ## 0.22 22 | 23 | * Use endpoint routing for remote services. 24 | 25 | ## 0.21 26 | 27 | * [#39](https://github.com/fsbolero/Template/issues/39) Add link to Blazor-generated `CLIENT_ASSEMBLY_NAME.styles.css`. 28 | 29 | * [#40](https://github.com/fsbolero/Template/issues/40) Enable WebAssembly debugging in the server project. 30 | 31 | ## 0.20 32 | 33 | * Update to Bolero 0.20's computation expression-based syntax. 34 | 35 | ## 0.18 36 | 37 | * Use GitHub Packages as source for `--nightly` rather than AppVeyor. 38 | 39 | * Fix `--paket`. 40 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Server/Index.fs: -------------------------------------------------------------------------------- 1 | module Bolero.Template._1.Server.Index 2 | 3 | //#if (isInteractive) 4 | open Microsoft.AspNetCore.Components 5 | open Microsoft.AspNetCore.Components.Web 6 | //#endif 7 | open Bolero 8 | open Bolero.Html 9 | open Bolero.Server.Html 10 | open Bolero.Template._1 11 | 12 | let page = doctypeHtml { 13 | head { 14 | meta { attr.charset "UTF-8" } 15 | meta { attr.name "viewport"; attr.content "width=device-width, initial-scale=1.0" } 16 | title { "Bolero Application" } 17 | ``base`` { attr.href "/" } 18 | //#if (!minimal) 19 | link { attr.rel "stylesheet"; attr.href "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css" } 20 | link { attr.rel "stylesheet"; attr.href "css/index.css" } 21 | //#endif 22 | link { attr.rel "stylesheet"; attr.href "Bolero.Template._1.Client.styles.css" } 23 | //#if (pwa) 24 | link { attr.rel "manifest"; attr.href "manifest.json" } 25 | link { attr.rel "apple-touch-icon"; attr.sizes "512x512"; attr.href "icon-512.png" } 26 | //#endif 27 | } 28 | body { 29 | //#if (!minimal) 30 | nav { 31 | attr.``class`` "navbar is-dark" 32 | "role" => "navigation" 33 | attr.aria "label" "main navigation" 34 | div { 35 | attr.``class`` "navbar-brand" 36 | a { 37 | attr.``class`` "navbar-item has-text-weight-bold is-size-5" 38 | attr.href "https://fsbolero.io" 39 | img { attr.style "height:40px"; attr.src "https://github.com/fsbolero/website/raw/master/src/Website/img/wasm-fsharp.png" } 40 | "  Bolero" 41 | } 42 | } 43 | } 44 | //#endif 45 | div { 46 | attr.id "main" 47 | //#if (isInteractive) 48 | comp { attr.renderMode RenderMode.RENDER_MODE } 49 | //#else 50 | comp 51 | //#endif 52 | } 53 | boleroScript 54 | //#if (pwa) 55 | script { rawHtml "navigator.serviceWorker.register('service-worker.js');" } 56 | //#endif 57 | } 58 | } 59 | //#if (isInteractive) 60 | 61 | [] 62 | type Page() = 63 | inherit Bolero.Component() 64 | override _.Render() = page 65 | //#endif 66 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/service-worker.published.js: -------------------------------------------------------------------------------- 1 | // Caution! Be sure you understand the caveats before publishing an application with 2 | // offline support. See https://aka.ms/blazor-offline-considerations 3 | 4 | self.importScripts('./service-worker-assets.js'); 5 | self.addEventListener('install', event => event.waitUntil(onInstall(event))); 6 | self.addEventListener('activate', event => event.waitUntil(onActivate(event))); 7 | self.addEventListener('fetch', event => event.respondWith(onFetch(event))); 8 | 9 | const cacheNamePrefix = 'offline-cache-'; 10 | const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`; 11 | const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/ ]; 12 | const offlineAssetsExclude = [ /^service-worker\.js$/ ]; 13 | 14 | async function onInstall(event) { 15 | console.info('Service worker: Install'); 16 | 17 | // Fetch and cache all matching items from the assets manifest 18 | const assetsRequests = self.assetsManifest.assets 19 | .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) 20 | .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) 21 | .map(asset => new Request(asset.url, { integrity: asset.hash })); 22 | await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); 23 | } 24 | 25 | async function onActivate(event) { 26 | console.info('Service worker: Activate'); 27 | 28 | // Delete unused caches 29 | const cacheKeys = await caches.keys(); 30 | await Promise.all(cacheKeys 31 | .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName) 32 | .map(key => caches.delete(key))); 33 | } 34 | 35 | async function onFetch(event) { 36 | let cachedResponse = null; 37 | if (event.request.method === 'GET') { 38 | // For all navigation requests, try to serve index.html from cache 39 | // If you need some URLs to be server-rendered, edit the following check to exclude those URLs 40 | const shouldServeIndexHtml = event.request.mode === 'navigate'; 41 | 42 | const request = shouldServeIndexHtml ? 'index.html' : event.request; 43 | const cache = await caches.open(cacheName); 44 | cachedResponse = await cache.match(request); 45 | } 46 | 47 | return cachedResponse || fetch(event.request); 48 | } 49 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Server/Startup.fs: -------------------------------------------------------------------------------- 1 | module Bolero.Template._1.Server.Program 2 | 3 | open Microsoft.AspNetCore 4 | open Microsoft.AspNetCore.Authentication.Cookies 5 | open Microsoft.AspNetCore.Builder 6 | open Microsoft.AspNetCore.Hosting 7 | open Microsoft.Extensions.DependencyInjection 8 | open Microsoft.Extensions.Hosting 9 | open Bolero 10 | open Bolero.Remoting.Server 11 | open Bolero.Server 12 | open Bolero.Template._1 13 | //#if (hotreload_actual) 14 | open Bolero.Templating.Server 15 | //#endif 16 | 17 | [] 18 | let main args = 19 | let builder = WebApplication.CreateBuilder(args) 20 | 21 | //#if (isInteractive) 22 | builder.Services.AddRazorComponents() 23 | .AddInteractiveServerComponents() 24 | .AddInteractiveWebAssemblyComponents() 25 | |> ignore 26 | //#elseif (hostpage == "razor") 27 | builder.Services.AddMvc().AddRazorRuntimeCompilation() |> ignore 28 | //#else 29 | builder.Services.AddMvc() |> ignore 30 | //#endif 31 | builder.Services.AddServerSideBlazor() |> ignore 32 | builder.Services.AddAuthorization() 33 | .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) 34 | .AddCookie() 35 | |> ignore 36 | //#if (!minimal) 37 | builder.Services.AddBoleroRemoting() |> ignore 38 | //#endif 39 | //#if (isInteractive) 40 | builder.Services.AddBoleroComponents() |> ignore 41 | //#elseif (hostpage != "html") 42 | builder.Services.AddBoleroHost(server = RENDER_SERVER) |> ignore 43 | //#endif 44 | //#if (hotreload_actual) 45 | #if DEBUG 46 | builder.Services.AddHotReload(templateDir = __SOURCE_DIRECTORY__ + "/../Bolero.Template.1.Client") |> ignore 47 | #endif 48 | //#endif 49 | 50 | let app = builder.Build() 51 | 52 | if app.Environment.IsDevelopment() then 53 | app.UseWebAssemblyDebugging() 54 | 55 | app 56 | .UseAuthentication() 57 | .UseStaticFiles() 58 | .UseRouting() 59 | .UseAuthorization() 60 | //#if (isInteractive) 61 | .UseAntiforgery() 62 | //#else 63 | .UseBlazorFrameworkFiles() 64 | //#endif 65 | |> ignore 66 | 67 | //#if (hotreload_actual) 68 | #if DEBUG 69 | app.UseHotReload() 70 | #endif 71 | //#endif 72 | app.MapBoleroRemoting() |> ignore 73 | //#if (isInteractive) 74 | app.MapRazorComponents() 75 | .AddInteractiveServerRenderMode() 76 | .AddInteractiveWebAssemblyRenderMode() 77 | .AddAdditionalAssemblies(typeof.Assembly) 78 | //#elseif (hostpage == "razor") 79 | app.MapBlazorHub() |> ignore 80 | app.MapFallbackToPage("/_Host") |> ignore 81 | //#elseif (hostpage == "bolero") 82 | app.MapBlazorHub() |> ignore 83 | app.MapFallbackToBolero(Index.page) |> ignore 84 | //#elseif (hostpage == "html") 85 | app.MapControllers() |> ignore 86 | app.MapFallbackToFile("index.html") |> ignore 87 | //#endif 88 | |> ignore 89 | 90 | app.Run() 91 | 0 92 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - '**' 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v1 15 | 16 | - name: Setup dotnet 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: '8.0.100' 20 | 21 | - name: NuGet cache 22 | uses: actions/cache@v4 23 | with: 24 | path: ~/.nuget/packages 25 | key: ${{ runner.os }}-nuget-${{ hashFiles('.config/dotnet-tools.json') }}-${{ hashFiles('*.lock') }} 26 | restore-keys: | 27 | ${{ runner.os }}-nuget- 28 | 29 | - name: Build 30 | run: | 31 | # GH Actions puts us in detached head, but for nbgv, we need to be on the branch 32 | if echo "${{github.ref}}" | grep -q "^refs/heads/"; then 33 | git checkout "$(echo ${{github.ref}} | sed -E 's|^refs/heads/||')"; 34 | fi 35 | # Build 36 | ./build.sh -t pack -c release 37 | 38 | - name: Upload nupkg 39 | uses: actions/upload-artifact@v4.4.0 40 | with: 41 | name: nuget 42 | path: build 43 | 44 | - name: Test 45 | run: | 46 | dotnet nuget add source https://nuget.pkg.github.com/fsbolero/index.json -n "Bolero nightly" -u "${{github.repository_owner}}" -p "${{secrets.GITHUB_TOKEN}}" --store-password-in-clear-text 47 | ./build.sh -t test-build 48 | 49 | prerelease: 50 | runs-on: ubuntu-latest 51 | needs: build 52 | if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'releases') }} 53 | steps: 54 | - name: Download nupkg 55 | uses: actions/download-artifact@v4.1.7 56 | with: 57 | name: nuget 58 | 59 | - name: Push to GitHub feed 60 | run: dotnet nuget push *.nupkg 61 | --api-key "${{secrets.GITHUB_TOKEN}}" 62 | --source "https://nuget.pkg.github.com/${{github.repository_owner}}/" 63 | --skip-duplicate 64 | 65 | release: 66 | runs-on: ubuntu-latest 67 | needs: build 68 | if: ${{ contains(github.ref, 'releases') }} 69 | steps: 70 | - name: Checkout 71 | uses: actions/checkout@v1 72 | 73 | - name: Setup dotnet 74 | uses: actions/setup-dotnet@v1 75 | with: 76 | dotnet-version: '8.0.100' 77 | 78 | - name: Prepare 79 | run: | 80 | # GH Actions puts us in detached head, but for nbgv, we need to be on the branch 81 | git checkout "$(echo ${{github.ref}} | sed -E 's|^refs/[^/]+/||')" 82 | dotnet tool restore 83 | SHORT_VERSION="$(dotnet nbgv get-version -v MajorMinorVersion)" 84 | echo "SHORT_VERSION=$SHORT_VERSION" >> $GITHUB_ENV 85 | echo "FULL_VERSION=$(dotnet nbgv get-version -v SemVer2)" >> $GITHUB_ENV 86 | # Parse the relevant changelog entry out of CHANGELOG.md 87 | sed -n "/^## ${SHORT_VERSION//./\\.}\$/{n;bl};d;:l;/^#/Q;p;n;bl" CHANGELOG.md > release.md 88 | 89 | - name: Create draft release 90 | uses: actions/create-release@v1 91 | with: 92 | tag_name: v${{ env.FULL_VERSION }} 93 | release_name: Version ${{ env.SHORT_VERSION }} 94 | body_path: release.md 95 | draft: true 96 | env: 97 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 98 | -------------------------------------------------------------------------------- /content/application/Bolero.Template.1.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | //#if (paket) 7 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{B356FE43-BEAF-40B2-BAAC-BC93E461E796}" 8 | ProjectSection(SolutionItems) = preProject 9 | paket.dependencies = paket.dependencies 10 | EndProjectSection 11 | EndProject 12 | //#endif 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{87F6C079-CBD7-4866-BDEB-CBDEA9E51D2A}" 14 | EndProject 15 | //#if (server) 16 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Bolero.Template.1.Server", "src\Bolero.Template.1.Server\Bolero.Template.1.Server.fsproj", "{4E2AA925-4694-4593-ADBC-F349D269587A}" 17 | EndProject 18 | //#endif 19 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Bolero.Template.1.Client", "src\Bolero.Template.1.Client\Bolero.Template.1.Client.fsproj", "{1481BBD6-A6DA-4912-A03A-134880D14701}" 20 | EndProject 21 | Global 22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 23 | Debug|Any CPU = Debug|Any CPU 24 | Debug|x64 = Debug|x64 25 | Debug|x86 = Debug|x86 26 | Release|Any CPU = Release|Any CPU 27 | Release|x64 = Release|x64 28 | Release|x86 = Release|x86 29 | EndGlobalSection 30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 31 | //#if (server) 32 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Debug|x64.ActiveCfg = Debug|Any CPU 35 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Debug|x64.Build.0 = Debug|Any CPU 36 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Debug|x86.ActiveCfg = Debug|Any CPU 37 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Debug|x86.Build.0 = Debug|Any CPU 38 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Release|x64.ActiveCfg = Release|Any CPU 41 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Release|x64.Build.0 = Release|Any CPU 42 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Release|x86.ActiveCfg = Release|Any CPU 43 | {4E2AA925-4694-4593-ADBC-F349D269587A}.Release|x86.Build.0 = Release|Any CPU 44 | //#endif 45 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Debug|x64.ActiveCfg = Debug|Any CPU 48 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Debug|x64.Build.0 = Debug|Any CPU 49 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Debug|x86.ActiveCfg = Debug|Any CPU 50 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Debug|x86.Build.0 = Debug|Any CPU 51 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Release|Any CPU.Build.0 = Release|Any CPU 53 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Release|x64.ActiveCfg = Release|Any CPU 54 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Release|x64.Build.0 = Release|Any CPU 55 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Release|x86.ActiveCfg = Release|Any CPU 56 | {1481BBD6-A6DA-4912-A03A-134880D14701}.Release|x86.Build.0 = Release|Any CPU 57 | EndGlobalSection 58 | GlobalSection(SolutionProperties) = preSolution 59 | HideSolutionNode = FALSE 60 | EndGlobalSection 61 | GlobalSection(NestedProjects) = preSolution 62 | //#if (server) 63 | {4E2AA925-4694-4593-ADBC-F349D269587A} = {87F6C079-CBD7-4866-BDEB-CBDEA9E51D2A} 64 | //#endif 65 | {1481BBD6-A6DA-4912-A03A-134880D14701} = {87F6C079-CBD7-4866-BDEB-CBDEA9E51D2A} 66 | EndGlobalSection 67 | GlobalSection(ExtensibilityGlobals) = postSolution 68 | SolutionGuid = {8CFD6033-FB8D-48BE-9628-9D83DC023CAB} 69 | EndGlobalSection 70 | EndGlobal 71 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/wwwroot/main.html: -------------------------------------------------------------------------------- 1 |
2 | 14 |
15 |
16 | ${Body} 17 | 18 |
19 |
${Error}
20 |
21 | 22 | 47 | 48 | 59 | 60 | 88 | 89 | 90 | 113 | 114 | 115 | 121 | 122 |
123 |
124 |
125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bolero Simple Template 2 | 3 | [![Build](https://github.com/fsbolero/Template/actions/workflows/build.yml/badge.svg)](https://github.com/fsbolero/Template/actions/workflows/build.yml) 4 | [![Nuget](https://img.shields.io/nuget/vpre/Bolero.Templates?logo=nuget)](https://nuget.org/packages/Bolero.Templates) 5 | 6 | 7 | This template can be used as a base to create a [Bolero](https://github.com/intellifactory/bolero) application. 8 | 9 | To learn more, you can check [the documentation](https://fsbolero.io/docs). 10 | 11 | ## Requirements 12 | 13 | To get started, you need the following installed: 14 | 15 | * .NET SDK 8.0. Download it [here](https://dotnet.microsoft.com/download/dotnet/8.0). 16 | 17 | ## Creating a project based on this template 18 | 19 | To create a project based on this template, first install the template to your local dotnet: 20 | 21 | ``` 22 | dotnet new -i Bolero.Templates 23 | ``` 24 | 25 | Then, you can create a project like so: 26 | 27 | ``` 28 | dotnet new bolero-app -o YourAppName 29 | ``` 30 | 31 | This will create a project in a new folder named `YourAppName`. 32 | 33 | ## Template options 34 | 35 | You can use the following options to customize the project being created: 36 | 37 | * Project content options: 38 | 39 | * `--minimal`, `-m`: 40 | 41 | If `true`, the created project is a minimal application skeleton with empty content. 42 | 43 | If `false` (the default), the created project includes Bolero features such as routed pages, HTML templates and remoting. 44 | 45 | * `--render`, `-r`: 46 | 47 | Determines the render mode. Can be one of: 48 | 49 | * `InteractiveWebAssembly` (the default) for client-side interactive render mode. 50 | 51 | * `InteractiveServer` for server-side interactive render mode (see https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-8.0). 52 | 53 | * `InteractiveAuto` for automatic interactive render mode (client-side if available, otherwise server-side while downloading the client-side runtime in the background). 54 | 55 | * `WebAssembly` for client-only WebAssembly without a server project. 56 | 57 | * `LegacyServer` for classic (pre-.NET 8) server-side mode. 58 | 59 | * `LegacyWebAssembly` for classic (pre-.NET 8) client-side mode. 60 | 61 | * `--hostpage`, `-hp`: 62 | 63 | Determines how the server-side HTML page content is written for `LegacyServer`. Can be one of: 64 | 65 | * `bolero` (the default): using Bolero.Html functions. 66 | 67 | * `razor`: using a dynamically-compiled Razor page. 68 | 69 | * `html`: using a plain .html file. 70 | 71 | This is ignored if `render` is not `LegacyServer`. 72 | 73 | * `--html`, `-ht`: 74 | 75 | If `true` (the default), use HTML templates. 76 | 77 | If `false`, use F# functions for HTML content. 78 | 79 | This is ignored if `minimal=true`, because the minimal project doesn't contain any HTML content. 80 | 81 | * `--hotreload`, `-hr`: 82 | 83 | Enable hot reloading for HTML templates. 84 | 85 | The default is `true`. 86 | 87 | This is ignored if `server=false`, because hot reloading requires a server side. 88 | 89 | * `--pwa`, `-pwa`: 90 | 91 | Create the client side as a progressive web app. 92 | 93 | * Package management options: 94 | 95 | * `--paket`, `-p`: 96 | 97 | Use [Paket](https://fsprojects.github.io/paket) for package management. 98 | 99 | * `--nightly`, `-ni`: 100 | 101 | Reference the "nightly" prerelease of Bolero. 102 | 103 | Starting with version 0.18, prereleases are published through GitHub Packages, and therefore require authentication. 104 | Make sure that you have set it up before creating your project: 105 | 106 | * Create a GitHub Personal Access Token [on this page](https://github.com/settings/tokens) with permission "read:packages". 107 | 108 | * If you use the default NuGet for package management, add the source with the following command: 109 | 110 | ```sh 111 | dotnet nuget add source https://nuget.pkg.github.com/fsbolero/index.json -n "Bolero nightly" -u GITHUB_USERNAME -p GITHUB_TOKEN 112 | ``` 113 | 114 | * If you use Paket, use the following command instead: 115 | 116 | ```sh 117 | dotnet paket config add-credentials https://nuget.pkg.github.com/fsbolero/index.json --username GITHUB_USERNAME --password GITHUB_TOKEN 118 | ``` 119 | 120 | ## Using this template 121 | 122 | Visual Studio Code or Visual Studio is recommended to edit this project. 123 | 124 | To compile the project, you can run: 125 | 126 | ```shell 127 | dotnet build 128 | ``` 129 | 130 | To run it: 131 | 132 | ```shell 133 | dotnet run -p src/YourAppName.Server 134 | 135 | # Or if you created the project with --server=false: 136 | dotnet run -p src/YourAppName.Client 137 | ``` 138 | 139 | ## Project structure 140 | 141 | * `src/YourAppName.Client` is the project that gets compiled to WebAssembly, and contains your client-side code. 142 | 143 | * `Startup.fs` sets up Blazor to get the application started. 144 | 145 | * `Main.fs` contains the main body of the page. 146 | 147 | * `src/YourAppName.Server` is the host ASP.NET Core application, and contains your server-side code. 148 | 149 | ## Learn more about Bolero 150 | 151 | To learn more about Bolero, you can check [the documentation](https://fsbolero.io/docs). 152 | -------------------------------------------------------------------------------- /.build/build.fs: -------------------------------------------------------------------------------- 1 | module Build 2 | 3 | open System.IO 4 | open Fake.Core 5 | open Fake.Core.TargetOperators 6 | open Fake.DotNet 7 | open Fake.IO 8 | open Fake.IO.FileSystemOperators 9 | open Utility 10 | 11 | let rec private getArgImpl prefix = function 12 | | s :: m :: _ when s = prefix -> Some m 13 | | _ :: rest -> getArgImpl prefix rest 14 | | [] -> None 15 | 16 | let getArgOpt prefix = cache <| fun (o: TargetParameter) -> 17 | getArgImpl prefix o.Context.Arguments 18 | 19 | let getArg prefix ``default`` = 20 | getArgOpt prefix 21 | >> Option.defaultValue ``default`` 22 | 23 | let getArgWith prefix ``default`` = cache <| fun (o: TargetParameter) -> 24 | match getArgImpl prefix o.Context.Arguments with 25 | | Some x -> x 26 | | None -> ``default`` o 27 | 28 | let getFlag flag = cache <| fun (o: TargetParameter) -> 29 | List.contains flag o.Context.Arguments 30 | 31 | // Command-line parameters 32 | let version = getArgOpt "-v" >> Option.defaultWith (fun () -> 33 | (dotnetOutput "nbgv" ["get-version"; "-v"; "SemVer2"]).Trim() 34 | ) 35 | let cleanTest o = getArg "--clean-test" "false" o |> System.Boolean.TryParse ||> (&&) 36 | 37 | // Constants 38 | let contentBaseDir = slnDir "content" 39 | let buildOutputDir = slnDir "build" 40 | let packageName = "Bolero.Templates" 41 | let packageOutputFile o = buildOutputDir $"{packageName}.{version o}.nupkg" 42 | let variantsToTest = 43 | let serverModes = [ 44 | ("LegacyWasm","LegacyWebAssembly") 45 | ("LegacyServer","LegacyServer") 46 | ("IntServer", "InteractiveServer") 47 | ("IntWasm", "InteractiveWebAssembly") 48 | ("IntAuto", "InteractiveAuto") 49 | ] 50 | [ 51 | for pwak, pwav in [("Pwa", "true"); ("NoPwa", "false")] do 52 | for minik, miniv in [("Minimal", "true"); ("Full", "false")] do 53 | for htmlk, reloadv, htmlv in [("Reload", "true", "true"); ("NoReload", "false", "true"); ("NoHtml", "false", "false")] do 54 | if not (miniv = "true" && htmlv = "true") then 55 | for renderk, renderv in serverModes do 56 | if renderv.StartsWith("Legacy") then 57 | for hostk, hostv in [("Bolero", "bolero"); ("Razor", "razor"); ("Html", "html")] do 58 | $"{minik}.{renderk}.{hostk}.{htmlk}.{pwak}", [ 59 | $"--minimal={miniv}" 60 | $"--hostpage={hostv}" 61 | $"--pwa={pwav}" 62 | $"--html={htmlv}" 63 | $"--hotreload={reloadv}" 64 | $"--render={renderv}" 65 | ] 66 | else 67 | $"{minik}.{renderk}.{htmlk}.{pwak}", [ 68 | $"--minimal={miniv}" 69 | $"--pwa={pwav}" 70 | $"--html={htmlv}" 71 | $"--hotreload={reloadv}" 72 | $"--render={renderv}" 73 | ] 74 | for htmlk, htmlv in [("Html", "true"); ("NoHtml", "false")] do 75 | if not (miniv = "true" && htmlv = "true") then 76 | $"{minik}.Wasm.{htmlk}.{pwak}", [ 77 | "--render=WebAssembly" 78 | $"--minimal={miniv}" 79 | $"--pwa={pwav}" 80 | $"--html={htmlv}" 81 | ] 82 | ] 83 | 84 | Target.description "Create the NuGet package containing the templates." 85 | Target.create "pack" <| fun o -> 86 | Shell.cp_r ".paket" "content/application/.paket" 87 | Paket.pack <| fun p -> 88 | { p with 89 | OutputPath = buildOutputDir 90 | Version = version o 91 | ToolType = ToolType.CreateLocalTool() 92 | } 93 | 94 | Target.description "Install the locally built template. Warning: uninstalls any previously installed version." 95 | Target.create "install" <| fun o -> 96 | if (dotnetOutput "new" ["list"]).Contains("bolero-app") then 97 | dotnet "new" ["uninstall"; packageName] 98 | dotnet "new" ["install"; packageOutputFile o; "--force"] 99 | 100 | Target.description "Test all the template projects by building them." 101 | Target.create "test-build" <| fun o -> 102 | // For each template variant, create and build a new project 103 | let testsDir = slnDir "test-build" 104 | if cleanTest o && Directory.Exists(testsDir) then 105 | Directory.Delete(testsDir, recursive = true) 106 | let now = System.DateTime.Now 107 | let baseDir = testsDir now.ToString("yyyy-MM-dd.HH.mm.ss") 108 | Directory.CreateDirectory(baseDir) |> ignore 109 | for name, args in variantsToTest do 110 | // Prepend a letter and change extension to avoid generating 111 | // identifiers that start with a number. 112 | let projectName = "Test." + name 113 | dotnet' baseDir [] "new" [ 114 | yield "bolero-app" 115 | yield "--nightly" 116 | yield! args 117 | yield "-o" 118 | yield projectName 119 | ] 120 | dotnet' (baseDir projectName) [] "build" ["-v"; "n"] 121 | 122 | Target.description "Run the full release pipeline." 123 | Target.create "release" ignore 124 | 125 | // Main dep path with soft dependencies 126 | "pack" 127 | ==> "install" 128 | ==> "test-build" 129 | ==> "release" 130 | |> ignore 131 | 132 | Target.runOrDefaultWithArguments "pack" 133 | -------------------------------------------------------------------------------- /paket.lock: -------------------------------------------------------------------------------- 1 | STORAGE: NONE 2 | RESTRICTION: == net8.0 3 | NUGET 4 | remote: https://api.nuget.org/v3/index.json 5 | BlackFox.VsWhere (1.1) 6 | FSharp.Core (>= 4.2.3) 7 | Microsoft.Win32.Registry (>= 4.7) 8 | Fake.Core.CommandLineParsing (6.1.3) 9 | FParsec (>= 1.1.1) 10 | FSharp.Core (>= 8.0.301) 11 | Fake.Core.Context (6.1.3) 12 | FSharp.Core (>= 8.0.301) 13 | Fake.Core.Environment (6.1.3) 14 | FSharp.Core (>= 8.0.301) 15 | Fake.Core.FakeVar (6.1.3) 16 | Fake.Core.Context (>= 6.1.3) 17 | FSharp.Core (>= 8.0.301) 18 | Fake.Core.Process (6.1.3) 19 | Fake.Core.Environment (>= 6.1.3) 20 | Fake.Core.FakeVar (>= 6.1.3) 21 | Fake.Core.String (>= 6.1.3) 22 | Fake.Core.Trace (>= 6.1.3) 23 | Fake.IO.FileSystem (>= 6.1.3) 24 | FSharp.Core (>= 8.0.301) 25 | System.Collections.Immutable (>= 8.0) 26 | Fake.Core.SemVer (6.1.3) 27 | FSharp.Core (>= 8.0.301) 28 | Fake.Core.String (6.1.3) 29 | FSharp.Core (>= 8.0.301) 30 | Fake.Core.Target (6.1.3) 31 | Fake.Core.CommandLineParsing (>= 6.1.3) 32 | Fake.Core.Context (>= 6.1.3) 33 | Fake.Core.Environment (>= 6.1.3) 34 | Fake.Core.FakeVar (>= 6.1.3) 35 | Fake.Core.Process (>= 6.1.3) 36 | Fake.Core.String (>= 6.1.3) 37 | Fake.Core.Trace (>= 6.1.3) 38 | FSharp.Control.Reactive (>= 5.0.2) 39 | FSharp.Core (>= 8.0.301) 40 | Fake.Core.Tasks (6.1.3) 41 | Fake.Core.Trace (>= 6.1.3) 42 | FSharp.Core (>= 8.0.301) 43 | Fake.Core.Trace (6.1.3) 44 | Fake.Core.Environment (>= 6.1.3) 45 | Fake.Core.FakeVar (>= 6.1.3) 46 | FSharp.Core (>= 8.0.301) 47 | Fake.Core.Xml (6.1.3) 48 | Fake.Core.String (>= 6.1.3) 49 | FSharp.Core (>= 8.0.301) 50 | Fake.DotNet.Cli (6.1.3) 51 | Fake.Core.Environment (>= 6.1.3) 52 | Fake.Core.Process (>= 6.1.3) 53 | Fake.Core.String (>= 6.1.3) 54 | Fake.Core.Trace (>= 6.1.3) 55 | Fake.DotNet.MSBuild (>= 6.1.3) 56 | Fake.DotNet.NuGet (>= 6.1.3) 57 | Fake.IO.FileSystem (>= 6.1.3) 58 | FSharp.Core (>= 8.0.301) 59 | Mono.Posix.NETStandard (>= 1.0) 60 | Newtonsoft.Json (>= 13.0.3) 61 | Fake.DotNet.MSBuild (6.1.3) 62 | BlackFox.VsWhere (>= 1.1) 63 | Fake.Core.Environment (>= 6.1.3) 64 | Fake.Core.Process (>= 6.1.3) 65 | Fake.Core.String (>= 6.1.3) 66 | Fake.Core.Trace (>= 6.1.3) 67 | Fake.IO.FileSystem (>= 6.1.3) 68 | FSharp.Core (>= 8.0.301) 69 | MSBuild.StructuredLogger (>= 2.1.815) 70 | Fake.DotNet.NuGet (6.1.3) 71 | Fake.Core.Environment (>= 6.1.3) 72 | Fake.Core.Process (>= 6.1.3) 73 | Fake.Core.SemVer (>= 6.1.3) 74 | Fake.Core.String (>= 6.1.3) 75 | Fake.Core.Tasks (>= 6.1.3) 76 | Fake.Core.Trace (>= 6.1.3) 77 | Fake.Core.Xml (>= 6.1.3) 78 | Fake.IO.FileSystem (>= 6.1.3) 79 | Fake.Net.Http (>= 6.1.3) 80 | FSharp.Core (>= 8.0.301) 81 | Newtonsoft.Json (>= 13.0.3) 82 | NuGet.Protocol (>= 6.10.1) 83 | Fake.DotNet.Paket (6.1.3) 84 | Fake.Core.Process (>= 6.1.3) 85 | Fake.Core.String (>= 6.1.3) 86 | Fake.Core.Trace (>= 6.1.3) 87 | Fake.DotNet.Cli (>= 6.1.3) 88 | Fake.IO.FileSystem (>= 6.1.3) 89 | FSharp.Core (>= 8.0.301) 90 | Fake.IO.FileSystem (6.1.3) 91 | Fake.Core.String (>= 6.1.3) 92 | Fake.Core.Trace (>= 6.1.3) 93 | FSharp.Core (>= 8.0.301) 94 | Fake.Net.Http (6.1.3) 95 | Fake.Core.Trace (>= 6.1.3) 96 | FSharp.Core (>= 8.0.301) 97 | FParsec (1.1.1) 98 | FSharp.Core (>= 4.3.4) 99 | FSharp.Control.Reactive (5.0.5) 100 | FSharp.Core (>= 4.7.2) 101 | System.Reactive (>= 5.0 < 6.0) 102 | FSharp.Core (9.0.100) 103 | Microsoft.Bcl.Cryptography (9.0) 104 | System.Formats.Asn1 (>= 9.0) 105 | Microsoft.Build.Framework (17.12.6) 106 | Microsoft.Win32.Registry (>= 5.0) 107 | System.Memory (>= 4.5.5) 108 | System.Runtime.CompilerServices.Unsafe (>= 6.0) 109 | System.Security.Principal.Windows (>= 5.0) 110 | Microsoft.Build.Utilities.Core (17.12.6) 111 | Microsoft.Build.Framework (>= 17.12.6) 112 | Microsoft.NET.StringTools (>= 17.12.6) 113 | Microsoft.Win32.Registry (>= 5.0) 114 | System.Collections.Immutable (>= 8.0) 115 | System.Configuration.ConfigurationManager (>= 8.0) 116 | System.Memory (>= 4.5.5) 117 | System.Runtime.CompilerServices.Unsafe (>= 6.0) 118 | System.Security.Principal.Windows (>= 5.0) 119 | System.Text.Encoding.CodePages (>= 7.0) 120 | Microsoft.NET.StringTools (17.12.6) 121 | System.Memory (>= 4.5.5) 122 | System.Runtime.CompilerServices.Unsafe (>= 6.0) 123 | Microsoft.Win32.Registry (5.0) 124 | System.Security.AccessControl (>= 5.0) 125 | System.Security.Principal.Windows (>= 5.0) 126 | Mono.Posix.NETStandard (1.0) 127 | MSBuild.StructuredLogger (2.2.386) 128 | Microsoft.Build.Framework (>= 17.5) 129 | Microsoft.Build.Utilities.Core (>= 17.5) 130 | System.Collections.Immutable (>= 8.0) 131 | Newtonsoft.Json (13.0.3) 132 | NuGet.Common (6.12.1) 133 | NuGet.Frameworks (>= 6.12.1) 134 | NuGet.Configuration (6.12.1) 135 | NuGet.Common (>= 6.12.1) 136 | System.Security.Cryptography.ProtectedData (>= 4.4) 137 | NuGet.Frameworks (6.12.1) 138 | NuGet.Packaging (6.12.1) 139 | Newtonsoft.Json (>= 13.0.3) 140 | NuGet.Configuration (>= 6.12.1) 141 | NuGet.Versioning (>= 6.12.1) 142 | System.Formats.Asn1 (>= 8.0.1) 143 | System.Security.Cryptography.Pkcs (>= 6.0.4) 144 | NuGet.Protocol (6.12.1) 145 | NuGet.Packaging (>= 6.12.1) 146 | NuGet.Versioning (6.12.1) 147 | System.Collections.Immutable (9.0) 148 | System.Configuration.ConfigurationManager (9.0) 149 | System.Diagnostics.EventLog (>= 9.0) 150 | System.Security.Cryptography.ProtectedData (>= 9.0) 151 | System.Diagnostics.EventLog (9.0) 152 | System.Formats.Asn1 (9.0) 153 | System.Memory (4.6) 154 | System.Reactive (5.0) 155 | System.Runtime.CompilerServices.Unsafe (6.1) 156 | System.Security.AccessControl (6.0.1) 157 | System.Security.Cryptography.Pkcs (9.0) 158 | Microsoft.Bcl.Cryptography (>= 9.0) 159 | System.Formats.Asn1 (>= 9.0) 160 | System.Security.Cryptography.ProtectedData (9.0) 161 | System.Security.Principal.Windows (5.0) 162 | System.Text.Encoding.CodePages (9.0) 163 | GITHUB 164 | remote: fsbolero/bolero 165 | .build/Utility.fs (5240aeb26334cdd6cc50fd97b4c2d7a086c7122b) -------------------------------------------------------------------------------- /content/application/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "IntelliFactory", 3 | "classifications": [ "Web", "Blazor", "Bolero" ], 4 | "name": "Bolero Hosted Application", 5 | "tags": { 6 | "language": "F#", 7 | "type": "project" 8 | }, 9 | "identity": "Bolero.Application.Template", 10 | "groupIdentity": "Bolero.Application", 11 | "shortName": "bolero-app", 12 | "sourceName": "Bolero.Template.1", 13 | "preferNameDirectory": true, 14 | "symbols": { 15 | "minimal": { 16 | "type": "parameter", 17 | "isRequired": false, 18 | "description": "Create a minimal application", 19 | "dataType": "bool", 20 | "defaultValue": "false" 21 | }, 22 | "render": { 23 | "type": "parameter", 24 | "isRequired": false, 25 | "description": "The type of rendering to use", 26 | "dataType": "choice", 27 | "replaces": "RENDER_MODE", 28 | "choices": [ 29 | {"choice":"WebAssembly","description":"WebAssembly only (no server project)"}, 30 | {"choice":"InteractiveServer","description":"InteractiveServer render mode"}, 31 | {"choice":"InteractiveWebAssembly","description":"InteractiveWebAssembly render mode"}, 32 | {"choice":"InteractiveAuto","description":"InteractiveAuto render mode"}, 33 | {"choice":"LegacyServer","description":"Legacy server-side mode"}, 34 | {"choice":"LegacyWebAssembly","description":"Legacy client-side mode"} 35 | ], 36 | "defaultValue": "InteractiveWebAssembly" 37 | }, 38 | "hostpage": { 39 | "type": "parameter", 40 | "isRequired": false, 41 | "description": "How the static HTML content is generated with render=LegacyServer", 42 | "dataType": "choice", 43 | "choices": [ 44 | {"choice":"bolero","description":"A page defined with Bolero's html functions"}, 45 | {"choice":"html","description":"A plain index.html file"}, 46 | {"choice":"razor","description":"A dynamically compiled Razor page"} 47 | ], 48 | "defaultValue":"bolero" 49 | }, 50 | "html": { 51 | "type": "parameter", 52 | "isRequired": false, 53 | "description": "Use HTML templates (ignored if minimal=true)", 54 | "dataType": "bool", 55 | "defaultValue": "true" 56 | }, 57 | "hotreload": { 58 | "type": "parameter", 59 | "isRequired": false, 60 | "description": "Include hot reload for HTML templates (ignored if html=false or render=WebAssembly)", 61 | "dataType": "bool", 62 | "defaultValue": "true" 63 | }, 64 | "server": { 65 | "type": "computed", 66 | "dataType": "bool", 67 | "value": "(render != \"WebAssembly\")" 68 | }, 69 | "isInteractive": { 70 | "type": "computed", 71 | "dataType": "bool", 72 | "value": "(render == \"InteractiveServer\" || render == \"InteractiveWebAssembly\" || render == \"InteractiveAuto\")" 73 | }, 74 | "renderServer": { 75 | "type": "generated", 76 | "generator": "switch", 77 | "replaces": "RENDER_SERVER", 78 | "parameters": { 79 | "evaluator": "C++", 80 | "datatype": "string", 81 | "cases": [ 82 | {"condition": "(render == \"Server\")", "value": "true"}, 83 | {"condition": "(render != \"Server\")", "value": "false"} 84 | ] 85 | } 86 | }, 87 | "pwa": { 88 | "type": "parameter", 89 | "isRequired": false, 90 | "description": "Create the client side as a progressive web app", 91 | "dataType": "bool", 92 | "defaultValue": "false" 93 | }, 94 | "nightly": { 95 | "type": "parameter", 96 | "isRequired": false, 97 | "description": "Reference the nightly release of Bolero (see https://github.com/fsbolero/template for authentication)", 98 | "dataType": "bool", 99 | "defaultValue": "false" 100 | }, 101 | "paket": { 102 | "type": "parameter", 103 | "isRequired": false, 104 | "description": "Use Paket for NuGet package management", 105 | "dataType": "bool", 106 | "defaultValue": "false" 107 | }, 108 | "hotreload_actual": { 109 | "type": "computed", 110 | "dataType": "bool", 111 | "value": "(hotreload && html && server)" 112 | }, 113 | "bolero_version": { 114 | "type": "generated", 115 | "generator": "switch", 116 | "replaces": "BOLERO_VERSION", 117 | "parameters": { 118 | "evaluator": "C++", 119 | "datatype": "string", 120 | "cases": [ 121 | {"condition": "(nightly)", "value": "0.*-*"}, 122 | {"condition": "(!nightly)", "value": "0.*"} 123 | ] 124 | } 125 | } , 126 | "bolero_paket_version": { 127 | "type": "generated", 128 | "generator": "switch", 129 | "replaces": "BOLERO_PAKET_VERSION", 130 | "parameters": { 131 | "evaluator": "C++", 132 | "datatype": "string", 133 | "cases": [ 134 | {"condition": "(nightly)", "value": "prerelease"}, 135 | {"condition": "(!nightly)", "value": ""} 136 | ] 137 | } 138 | }, 139 | "port_server": { 140 | "type": "generated", 141 | "generator": "port", 142 | "replaces": "PORT_SERVER_HTTP", 143 | "parameters": { 144 | "low": "5000", 145 | "high": "5049", 146 | "fallback": "5000" 147 | } 148 | }, 149 | "port_client": { 150 | "type": "generated", 151 | "generator": "port", 152 | "replaces": "PORT_CLIENT_HTTP", 153 | "parameters": { 154 | "low": "5050", 155 | "high": "5099", 156 | "fallback": "5050" 157 | } 158 | }, 159 | "port_server_ssl": { 160 | "type": "generated", 161 | "generator": "port", 162 | "replaces": "PORT_SERVER_SSL", 163 | "parameters": { 164 | "low": "44300", 165 | "high": "44349", 166 | "fallback": "44320" 167 | } 168 | }, 169 | "port_client_ssl": { 170 | "type": "generated", 171 | "generator": "port", 172 | "replaces": "PORT_CLIENT_SSL", 173 | "parameters": { 174 | "low": "44350", 175 | "high": "44399", 176 | "fallback": "44360" 177 | } 178 | } 179 | }, 180 | "sources": [ 181 | { 182 | "exclude": [ 183 | "src/Bolero.Template.1.Client/Main.minimal.fs", 184 | "**/.template.config/**/*", 185 | "nuget.config" 186 | ], 187 | "modifiers": [ 188 | { 189 | "condition": "(server)", 190 | "rename": { 191 | "src/Bolero.Template.1.Client/wwwroot/books.json": "src/Bolero.Template.1.Server/data/books.json" 192 | } 193 | }, 194 | { 195 | "condition": "(!server)", 196 | "exclude": [ 197 | "src/Bolero.Template.1.Server/**/*" 198 | ] 199 | }, 200 | { 201 | "condition": "(minimal)", 202 | "exclude": [ 203 | "src/Bolero.Template.1.Server/BookService.fs", 204 | "src/Bolero.Template.1.Client/wwwroot/books.json", 205 | "src/Bolero.Template.1.Client/wwwroot/favicon.ico", 206 | "src/Bolero.Template.1.Client/wwwroot/css/*", 207 | "src/Bolero.Template.1.Client/Main.fs" 208 | ], 209 | "include": [ 210 | "src/Bolero.Template.1.Client/Main.minimal.fs" 211 | ], 212 | "rename": { 213 | "src/Bolero.Template.1.Client/Main.minimal.fs": "src/Bolero.Template.1.Client/Main.fs" 214 | } 215 | }, 216 | { 217 | "condition": "(!html)", 218 | "exclude": [ 219 | "src/Bolero.Template.1.Client/wwwroot/main.html" 220 | ] 221 | }, 222 | { 223 | "condition": "(hostpage != \"bolero\")", 224 | "exclude": [ 225 | "src/Bolero.Template.1.Server/Index.fs" 226 | ] 227 | }, 228 | { 229 | "condition": "(hostpage != \"razor\")", 230 | "exclude": [ 231 | "src/Bolero.Template.1.Server/Pages/_Host.cshtml", 232 | "src/Bolero.Template.1.Server/HostModel.fs" 233 | ] 234 | }, 235 | { 236 | "condition": "(server && hostpage != \"html\")", 237 | "exclude": [ 238 | "src/Bolero.Template.1.Client/wwwroot/index.html" 239 | ] 240 | }, 241 | { 242 | "condition": "(nightly && !paket)", 243 | "include": ["nuget.config"] 244 | }, 245 | { 246 | "condition": "(!paket)", 247 | "exclude": [ 248 | ".config/dotnet-tools.json", 249 | ".paket/*", 250 | "paket.dependencies", 251 | "**/paket.references" 252 | ] 253 | }, 254 | { 255 | "condition": "(!pwa)", 256 | "exclude": [ 257 | "src/Bolero.Template.1.Client/wwwroot/icon-512.png", 258 | "src/Bolero.Template.1.Client/wwwroot/manifest.json", 259 | "src/Bolero.Template.1.Client/wwwroot/service-worker.js", 260 | "src/Bolero.Template.1.Client/wwwroot/service-worker.published.js" 261 | ] 262 | } 263 | ] 264 | } 265 | ], 266 | "SpecialCustomOperations": { 267 | "*": { 268 | "flagPrefix": "//#", 269 | "operations": [ 270 | { 271 | "type": "conditional", 272 | "configuration": { 273 | "if": [ "//#if" ], 274 | "else": [ "//#else" ], 275 | "elseif": [ "//#elseif" ], 276 | "endif": [ "//#endif" ], 277 | "true": true, 278 | "wholeLine": true, 279 | "evaluator": "C++" 280 | } 281 | } 282 | ] 283 | } 284 | }, 285 | "postActions": [ 286 | { 287 | "condition": "(paket)", 288 | "description": "Convert project to Paket", 289 | "actionId": "3A7C4B45-1F5D-4A30-959A-51B88E82B5D2", 290 | "args": { 291 | "redirectStandardOutput": "false", 292 | "executable": "dotnet", 293 | "args": "tool restore" 294 | }, 295 | "continueOnError": false 296 | }, 297 | { 298 | "condition": "(paket)", 299 | "description": "Convert project to Paket", 300 | "actionId": "3A7C4B45-1F5D-4A30-959A-51B88E82B5D2", 301 | "args": { 302 | "redirectStandardOutput": "false", 303 | "executable": "dotnet", 304 | "args": "paket install" 305 | }, 306 | "continueOnError": false 307 | } 308 | ] 309 | } 310 | -------------------------------------------------------------------------------- /content/application/src/Bolero.Template.1.Client/Main.fs: -------------------------------------------------------------------------------- 1 | module Bolero.Template._1.Client.Main 2 | 3 | open System 4 | //#if (!server) 5 | open System.Net.Http 6 | open System.Net.Http.Json 7 | open Microsoft.AspNetCore.Components 8 | //#endif 9 | open Elmish 10 | open Bolero 11 | open Bolero.Html 12 | //#if (server) 13 | open Bolero.Remoting 14 | open Bolero.Remoting.Client 15 | //#endif 16 | //#if (hotreload_actual) 17 | open Bolero.Templating.Client 18 | //#endif 19 | 20 | /// Routing endpoints definition. 21 | type Page = 22 | | [] Home 23 | | [] Counter 24 | | [] Data 25 | 26 | /// The Elmish application's model. 27 | type Model = 28 | { 29 | page: Page 30 | counter: int 31 | books: Book[] option 32 | error: string option 33 | //#if (server) 34 | username: string 35 | password: string 36 | signedInAs: option 37 | signInFailed: bool 38 | //#endif 39 | } 40 | 41 | and Book = 42 | { 43 | title: string 44 | author: string 45 | publishDate: DateTime 46 | isbn: string 47 | } 48 | 49 | let initModel = 50 | { 51 | page = Home 52 | counter = 0 53 | books = None 54 | error = None 55 | //#if (server) 56 | username = "" 57 | password = "" 58 | signedInAs = None 59 | signInFailed = false 60 | //#endif 61 | } 62 | 63 | //#if (server) 64 | /// Remote service definition. 65 | type BookService = 66 | { 67 | /// Get the list of all books in the collection. 68 | getBooks: unit -> Async 69 | 70 | /// Add a book in the collection. 71 | addBook: Book -> Async 72 | 73 | /// Remove a book from the collection, identified by its ISBN. 74 | removeBookByIsbn: string -> Async 75 | 76 | /// Sign into the application. 77 | signIn : string * string -> Async> 78 | 79 | /// Get the user's name, or None if they are not authenticated. 80 | getUsername : unit -> Async 81 | 82 | /// Sign out from the application. 83 | signOut : unit -> Async 84 | } 85 | 86 | interface IRemoteService with 87 | member this.BasePath = "/books" 88 | //#endif 89 | 90 | /// The Elmish application's update messages. 91 | type Message = 92 | | SetPage of Page 93 | | Increment 94 | | Decrement 95 | | SetCounter of int 96 | | GetBooks 97 | | GotBooks of Book[] 98 | //#if (server) 99 | | SetUsername of string 100 | | SetPassword of string 101 | | ClearLoginForm 102 | | GetSignedInAs 103 | | RecvSignedInAs of option 104 | | SendSignIn 105 | | RecvSignIn of option 106 | | SendSignOut 107 | | RecvSignOut 108 | //#endif 109 | | Error of exn 110 | | ClearError 111 | 112 | //#if (server) 113 | let update remote message model = 114 | let onSignIn = function 115 | | Some _ -> Cmd.batch [ Cmd.ofMsg GetBooks; Cmd.ofMsg ClearLoginForm ] 116 | | None -> Cmd.none 117 | //#else 118 | let update (http: HttpClient) message model = 119 | //#endif 120 | match message with 121 | | SetPage page -> 122 | { model with page = page }, Cmd.none 123 | 124 | | Increment -> 125 | { model with counter = model.counter + 1 }, Cmd.none 126 | | Decrement -> 127 | { model with counter = model.counter - 1 }, Cmd.none 128 | | SetCounter value -> 129 | { model with counter = value }, Cmd.none 130 | 131 | | GetBooks -> 132 | //#if (server) 133 | let cmd = Cmd.OfAsync.either remote.getBooks () GotBooks Error 134 | //#else 135 | let getBooks() = http.GetFromJsonAsync("/books.json") 136 | let cmd = Cmd.OfTask.either getBooks () GotBooks Error 137 | //#endif 138 | { model with books = None }, cmd 139 | | GotBooks books -> 140 | { model with books = Some books }, Cmd.none 141 | 142 | //#if (server) 143 | | SetUsername s -> 144 | { model with username = s }, Cmd.none 145 | | SetPassword s -> 146 | { model with password = s }, Cmd.none 147 | | ClearLoginForm -> 148 | { model with 149 | username = "" 150 | password = "" }, Cmd.none 151 | | GetSignedInAs -> 152 | model, Cmd.OfAuthorized.either remote.getUsername () RecvSignedInAs Error 153 | | RecvSignedInAs username -> 154 | { model with signedInAs = username }, onSignIn username 155 | | SendSignIn -> 156 | model, Cmd.OfAsync.either remote.signIn (model.username, model.password) RecvSignIn Error 157 | | RecvSignIn username -> 158 | { model with signedInAs = username; signInFailed = Option.isNone username }, onSignIn username 159 | | SendSignOut -> 160 | model, Cmd.OfAsync.either remote.signOut () (fun () -> RecvSignOut) Error 161 | | RecvSignOut -> 162 | { model with signedInAs = None; signInFailed = false }, Cmd.none 163 | 164 | | Error RemoteUnauthorizedException -> 165 | { model with error = Some "You have been logged out."; signedInAs = None }, Cmd.none 166 | //#endif 167 | | Error exn -> 168 | { model with error = Some exn.Message }, Cmd.none 169 | | ClearError -> 170 | { model with error = None }, Cmd.none 171 | 172 | /// Connects the routing system to the Elmish application. 173 | let router = Router.infer SetPage (fun model -> model.page) 174 | 175 | //#if (html) 176 | type Main = Template<"wwwroot/main.html"> 177 | 178 | let homePage model dispatch = 179 | Main.Home().Elt() 180 | 181 | let counterPage model dispatch = 182 | Main.Counter() 183 | .Decrement(fun _ -> dispatch Decrement) 184 | .Increment(fun _ -> dispatch Increment) 185 | .Value(model.counter, fun v -> dispatch (SetCounter v)) 186 | .Elt() 187 | 188 | //#if (server) 189 | let dataPage model (username: string) dispatch = 190 | //#else 191 | let dataPage model dispatch = 192 | //#endif 193 | Main.Data() 194 | .Reload(fun _ -> dispatch GetBooks) 195 | //#if (server) 196 | .Username(username) 197 | .SignOut(fun _ -> dispatch SendSignOut) 198 | //#endif 199 | .Rows(cond model.books <| function 200 | | None -> 201 | Main.EmptyData().Elt() 202 | | Some books -> 203 | forEach books <| fun book -> 204 | tr { 205 | td { book.title } 206 | td { book.author } 207 | td { book.publishDate.ToString("yyyy-MM-dd") } 208 | td { book.isbn } 209 | }) 210 | .Elt() 211 | 212 | //#if (server) 213 | let signInPage model dispatch = 214 | Main.SignIn() 215 | .Username(model.username, fun s -> dispatch (SetUsername s)) 216 | .Password(model.password, fun s -> dispatch (SetPassword s)) 217 | .SignIn(fun _ -> dispatch SendSignIn) 218 | .ErrorNotification( 219 | cond model.signInFailed <| function 220 | | false -> empty() 221 | | true -> 222 | Main.ErrorNotification() 223 | .HideClass("is-hidden") 224 | .Text("Sign in failed. Use any username and the password \"password\".") 225 | .Elt() 226 | ) 227 | .Elt() 228 | //#endif 229 | 230 | let menuItem (model: Model) (page: Page) (text: string) = 231 | Main.MenuItem() 232 | .Active(if model.page = page then "is-active" else "") 233 | .Url(router.Link page) 234 | .Text(text) 235 | .Elt() 236 | 237 | let view model dispatch = 238 | Main() 239 | .Menu(concat { 240 | menuItem model Home "Home" 241 | menuItem model Counter "Counter" 242 | menuItem model Data "Download data" 243 | }) 244 | .Body( 245 | cond model.page <| function 246 | | Home -> homePage model dispatch 247 | | Counter -> counterPage model dispatch 248 | | Data -> 249 | //#if (server) 250 | cond model.signedInAs <| function 251 | | Some username -> dataPage model username dispatch 252 | | None -> signInPage model dispatch 253 | //#else 254 | dataPage model dispatch 255 | //#endif 256 | ) 257 | .Error( 258 | cond model.error <| function 259 | | None -> empty() 260 | | Some err -> 261 | Main.ErrorNotification() 262 | .Text(err) 263 | .Hide(fun _ -> dispatch ClearError) 264 | .Elt() 265 | ) 266 | .Elt() 267 | //#else 268 | let homePage model dispatch = 269 | div { 270 | attr.``class`` "content" 271 | h1 { attr.``class`` "title"; "Welcome to Bolero!" } 272 | p { "This application demonstrates Bolero's major features." } 273 | ul { 274 | li { 275 | "The entire application is driven by " 276 | a { 277 | attr.target "_blank" 278 | attr.href "https://fsbolero.github.io/docs/Elmish" 279 | "Elmish" 280 | } 281 | "." 282 | } 283 | li { 284 | "The menu on the left switches pages based on " 285 | a { 286 | attr.target "_blank" 287 | attr.href "https://fsbolero.github.io/docs/Routing" 288 | "routes" 289 | } 290 | "." 291 | } 292 | li { 293 | "The " 294 | a { router.HRef Counter; "Counter" } 295 | " page demonstrates event handlers and data binding in " 296 | a { 297 | attr.target "_blank" 298 | attr.href "https://fsbolero.github.io/docs/Templating" 299 | "HTML templates" 300 | } 301 | "." 302 | } 303 | li { 304 | "The " 305 | a { router.HRef Data; "Download data" } 306 | //#if (server) 307 | " page demonstrates the use of " 308 | a { 309 | attr.target "_blank" 310 | attr.href "https://fsbolero.github.io/docs/Remoting" 311 | "remote functions" 312 | } 313 | "." 314 | //#else 315 | " page demonstrates the use of HTTP requests to the server." 316 | //#endif 317 | } 318 | p { "Enjoy writing awesome apps!" } 319 | } 320 | } 321 | 322 | let counterPage model dispatch = 323 | concat { 324 | h1 { attr.``class`` "title"; "A simple counter" } 325 | p { 326 | button { 327 | on.click (fun _ -> dispatch Decrement) 328 | attr.``class`` "button" 329 | "-" 330 | } 331 | input { 332 | attr.``type`` "number" 333 | attr.id "counter" 334 | attr.``class`` "input" 335 | bind.input.int model.counter (fun v -> dispatch (SetCounter v)) 336 | } 337 | button { 338 | on.click (fun _ -> dispatch Increment) 339 | attr.``class`` "button" 340 | "+" 341 | } 342 | } 343 | } 344 | 345 | //#if (server) 346 | let dataPage model (username: string) dispatch = 347 | //#else 348 | let dataPage model dispatch = 349 | //#endif 350 | concat { 351 | h1 { 352 | attr.``class`` "title" 353 | "Download data " 354 | button { 355 | attr.``class`` "button" 356 | on.click (fun _ -> dispatch GetBooks) 357 | "Reload" 358 | } 359 | } 360 | //#if (server) 361 | p { 362 | $"Signed in as {username}. " 363 | button { 364 | attr.``class`` "button" 365 | on.click (fun _ -> dispatch SendSignOut) 366 | "Sign out" 367 | } 368 | } 369 | //#endif 370 | table { 371 | attr.``class`` "table is-fullwidth" 372 | thead { 373 | tr { 374 | th { "Title" } 375 | th { "Author" } 376 | th { "Published" } 377 | th { "ISBN" } 378 | } 379 | } 380 | tbody { 381 | cond model.books <| function 382 | | None -> 383 | tr { 384 | td { attr.colspan 4; "Downloading book list..." } 385 | } 386 | | Some books -> 387 | forEach books <| fun book -> 388 | tr { 389 | td { book.title } 390 | td { book.author } 391 | td { book.publishDate.ToString("yyyy-MM-dd") } 392 | td { book.isbn } 393 | } 394 | } 395 | } 396 | } 397 | 398 | let errorNotification errorText closeCallback = 399 | div { 400 | attr.``class`` "notification is-warning" 401 | cond closeCallback <| function 402 | | None -> empty() 403 | | Some closeCallback -> button { attr.``class`` "delete"; on.click closeCallback } 404 | text errorText 405 | } 406 | 407 | //#if (server) 408 | let field (content: Node) = div { attr.``class`` "field"; content } 409 | let control (content: Node) = div { attr.``class`` "control"; content } 410 | 411 | let inputField (fieldLabel: string) (inputAttrs: Attr) = 412 | field (concat { 413 | label { attr.``class`` "label"; fieldLabel } 414 | control (input { attr.``class`` "input"; inputAttrs }) 415 | }) 416 | 417 | let signInPage model dispatch = 418 | concat { 419 | h1 { attr.``class`` "title"; "Sign in" } 420 | form { 421 | on.submit (fun _ -> dispatch SendSignIn) 422 | inputField "Username" ( 423 | bind.input.string model.username (fun s -> dispatch (SetUsername s)) 424 | ) 425 | inputField "Password" (attrs { 426 | attr.``type`` "password" 427 | bind.input.string model.password (fun s -> dispatch (SetPassword s)) 428 | }) 429 | field ( 430 | control ( 431 | input { attr.``type`` "submit"; attr.value "Sign in" } 432 | ) 433 | ) 434 | cond model.signInFailed <| function 435 | | false -> empty() 436 | | true -> errorNotification "Sign in failed. Use any username and the password \"password\"." None 437 | } 438 | } 439 | 440 | //#endif 441 | let menuItem (model: Model) (page: Page) (itemText: string) = 442 | li { 443 | a { 444 | attr.``class`` (if model.page = page then "is-active" else "") 445 | router.HRef page 446 | itemText 447 | } 448 | } 449 | 450 | let view model dispatch = 451 | div { 452 | attr.``class`` "columns" 453 | aside { 454 | attr.``class`` "column sidebar is-narrow" 455 | section { 456 | attr.``class`` "section" 457 | nav { 458 | attr.``class`` "menu" 459 | ul { 460 | attr.``class`` "menu-list" 461 | menuItem model Home "Home" 462 | menuItem model Counter "Counter" 463 | menuItem model Data "Download data" 464 | } 465 | } 466 | } 467 | } 468 | div { 469 | attr.``class`` "column" 470 | section { 471 | attr.``class`` "section" 472 | cond model.page <| function 473 | | Home -> homePage model dispatch 474 | | Counter -> counterPage model dispatch 475 | | Data -> 476 | //#if (server) 477 | cond model.signedInAs <| function 478 | | Some username -> dataPage model username dispatch 479 | | None -> signInPage model dispatch 480 | //#else 481 | dataPage model dispatch 482 | //#endif 483 | div { 484 | attr.id "notification-area" 485 | cond model.error <| function 486 | | None -> empty() 487 | | Some err -> errorNotification err (Some (fun _ -> dispatch ClearError)) 488 | } 489 | } 490 | } 491 | } 492 | //#endif 493 | 494 | type MyApp() = 495 | inherit ProgramComponent() 496 | 497 | override _.CssScope = CssScopes.MyApp 498 | 499 | //#if (!server) 500 | [] 501 | member val HttpClient = Unchecked.defaultof with get, set 502 | 503 | //#endif 504 | override this.Program = 505 | //#if (server) 506 | let bookService = this.Remote() 507 | let update = update bookService 508 | Program.mkProgram (fun _ -> initModel, Cmd.ofMsg GetSignedInAs) update view 509 | //#else 510 | let update = update this.HttpClient 511 | Program.mkProgram (fun _ -> initModel, Cmd.ofMsg GetBooks) update view 512 | //#endif 513 | |> Program.withRouter router 514 | //#if (hotreload_actual) 515 | #if DEBUG 516 | |> Program.withHotReload 517 | #endif 518 | //#endif 519 | -------------------------------------------------------------------------------- /.paket/Paket.Restore.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 8 | 9 | $(MSBuildVersion) 10 | 15.0.0 11 | false 12 | true 13 | 14 | true 15 | $(MSBuildThisFileDirectory) 16 | $(MSBuildThisFileDirectory)..\ 17 | $(PaketRootPath)paket-files\paket.restore.cached 18 | $(PaketRootPath)paket.lock 19 | classic 20 | proj 21 | assembly 22 | native 23 | /Library/Frameworks/Mono.framework/Commands/mono 24 | mono 25 | 26 | 27 | $(PaketRootPath)paket.bootstrapper.exe 28 | $(PaketToolsPath)paket.bootstrapper.exe 29 | $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\ 30 | 31 | "$(PaketBootStrapperExePath)" 32 | $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)" 33 | 34 | 35 | 36 | 37 | true 38 | true 39 | 40 | 41 | True 42 | 43 | 44 | False 45 | 46 | $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/')) 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | $(PaketRootPath)paket 56 | $(PaketToolsPath)paket 57 | 58 | 59 | 60 | 61 | 62 | $(PaketRootPath)paket.exe 63 | $(PaketToolsPath)paket.exe 64 | 65 | 66 | 67 | 68 | 69 | <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json")) 70 | <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"')) 71 | <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | <_PaketCommand>dotnet paket 83 | 84 | 85 | 86 | 87 | 88 | $(PaketToolsPath)paket 89 | $(PaketBootStrapperExeDir)paket 90 | 91 | 92 | paket 93 | 94 | 95 | 96 | 97 | <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)")) 98 | <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)" 99 | <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" 100 | <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)" 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | true 122 | $(NoWarn);NU1603;NU1604;NU1605;NU1608 123 | false 124 | true 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) 134 | 135 | 136 | 137 | 138 | 139 | 141 | $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``)) 142 | $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``)) 143 | 144 | 145 | 146 | 147 | %(PaketRestoreCachedKeyValue.Value) 148 | %(PaketRestoreCachedKeyValue.Value) 149 | 150 | 151 | 152 | 153 | true 154 | false 155 | true 156 | 157 | 158 | 162 | 163 | true 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached 183 | 184 | $(MSBuildProjectFullPath).paket.references 185 | 186 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references 187 | 188 | $(MSBuildProjectDirectory)\paket.references 189 | 190 | false 191 | true 192 | true 193 | references-file-or-cache-not-found 194 | 195 | 196 | 197 | 198 | $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)')) 199 | $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)')) 200 | references-file 201 | false 202 | 203 | 204 | 205 | 206 | false 207 | 208 | 209 | 210 | 211 | true 212 | target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths) 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | false 224 | true 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length) 236 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) 237 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) 238 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[2]) 239 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4]) 240 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5]) 241 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[6]) 242 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[7]) 243 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[8]) 244 | 245 | 246 | %(PaketReferencesFileLinesInfo.PackageVersion) 247 | All 248 | runtime 249 | $(ExcludeAssets);contentFiles 250 | $(ExcludeAssets);build;buildMultitargeting;buildTransitive 251 | %(PaketReferencesFileLinesInfo.Aliases) 252 | true 253 | true 254 | 255 | 256 | 257 | 258 | %(PaketReferencesFileLinesInfo.PackageVersion) 259 | 260 | 261 | 262 | 263 | $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0]) 273 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1]) 274 | 275 | 276 | %(PaketCliToolFileLinesInfo.PackageVersion) 277 | 278 | 279 | 280 | 284 | 285 | 286 | 287 | 288 | 289 | false 290 | 291 | 292 | 293 | 294 | 295 | <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/> 296 | 297 | 298 | 299 | 300 | 301 | $(MSBuildProjectDirectory)/$(MSBuildProjectFile) 302 | true 303 | false 304 | true 305 | false 306 | true 307 | false 308 | true 309 | false 310 | true 311 | false 312 | true 313 | $(PaketIntermediateOutputPath)\$(Configuration) 314 | $(PaketIntermediateOutputPath) 315 | 316 | 317 | 318 | <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/> 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 378 | 379 | 428 | 429 | 474 | 475 | 519 | 520 | 563 | 564 | 565 | 566 | --------------------------------------------------------------------------------