Skip to content

Commit

Permalink
add docs (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
elringus authored Feb 7, 2024
1 parent 4656f67 commit 0690313
Show file tree
Hide file tree
Showing 32 changed files with 1,248 additions and 57 deletions.
1 change: 1 addition & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
run: |
cd docs
npm install
npm run docs:api
npm run docs:build
- uses: actions/configure-pages@v3
- uses: actions/upload-pages-artifact@v2
Expand Down
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,24 @@
</p>
<br/>

# Bootsharp
# Use C# in web apps with comfort

Compile C# solution into single-file ES module with auto-generated JavaScript bindings and type definitions.
Author domain in C#, while taking full advantage of the modern JavaScript frontend ecosystem.

![](https://raw.githubusercontent.com/elringus/bootsharp/main/docs/public/img/banner.png)
✨ Generates JavaScript bindings and type declarations for your C# APIs facilitating seamless interop between the domain and UI.

Documentation will be added later. Please refer to [samples](https://github.com/elringus/bootsharp/tree/main/samples) for the time being.
📦 Choose between embedding all the C# binaries into single-file ES module for portability or sideload for best performance and build size.

🗺️ Node, Deno, Bun, web browsers and even constrained environments, such as VS Code extensions — your app will work everywhere.

⚡ Manually author interop APIs via static C# methods or simply feed Bootsharp your domain-specific interfaces — it'll figure the rest.

🏷️ When an interface value is specified in interop API, instance binding is generated allowing to interoperate on stateful objects.

🛠️ Configure namespaces for emitted bindings, function and event names, C# -> TypeScript type mappings and more.

🔥 Supports latest .NET features: WASM multi-threading, AOT compilation, assembly trimming, streaming module instantiation.

### 🎬 Get Started

https://bootsharp.com/guide
2 changes: 2 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cache
api
27 changes: 24 additions & 3 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineConfig } from "vitepress";
import proc from "node:child_process";
import imgit from "imgit/vite";
import md from "./md";

Expand All @@ -15,6 +16,7 @@ export default defineConfig({
["link", { rel: "icon", href: "/favicon.svg" }],
["link", { rel: "preload", href: "/fonts/inter.woff2", as: "font", type: "font/woff2", crossorigin: "" }],
["link", { rel: "preload", href: "/fonts/jb.woff2", as: "font", type: "font/woff2", crossorigin: "" }],
["meta", { name: "og:image", content: "/img/og.jpg" }],
["meta", { name: "twitter:card", content: "summary_large_image" }]
],
themeConfig: {
Expand All @@ -30,8 +32,9 @@ export default defineConfig({
docFooter: { prev: "Previous page", next: "Next page" },
nav: [
{ text: "Guide", link: "/guide/", activeMatch: "/guide/" },
{ text: "Reference", link: "/api/", activeMatch: "/api/" },
{
text: "v0.1.0", items: [
text: proc.execSync("git describe --abbrev=0 --tags").toString(), items: [
{ text: "Changes", link: "https://github.com/elringus/bootsharp/releases/latest" },
{ text: "Contribute", link: "https://github.com/elringus/bootsharp/labels/help%20wanted" }
]
Expand All @@ -46,10 +49,28 @@ export default defineConfig({
{
text: "Guide",
items: [
{ text: "Introduction", link: "/guide/" }
{ text: "Introduction", link: "/guide/" },
{ text: "Getting Started", link: "/guide/getting-started" },
{ text: "Type Declarations", link: "/guide/declarations" },
{ text: "Namespaces", link: "/guide/namespaces" },
{ text: "Events", link: "/guide/events" },
{ text: "Serialization", link: "/guide/serialization" },
{ text: "Interop Interfaces", link: "/guide/interop-interfaces" },
{ text: "Interop Instances", link: "/guide/interop-instances" },
{ text: "Emit Preferences", link: "/guide/emit-prefs" },
{ text: "Build Configuration", link: "/guide/build-config" },
{ text: "Sideloading Binaries", link: "/guide/sideloading" }
]
},
{
text: "Extensions",
items: [
{ text: "Dependency Injection", link: "/guide/extensions/dependency-injection" },
{ text: "File System ✨", link: "/guide/extensions/file-system" }
]
}
]
],
"/api/": [{ text: "Reference", items: (await import("./../api/typedoc-sidebar.json")).default }]
}
},
sitemap: { hostname: "https://bootsharp.com" }
Expand Down
51 changes: 27 additions & 24 deletions docs/.vitepress/theme/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@
font-optical-sizing: auto;

/* Main highlight/link color (light mode). */
/*--vp-c-brand-1: #d22c40;*/
/*--vp-c-brand-1: #9c00e7;*/
/* Link hover color (light mode). */
/*--vp-c-brand-2: #be2033;*/
/*--vp-c-brand-2: #b519ff;*/
/* Danger block override for sponsors. (light mode) */
--vp-custom-block-danger-bg: #fee3f5;
}

.dark {
/* Main highlight/link color (dark mode). */
/*--vp-c-brand-1: #ee3248;*/
/*--vp-c-brand-1: #b583ff;*/
/* Link hover color (dark mode). */
/*--vp-c-brand-2: #f35d44;*/
--vp-c-brand-2: #c7cdff;
/* Danger block override for sponsors. (dark mode) */
--vp-custom-block-danger-bg: #55223c;
}

.dark .dark-only,
Expand Down Expand Up @@ -140,6 +144,12 @@ table > tfoot:not(:last-child) {
background: none !important;
}

/* remove opacity gradient under navbar */
.curtain,
.aside-curtain {
display: none !important;
}

/* a hack for logo title to keep sidebar bg color */
@media (min-width: 960px) {
.VPNavBar.has-sidebar div.title {
Expand All @@ -148,24 +158,16 @@ table > tfoot:not(:last-child) {
}

/* a bit of tint to make navbar not as transparent */
.VPNavBar {
background: rgba(255, 255, 255, 0.75) !important;
}

.dark .VPNavBar {
background: rgba(30, 30, 32, 0.5) !important;
}

.VPLocalNav {
.VPNavBar:not(.top) {
background: rgba(255, 255, 255, 0.75) !important;
}

.dark .VPLocalNav {
.dark .VPNavBar:not(.top) {
background: rgba(30, 30, 32, 0.5) !important;
}

/* the blur effect */
.VPNav::after {
.VPNavBar:not(.top)::after {
content: "";
position: absolute;
top: 0;
Expand All @@ -176,13 +178,14 @@ table > tfoot:not(:last-child) {
z-index: -1;
}

.VPLocalNav::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
backdrop-filter: saturate(180%) blur(5px);
z-index: -1;
.VPNavBar.top::after {
opacity: 0;
}

.VPNavBar.top {
background-color: transparent;
}

.VPNavBar {
transition: border-bottom-color 0.25s, background-color 0.25s, opacity 0.25s;
}
36 changes: 36 additions & 0 deletions docs/guide/build-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Build Configuration

Build and publish related options are configured in `.csproj` file via MSBuild properties.

| Property | Default | Description |
|-----------------------------|------------|--------------------------------------------------------------|
| BootsharpName | bootsharp | Name of the generated JavaScript module. |
| BootsharpEmbedBinaries | true | Whether to embed binaries to the JavaScript module file. |
| BootsharpAggressiveTrimming | false | Whether to disable some .NET features to reduce binary size. |
| BootsharpBundleCommand | npx rollup | The command to bundle generated JavaScrip solution. |
| BootsharpPublishDirectory | /bin | Directory to publish generated JavaScript module. |
| BootsharpTypesDirectory | /types | Directory to publish type declarations. |
| BootsharpBinariesDirectory | /bin | Directory to publish binaries when `EmbedBinaries` disabled. |
| BootsharpPackageDirectory | / | Directory to publish `package.json` file. |

Below is an example configuration, which will make Bootsharp name compiled module "backend" (instead of the default "bootsharp"), publish the module under solution directory root (instead of "/bin"), disable binaries embedding and instead publish them under "public/bin" directory one level above the solution root and enable aggressive assembly trimming to reduce build size:

```xml
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<BootsharpName>backend</BootsharpName>
<BootsharpPackageDirectory>$(SolutionDir)</BootsharpPackageDirectory>
<BootsharpEmbedBinaries>false</BootsharpEmbedBinaries>
<BootsharpBinariesDirectory>$(SolutionDir)../public/bin</BootsharpBinariesDirectory>
<BootsharpAggressiveTrimming>true</BootsharpAggressiveTrimming>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Bootsharp" Version="*-*"/>
</ItemGroup>

</Project>
```
121 changes: 121 additions & 0 deletions docs/guide/declarations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Type Declarations

Bootsharp will automatically generate [type declarations](https://www.typescriptlang.org/docs/handbook/2/type-declarations) for interop APIs when building the solution. The files are emitted under "types" directory of the compiled module package.

## Function Declarations

For the interop methods, function declarations are emitted.

Exported `[JSInvokable]` methods will have associated function assigned under the declaring type space:

```csharp
public class Foo
{
[JSInvokable]
public static void Bar() { }
}
```

— will make following emitted in the declaration file:

```ts
export namespace Foo {
export function bar(): void;
}
```

— which allows consuming the API in JavaScript as follows:

```ts
import { Foo } from "bootsharp";

Foo.bar();
```

Imported `[JSFunction]` methods will be emitted as properties, which have to be assigned before booting the runtime:

::: code-group

```csharp [Foo.cs]
public partial class Foo
{
[JSFunction]
public static partial void Bar();
}
```

```ts [bindings.d.ts]
export namespace Foo {
export let bar: () => void;
}
```

```ts [main.ts]
import { Foo } from "bootsharp";

Foo.bar = () => {};
```

:::

## Event Declarations

`[JSEvent]` methods will be emitted as objects with `subscribe` and `unsubscribe` methods:

::: code-group

```csharp [Foo.cs]
public class Foo
{
[JSEvent]
public static partial void OnBar (string payload);
}
```

```ts [bindings.d.ts]
export namespace Foo {
export const onBar: Event<[string]>;
}
```

```ts [main.ts]
import { Foo } from "bootsharp";

Foo.onBar.subscribe(pyaload => {});
```

:::

## Type Crawling

Bootsharp will crawl types from the interop signatures and mirror them in the emitted declarations. For example, if you have a custom record with property of another custom record implementing a custom interface, both records and the interface will be emitted:

::: code-group

```csharp [Foo.cs]
public interface IFoo { };
public record Foo : IFoo;
public record Bar (Foo foo);

public partial class Foo
{
[JSFunction]
public static partial Bar GetBar();
}
```

```ts [bindings.d.ts]
export interface IFoo {}
export interface Foo implements IFoo {}
export interface Bar {foo: Foo;}

export namespace Foo {
export function getBar(): Bar;
}
```

:::

## Configuring Type Mappings

You can override which type declaration are generated for associated C# types via `Type` patterns of [emit preferences](/guide/emit-prefs).
33 changes: 33 additions & 0 deletions docs/guide/emit-prefs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Emit Preferences

Use `[JSPreferences]` assembly attribute to customize Bootsharp behaviour at build time when the interop code is emitted. It has several properties that takes array of `(pattern, replacement)` strings, which are feed to [Regex.Replace](https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.replace?view=net-6.0#system-text-regularexpressions-regex-replace(system-string-system-string-system-string)) when emitted associated code. Each consequent pair is tested in order; on first match the result replaces the default.

## Space

By default, all the generated JavaScript binding objects and TypeScript declarations are grouped under corresponding C# namespaces; refer to [namespaces](/guide/namespaces) docs for more info.

To customize emitted spaces, use `Space` parameter. For example, to make all bindings declared under "Foo.Bar" C# namespace have "Baz" namespace in JavaScript:

```cs
[assembly: JSPreferences(
Space = ["^Foo\.Bar\.(\S+)", "Baz.$1"]
)]
```

The patterns are matched against full type name of declaring C# type when generating JavaScript objects for interop methods and against namespace when generating TypeScript syntax for C# types. Matched type names have the following modifications:

- interfaces have first character removed
- generics have parameter spec removed
- nested type names have `+` replaced with `.`

## Type

Allows customizing generated TypeScript type syntax. The patterns are matched against full C# type names of interop method arguments, return values and object properties.

## Event

Used to customize which C# methods should be transformed into JavaScript events, as well as generated event names. The patterns are matched against C# method names declared under `[JSImport]` interfaces. By default, methods starting with "Notify..." are matched and renamed to "On...".

## Function

Customizes generated JavaScript function names. The patterns are matched against C# interop method names.
Loading

0 comments on commit 0690313

Please sign in to comment.