Skip to content

Commit 660408a

Browse files
authored
Merge pull request #40 from MLH-Fellowship/wasm-rust-sample
Added Rust/WebAssembly Sample
2 parents 9815b5a + 0f4d6a9 commit 660408a

26 files changed

+5974
-0
lines changed

wasm-rust-sample/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
dist/
3+
target/
4+
pkg/
5+
wasm/
6+
wasm-pack.log
7+
*.wasm.js

wasm-rust-sample/Cargo.lock

Lines changed: 204 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wasm-rust-sample/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "uxp-wasm-rust-sample"
3+
description = "UXP Sample for using Rust and WebAssembly in Photoshop"
4+
version = "0.1.0"
5+
categories = ["wasm", "uxp"]
6+
edition = "2018"
7+
8+
[lib]
9+
crate-type = ["cdylib"]
10+
11+
[dependencies]
12+
wasm-bindgen = "0.2.75"
13+
14+
[dev-dependencies]
15+
wasm-bindgen-test = "0.3.25"

wasm-rust-sample/README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# WebAssembly and Rust Example
2+
3+
This plugin is a starting point for leveraging Rust and WebAssembly in your UXP plugins. It comes defined with most of the dependencies you need to get started. As this plugin does rely on the [Rust Programming Language](https://www.rust-lang.org/), an environment configured for Rust development will be required before this will be usable in Photoshop.
4+
5+
# Configuration
6+
7+
## Rust Environment
8+
9+
Before beginning ensure that the [Rust toolchain](https://www.rust-lang.org/tools/install) is installed and configured on your machine.
10+
11+
Follow the instructions and the `rustup` installation process. Once completed, your shell will have access to `cargo` commands.
12+
13+
> You **must** have the Rust toolchain installed in order to build the project
14+
15+
**Note:** For Windows users, the [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) must be installed for the Rust compiler to work properly. For more information, consult the [Rust documentation](https://doc.rust-lang.org/book/ch01-01-installation.html#installing-rustup-on-windows).
16+
17+
### 1. Install [wasm-pack](https://github.com/rustwasm/wasm-pack)
18+
19+
```
20+
$ cargo install wasm-pack
21+
```
22+
23+
### 2. Test local Rust configuration and [wasm-pack](https://github.com/rustwasm/wasm-pack) installation
24+
25+
```
26+
$ yarn test # or cargo test && wasm-pack test --node
27+
```
28+
29+
## Node.js
30+
31+
### 1. Install the Node.js dependencies:
32+
33+
```
34+
$ yarn install # or npm install
35+
```
36+
37+
### 2. Run plugin in watch or build mode
38+
39+
```
40+
$ yarn watch # or npm run watch
41+
42+
# OR
43+
44+
$ yarn build # or npm run build
45+
```
46+
47+
> You **must** run `build` prior to trying to use this plugin within Photoshop!
48+
49+
- `yarn watch` or `npm run watch` will build a development version of the plugin, and recompile everytime you make a change to the source files. The result is placed in `dist`.
50+
- `yarn build` or `npm run build` will build a production version of the plugin and place it in `dist`. It will not update every time you make a change to the source files.
51+
52+
**Note:** Since UXP does not have implicit access to `localhost` for leveraging a development server, this plugin uses inline WebAssembly to work properly. As such, you'll find the following import in `js/index.js`:
53+
54+
```
55+
import encodedRust from '../wasm/uxp.wasm';
56+
```
57+
58+
When the build script is triggerred, this JS file with the inline WebAssembly is generated. Should you wish to generate this file yourself, execute the following commands:
59+
60+
```
61+
$ yarn inlinewasm # generate JS file containing the inline WebAssembly data
62+
```
63+
64+
## Launching in Photoshop
65+
66+
You can use the UXP Developer Tools to load the plugin into Photoshop.
67+
68+
If the plugin hasn't already been added to your workspace in the UXP Developer Tools, you can add it by clicking "Add Plugin..." and selecting `dist/manifest.json`. **DO NOT** select the `manifest.json` file inside the `plugin` folder.
69+
70+
Once added, you can load it into Photoshop by clicking the ••• button on the corresponding row, and clicking "Load". Switch to Photoshop and you should see the starter panels.
71+
72+
## What this plugin does
73+
74+
This plugin uses a basic Rust implementation to hold state for a counter component that is surfaced on the UI. It also uses the `wasm-bindgen` API to make use of JavaScript API methods in Rust, such as `console.log`. Finally, the plugin demonstrates a potential build process for leveraging Rust and WebAssembly in your UXP plugins.

wasm-rust-sample/js/index.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { entrypoints } from 'uxp';
2+
import { decodeWebAssembly } from './utils';
3+
4+
import encodedRust from '../wasm/uxp.wasm';
5+
import init, { add, multiply, global_sys, Counter } from '../pkg/uxp_wasm.js';
6+
7+
entrypoints.setup({
8+
plugin: {
9+
create(plugin) {
10+
console.log('Plugin created successfully.', plugin);
11+
},
12+
panels: {
13+
plugin: this,
14+
},
15+
},
16+
});
17+
18+
const main = async () => {
19+
const decodedRust = decodeWebAssembly(encodedRust);
20+
21+
// Manually pass WebAssembly to prevent `wasm-bindgen` from using `fetch()`
22+
await init(decodedRust);
23+
24+
console.log(`Log 3: Sent from JavaScript! (2 + 2 = ${add(2, 2)})`);
25+
console.log(`Log 4: Sent from JavaScript! (12 * 12 = ${multiply(12, 12)})`);
26+
27+
const counter = Counter.new();
28+
setInterval(() => {
29+
counter.increment();
30+
document.getElementById('timer').textContent = counter.get_count();
31+
}, 1000);
32+
};
33+
34+
await main().catch((err) => {
35+
console.log(err);
36+
});

wasm-rust-sample/js/utils.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Buffer } from 'buffer';
2+
3+
/**
4+
* Decodes WebAssembly from base64 to binary
5+
* js-inline-wasm can serve this as decoded, however the decoding method is deprecated from the Node.js API
6+
*/
7+
export const decodeWebAssembly = async (encodedWebAssembly) => {
8+
let decodedRust = Buffer.from(encodedWebAssembly, 'base64').toString(
9+
'binary'
10+
);
11+
12+
const len = decodedRust.length;
13+
const byteArray = new Uint8Array(len);
14+
15+
for (var i = 0; i < len; i++) {
16+
byteArray[i] = decodedRust.charCodeAt(i);
17+
}
18+
19+
return byteArray;
20+
};

wasm-rust-sample/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "com.adobe.example.wasm-rust-sample",
3+
"version": "1.0.0",
4+
"license": "none",
5+
"private": true,
6+
"scripts": {
7+
"build": "rimraf dist && webpack --mode development",
8+
"watch": "nodemon -w src -w js -w webpack.config.js -e js,rs,json,css,html -x npm run build",
9+
"inlinewasm": "npx crlf --set=LF node_modules/.bin/inlinewasm && inlinewasm pkg/uxp_wasm_bg.wasm -o wasm/uxp.wasm.js -t encoded",
10+
"test": "cargo test && wasm-pack test --node"
11+
},
12+
"devDependencies": {
13+
"@babel/core": "^7.14.6",
14+
"@babel/preset-env": "^7.14.7",
15+
"@wasm-tool/wasm-pack-plugin": "^1.5.0",
16+
"babel-loader": "^8.2.2",
17+
"babel-polyfill": "^6.26.0",
18+
"buffer": "^6.0.3",
19+
"copy-webpack-plugin": "^9.0.1",
20+
"css-loader": "^5.2.6",
21+
"js-inline-wasm": "^0.0.7",
22+
"nodemon": "^2.0.12",
23+
"rimraf": "^3.0.2",
24+
"style-loader": "^3.0.0",
25+
"text-encoding": "^0.7.0",
26+
"webpack": "^5.44.0",
27+
"webpack-cli": "^4.7.2",
28+
"webpack-dev-server": "^3.11.2",
29+
"webpack-shell-plugin-next": "^2.2.2"
30+
}
31+
}

wasm-rust-sample/plugin/ferris.png

5.24 KB
Loading
452 Bytes
Loading
501 Bytes
Loading

0 commit comments

Comments
 (0)