Skip to content

Split out Component binaries into @ruby/wasm-wasip2 package #528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ compile_commands.json
html

build_manifest.json
ci_matrix.json

vendor/bundle
/pkg
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ $ rake build:download_prebuilt
$ rake build:head-wasm32-unknown-wasip1-full

# Build npm package
$ rake npm:ruby-head-wasm-wasi
$ rake npm:ruby-head-wasm-wasip2:build
# Test npm package
$ rake npm:ruby-head-wasm-wasi:check
$ rake npm:ruby-head-wasm-wasip2:check
```

If you need to re-build Ruby, please clean `./rubies` directory, and run `rake npm:ruby-head-wasm-wasi` again.
Expand Down
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ NPM_PACKAGES = [
ruby_version: "head",
gemfile: "packages/npm-packages/ruby-head-wasm-wasi/Gemfile",
target: "wasm32-unknown-wasip1",
},
{
name: "ruby-head-wasm-wasip2",
ruby_version: "head",
gemfile: "packages/npm-packages/ruby-head-wasm-wasip2/Gemfile",
target: "wasm32-unknown-wasip2",
enable_component_model: true,
},
{
Expand Down
1 change: 1 addition & 0 deletions builders/wasm32-unknown-wasip1
15 changes: 13 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/npm-packages/ruby-head-wasm-wasi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

[![npm version](https://badge.fury.io/js/@ruby%2Fhead-wasm-wasi.svg)](https://www.npmjs.com/package/@ruby/head-wasm-wasi)

This package provides WebAssembly binaries of CRuby built from the latest `HEAD` source code targeting WASI-compatible environments.
This package provides WebAssembly binaries of CRuby built from the latest `HEAD` source code targeting environments compatible with WASI Preview1.

See [`@ruby/wasm-wasi`](https://github.com/ruby/ruby.wasm/blob/main/packages/npm-packages/ruby-wasm-wasi/README.md) for how to use this package.
2 changes: 1 addition & 1 deletion packages/npm-packages/ruby-head-wasm-wasi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"README.md"
],
"scripts": {
"test": "RUBY_NPM_PACKAGE_ROOT=../ruby-head-wasm-wasi npm -C ../ruby-wasm-wasi run test:run:all",
"test": "RUBY_NPM_PACKAGE_ROOT=../ruby-head-wasm-wasi npm -C ../ruby-wasm-wasi run test:run",
"build:deps": "cd ../ruby-wasm-wasi && npm run build",
"build:static:files": "../ruby-wasm-wasi/tools/pack-static-files.sh ./dist",
"build:static:compat": "../ruby-wasm-wasi/tools/pack-compat-shim.mjs --dist=./dist --pkg=ruby-head-wasm-wasi",
Expand Down
4 changes: 4 additions & 0 deletions packages/npm-packages/ruby-head-wasm-wasip2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.tgz
/tmp
/bundle
/vendor
15 changes: 15 additions & 0 deletions packages/npm-packages/ruby-head-wasm-wasip2/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

source "https://rubygems.org"

# We build ./vendor/cache/js-{version}.gem just before evaluating this Gemfile
# so that Bundler builds extensions even from the local gem. (gem extensions
# from "path:" gems are not built by Bundler.)
# Thus even we specify version of "js" gem here, it should always installed
# from the ./vendor/cache/js-{version}.gem, not from rubygems.org. To achieve this,
# we always use non-exist version during development.
require_relative "../../gems/js/lib/js/version.rb"
gem "js", JS::VERSION
gem "ruby_wasm", path: "../../../", group: [:build]
gem "power_assert"
gem "test-unit"
25 changes: 25 additions & 0 deletions packages/npm-packages/ruby-head-wasm-wasip2/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
PATH
remote: ../../..
specs:
ruby_wasm (2.6.2.dev)

GEM
remote: https://rubygems.org/
specs:
js (2.6.2.dev)
power_assert (2.0.3)
test-unit (3.6.2)
power_assert

PLATFORMS
ruby
x86_64-linux

DEPENDENCIES
js (= 2.6.2.dev)
power_assert
ruby_wasm!
test-unit

BUNDLED WITH
2.6.0.dev
7 changes: 7 additions & 0 deletions packages/npm-packages/ruby-head-wasm-wasip2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @ruby/head-wasm-wasip2

[![npm version](https://badge.fury.io/js/@ruby%2Fhead-wasm-wasip2.svg)](https://www.npmjs.com/package/@ruby/head-wasm-wasip2)

This package provides WebAssembly binaries of CRuby built from the latest `HEAD` source code targeting environments compatible with WASI Preview2.

See [`@ruby/wasm-wasi`](https://github.com/ruby/ruby.wasm/blob/main/packages/npm-packages/ruby-wasm-wasi/README.md) for how to use this package.
58 changes: 58 additions & 0 deletions packages/npm-packages/ruby-head-wasm-wasip2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@ruby/head-wasm-wasip2",
"version": "2.6.2",
"description": "Ruby head built on WASI Preview 2",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"private": true,
"exports": {
".": {
"browser": "./dist/esm/index.js",
"umd": "./dist/umd/index.js",
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
},
"./dist/*": {
"browser": "./dist/esm/*.js",
"umd": "./dist/umd/*.js",
"import": "./dist/esm/*.js",
"require": "./dist/cjs/*.js"
},
"./*.wasm": {
"browser": "./*.wasm",
"umd": "./*.wasm",
"import": "./*.wasm",
"require": "./*.wasm"
}
},
"files": [
"dist",
"README.md"
],
"scripts": {
"__comment": "FIXME: Enable test:e2e after https://github.com/bytecodealliance/jco/pull/499 is merged",
"test": "npm run run-script -- test:unit && npm run run-script -- test:vitest -- --run",
"run-script": "RUBY_NPM_PACKAGE_ROOT=../ruby-head-wasm-wasip2 ENABLE_COMPONENT_TESTS=1 npm -C ../ruby-wasm-wasi run",
"build:deps": "cd ../ruby-wasm-wasi && npm run build",
"build:static:files": "../ruby-wasm-wasi/tools/pack-static-files.sh ./dist",
"build:static": "npm run build:static:files",
"build:rollup": "rollup -c rollup.config.mjs",
"build": "npm run build:deps && npm run build:static && npm run build:rollup"
},
"repository": "https://github.com/ruby/ruby.wasm",
"homepage": "https://github.com/ruby/ruby.wasm/tree/main/packages/npm-packages/ruby-head-wasm-wasi",
"publishConfig": {
"access": "public"
},
"keywords": [
"wasm",
"webassembly",
"wasi",
"ruby"
],
"license": "MIT",
"dependencies": {
"@ruby/wasm-wasi": "^2.0.0",
"@bytecodealliance/preview2-shim": "^0.16.5"
}
}
21 changes: 21 additions & 0 deletions packages/npm-packages/ruby-head-wasm-wasip2/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import json from "@rollup/plugin-json";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import fs from "fs";
import path from "path";

/** @type {import('rollup').RollupOptions[]} */
export default [
{
input: "src/browser.script.js",
output: [
{
file: "dist/browser.script.iife.js",
format: "iife",
banner: "/* " + fs.readFileSync(path.resolve("../../../NOTICE"), "utf8") + "*/",
}
],
plugins: [
json(), nodeResolve()
],
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { instantiate } from "../dist/component/ruby.component"
import { componentMain } from "@ruby/wasm-wasi/dist/browser.script"
import * as wasip2 from "@bytecodealliance/preview2-shim"
import * as pkg from "../package.json"

componentMain(pkg, { instantiate, wasip2 })
1 change: 1 addition & 0 deletions packages/npm-packages/ruby-wasm-wasi/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
!.gitkeep
/coverage
/playwright-report
/test-results
*.tgz
1 change: 0 additions & 1 deletion packages/npm-packages/ruby-wasm-wasi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
],
"license": "MIT",
"scripts": {
"test:run:all": "npm run test:run && ENABLE_COMPONENT_TESTS=1 npm run test:run",
"test:run": "npm run test:unit && npm run test:vitest -- --run && npm run test:e2e",
"test:vitest": "vitest ./test/",
"test:unit": "./tools/run-test-unit.mjs",
Expand Down
29 changes: 29 additions & 0 deletions packages/npm-packages/ruby-wasm-wasi/src/browser.script.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { DefaultRubyVM } from "./browser.js";
import { RubyInitComponentOptions, RubyComponentInstantiator, RubyVM } from "./vm.js";

/**
* The main entry point of `<script type="text/ruby">`-based scripting with WebAssembly Core Module.
*/
export const main = async (
pkg: { name: string; version: string },
options?: Parameters<typeof DefaultRubyVM>[1],
Expand All @@ -9,7 +13,32 @@ export const main = async (
);
const module = await compileWebAssemblyModule(response);
const { vm } = await DefaultRubyVM(module, options);
await mainWithRubyVM(vm);
};

/**
* The main entry point of `<script type="text/ruby">`-based scripting with WebAssembly Component.
*/
export const componentMain = async (
pkg: { name: string; version: string },
options: {
instantiate: RubyComponentInstantiator;
wasip2: any;
}
) => {
const componentUrl = `https://cdn.jsdelivr.net/npm/${pkg.name}@${pkg.version}/dist/component`;
const fetchComponentFile = (relativePath: string) => fetch(`${componentUrl}/${relativePath}`);
const { vm } = await RubyVM.instantiateComponent({
...options,
getCoreModule: (relativePath: string) => {
const response = fetchComponentFile(relativePath);
return compileWebAssemblyModule(response);
},
});
await mainWithRubyVM(vm);
};

const mainWithRubyVM = async (vm: RubyVM) => {
vm.printVersion();

globalThis.rubyVM = vm;
Expand Down
19 changes: 12 additions & 7 deletions packages/npm-packages/ruby-wasm-wasi/src/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ import {
} from "./bindgen/legacy/rb-js-abi-host.js";
import { Binding, ComponentBinding, LegacyBinding, RbAbiValue } from "./binding.js";

/**
* A function type that instantiates a Ruby component
*/
export type RubyComponentInstantiator = (
(
getCoreModule: (path: string) => WebAssembly.Module,
importObject: any,
instantiateCore?: (module: WebAssembly.Module, imports: Record<string, any>) => WebAssembly.Instance | Promise<WebAssembly.Instance>,
) => Promise<({ rubyRuntime: typeof RubyJsRubyRuntime })>
)

export type RubyInitComponentOptions = {
/**
* A lower-level instantiation function that instantiates the Ruby component with the given component
Expand All @@ -26,13 +37,7 @@ export type RubyInitComponentOptions = {
/**
* An `instantiate` function generated by `@bytecodealliance/jco` that instantiates the Ruby component.
*/
instantiate: (
(
getCoreModule: (path: string) => WebAssembly.Module,
importObject: any,
instantiateCore?: (module: WebAssembly.Module, imports: Record<string, any>) => WebAssembly.Instance | Promise<WebAssembly.Instance>,
) => Promise<({ rubyRuntime: typeof RubyJsRubyRuntime })>
),
instantiate: RubyComponentInstantiator,

/**
* A function that returns a WebAssembly Core module within the Ruby component transpiled by `@bytecodealliance/jco`.
Expand Down
16 changes: 13 additions & 3 deletions packages/npm-packages/ruby-wasm-wasi/test/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ import { WASI } from "wasi";
import { RubyVM } from "../src/index";
import * as preview2Shim from "@bytecodealliance/preview2-shim"

const rubyModule = (async () => {
const memoize = (fn) => {
let result;
return async () => {
if (!result) {
result = await fn();
}
return result;
};
};

const getRubyModule = memoize(async () => {
let binaryPath;
if (process.env.RUBY_ROOT) {
binaryPath = path.join(process.env.RUBY_ROOT, "./usr/local/bin/ruby");
Expand All @@ -18,7 +28,7 @@ const rubyModule = (async () => {
}
const binary = await fs.readFile(binaryPath);
return await WebAssembly.compile(binary.buffer);
})();
});

const initModuleRubyVM = async ({ suppressStderr } = { suppressStderr: false }) => {
let preopens = {};
Expand All @@ -38,7 +48,7 @@ const initModuleRubyVM = async ({ suppressStderr } = { suppressStderr: false })
preopens,
});

const module = await rubyModule;
const module = await getRubyModule();
const { vm } = await RubyVM.instantiateModule({ module, wasip1: wasi })
return vm;
};
Expand Down
5 changes: 4 additions & 1 deletion packages/npm-packages/ruby-wasm-wasi/test/package.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ const initRubyVM = async (rubyModule, args) => {
};

describe("Packaging validation", () => {
if (!process.env.RUBY_NPM_PACKAGE_ROOT) {
if (
!process.env.RUBY_NPM_PACKAGE_ROOT ||
(process.env.ENABLE_COMPONENT_TESTS && process.env.ENABLE_COMPONENT_TESTS !== 'false')
) {
test.skip("skip", () => {});
return;
}
Expand Down
Loading
Loading