与 Hermes 共享床单
Hermes 是一个用 C++编写的嵌入式 JS 引擎。
¥Hermes is an embeddable JS engine written in C++.
SheetJS 是一个用于从电子表格读取和写入数据的 JavaScript 库。
¥SheetJS is a JavaScript library for reading and writing data from spreadsheets.
该演示使用 Hermes 和 SheetJS 从电子表格中提取数据并打印 CSV 行。我们将探讨如何在 Hermes 上下文中加载 SheetJS 并从 C++ 程序处理电子表格。
¥This demo uses Hermes and SheetJS to pull data from a spreadsheet and print CSV rows. We'll explore how to load SheetJS in a Hermes context and process spreadsheets from a C++ program.
"集成示例" 部分包括一个完整的命令行工具,用于从文件中读取数据。
¥The "Integration Example" section includes a complete command-line tool for reading data from files.
集成详情
¥Integration Details
Hermes 的许多功能都没有文档记录。该解释已针对提交 15b323d
进行了验证。
¥Many Hermes functions are not documented. The explanation was verified against
commit 15b323d
.
Hermes 的主要目标是 React Native。在撰写本文时,还没有关于在 C++ 程序中嵌入 Hermes 引擎的官方文档。
¥The main target for Hermes is React Native. At the time of writing, there was no official documentation for embedding the Hermes engine in C++ programs.
初始化 Hermes
¥Initialize Hermes
使用 facebook::hermes::makeHermesRuntime
创建 Hermes 引擎实例:
¥A Hermes engine instance is created with facebook::hermes::makeHermesRuntime
:
std::unique_ptr<facebook::jsi::Runtime> rt(facebook::hermes::makeHermesRuntime());
基本对象
¥Essential Objects
Hermes 不公开 console
或 global
变量,但它们可以在运行时从 JS 代码合成:
¥Hermes does not expose a console
or global
variable, but they can be
synthesized from JS code in the runtime:
-
global
可以通过未绑定函数中对this
的引用获得:¥
global
can be obtained from a reference tothis
in an unbound function:
/* create global object */
var global = (function(){ return this; }).call(null);
-
console.log
可以由内置print
函数构造:¥
console.log
can be constructed from the builtinprint
function:
/* create a fake `console` from the hermes `print` builtin */
var console = { log: function(x) { print(x); } };
代码可以存储在 C 字符串中,并使用 prepareJavascript
来准备代码并使用 evaluatePreparedJavascript
来评估:
¥The code can be stored in a C string and evaluated using prepareJavascript
to
prepare code and evaluatePreparedJavascript
to evaluate:
const char *init_code =
/* create global object */
"var global = (function(){ return this; }).call(null);"
/* create a fake `console` from the hermes `print` builtin */
"var console = { log: function(x) { print(x); } };"
;
auto src = std::make_shared<facebook::jsi::StringBuffer>(init_code);
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
rt->evaluatePreparedJavaScript(js);
Hermes 集成代码中使用标准 C++ 异常处理模式。Hermes 异常的基类是 facebook::jsi::JSIException
:
¥Standard C++ exception handling patterns are used in Hermes integration code.
The base class for Hermes exceptions is facebook::jsi::JSIException
:
try {
const char *init_code = "...";
auto src = std::make_shared<facebook::jsi::StringBuffer>(init_code);
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
rt->evaluatePreparedJavaScript(js);
} catch (const facebook::jsi::JSIException &e) {
std::cerr << "JavaScript exception: " << e.what() << std::endl;
return 1;
}
加载 SheetJS 脚本
¥Load SheetJS Scripts
SheetJS 独立脚本 可以在 Hermes 上下文中进行解析和评估。
¥SheetJS Standalone scripts can be parsed and evaluated in a Hermes context.
可以通过从文件系统读取脚本并在 Hermes 上下文中进行评估来加载主库。
¥The main library can be loaded by reading the script from the file system and evaluating in the Hermes context.
有一些非标准技巧可以将整个脚本嵌入到二进制文件中。有诸如 #embed
之类的语言提案(反映了 C23 中的相同功能)。
¥There are nonstandard tricks to embed the entire script in the binary. There are
language proposals such as #embed
(mirroring the same feature in C23).
为简单起见,示例从文件系统读取脚本文件。
¥For simplicity, the examples read the script file from the filesystem.
从文件系统读取脚本
¥Reading scripts from the filesystem
出于本演示的目的,使用标准 C <stdio.h>
方法:
¥For the purposes of this demo, the standard C <stdio.h>
methods are used:
static char *read_file(const char *filename, size_t *sz) {
FILE *f = fopen(filename, "rb");
if(!f) return NULL;
long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
char *buf = (char *)malloc(fsize * sizeof(char));
*sz = fread((void *) buf, 1, fsize, f);
fclose(f);
return buf;
}
// ...
/* read SheetJS library from filesystem */
size_t sz; char *xlsx_full_min_js = read_file("xlsx.full.min.js", &sz);
对于 Windows 应用,字符串必须以 null 结尾:
¥For Windows applications, the string must be null-terminated:
/* Hermes-Windows requires the null terminator */
static char *read_file_null(const char *filename, size_t *sz) {
FILE *f = fopen(filename, "rb");
if(!f) return NULL;
long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f) + 1; fseek(f, 0, SEEK_SET); }
char *buf = (char *)malloc(fsize * sizeof(char));
*sz = fread((void *) buf, 1, fsize, f);
buf[fsize - 1] = 0;
fclose(f);
return buf;
}
// ...
/* read SheetJS library from filesystem */
size_t sz; char *xlsx_full_min_js = read_file_null("xlsx.full.min.js", &sz);
Hermes 封装纸
¥Hermes Wrapper
Hermes 没有提供一种友好的方式来准备存储在标准堆分配的 C 字符串中的 JavaScript 代码。幸运的是,可以创建一个封装器:
¥Hermes does not provide a friendly way to prepare JavaScript code stored in a standard heap-allocated C string. Fortunately a wrapper can be created:
/* Unfortunately the library provides no C-friendly Buffer classes */
class CBuffer : public facebook::jsi::Buffer {
public:
CBuffer(const uint8_t *data, size_t size) : buf(data), sz(size) {}
size_t size() const override { return sz; }
const uint8_t *data() const override { return buf; }
private:
const uint8_t *buf;
size_t sz;
};
// ...
/* load SheetJS library */
auto src = std::make_shared<CBuffer>(CBuffer((uint8_t *)xlsx_full_min_js, sz));
评估 SheetJS 库代码
¥Evaluating SheetJS Library Code
代码封装器可以是 "prepared" 与 prepareJavascript
以及 "evaluated" 与 evaluatePreparedJavascript
。
¥The code wrapper can be "prepared" with prepareJavascript
and "evaluated" with
evaluatePreparedJavascript
.
preparedJavascript
的第二个参数是保存源 URL 的 C++ std::string
。通常,像 xlsx.full.min.js
这样的名称有助于将 SheetJS 库异常与应用的其他部分区分开来。
¥The second argument to preparedJavascript
is a C++ std::string
that holds
the source URL. Typically a name like xlsx.full.min.js
helps distinguish
SheetJS library exceptions from other parts of the application.
auto js = rt->prepareJavaScript(src, std::string("xlsx.full.min.js"));
rt->evaluatePreparedJavaScript(js);
测试
¥Testing
如果加载了库,XLSX.version
将是一个字符串。可以将该字符串拉入主 C++ 程序中。
¥If the library is loaded, XLSX.version
will be a string. This string can be
pulled into the main C++ program.
evaluatePreparedJavascript
方法返回代表结果的 facebook::jsi::Value
对象:
¥The evaluatePreparedJavascript
method returns a facebook::jsi::Value
object
that represents the result:
/* evaluate XLSX.version and capture the result */
auto src = std::make_shared<facebook::jsi::StringBuffer>("XLSX.version");
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
facebook::jsi::Value jsver = rt->evaluatePreparedJavaScript(js);
getString
方法提取字符串值并返回内部字符串对象 (facebook::jsi::String
)。给定该字符串对象,utf8
方法返回可以打印的正确 C++ std::string
:
¥The getString
method extracts the string value and returns an internal string
object (facebook::jsi::String
). Given that string object, the utf8
method
returns a proper C++ std::string
that can be printed:
/* pull the version string into C++ code and print */
facebook::jsi::String jsstr = jsver.getString(*rt);
std::string cppver = jsstr.utf8(*rt);
std::cout << "SheetJS version " << cppver << std::endl;
读取文件
¥Reading Files
通常,C++ 代码将读取文件,而 Hermes 会将 JS 引擎中的数据投影为 ArrayBuffer
。SheetJS 库可以解析 ArrayBuffer
数据。
¥Typically C++ code will read files and Hermes will project the data in the JS
engine as an ArrayBuffer
. SheetJS libraries can parse ArrayBuffer
data.
标准 SheetJS 操作可以选择第一个工作表并从该工作表生成 CSV 字符串数据。Hermes 提供了将 JS 字符串转换回 std::string
对象的方法,以便在 C++ 中进一步处理。
¥Standard SheetJS operations can pick the first worksheet and generate CSV string
data from the worksheet. Hermes provides methods to convert the JS strings back
to std::string
objects for further processing in C++.
强烈建议创建一个存根函数来在 JS 代码中执行整个工作流程并将最终结果传递回 C++。
¥It is strongly recommended to create a stub function to perform the entire workflow in JS code and pass the final result back to C++.
Hermes 封装纸
¥Hermes Wrapper
Hermes 支持 ArrayBuffer
,但没有简单的辅助程序来读取原始内存。库预计实现 MutableBuffer
:
¥Hermes supports ArrayBuffer
but has no simple helper to read raw memory.
Libraries are expected to implement MutableBuffer
:
/* ArrayBuffer constructor expects MutableBuffer */
class CMutableBuffer : public facebook::jsi::MutableBuffer {
public:
CMutableBuffer(uint8_t *data, size_t size) : buf(data), sz(size) {}
size_t size() const override { return sz; }
uint8_t *data() override { return buf; }
private:
uint8_t *buf;
size_t sz;
};
可以使用封装器创建 facebook::jsi::ArrayBuffer
对象:
¥A facebook::jsi::ArrayBuffer
object can be created using the wrapper:
/* load payload as ArrayBuffer */
size_t sz; char *data = read_file("pres.xlsx", &sz);
auto payload = std::make_shared<CMutableBuffer>(CMutableBuffer((uint8_t *)data, sz));
auto ab = facebook::jsi::ArrayBuffer(*rt, payload);
SheetJS 操作
¥SheetJS Operations
在此示例中,目标是提取第一个工作表并生成 CSV 行。
¥In this example, the goal is to pull the first worksheet and generate CSV rows.
XLSX.read
[^1] 解析 ArrayBuffer
并返回一个 SheetJS 工作簿对象:
¥XLSX.read
[^1] parses the ArrayBuffer
and returns a SheetJS workbook object:
var wb = XLSX.read(buf);
SheetNames
属性 [^2] 是工作簿中工作表名称的数组。第一个工作表名称可以通过以下 JS 片段获取:
¥The SheetNames
property[^2] is an array of the sheet names in the workbook.
The first sheet name can be obtained with the following JS snippet:
var first_sheet_name = wb.SheetNames[0];
Sheets
属性 [^3] 是一个对象,其键是工作表名称,其对应的值是工作表对象。
¥The Sheets
property[^3] is an object whose keys are sheet names and whose
corresponding values are worksheet objects.
var first_sheet = wb.Sheets[first_sheet_name];
sheet_to_csv
实用函数 [^4] 从工作表生成 CSV 字符串:
¥The sheet_to_csv
utility function[^4] generates a CSV string from the sheet:
var csv = XLSX.utils.sheet_to_csv(first_sheet);
C++集成代码
¥C++ integration code
存根函数将传递一个 ArrayBuffer
对象:
¥The stub function will be passed an ArrayBuffer
object:
function(buf) {
/* `buf` will be an ArrayBuffer */
var wb = XLSX.read(buf);
return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
}
评估存根后的结果是 facebook::jsi::Value
对象:
¥The result after evaluating the stub is a facebook::jsi::Value
object:
/* define stub function to read and convert first sheet to CSV */
auto src = std::make_shared<facebook::jsi::StringBuffer>(
"(function(buf) {"
"var wb = XLSX.read(buf);"
"return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);"
"})"
);
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
facebook::jsi::Value funcval = rt->evaluatePreparedJavaScript(js);
要调用此函数,必须将不透明的 Value
转换为 Function
:
¥To call this function, the opaque Value
must be converted to a Function
:
facebook::jsi::Function func = func.asObject(*rt).asFunction(*rt);
Function
公开了 call
方法来执行函数调用。存根接受 ArrayBuffer
参数:
¥The Function
exposes a call
method to perform the function invocation. The
stub accepts an ArrayBuffer
argument:
/* call stub function and capture result */
facebook::jsi::Value csv = func.call(*rt, ab);
以与将库版本字符串提取到 C++ 代码中的方式相同的方式,可以使用 getString
和 utf8
方法捕获 CSV 数据:
¥In the same way the library version string was pulled into C++ code, the CSV
data can be captured using getString
and utf8
methods:
/* interpret as utf8 */
std::string str = csv.getString(*rt).utf8(*rt);
std::cout << str << std::endl;
完整示例
¥Complete Example
"集成示例" 涵盖了 C++ 应用中的传统集成,而 "CLI 测试" 使用 hermes
CLI 工具演示了其他概念。
¥The "Integration Example" covers a traditional integration in a C++ application,
while the "CLI Test" demonstrates other concepts using the hermes
CLI tool.
集成示例
¥Integration Example
该演示在以下部署中进行了测试:
¥This demo was tested in the following deployments:
架构 | Git 提交 | 日期 |
---|---|---|
darwin-x64 | d070c74 | 2024-04-25 |
darwin-arm | d070c74 | 2024-05-23 |
linux-x64 | d217af8 | 2024-03-21 |
linux-arm | d070c74 | 2024-05-25 |
Hermes 主要源代码树不支持 Windows。为 Windows 版 React Native 提供支持的 hermes-windows
分支确实具有内置支持 [^5]
¥The main Hermes source tree does not have Windows support. The hermes-windows
fork, which powers React Native for Windows, does have built-in support[^5]
架构 | Git 提交 | 日期 |
---|---|---|
win10-x64 | 240573e | 2024-03-24 |
win11-arm | 240573e | 2024-06-20 |
"Windows 示例" 覆盖 hermes-windows
。
¥The "Windows Example" covers hermes-windows
.
-
安装 dependencies
¥Install dependencies
Installation Notes (click to show)
The official guidance[^6] has been verified in macOS and HoloOS (Linux).
On macOS:
brew install icu4c cmake ninja
On HoloOS (and other Arch Linux distros):
sudo pacman -Syu cmake git ninja icu python zip readline
On Debian and Ubuntu:
sudo apt install cmake git ninja-build libicu-dev python zip libreadline-dev
When using virtual machines, Linux builds require at least 8 GB memory.
-
建立一个项目目录:
¥Make a project directory:
mkdir sheetjs-hermes
cd sheetjs-hermes
curl -LO https://xlsx.nodejs.cn/hermes/Makefile
-
¥Download
sheetjs-hermes.cpp
:
curl -LO https://xlsx.nodejs.cn/hermes/sheetjs-hermes.cpp
-
构建库(这是
init
目标):¥Build the library (this is the
init
target):
make init
在某些测试运行中,由于 Ninja 问题,构建失败:
¥In some test runs, the build failed due to Ninja issues:
CMake Error at CMakeLists.txt:64 (project):
Running
'/usr/local/lib/depot_tools/ninja' '--version'
failed with:
depot_tools/ninja.py: Could not find Ninja in the third_party of the current project, nor in your PATH.
这是由于与 depot_tools
附带的 Ninja 版本发生冲突。
¥This is due to a conflict with the Ninja version that ships with depot_tools
.
由于 depot_tools
通常添加在系统 PATH
变量中的其他文件夹之前,因此强烈建议重命名 ninja
二进制文件、构建 Hermes 库并恢复 ninja
二进制文件:
¥Since depot_tools
typically is added before other folders in the system PATH
variable, it is strongly recommended to rename the ninja
binary, build the
Hermes libraries, and restore the ninja
binary:
# Rename `ninja`
mv /usr/local/lib/depot_tools/ninja /usr/local/lib/depot_tools/ninja_tmp
# Build Hermes
make init
# Restore `ninja`
mv /usr/local/lib/depot_tools/ninja_tmp /usr/local/lib/depot_tools/ninja
在某些测试中,构建失败,并显示一条引用丢失标头的消息:
¥In some tests, the build failed with a message referencing a missing header:
hermes/API/hermes/inspector/chrome/tests/SerialExecutor.cpp:34:16: note: ‘std::runtime_error’ is defined in header ‘<stdexcept>’; did you forget to ‘#include <stdexcept>’?
此错误影响 Hermes 官方发布!
¥This error affects the official Hermes releases!
修复方法是在相应的头文件中手动添加 #include
语句(repo 中的 API/hermes/inspector/chrome/tests/SerialExecutor.h
):
¥The fix is to manually add a #include
statement in the corresponding header
file (API/hermes/inspector/chrome/tests/SerialExecutor.h
in the repo):
#include <memory>
#include <mutex>
#if !defined(_WINDOWS) && !defined(__EMSCRIPTEN__)
#include <stdexcept>
#include <pthread.h>
#else
#include <thread>
-
构建应用:
¥Build the application:
make sheetjs-hermes
-
下载 SheetJS Standalone 脚本和测试文件。将这两个文件保存在项目目录中:
¥Download the SheetJS Standalone script and the test file. Save both files in the project directory:
curl -LO https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
curl -LO https://xlsx.nodejs.cn/pres.numbers
-
将
libhermes
和libjsi
库复制到当前文件夹中:¥Copy the
libhermes
andlibjsi
libraries into the current folder:
- Linux
- MacOS
cp ./build_release/API/hermes/libhermes.so .
cp ./build_release/jsi/libjsi.so .
cp ./build_release/API/hermes/libhermes.dylib .
cp ./build_release/jsi/libjsi.dylib .
-
运行应用:
¥Run the application:
./sheetjs-hermes pres.numbers
如果成功,程序将打印库版本号和第一张表的内容作为 CSV 行。
¥If successful, the program will print the library version number and the contents of the first sheet as CSV rows.
Windows 示例
¥Windows Example
在 ARM64 上,命令必须在 "ARM64 原生工具命令提示符" 中运行。
¥On ARM64, the commands must be run in a "ARM64 Native Tools Command Prompt".
-
安装依赖。
¥Install dependencies.
Installation Notes (click to show)
The build sequence requires Python, which can be installed from the official Windows installer[^7].
Visual Studio with "Desktop development with C++" workload and Cmake must be installed[^8]. In addition, the following Spectre-mitigated libs must be added:
- MSVC C++ x64/x86 Spectre-mitigated libs (Latest)
- C++ ATL for latest build tools with Spectre Mitigations (x86 & x64)
- C++ MFC for latest build tools with Spectre Mitigations (x86 & x64)
The easiest way to install is to select "Individual components" and search for "spectre latest" (no quotation marks). Pick each option for the relevant CPU.
-
设置
depot_tools
。¥Set up
depot_tools
.
必须下载 depot_tools.zip
并将其解压到 c:\src\depot_tools\
。
¥depot_tools.zip
must be downloaded and extracted to c:\src\depot_tools\
.
该 ZIP 有许多隐藏文件和文件夹(包括 .git
),应与普通文件一起提取。
¥This ZIP has a number of hidden files and folders (including .git
) which
should be extracted along with the normal files.
将路径 c:\src\depot_tools\
添加到用户 PATH
环境变量中
¥Add the path c:\src\depot_tools\
to the User PATH
environment variable
Environment Variable Setup (click to show)
Type env
in the search bar and select "Edit the system environment variables".
In the new window, click the "Environment Variables..." button.
In the new window, look for the "User variables" section. Select "Path" in the list and click "Edit".
In the new window, click "New" and type c:\src\depot_tools
and press Enter.
Select the row and repeatedly click "Move Up" until it is the first entry.
Click "OK" in each window (3 windows) and restart your computer.
-
删除
c:\src\depot_tools\ninja
(如果存在),然后下载 官方 Windows 版本,并将ninja.exe
移动到c:\src\depot_tools
。如果文件夹中存在ninja.exe
,则替换现有程序。¥Delete
c:\src\depot_tools\ninja
if it exists, then download the official Windows release and move theninja.exe
intoc:\src\depot_tools
. If aninja.exe
exists in the folder, replace the existing program. -
建立一个项目目录:
¥Make a project directory:
mkdir sheetjs-hermes
cd sheetjs-hermes
-
克隆
hermes-windows
存储库:¥Clone the
hermes-windows
repo:
git clone https://github.com/microsoft/hermes-windows
cd hermes-windows
git checkout 240573e
cd ..
如果出现与 SSL 或证书或 CApath
相关的错误,请在 Git 中暂时禁用 SSL:
¥If there are errors related to SSL or certificates or CApath
, temporarily
disable SSL in Git:
git config --global http.sslVerify false
git clone https://github.com/microsoft/hermes-windows
git config --global http.sslVerify true
-
构建库:
¥Build the library:
- x64
- ARM64
cd hermes-windows
.\.ado\scripts\cibuild.ps1 -AppPlatform win32 -Platform x64 -ToolsPlatform x64
cd ..
该脚本可能会失败并显示以下消息:
¥The script may fail with the message:
无法加载,因为运行脚本在此系统上被禁用
¥cannot be loaded because running scripts is disabled on this system
在 "以管理员身份运行" powershell 窗口中,运行以下命令:
¥In a "Run as Administrator" powershell window, run the following command:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
在某些测试运行中,该命令在尝试复制 hermes.exe
时失败:
¥In some test runs, the command failed when trying to copy hermes.exe
:
Copy-Item: C:\Users\Me\Documents\hermes-windows\.ado\scripts\cibuild.ps1:331
Line |
331 | Copy-Item "$compilerAndToolsBuildPath\bin\hermes.exe" -Destinatio …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'C:\Users\Me\Documents\hermes-windows\workspace\build\tools\bin\hermes.exe'
| because it does not exist.
首先构建库,嵌入 Hermes 时不需要独立的二进制文件,因此可以安全地忽略错误消息。
¥The libraries are built first and the standalone binary is not needed when embedding Hermes, so the error message can be safely ignored.
cmake -S hermes-windows -B build -G "Visual Studio 17 2022" -A arm64
cmake --build ./build
-
将每个生成的
.lib
和.dll
文件复制到主文件夹中:¥Copy every generated
.lib
and.dll
file into the main folder:
- x64
- ARM64
dir -r -Path .\hermes-windows\workspace\build\win32-x64-debug\ -Filter "*.dll" | Copy-Item -Destination .\
dir -r -Path .\hermes-windows\workspace\build\win32-x64-debug\ -Filter "*.lib" | Copy-Item -Destination .\
在 PowerShell 会话中运行以下命令:
¥Run the following commands in a PowerShell session:
dir -r -Path .\build -Filter "*.dll" | Copy-Item -Destination .\
dir -r -Path .\build -Filter "*.lib" | Copy-Item -Destination .\
-
¥Download
sheetjs-hermes.cpp
:
curl -o sheetjs-hermesw.cpp https://xlsx.nodejs.cn/hermes/sheetjs-hermesw.cpp
-
构建应用:
¥Build the application:
cl /MDd sheetjs-hermesw.cpp DbgHelp.lib *.lib /I hermes-windows\API /I hermes-windows\include /I hermes-windows\public\ /I hermes-windows\API\jsi
如果没有找到 cl
,则运行 "原生工具命令提示符" 中的命令
¥If cl
is not found, run the command in the "Native Tools Command Prompt"
-
下载 SheetJS Standalone 脚本和测试文件。将这两个文件保存在项目目录中:
¥Download the SheetJS Standalone script and the test file. Save both files in the project directory:
curl -o xlsx.full.min.js https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
curl -o pres.numbers https://xlsx.nodejs.cn/pres.numbers
-
运行应用:
¥Run the application:
.\sheetjs-hermesw.exe pres.numbers
如果成功,程序将打印库版本号和第一张表的内容作为 CSV 行。
¥If successful, the program will print the library version number and the contents of the first sheet as CSV rows.
CLI 测试
¥CLI Test
该演示在以下部署中进行了测试:
¥This demo was tested in the following deployments:
架构 | Hermes | 日期 |
---|---|---|
darwin-x64 | 0.12.0 | 2024-03-13 |
由于独立二进制文件的限制,该演示将测试文件编码为 Base64 字符串,并将其直接添加到合并脚本中。
¥Due to limitations of the standalone binary, this demo will encode a test file as a Base64 string and directly add it to an amalgamated script.
安装命令行接口
¥Install CLI
-
安装 Hermes 命令行工具:
¥Install the Hermes command line tools:
npx jsvu hermes@0.12.0
出现提示时,选择适当的操作系统。
¥When prompted, select the appropriate operating system.
-
检查安装程序的输出。查找 "安装二进制文件" 行:
¥Inspect the output of the installer. Look for "Installing binary" lines:
❯ Extracting…
Installing binary to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0…
Installing symlink at ~/.jsvu/bin/hermes-0.12.0 pointing to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0…
Installing binary to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0-compiler…
Installing symlink at ~/.jsvu/bin/hermes-0.12.0-compiler pointing to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0-compiler…
第一 "安装二进制文件" 行提到了 hermes
工具的路径。
¥The first "Installing binary" line mentions the path to the hermes
tool.
设置项目
¥Setup Project
-
创建一个新的项目文件夹:
¥Create a new project folder:
mkdir sheetjs-hermes-cli
cd sheetjs-hermes-cli
-
将步骤 1 中的二进制文件复制到当前文件夹中。例如,在 macOS 上:
¥Copy the binary from Step 1 into the current folder. For example, on macOS:
cp ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0 .
创建脚本
¥Create Script
-
下载 SheetJS Standalone 脚本和测试文件。将这两个文件保存在项目目录中:
¥Download the SheetJS Standalone script and the test file. Save both files in the project directory:
curl -LO https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
curl -LO https://xlsx.nodejs.cn/pres.numbers
-
打包测试文件并创建
payload.js
:¥Bundle the test file and create
payload.js
:
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
-
创建支持脚本:
¥Create support scripts:
-
global.js
创建一个global
变量并定义一个假console
:¥
global.js
creates aglobal
variable and defines a fakeconsole
:
var global = (function(){ return this; }).call(null);
var console = { log: function(x) { print(x); } };
-
hermes.js
将调用XLSX.read
和XLSX.utils.sheet_to_csv
:¥
hermes.js
will callXLSX.read
andXLSX.utils.sheet_to_csv
:
var wb = XLSX.read(payload, {type:'base64'});
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
-
创建合并
sheetjs.hermes.js
:¥Create the amalgamation
sheetjs.hermes.js
:
cat global.js xlsx.full.min.js payload.js hermes.js > sheetjs.hermes.js
最终脚本在加载独立库之前定义了 global
。准备就绪后,它将读取打包的测试数据并将内容打印为 CSV。
¥The final script defines global
before loading the standalone library. Once
ready, it will read the bundled test data and print the contents as CSV.
测试
¥Testing
-
使用 Hermes 独立二进制文件运行脚本:
¥Run the script using the Hermes standalone binary:
./hermes-0.12.0 sheetjs.hermes.js
如果成功,脚本将从测试文件中打印 CSV 数据。
¥If successful, the script will print CSV data from the test file.
[^1]: 见 read
于 "读取文件"
[^2]: 见 "工作簿对象"
¥See "Workbook Object"
[^3]: 见 "工作簿对象"
¥See "Workbook Object"
[^4]: 见 sheet_to_csv
于 "实用工具"
¥See sheet_to_csv
in "Utilities"
[^5]: 请参阅 GitHub 上的 microsoft/hermes-windows
¥See microsoft/hermes-windows
on GitHub
[^6]: 请参阅 Hermes 文档中的 "依赖" 于 "构建和运行"
¥See "Dependencies" in "Building and Running" in the Hermes Documentation
[^7]: 请参阅 Python 网站中的 "下载 Python"。
¥See "Download Python" in the Python website.
[^8]: 请参阅 Visual Studio 网站 下载链接。
¥See the Visual Studio website for download links.