Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: reduce wasm file size and improve Gas and size benchmark compar…
Browse files Browse the repository at this point in the history
…e to NEAR-SDK-RS
Pavel Ivanov committed Oct 9, 2024
1 parent 9623545 commit 2fd75ed
Showing 21 changed files with 1,878 additions and 1,674 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ on:
- develop
jobs:
tests:
timeout-minutes: 30
strategy:
matrix:
platform: [ubuntu-latest, macos-latest]
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
node_modules
vendor
.idea
700 changes: 269 additions & 431 deletions benchmark/README.md

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions examples/WASM-FILE-SIZE-COMPARISON.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# NEAR-SDK-JS EXAMPLES

### WASM File Size Comparison Before and After Optimization

| File Name | Before Opt (KB) | After Opt (KB) | % Diff |
| :-------------------------------------- | ------------------: | ------------------: | ------------------: |
| basic-updates-base.wasm | 500.53 | 477.35 | -4.63% |
| basic-updates-update.wasm | 562.14 | 498.71 | -11.27% |
| clean-state.wasm | 496.45 | 473.48 | -4.62% |
| counter-lowlevel.wasm | 472.62 | 468.67 | -0.84% |
| counter-ts.wasm | 496.66 | 473.56 | -4.66% |
| counter.wasm | 496.56 | 473.51 | -4.64% |
| cross-contract-call-loop.wasm | 504.86 | 480.77 | -4.77% |
| cross-contract-call-ts.wasm | 498.54 | 475.04 | -4.71% |
| cross-contract-call.wasm | 498.51 | 475.01 | -4.71% |
| fungible-token-helper.wasm | 495.88 | 472.92 | -4.63% |
| fungible-token-lockable.wasm | 505.26 | 481.73 | -4.66% |
| fungible-token.wasm | 505.12 | 481.39 | -4.69% |
| my-ft.wasm | 520.98 | 495.55 | -4.89% |
| my-nft.wasm | 534.88 | 507.94 | -5.04% |
| nested-collections.wasm | 504.90 | 481.18 | -4.71% |
| nft-approval-receiver.wasm | 504.91 | 480.82 | -4.76% |
| nft-receiver.wasm | 505.10 | 481.05 | -4.76% |
| non-fungible-token-receiver.wasm | 496.51 | 473.51 | -4.63% |
| non-fungible-token.wasm | 503.30 | 479.39 | -4.76% |
| parking-lot.wasm | 500.11 | 476.87 | -4.65% |
| programmatic-update-after.wasm | 496.49 | 473.41 | -4.65% |
| programmatic-update-before.wasm | 496.47 | 473.38 | -4.65% |
| state-migration-new.wasm | 501.13 | 477.72 | -4.67% |
| state-migration-original.wasm | 499.98 | 476.68 | -4.65% |
| status-deserialize-class.wasm | 522.52 | 498.15 | -4.66% |
| status-message-borsh.wasm | 506.13 | 482.19 | -4.73% |
| status-message-collections.wasm | 505.38 | 481.67 | -4.70% |
| status-message-deserialize-err.wasm | 496.05 | 473.03 | -4.64% |
| status-message-migrate-add-field.wasm | 498.11 | 475.02 | -4.64% |
| status-message-serialize-err.wasm | 496.05 | 473.03 | -4.64% |
| status-message.wasm | 496.19 | 473.16 | -4.65% |
3 changes: 2 additions & 1 deletion examples/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "es2020",
"moduleResolution": "node",
"target": "es2020",
"skipLibCheck": true,
"noEmit": true
},
"exclude": ["node_modules"]
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
"docs:generate": "typedoc"
},
"devDependencies": {
"turbo": "1.10.16",
"turbo": "1.13.3",
"typedoc": "0.25.4",
"typescript": "4.7.4"
}
1 change: 0 additions & 1 deletion packages/near-contract-standards/package.json
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@
"author": "Near Inc <hello@nearprotocol.com>",
"license": "Apache-2.0",
"dependencies": {
"lodash-es": "4.17.21",
"near-sdk-js": "workspace:*"
},
"devDependencies": {
2,378 changes: 1,195 additions & 1,183 deletions packages/near-sdk-js/builder/builder.c

Large diffs are not rendered by default.

31 changes: 29 additions & 2 deletions packages/near-sdk-js/lib/cli/cli.js

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

22 changes: 21 additions & 1 deletion packages/near-sdk-js/lib/cli/post-install.js

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

9 changes: 9 additions & 0 deletions packages/near-sdk-js/lib/types/index.d.ts

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

1 change: 1 addition & 0 deletions packages/near-sdk-js/lib/utils.d.ts

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

48 changes: 46 additions & 2 deletions packages/near-sdk-js/lib/utils.js

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

3 changes: 2 additions & 1 deletion packages/near-sdk-js/package.json
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@
"near-typescript-json-schema": "0.55.0",
"rollup": "2.79.1",
"rollup-plugin-sourcemaps": "0.6.3",
"rollup-plugin-terser": "7.0.2",
"signale": "1.4.0",
"ts-morph": "16.0.0",
"typescript": "4.7.4"
@@ -67,7 +68,7 @@
"@types/babel__core": "7.20.5",
"@types/babel__traverse": "7.20.4",
"@types/eslint": "9.6.0",
"@types/node": "17.0.45",
"@types/node": "17.0.38",
"@types/rollup": "0.54.0",
"@types/signale": "1.4.7",
"@typescript-eslint/eslint-plugin": "5.62.0",
37 changes: 35 additions & 2 deletions packages/near-sdk-js/src/cli/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env node

import { terser } from "rollup-plugin-terser";

import fs from "fs";
import path, { basename, dirname } from "path";

@@ -135,7 +137,7 @@ function ensureTargetDirExists(target: string): void {
}

signal.await(`Creating ${targetDir} directory...`);
fs.mkdirSync(targetDir, {});
fs.mkdirSync(targetDir);
}

export async function validateCom(
@@ -242,6 +244,8 @@ export async function transpileJsAndBuildWasmCom(
signale.await("Executing wasi-stub...");
await wasiStubContract(getContractTarget(target), verbose);

await optimizeWasmContract(target, verbose);

signale.success(
`Generated ${getContractTarget(target)} contract successfully!`
);
@@ -298,7 +302,6 @@ async function createJsFileWithRullup(
extensions: [".js", ".ts"],
}),
sourcemaps(),
// commonjs(),
babel({
babelHelpers: "bundled",
extensions: [".ts", ".js", ".jsx", ".es6", ".es", ".mjs"],
@@ -312,6 +315,28 @@ async function createJsFileWithRullup(
["@babel/plugin-proposal-decorators", { version: "legacy" }],
],
}),
terser({
mangle: false,
compress: {
passes: 5,
hoist_vars: true,
reduce_funcs: true,
reduce_vars: true,
collapse_vars: true,
dead_code: true,
conditionals: true,
evaluate: true,
unused: true,
if_return: true,
join_vars: true,
sequences: true,
side_effects: true,
inline: true,
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log'],
},
}),
],
});

@@ -389,3 +414,11 @@ async function wasiStubContract(contractTarget: string, verbose = false) {
const WASI_STUB = `${NEAR_SDK_JS}/lib/cli/deps/binaryen/wasi-stub/run.sh`;
await executeCommand(`${WASI_STUB} ${contractTarget}`, verbose);
}

async function optimizeWasmContract(contractTarget: string, verbose = false) {
const WASM_OPT = `${NEAR_SDK_JS}/lib/cli/deps/webassembly/bin/wasm-opt`;
await executeCommand(
`${WASM_OPT} -Oz -o ${contractTarget} ${contractTarget}`,
verbose
);
}
35 changes: 34 additions & 1 deletion packages/near-sdk-js/src/cli/post-install.ts
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ const BINARYEN_VERSION_TAG = `v${BINARYEN_VERSION}`;

const BINARYEN_SYSTEM_NAME =
PLATFORM === "linux"
? "Linux"
? "linux"
: PLATFORM === "darwin"
? "macOS"
: PLATFORM === "win32"
@@ -58,6 +58,39 @@ fs.mkdirSync("binaryen");
await executeCommand(`tar xvf ${BINARYEN_TAR_NAME} --directory binaryen`);
fs.rmSync(BINARYEN_TAR_NAME);

signale.await("Installing WebAssembly Binaryen...");

const WEB_ASSEMBLY_BINARYEN_VERSION = `version_118`;
const WEB_ASSEMBLY_BINARYEN_VERSION_TAG = WEB_ASSEMBLY_BINARYEN_VERSION;

const WEB_ASSEMBLY_BINARYEN_SYSTEM_NAME =
PLATFORM === "linux"
? "linux"
: PLATFORM === "darwin"
? "macos"
: PLATFORM === "win32"
? "windows"
: "other";

const WEB_ASSEMBLY_BINARYEN_ARCH_NAME = ARCH === "x64" ? "x86_64" : ARCH === "arm64" ? "arm64" : "unsupported";
if (WEB_ASSEMBLY_BINARYEN_ARCH_NAME === "unsupported") {
console.error(`Architecture ${ARCH} is not supported for downloading binaries.`);
process.exit(1);
}

const WEB_ASSEMBLY_BINARYEN_TAR_NAME = `binaryen-${WEB_ASSEMBLY_BINARYEN_VERSION_TAG}-${WEB_ASSEMBLY_BINARYEN_ARCH_NAME}-${WEB_ASSEMBLY_BINARYEN_SYSTEM_NAME}.tar.gz`;


await download(
`https://github.com/WebAssembly/binaryen/releases/download/${WEB_ASSEMBLY_BINARYEN_VERSION_TAG}/${WEB_ASSEMBLY_BINARYEN_TAR_NAME}`
);

fs.mkdirSync("webassembly");

await executeCommand(`tar --strip-components=1 -xvf ${WEB_ASSEMBLY_BINARYEN_TAR_NAME} --directory webassembly`);
fs.rmSync(WEB_ASSEMBLY_BINARYEN_TAR_NAME);


signale.await("Installing QuickJS...");

const QUICK_JS_VERSION = `0.1.3`;
11 changes: 11 additions & 0 deletions packages/near-sdk-js/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import * as ts from "typescript";

export * from "./account_id";
export * from "./gas";
export * from "./primitives";
export * from "./public_key";
export * from "./vm_types";

declare module "typescript" {
interface ClassDeclaration {
decorators?: ts.NodeArray<ts.Decorator>;
}
interface MethodDeclaration {
decorators?: ts.NodeArray<ts.Decorator>;
}
}
58 changes: 56 additions & 2 deletions packages/near-sdk-js/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { GetOptions } from "./types/collections";
import { cloneDeep } from "lodash-es";

export interface Env {
uint8array_to_latin1_string(a: Uint8Array): string;
@@ -266,7 +265,8 @@ export function decodeObj2class(class_instance, obj) {
class_instance[key] = obj[key];
}
}
const instance_tmp = cloneDeep(class_instance);
const instance_tmp = deepCopy(class_instance);

for (key in obj) {
if (
typeof class_instance[key] == "object" &&
@@ -360,3 +360,57 @@ export function decode(a: Uint8Array): string {
export interface IntoStorageKey {
into_storage_key(): string;
}

export function deepCopy<T>(obj: T): T {
// Handle primitives and null
if (obj === null || typeof obj !== "object") {
return obj;
}

// Handle Date objects
if (obj instanceof Date) {
return new Date(obj.getTime()) as unknown as T;
}

// Handle RegExp objects
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags) as unknown as T;
}

// Handle Map objects
if (obj instanceof Map) {
const mapCopy = new Map();
obj.forEach((value, key) => {
mapCopy.set(deepCopy(key), deepCopy(value));
});
return mapCopy as unknown as T;
}

// Handle Set objects
if (obj instanceof Set) {
const setCopy = new Set();
obj.forEach((value) => {
setCopy.add(deepCopy(value));
});
return setCopy as unknown as T;
}

// Handle Arrays
if (Array.isArray(obj)) {
return obj.map((item) => deepCopy(item)) as unknown as T;
}

// Handle Objects
const copy = Object.create(Object.getPrototypeOf(obj));
Object.getOwnPropertyNames(obj).forEach((key) => {
copy[key] = deepCopy(obj[key]);
});

// Handle symbol properties
const symbols = Object.getOwnPropertySymbols(obj);
symbols.forEach((sym) => {
copy[sym] = deepCopy(obj[sym]);
});

return copy as T;
}
1 change: 1 addition & 0 deletions packages/near-sdk-js/tsconfig.json
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
"noImplicitReturns": true,
"noUnusedLocals": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"resolveJsonModule": true,
"allowJs": true,
"skipLibCheck": true
170 changes: 125 additions & 45 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"compilerOptions": {
"moduleResolution": "node",
"experimentalDecorators": true,
"moduleResolution": "node",
"target": "es2020",
"skipLibCheck": true,
"noEmit": true
},
"exclude": ["node_modules"]

0 comments on commit 2fd75ed

Please sign in to comment.