Skip to main content

Using in Browser

Available since
  • @kosko/env v2.0.0
  • @kosko/generate v1.2.0

Kosko can be used in browsers via the programmatic API. Currently only @kosko/env and @kosko/generate packages are browser-ready.

Entry File

@kosko/env doesn't come with any default environment loaders in browser. You have to set one manually. This is because bundlers (e.g. Webpack, Parcel) transpile import statements and bundlers can't parse dynamic import paths without any contexts. Import paths are much simpler in userland. (import(path) v.s. import("./envs/" + name))

Another difference is that you can't use the generate function exported from the @kosko/generate package. Instead, use the resolve function to resolve and validate components. This is because the generate function finds matched components with glob, which is not available in browsers.

Below is a basic example of an entry file. First, we use dynamic import to load environment variables. Then, use the resolve function to resolve and validate components. And finally, print the resolved manifests with the print function.

import env, { createAsyncLoaderReducers } from "@kosko/env";
import { resolve, print, PrintFormat } from "@kosko/generate";

// Load environment variables with dynamic import
env.setReducers((reducers) => [
...reducers,
...createAsyncLoaderReducers({
global: () =>
import("./environments/dev/index.js").then((mod) => mod.default),
component: (name) =>
import(`./environments/dev/${name}.js`).then((mod) => mod.default)
})
]);

(async () => {
// Resolve and validate components
const manifests = await resolve(
import("./components/nginx.js").then((mod) => mod.default)
);

// Print resolved manifests
print(
{ manifests },
{
format: PrintFormat.YAML,
writer: { write: (data) => console.log(data) }
}
);
})();

See API docs for more details.

Environments

Async

@kosko/env is asynchronous by default in browser. You MUST add await when retrieving environment variables.

import env from "@kosko/env";

const globalParams = await env.global();
const componentParams = await env.component("demo");

export default [new Deployment()];

However, top-level await is only available on Webpack 5 and mainstream browsers. If your bundler or browser doesn't support top-level await yet, you must wrap components with an async function.

import env from "@kosko/env";

export default async function () {
const params = await env.component("demo");

return [new Deployment()];
}

Sync

The other way is to create a synchronous environment, so you don't have to add await when retrieving environment variables.

import { createSyncEnvironment, createSyncLoaderReducers } from "@kosko/env";

const env = createSyncEnvironment();

env.setReducers((reducers) => [
...reducers,
...createSyncLoaderReducers({
global: () => {},
component: (name) => {}
})
]);

export default env;

One caveat is that you can't use dynamic imports in the environment loader anymore. In Webpack, you can use require.context to import files in a folder.

const dev = require.context("./environments/dev");

env.setReducers((reducers) => [
...reducers,
...createSyncLoaderReducers({
global: () => dev("./index"),
component: (name) => dev(`./${name}`)
})
]);

Another caveat is that you have to rewrite the @kosko/env import paths in components, or use aliases.

Without Bundlers

Examples

Kosko can also be used without a bundler. You can import modules from a CDN that supports ECMAScript modules (e.g. Skypack, JSPM, etc.).

import env from "https://jspm.dev/@kosko/env";
import { Deployment } from "https://jspm.dev/kubernetes-models/apps/v1/Deployment";

const params = await env.component("demo");

export default [new Deployment()];

You can also use import maps so you don't have to rewrite import paths. Please note that it is only supported on Chrome (as of April 2021). You might need a polyfill such as es-module-shims.

<script type="importmap">
{
"imports": {
"@kosko/env": "https://jspm.dev/@kosko/env",
"@kosko/generate": "https://jspm.dev/@kosko/generate",
"kubernetes-models/": "https://jspm.dev/kubernetes-models/"
}
}
</script>