不使用打包工具

檢視完整原始碼

此範例示範如何使用 --target web 旗標直接在瀏覽器中載入程式碼。對於此部署策略,不需要像 Webpack 這樣的打包工具。有關部署的更多資訊,請參閱專門的文件

首先,您需要將 web-sys 新增至您的 Cargo.toml。

[dependencies.web-sys]
version = "0.3.4"
features = [
  'Document',
  'Element',
  'HtmlElement',
  'Node',
  'Window',
]

然後,讓我們看一下程式碼,看看當我們使用 --target web 時,我們實際上沒有失去任何功能!

use wasm_bindgen::prelude::*;

// Called when the Wasm module is instantiated
#[wasm_bindgen(start)]
fn main() -> Result<(), JsValue> {
    // Use `web_sys`'s global `window` function to get a handle on the global
    // window object.
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");
    let body = document.body().expect("document should have a body");

    // Manufacture the element we're gonna append
    let val = document.create_element("p")?;
    val.set_inner_html("Hello from Rust!");

    body.append_child(&val)?;

    Ok(())
}

#[wasm_bindgen]
pub fn add(a: u32, b: u32) -> u32 {
    a + b
}

否則,其餘的部署魔法會在 index.html 中發生

<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
  </head>
  <body>
    <!-- Note the usage of `type=module` here as this is an ES6 module -->
    <script type="module">
      // Use ES module import syntax to import functionality from the module
      // that we have compiled.
      //
      // Note that the `default` import is an initialization function which
      // will "boot" the module and make it ready to use. Currently browsers
      // don't support natively imported WebAssembly as an ES module, but
      // eventually the manual initialization won't be required!
      import init, { add } from './pkg/without_a_bundler.js';

      async function run() {
        // First up we need to actually load the Wasm file, so we use the
        // default export to inform it where the Wasm file is located on the
        // server, and then we wait on the returned promise to wait for the
        // Wasm to be loaded.
        //
        // It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`,
        // but there is also a handy default inside `init` function, which uses
        // `import.meta` to locate the Wasm file relatively to js file.
        //
        // Note that instead of a string you can also pass in any of the
        // following things:
        //
        // * `WebAssembly.Module`
        //
        // * `ArrayBuffer`
        //
        // * `Response`
        //
        // * `Promise` which returns any of the above, e.g. `fetch("./path/to/wasm")`
        //
        // This gives you complete control over how the module is loaded
        // and compiled.
        //
        // Also note that the promise, when resolved, yields the Wasm module's
        // exports which is the same as importing the `*_bg` module in other
        // modes
        await init();

        // And afterwards we can use all the functionality defined in wasm.
        const result = add(1, 2);
        console.log(`1 + 2 = ${result}`);
        if (result !== 3)
          throw new Error("wasm addition doesn't work!");
      }

      run();
    </script>
  </body>
</html>

注意:由於 CORS 限制,您無法直接在網頁瀏覽器中開啟 index.html。相反地,您可以使用 Python 內建的 HTTP 伺服器來設定快速開發環境

wasm-pack build --target web
python3 -m http.server 8080

如果您沒有安裝 Python,您也可以使用 miniserve,它可透過 Cargo 安裝

cargo install miniserve
miniserve . --index "index.html" -p 8080

就是這樣!請務必閱讀部署選項,以了解在不使用打包工具的情況下進行部署的含義。

使用較舊的 --target no-modules

檢視完整原始碼

在不使用打包工具的情況下使用 wasm-bindgen 的較舊版本,是在 wasm-bindgen CLI 中使用 --target no-modules 旗標。

雖然與較新的 --target web 類似,但 --target no-modules 旗標有一些注意事項

  • 它不支援 本機 JS 片段
  • 它不會產生 ES 模組
  • 它不支援在文件外部(例如,在 worker 內部)使用 --split-linked-modules

考慮到這一點,主要區別在於如何載入 wasm/JS 程式碼,以下是一個載入 wasm-pack 針對與上述相同模組的輸出的範例。

<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
  </head>
  <body>
    <!-- Include the JS generated by `wasm-pack build` -->
    <script src='pkg/without_a_bundler_no_modules.js'></script>

    <script>
      // Like with the `--target web` output the exports are immediately
      // available but they won't work until we initialize the module. Unlike
      // `--target web`, however, the globals are all stored on a
      // `wasm_bindgen` global. The global itself is the initialization
      // function and then the properties of the global are all the exported
      // functions.
      //
      // Note that the name `wasm_bindgen` can be configured with the
      // `--no-modules-global` CLI flag
      const { add } = wasm_bindgen;

      async function run() {
        await wasm_bindgen();

        const result = add(1, 2);
        console.log(`1 + 2 = ${result}`);
      }

      run();
    </script>
  </body>
</html>