title: [Начало работы с WebAssembly] Связывание с Webpack
date: 2018-4-6 19:40:00
категории: WebAssembly, Заметки
tags: WebAssembly, JavaScript, Rust, LLVM toolchain
auther: Yiniau
Связь с вебпаком
Очень медленно рутинно писать ржавый код, а затем вручную компилировать его в файл wasm.В настоящее время есть несколько решений.Далее я улучшу эффективность написания WebAssembly на основе webpack.
первый,webpack 4Требуется, версия на момент написания этой статьиwebpack 4.5.0
Конкретная установка вебпака решается сама собой
настроить веб-пакет
Создаватьwebpack.config.js
, введите следующий код
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
const paths = {
src: path.resolve(__dirname, 'src'),
entryFile: path.resolve(__dirname, 'src', 'index.js'),
dist: path.resolve(__dirname, 'dist'),
wasm: path.relative(__dirname, 'build'),
}
module.exports = {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: __dirname,
hot: true,
port: 10001,
open: true, // will open on browser after started
},
entry: paths.entryFile,
output: {
path: paths.dist,
filename: 'main.js'
},
resolve: {
alias: {
wasm: paths.wasm,
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
cacheDirectory: true,
}
}],
},
],
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'WebAssembly Hello World'
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
};
Интерпретация файла конфигурации не будет выполняться. Это очень простая конфигурация. Если вы хотите изучить расширенную настройку, вы можете посмотретьcreate-react-app
Файл конфигурации веб-пакета из извлечения
настроить бабел
.babelrc
{
"presets": [
"env"
],
"plugins": [
"syntax-dynamic-import",
"syntax-async-functions"
]
}
Это здесьasync
поддержка иimport()
Поддержка динамического импорта
Следует отметить, что статический импорт импортирует.wasm
Файл не поддерживается встроенным веб-пакетом, веб-пакет напечатает сообщение об ошибке в консоли, предлагая вам перейти на динамический импорт (Динамический импорт)
Не добавлять поддержку загрузчика сообщества
webpack 4 имеет встроенную поддержку парсинга.wasm
файл, а импорт имеет наивысший приоритет поиска, когда не пишется суффикс
Давайте сначала посмотрим на каталог
𝝪 yiniau @ yiniau in /Users/yiniau/code/WebAssembly/hello_world
↪ ll
total 952
-rw-r--r-- 1 yiniau staff 52B 3 25 22:14 Cargo.lock
-rw-r--r-- 1 yiniau staff 143B 4 6 21:51 Cargo.toml
drwxr-xr-x 4 yiniau staff 128B 4 6 01:36 build
-rw-r--r-- 1 yiniau staff 12B 3 26 21:53 build.sh
-rw-r--r-- 1 yiniau staff 170B 4 4 16:26 index.html
drwxr-xr-x 809 yiniau staff 25K 4 6 20:34 node_modules
-rw-r--r-- 1 yiniau staff 782B 4 6 20:34 package.json
drwxr-xr-x 3 yiniau staff 96B 4 4 16:41 rust
drwxr-xr-x 4 yiniau staff 128B 4 4 17:16 src
drwxr-xr-x 5 yiniau staff 160B 3 29 15:29 target
-rw-r--r-- 1 yiniau staff 1.2K 4 6 15:51 webpack.config.js
-rw-r--r-- 1 yiniau staff 230K 4 6 01:07 yarn-error.log
-rw-r--r-- 1 yiniau staff 216K 4 6 16:09 yarn.lock
в
-
rust
Хранится в.rs
документ -
src
Хранится в.js
документ -
build
Хранится в.wasm
документ -
index.js
Файл записи, указанный для записи, здесь я ввожу полифилл
𝝪 yiniau @ yiniau in /Users/yiniau/code/WebAssembly/hello_world
↪ ll src
total 16
-rw-r--r-- 1 yiniau staff 77B 4 6 20:39 index.js
-rw-r--r-- 1 yiniau staff 1.9K 4 6 21:30 main.js
хорошо, давайтеmain.js
Завершите основную логику в
main.js
(async () => {
import('../build/hello.wasm')
.then(bytes => bytes.arrayBuffer())
.then(res => WebAssembly.instantiate(bytes, imports))
.then(results => {
console.log(results);
const exports = results.instance.exports;
console.log(exports);
mem = exports.memory;
});
})()
о черт!!Почему я получаю сообщение об ошибке! !
Все в порядке, сообщение об ошибке ясно
WebAssembly.Instance is disallowed on the main thread, if the buffer size is larger than 4KB. Use WebAssembly.instantiate.
Если размер буфера превышает4KB,WebAssembly.Instance
Запрещено в основном потоке. Нужно использоватьWebAssembly.instantiate
На месте, но проблема пришла.
import()
ImportSObject не может быть передан. Давайте посмотрим на проблемы на GitHub WebPack:
linclark (автор мультфильма к WebAssembly) предлагает использоватьinstantiateStreaming
заменятьcompileStreaming
, чтобы избежать влияния ограничений быстрой памяти на ios.
Сокра немного против этого (должна быть очень против!)
Причина не поддерживается
Предварительная информация
webpack пытается рассматривать WASM как ESM. Примените все правила/допущения, применимые к ESM, и к WASM. Гипотетически в будущем WASM JS API может быть интегрирован WASM в граф модуля ESM.
Это означает, что в файле WASMimports
Раздел (importsObject) по сравнению с ESMimport
разбираются как предложения,exports
Разделы (instance.exports) обрабатываются как в ESMexport
часть.
Модуль WASM также имеетstart
раздел, который выполняется при создании экземпляра WASM.
В WASM импорт JS API проходит черезimportsObject
Передано созданному модулю WASM.
Спецификация ЕСМ
Спецификация ESM определяет несколько этапов. СценаModuleEvaluation
. На этом этапе все модули оцениваются в четком порядке. Эта фаза является синхронной. Все модули оцениваются с одной и той же «галочкой».
Когда WASM находится на блок-диаграмме, это означает:
-
start
Детали выполнены в одном "галочке" - Все зависимости WASM выполняются в один и тот же «тик»
- ESM, импортированный в WASM, выполняется в том же «тике»
Для использования промисовinstantiate
, такое поведение невозможно. Обещание всегда откладывает свое выполнение до другого «тика».
Это возможно только при использовании созданной синхронной версии (WebAssembly.Instance).
Примечание. Технически можетstart
Частично и нет зависимости WASM. В данном случае это неприменимо. Но мы не можем думать, что ситуация всегда.
webpack хочет загружать/компилировать файлы wasm параллельно с загрузкой кода JS. использоватьinstantiateStreaming
не допустит этого (когда WASM имеет зависимости), потому что создание экземпляра должно пройтиimportsObject
. СоздайтеimportsObject
Все зависимости/импорты WASM необходимо оценить, поэтому эти зависимости необходимо загрузить перед началом загрузки WASM.
когда используешьcompileStreaming
+ new WebAssembly.Instance
Параллельная загрузка и компиляция возможны, потому чтоcompileStreaming
не нужен одинimportsObject
. Может быть создан после завершения загрузки WASM и JS.importsObject
.
Спецификация WebAssembly
Я также хотел бы обратиться к спецификации WebAssembly. В нем говорится, что компиляция происходит в фоновом потокеcompile
и создание экземпляра происходит в основном потоке.
Прямо об этом не сказано, но мне кажется, что поведение АО нестандартно.
другие инструкции
В WASM также отсутствует возможность использовать живые привязки импортированных идентификаторов. Напротив,importsObject
будет скопировано. Это может привести к странным циклическим зависимостям и проблемам с WASM.
существуетimportsObject
средняя поддержкаgetter
и может выполнитьstart
Было бы лучше получить экспорт раньше некоторых.
Попробуйте использовать загрузчик для прямого анализа.rs
wasm-loader
Есть проблема с поддержкой файлов .wasm, скомпилированных напрямую rustup wasm32-unknown-unknown.Я видел, что wasm-loader использует файлы wasm на основе тулчейна emcc.Я пытался использовать его напрямую
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
cacheDirectory: true,
}
}],
},
{
test: /\.wasm$/,
include: path.resolve(__dirname, 'wasm'),
use: 'wasm-loader',
},
],
Но выдаст ошибку:
Это должно быть проблемой кодирования, созданной набором инструментов
Поэтому я попытался снова, используяrust-native-wasm-loader
:
webpack.config.js
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
cacheDirectory: true,
}
}],
},
{
test: /\.rs$/,
include: paths.rust,
use: [{
loader: 'wasm-loader'
}, {
loader: 'rust-native-wasm-loader',
options: {
release: true,
},
},]
},
],
rust/add.rs
#[no_mangle]
pub fn add(a: i32, b: i32) -> i32 {
eprintln!("add({:?}, {:?}) was called", a, b);
a + b
}
main.js
import loadAdd from 'rust/add.rs';
loadAdd().then(result => {
const add = result.instance.exports['add'];
console.log('return value was', add(2, 3));
});
BUT!
Чен Чен не пришел! !
Я его полностью переделал по примеру rust-native-wasm-loader, но похоже, что нынешние плагины все остались с эпохи asm.js, и все они разобраны в.wasm
Не удается ли выполнить этот шаг, поскольку WebAssembly не подходит для синхронного вызова? . На данный момент, если вы вызовете ржавчинуstd::mem
Для работы с объектами памяти размер файла будет очень большим — используйтеwasm-gc
Осталось еще более 200 КБ после
#![feature(custom_attribute)]
#![feature(wasm_import_memory)]
#![wasm_import_memory]
use std::mem;
use std::ffi::{CString, CStr};
use std::os::raw::{c_char, c_void};
/// alloc memory
#[no_mangle]
// In order to work with the memory we expose (de)allocation methods
pub extern fn alloc(size: usize) -> *mut c_void {
let mut buf = Vec::with_capacity(size);
let ptr = buf.as_mut_ptr();
mem::forget(buf);
ptr as *mut c_void
}
Возможно, практика веб-пакета не подходит для всех режимов применения веб-сборки, и она обрабатывается по пути ESM..wasm
Это кажется очень хорошим, но фактическое использование может быть проблемой.В настоящее время это в основном логика обработки js.Чтобы быть совместимым с браузерами более низких версий, асинхронная обработка (возможно) необходима?
2018-4-17 12:00 Обновить
Пакет!
Обновился PR поддержки webpack для webassembly! Скромный советI don't know if this helps but it seems parceljs has got support for rust functions. BY pyros2097 https://medium.com/@devongovett/parcel-v1-5-0-released-source-maps-webassembly-rust-and-more-3a6385e43b95
ok
Я еду в Посылку...
Хотя импорт нельзя передать, его также можно использовать для однофункциональной разработки.