Skip to content

Commit c85d64c

Browse files
authored
[Debt] Make tvmjs an npm package, simplify build from source (#570)
In the past, building WebLLM from source could be cumbersome as users needed to build TVMjs by themselves by setting up `emscripten` and running `./scripts/prep_deps.sh`, while TVMjs is, most of the time, not where the users may want to modify the code. This PR modifies `package.json`'s `"tvmjs": "file:./tvm_home/web",` to `"@mlc-ai/tvmjs": "0.18.0-dev0",`, as we uploaded TVMjs as an npm package, so users no longer need to run `./scripts/prep_deps.sh`. We update `README.md`'s directions for building from source accordingly. Users can still build TVMjs from source with similar steps as before, as described in the `README.md`. Note that an extra step required by this change is addressing `"import require$$4 from 'ws'"` and `const WebSocket = require(\"ws\")` in `lib/index.js` and `lib/index.js.map` after `npm run build`. We take care of it in `cleanup-idnex-js.sh` by following similar measures for `perf_hooks`.
1 parent 6b4fa87 commit c85d64c

14 files changed

+2033
-6516
lines changed

README.md

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -360,30 +360,56 @@ see `webllm.prebuiltAppConfig`.
360360

361361
## Build WebLLM Package From Source
362362

363-
NOTE: you don't need to build by yourself unless you would
364-
like to change the WebLLM package. To simply use the npm, follow [Get Started](#get-started) or any of the [examples](examples) instead.
363+
NOTE: you don't need to build from source unless you would like to modify the WebLLM package.
364+
To use the npm, simply follow [Get Started](#get-started) or any of the [examples](examples) instead.
365365

366-
WebLLM package is a web runtime designed for [MLC LLM](https://github.com/mlc-ai/mlc-llm).
366+
To build from source, simply run:
367367

368-
1. Install all the prerequisites for compilation:
368+
```bash
369+
npm install
370+
npm run build
371+
```
372+
373+
Then, to test the effects of your code change in an example, inside `examples/get-started/package.json`, change from `"@mlc-ai/web-llm": "^0.2.65"` to `"@mlc-ai/web-llm": ../..`.
374+
375+
Then run:
376+
377+
```bash
378+
cd examples/get-started
379+
npm install
380+
npm start
381+
```
382+
383+
Note that sometimes you would need to switch between `file:../..` and `../..` to trigger npm to recognize new changes. In the worst case, you can run:
384+
385+
```bash
386+
cd examples/get-started
387+
rm -rf node_modules dist package-lock.json .parcel-cache
388+
npm install
389+
npm start
390+
```
391+
392+
### In case you need to build TVMjs from source
393+
394+
WebLLM's runtime largely depends on TVMjs: https://github.com/apache/tvm/tree/main/web
395+
396+
While it is also available as an npm package: https://www.npmjs.com/package/@mlc-ai/web-runtime, you can build it from source if needed by following the steps below.
397+
398+
1. Install [emscripten](https://emscripten.org). It is an LLVM-based compiler that compiles C/C++ source code to WebAssembly.
399+
- Follow the [installation instruction](https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended) to install the latest emsdk.
400+
- Source `emsdk_env.sh` by `source path/to/emsdk_env.sh`, so that `emcc` is reachable from PATH and the command `emcc` works.
401+
402+
We can verify the successful installation by trying out `emcc` terminal.
369403

370-
1. [emscripten](https://emscripten.org). It is an LLVM-based compiler that compiles C/C++ source code to WebAssembly.
371-
- Follow the [installation instruction](https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended) to install the latest emsdk.
372-
- Source `emsdk_env.sh` by `source path/to/emsdk_env.sh`, so that `emcc` is reachable from PATH and the command `emcc` works.
373-
2. Install jekyll by following the [official guides](https://jekyllrb.com/docs/installation/). It is the package we use for website. This is not needed if you're using nextjs (see next-simple-chat in the examples).
374-
3. Install jekyll-remote-theme by command. Try [gem mirror](https://gems.ruby-china.com/) if install blocked.
375-
`shell
376-
gem install jekyll-remote-theme
377-
`
378-
We can verify the successful installation by trying out `emcc` and `jekyll` in terminal, respectively.
404+
Note: We recently found that using the latest `emcc` version may run into issues during runtime. Use `./emsdk install 3.1.56` instead of `./emsdk install latest` for now as a workaround. The error may look like
405+
```
406+
Init error, LinkError: WebAssembly.instantiate(): Import #6 module="wasi_snapshot_preview1"
407+
function="proc_exit": function import requires a callable
408+
```
379409
380-
Note: We recently found that using the latest `emcc` version may run into issues during runtime. Use `./emsdk install 3.1.56` instead of `./emsdk install latest` for now as a workaround. The error may look like
381-
```
382-
Init error, LinkError: WebAssembly.instantiate(): Import #6 module="wasi_snapshot_preview1"
383-
function="proc_exit": function import requires a callable
384-
```
410+
2. In `./package.json`, change from `"@mlc-ai/web-runtime": "0.18.0-dev0",` to `"tvmjs": "file:./tvm_home/web",`.
385411
386-
2. Setup necessary environment
412+
3. Setup necessary environment
387413
388414
Prepare all the necessary dependencies for web build:
389415
@@ -400,7 +426,7 @@ gem install jekyll-remote-theme
400426

401427
Besides, `--recursive` is necessary and important. Otherwise, you may encounter errors like `fatal error: 'dlpack/dlpack.h' file not found`.
402428

403-
4. Buld WebLLM Package
429+
4. Build WebLLM Package
404430

405431
```shell
406432
npm run build

cleanup-index-js.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ sed -e s/"import require\$\$3 from 'perf_hooks';"/"const require\$\$3 = \"MLC_DU
1818
# Similarly replace `const performanceNode = require(\"perf_hooks\")` with `const performanceNode = \"MLC_DUMMY_REQUIRE_VAR\"`
1919
sed -e s/'require(\\\"perf_hooks\\\")'/'\\\"MLC_DUMMY_REQUIRE_VAR\\\"'/g -i .backup lib/index.js.map
2020

21+
# Below is added when we include dependency @mlc-ai/web-runtime, rather than using local tvm_home
22+
# Replace "import require$$4 from 'ws'" with a string "const require$$3 = "MLC_DUMMY_REQUIRE_VAR""
23+
# This is to prevent error `Cannot find module 'ws'`
24+
sed -e s/"import require\$\$4 from 'ws';"/"const require\$\$4 = \"MLC_DUMMY_REQUIRE_VAR\""/g -i .backup lib/index.js
25+
# Similarly replace `const WebSocket = require(\"ws\")` with `const WebSocket = \"MLC_DUMMY_REQUIRE_VAR\"`
26+
sed -e s/'require(\\\"ws\\\")'/'\\\"MLC_DUMMY_REQUIRE_VAR\\\"'/g -i .backup lib/index.js.map
27+
2128
# Cleanup backup files
2229
rm lib/index.js.backup
2330
rm lib/index.js.map.backup

0 commit comments

Comments
 (0)