Skip to main content

Embedding

Instead of always shipping the frontend files alongside your binary it is also possible to embed all the web-content into your saucer application. The easiest way to accomplish this is to use the saucer-cli.

Pre-Requisites

  • A built version of your website (that should consist of .html, .js, ... files)

Automated Embedding

We recommend to use the saucer-cli within your package.json build script.

Simply add @saucer-dev/cli as a dependency (i.e. pnpm install @saucer-dev/cli) and then conduct the following changes:

{
// ...
"scripts": {
"build": "<deploy normally> && saucer embed <output-folder>"
}
// ...
}

CLI Usage

As we've seen above, the CLI simply consumes a given folder and produces C++ headers which handle the embedding.

You can also install the CLI globally.
This can be achieved by installing it as a global npm package: npm i -g @saucer-dev/cli.

If you now want to embed some specific files simply place them into a single directory ("out" in the example below).

Example: Folder Structure
out
├── 404.html
├── icon.webp
├── index.html
├── logos
└── _next
├── data
│ └── I0JjY_SsFNIFkY51LHHZ8
│ └── index.json
├── I0JjY_SsFNIFkY51LHHZ8
└── static
├── chunks
│ ├── 617-62e76ca49feff4cf.js
│ ├── ef6529d7-eceeabab9e91fbfa.js
│ ├── framework-4556c45dd113b893.js
│ ├── main-8622cd0e77d03013.js
│ ├── pages
│ │ ├── _app-21ef9ef16725f9ba.js
│ │ ├── _error-a4ba2246ff8fb532.js
│ │ └── index-5206a6595f9ffd08.js
│ ├── polyfills-0d1b80a048d4787e.js
│ └── webpack-c491b2a411a4f8fa.js
└── I0JjY_SsFNIFkY51LHHZ8
├── _buildManifest.js
└── _ssgManifest.js

And then use the saucer-cli to generate the required embedding files.

Command Syntax
saucer embed <source> [<destination>]
Example Command
saucer embed "out"

Using the Embedding Files

After running the embed command through the cli, a folder named "embedded" - unless otherwise specified - will be generated.

Now simply consume this folder as a include directory.

Example: Consuming Embedded Folder
target_include_directories(${PROJECT_NAME} PRIVATE "path/to/generated/folder")

Now it's only a matter of including the header in your code and calling embed on the webview.
To serve the files simply call serve and specify the file name.

Example: Using Embedded Files
#include <saucer/smartview.hpp>
#include <output_folder/all.hpp>

int main()
{
auto app = saucer::application::acquire({
.id = "embedding",
});

saucer::smartview smartview{{
.application = app,
}};

smartview.set_title("Hello World!");

smartview.expose("add_ten", [](int i)
{
return i + 10;
});

smartview.set_url("https://google.com");
smartview.embed(saucer::embedded::all());
smartview.serve("index.html");

smartview.show();
app->run();

return 0;
}

Manual Embedding

The CLI tool seen above will include all embedded files verbatim into your binary.
If you wish to have more control over how embedded files are loaded you can do so by manually creating the saucer::embedded_files.

The example below demonstrates how to embed a file that will load the given resource from a server lazily.

Example: Lazy Embedding
#include <saucer/smartview.hpp>
#include <cpr/cpr.h>

int main()
{
auto app = saucer::application::acquire({
.id = "embedding",
});

saucer::smartview smartview{{
.application = app,
}};

smartview.embed({{"index.html", saucer::embedded_file{
.content = saucer::stash<>::lazy(
[]()
{
auto req = cpr::Get(cpr::Url{"..."});
return saucer::make_stash(req.text);
}),
.mime = "text/html",
}}});

smartview.serve("index.html");

smartview.show();
app->run();

return 0;
}

Once the webview requests to load the index.html the given GET request will be started. Subsequent requests to load the index.html will re-use the initial result. For more information on saucer::stash see custom schemes.

tip

Calling webview::embed multiple times will merge the given files with the already embedded ones. Thus you can safely use the CLI-approach and lazy load only some files.