WASM API
KCL 核心用 Rust 编写,可以使用 cargo 等工具链编译到 wasm-wasi 目标。在 WASM 的帮助下,也可以轻松实现多语言和浏览器集成。以下是在浏览器, Node.js 环境, Go 和 Rust 中使用 KCL WASM 模块的方法。
快速开始
可以从这里找到 KCL WASM 模块。
浏览器环境
安装依赖
npm install buffer @wasmer/wasi @kcl-lang/wasm-lib
注意:buffer 是 @wasmer/wasi 所需的依赖。
编写代码
import { load, invokeKCLRun } from "@kcl-lang/wasm-lib";
async function main() {
  const inst = await load();
  const result = invokeKCLRun(inst, {
    filename: "test.k",
    source: `
schema Person:
  name: str
p = Person {name = "Alice"}`,
  });
  console.log(result);
}
main();
在这里,我们使用 webpack 来打包网站, webpack.config.js 的配置如下。
注意:此配置包含了 @wasmer/wasi 所需的必要设置和其他必需的插件。
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
const webpack = require("webpack");
const dist = path.resolve("./dist");
const isProduction = process.argv.some((x) => x === "--mode=production");
const hash = isProduction ? ".[contenthash]" : "";
module.exports = {
  mode: "development",
  entry: {
    main: "./src/main.ts",
  },
  target: "web",
  output: {
    path: dist,
    filename: `[name]${hash}.js`,
    clean: true,
  },
  devServer: {
    hot: true,
    port: 9000,
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      {
        test: /\.m?js$/,
        resourceQuery: { not: [/(raw|wasm)/] },
      },
      {
        resourceQuery: /raw/,
        type: "asset/source",
      },
      {
        resourceQuery: /wasm/,
        type: "asset/resource",
        generator: {
          filename: "wasm/[name][ext]",
        },
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "./src/index.html"),
    }),
    new webpack.IgnorePlugin({
      resourceRegExp: /^(path|ws|crypto|fs|os|util|node-fetch)$/,
    }),
    // needed by @wasmer/wasi
    new webpack.ProvidePlugin({
      Buffer: ["buffer", "Buffer"],
    }),
  ],
  externals: {
    // needed by @wasmer/wasi
    "wasmer_wasi_js_bg.wasm": true,
  },
  resolve: {
    fallback: {
      // needed by @wasmer/wasi
      buffer: require.resolve("buffer/"),
    },
  },
};
完整的代码示例可以在这里找到。
错误排查
如果遇到任何问题,请确保:
- 所有依赖都正确安装。
- webpack.config.js 配置正确。
- 使用的是支持 WebAssembly 的现代浏览器。
- KCL WASM 模块正确加载并可访问。
Node.js
安装依赖:
npm install @kcl-lang/wasm-lib
编写代码:
import { load, invokeKCLRun } from "@kcl-lang/wasm-lib";
async function main() {
  const inst = await load();
  const result = invokeKCLRun(inst, {
    filename: "test.k",
    source: `
schema Person:
  name: str
p = Person {name = "Alice"}`,
  });
  console.log(result);
}
main();
输出结果为:
p:
  name: Alice
完整的代码示例可以在这里找到。
Rust
在 Rust 中,我们以 wasmtime 为例,当然你也可以使用其他支持 WASI 的运行时来完成这一任务。
安装依赖:
cargo add kcl-wasm-lib --git https://github.com/kcl-lang/lib
cargo add anyhow
编写代码:
use anyhow::Result;
use kcl_wasm_lib::{KCLModule, RunOptions};
fn main() -> Result<()> {
    let opts = RunOptions {
        filename: "test.k".to_string(),
        source: "a = 1".to_string(),
    };
    // 注意修改路径为你的 kcl.wasm 路径
    let mut module = KCLModule::from_path("path/to/kcl.wasm")?;
    let result = module.run(&opts)?;
    println!("{}", result);
    Ok(())
}
输出结果为:
a: 1
完整的代码示例可以在这里找到。
Go
在 Go 中,我们以 wasmtime 为例,当然你也可以使用其他支持 WASI 的运行时来完成这一任务。
编写代码,关于包 github.com/kcl-lang/wasm-lib/pkg/module 的代码可以在这里找到。
package main
import (
    "fmt"
    "github.com/kcl-lang/wasm-lib/pkg/module"
)
func main() {
    m, err := module.New("path/to/kcl.wasm")
    if err != nil {
        panic(err)
    }
    result, err := m.Run(&module.RunOptions{
        Filename: "test.k",
        Source:   "a = 1",
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(result)
}
输出结果为:
a: 1
完整的代码示例可以在这里找到。