Skip to content

Commit

Permalink
Publishing WASM packages to NPM (#512)
Browse files Browse the repository at this point in the history
* Drafting NodeJS package template for publishing to NPM

* Adding boilerplate for `fuel-types` package

* Encapsulating commands as a function for optimal reuse

* Adding `fuel-types` to the build/publish script routine

* Removing all boilerplate files

* Moving .gitignore one directory up

* Turning all boilerplate files into reusable templates

* Refactoring the main script for WASM generation and NPM pkg assembling

* Tyop

* Fixing template tags for package `name` and `version`

* Moving template around

* Renaming templates directory

* DRY-refactoring script; formatting; fetching version from `Cargo.toml`

* Renaming method and removing TODO - publishing routine should be in CI

* Renaming and moving script inside `.npm` dir (decluttering root dir)

* Cd’ing to the previous dir without echoing its path

* Adjusting templates, using `@fuels/` org prefix for NPM packages

* Re-shaping `.npm` directory as a workspace for easier maintenance

* Linting - removing extraneous whitespaces

* Adjusting `package.json`

* Drafting CI action for NPM publishing

* Adjusting nomenclature

* Commenting requirements temporarily

* Adjusting order of CI job steps

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Adjusting sed flags; updating lock file

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Debugging CI

* Adding step to ensure NPM access is ok

* Adding README

* Docs

* Tyop

* Debugging CI

* Removing `dryRun` flag, preparing for real publishing

* Fixing package title, adding `@fuels` suffix

* Setting up job constrains

* Validating real publishing flow

* Scoped packages needs to be explicitly published with `--access public`

* Rolling back release constrains

* Renaming dubious files and scripts

* Docs

* Trimming jobs dependencies; formatting

* Rolling back git checks

* Update .npm/.scripts/prepare-wasm-packages.sh

Co-authored-by: Green Baneling <XgreenX9999@gmail.com>

---------

Co-authored-by: Green Baneling <XgreenX9999@gmail.com>
  • Loading branch information
arboleya and xgreenx authored Jul 24, 2023
1 parent 59663bd commit e7642d0
Show file tree
Hide file tree
Showing 17 changed files with 1,830 additions and 3 deletions.
53 changes: 51 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- command: check
args: --all-targets -p fuel-crypto
- command: check
args: --all-targets -p fuel-merkle
args: --all-targets -p fuel-merkle
- command: check
args: --all-targets -p fuel-storage
- command: check
Expand Down Expand Up @@ -160,7 +160,7 @@ jobs:
uses: katyo/publish-crates@v2
with:
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}

cargo_audit:
runs-on: ubuntu-latest
continue-on-error: true
Expand All @@ -169,3 +169,52 @@ jobs:
- uses: rustsec/audit-check@v1.4.1
with:
token: ${{ secrets.GITHUB_TOKEN }}

publish_wasm_packages:
needs:
- publish
if: github.event_name == 'release' && github.event.action == 'published'
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}

- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
targets: "wasm32-unknown-unknown"

- name: Installing required crates
run: cargo install wasm-bindgen-cli wasm-opt

- name: Setup PNPM
uses: pnpm/action-setup@v2
with:
version: 8.6.9

- name: Setup Node
uses: actions/setup-node@v3
with:
cache: "pnpm"
node-version: 18.14.1
node-version-file: ".npm/package.json"
cache-dependency-path: ".npm/pnpm-lock.yaml"
registry-url: 'https://registry.npmjs.org'

- name: Build and Test packages
run: |
pnpm -C .npm install
pnpm -C .npm pack:all
- name: Ensure NPM access
run: npm whoami
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Publish
run: pnpm -C .npm publish -r --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk

.vscode/
.vscode/
.history
6 changes: 6 additions & 0 deletions .npm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.turbo
node_modules

packages/*/*
!packages/*/index.test.cjs
!packages/*/index.test.mjs
59 changes: 59 additions & 0 deletions .npm/.scripts/prepare-wasm-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash

ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
NPM_DIR=${ROOT_DIR}/.npm
PKGS_DIR=${NPM_DIR}/packages


write_template ()
{
NAME_DASHED=$1
NAME_UNDERSCORED=$2
TEMPLATE=$3

PKG_TEMPLATE_DIR=${NPM_DIR}/.scripts/template
PKG_DIR=${PKGS_DIR}/${NAME_DASHED}

PKG_NAME=$(echo "${NAME_DASHED}" | sed -e 's/fuel-//g')
PKG_VERSION=$(cat ${ROOT_DIR}/Cargo.toml | sed -nr 's/^version = "([^"]+)"/\1/p')

echo "$(
cat ${PKG_TEMPLATE_DIR}/${TEMPLATE} \
| sed -e "s/{{NAME_DASHED}}/${NAME_DASHED}/g" \
| sed -e "s/{{NAME_UNDERSCORED}}/${NAME_UNDERSCORED}/g" \
| sed -e "s/{{PKG_NAME}}/${PKG_NAME}/g" \
| sed -e "s/{{PKG_VERSION}}/${PKG_VERSION}/g"
)" > ${PKG_DIR}/${TEMPLATE}

}


build_wasm_npm_pkg_for ()
{
NAME_DASHED=$1
NAME_UNDERSCORED=$(echo "${NAME_DASHED}" | sed -e 's/-/_/g')

PKG_DIR=${PKGS_DIR}/${NAME_DASHED}

rm -rf ${PKG_DIR}/{src,dist}

cd ${ROOT_DIR}
cargo rustc -p ${NAME_DASHED} --target wasm32-unknown-unknown --features typescript --crate-type=cdylib --release
wasm-bindgen --typescript --target web ./target/wasm32-unknown-unknown/release/${NAME_UNDERSCORED}.wasm --out-dir ${PKG_DIR}/src
wasm-opt ${PKG_DIR}/src/${NAME_UNDERSCORED}_bg.wasm -o ${PKG_DIR}/src/${NAME_UNDERSCORED}_bg.wasm -Oz
cd ~-

write_template ${NAME_DASHED} ${NAME_UNDERSCORED} README.md
write_template ${NAME_DASHED} ${NAME_UNDERSCORED} package.json
write_template ${NAME_DASHED} ${NAME_UNDERSCORED} rollup.config.mjs
write_template ${NAME_DASHED} ${NAME_UNDERSCORED} src/index.js

# commenting out all `new URL()` and `fetch()` calls for great compatibility with JS bundlers
sed -i.bkp -r 's;(input = new URL.+);//\1;g' ${PKG_DIR}/src/${NAME_UNDERSCORED}.js
sed -i.bkp -r 's;(input = fetch.+);//\1;g' ${PKG_DIR}/src/${NAME_UNDERSCORED}.js
rm ${PKG_DIR}/src/${NAME_UNDERSCORED}.js.bkp
}


build_wasm_npm_pkg_for "fuel-asm"
build_wasm_npm_pkg_for "fuel-types"
6 changes: 6 additions & 0 deletions .npm/.scripts/template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

# @fuels/vm-{{NAME_DASHED}}

WASM version of `{{NAME_DASHED}}` Rust crate:
- https://crates.io/crates/{{NAME_DASHED}}
- https://github.com/FuelLabs/fuel-vm/tree/master/{{NAME_DASHED}}
17 changes: 17 additions & 0 deletions .npm/.scripts/template/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@fuels/vm-{{PKG_NAME}}",
"version": "{{PKG_VERSION}}",
"description": "WASM version of `{{NAME_DASHED}}` Rust crate",
"author": "Fuel Labs <contact@fuel.sh> (https://fuel.network/)",
"main": "dist/node/index.cjs",
"types": "dist/node/index.d.ts",
"browser": "dist/web/index.mjs",
"files": [
"dist"
],
"scripts": {
"build": "rollup -c rollup.config.mjs",
"test": "mocha index.test.cjs index.test.mjs"
},
"license": "Apache-2.0"
}
25 changes: 25 additions & 0 deletions .npm/.scripts/template/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { wasm } from '@rollup/plugin-wasm'
import dts from 'rollup-plugin-dts'

export default [
{
plugins: [wasm({ targetEnv: 'auto-inline' })],
input: 'src/index.js',
output: [
{ file: 'dist/node/index.cjs', format: 'cjs' },
]
}, {
plugins: [wasm({ targetEnv: 'auto-inline' })],
input: 'src/index.js',
output: [
{ file: 'dist/web/index.mjs', format: 'es' },
]
}, {
plugins: [dts()],
input: 'src/{{NAME_UNDERSCORED}}.d.ts',
output: [
{ file: 'dist/web/index.d.ts', format: 'es' },
{ file: 'dist/node/index.d.ts', format: 'es' }
],
}
]
6 changes: 6 additions & 0 deletions .npm/.scripts/template/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import init from './{{NAME_UNDERSCORED}}.js'
import wasm from './{{NAME_UNDERSCORED}}_bg.wasm'

init(wasm())

export * from './{{NAME_UNDERSCORED}}.js'
73 changes: 73 additions & 0 deletions .npm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# WASM version of Rust Crates

You'll find all the routines to publish selected Rust crates as NPM packages here.

# Testing Locally

To get started and test things locally, you'll need to:

```shell
# install the required crates
cargo install wasm-bindgen-cli wasm-opt

# ensure you have the needed target
rustup target add wasm32-unknown-unknown

# then install deps, generate wasm files, build and test the package
pnpm install
pnpm run wasm
pnpm run build
pnpm run test
```

# Output

The above commands will give ready-to-publish packages inside `.npm/packages`.

```shell
.npm
├── .scripts
│   └── prepare-wasm-packages
├── packages
│   ├── fuel-asm # <—— package #1
│   └── fuel-types # <—— package #2
└── package.json
```

# How does it work?

For an in-depth understanding, check:
- `.npm/package.json`
- `.npm/.scripts/prepare-wasm-packages.sh`
- `.github/workflows/ci.yml`
- _Look for the `publish_wasm_packages` job_

# Using local sym-linked packages

First, we need to link our `packages` package globally in our local `global pnpm store`:

```sh
cd packages/fuel-asm
pnpm link -g
```

Let's check it out:

```sh
pnpm list -g
```

You should see something like:

```
@fuels/vm-asm link:<...>/fuel-vm/.npm/packages/fuel-asm
```

Cool, now on the root directory of your desired project `my-local-project`:

```sh
cd my-local-project
pnpm link -g @fuels/vm-asm
```

Done — you're using the local version of `@fuels/vm-asm`.
28 changes: 28 additions & 0 deletions .npm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"private": true,
"name": "@fuels/wasm-packages",
"version": "0.0.0",
"description": "Workspace for building WASM versions of Rust crates",
"author": "Fuel Labs <contact@fuel.sh> (https://fuel.network/)",
"engines": {
"node": ">= 18.14.1",
"pnpm": ">= 8.1.1"
},
"packageManager": "pnpm@8.1.1",
"scripts": {
"wasm": ".scripts/prepare-wasm-packages.sh",
"build": "turbo run build",
"test": "turbo run test",
"pack:all": "pnpm run-s wasm build test"
},
"license": "Apache-2.0",
"devDependencies": {
"@rollup/plugin-wasm": "^6.1.3",
"chai": "^4.3.7",
"mocha": "^10.2.0",
"npm-run-all": "^4.1.5",
"rollup": "^3.26.2",
"rollup-plugin-dts": "^5.3.0",
"turbo": "^1.10.9"
}
}
33 changes: 33 additions & 0 deletions .npm/packages/fuel-asm/index.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { expect } = require('chai')
const asm = require('.')

describe('fuel-asm [cjs]', () => {

it('should compose simple script', () => {

const gtf = asm.gtf(0x10, 0x00, asm.GTFArgs.ScriptData)
const addi = asm.addi(0x11, 0x10, 0x20)
const lw = asm.lw(0x12, 0x11, 0x0)
const addi2 = asm.addi(0x13, 0x11, 0x8)
const tr = asm.tr(0x10, 0x12, 0x13)
const ret = asm.ret(0x1)

const script = Uint8Array.from([
...gtf.to_bytes(),
...addi.to_bytes(),
...lw.to_bytes(),
...addi2.to_bytes(),
...tr.to_bytes(),
...ret.to_bytes(),
])

const expected = new Uint8Array([
97, 64, 0, 12, 80, 69, 0, 32,
93, 73, 16, 0, 80, 77, 16, 8,
60, 65, 36, 192, 36, 4, 0, 0
])

expect(script).to.deep.equal(expected)
})

})
33 changes: 33 additions & 0 deletions .npm/packages/fuel-asm/index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { expect } from 'chai'
import * as asm from './dist/web/index.mjs'

describe('fuel-asm [esm]', () => {

it('should compose simple script', () => {

const gtf = asm.gtf(0x10, 0x00, asm.GTFArgs.ScriptData)
const addi = asm.addi(0x11, 0x10, 0x20)
const lw = asm.lw(0x12, 0x11, 0x0)
const addi2 = asm.addi(0x13, 0x11, 0x8)
const tr = asm.tr(0x10, 0x12, 0x13)
const ret = asm.ret(0x1)

const script = Uint8Array.from([
...gtf.to_bytes(),
...addi.to_bytes(),
...lw.to_bytes(),
...addi2.to_bytes(),
...tr.to_bytes(),
...ret.to_bytes(),
])

const expected = new Uint8Array([
97, 64, 0, 12, 80, 69, 0, 32,
93, 73, 16, 0, 80, 77, 16, 8,
60, 65, 36, 192, 36, 4, 0, 0
])

expect(script).to.deep.equal(expected)
})

})
24 changes: 24 additions & 0 deletions .npm/packages/fuel-types/index.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const { expect } = require('chai')
const types = require('.')

describe('fuel-types [cjs]', () => {

it('should export all types', () => {

expect(types.Address).to.be.ok
expect(types.AssetId).to.be.ok
expect(types.BlockHeight).to.be.ok
expect(types.Bytes20).to.be.ok
expect(types.Bytes32).to.be.ok
expect(types.Bytes4).to.be.ok
expect(types.Bytes64).to.be.ok
expect(types.Bytes8).to.be.ok
expect(types.ChainId).to.be.ok
expect(types.ContractId).to.be.ok
expect(types.MessageId).to.be.ok
expect(types.Nonce).to.be.ok
expect(types.Salt).to.be.ok

})

})
Loading

0 comments on commit e7642d0

Please sign in to comment.