From 3d4311bd991d58b542435c31c9d1274114b85f3c Mon Sep 17 00:00:00 2001 From: Ophir Lojkine Date: Fri, 9 Oct 2026 19:11:52 +0000 Subject: [PATCH 1/2] Deprecate asm.js builds and add inline WebAssembly variants --- .github/workflows/CI.yml | 2 +- .github/workflows/release.yml | 16 ++--- CONTRIBUTING.md | 12 ++++ Makefile | 40 +++++++++--- README.md | 52 +++++++++------ documentation_index.md | 20 +++++- examples/requireJS.html | 12 +--- package.json | 14 ++-- src/asm-deprecation.js | 9 +++ test/builds.js | 116 ++++++++++++++++++++++++++++++++++ test/test_workers.html | 6 +- 11 files changed, 240 insertions(+), 59 deletions(-) create mode 100644 src/asm-deprecation.js create mode 100644 test/builds.js diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 25a41a00..3304362d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -11,7 +11,7 @@ jobs: uses: ./.github/actions/build-sqljs - uses: actions/upload-artifact@v4 with: {name: dist, path: dist} - - name: test + - name: test WebAssembly builds and distribution behavior run: npm ci && npm test - name: generate documentation run: npm run doc diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a7cf8934..bb06c7ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,15 +39,15 @@ jobs: asset_name: sqljs-wasm.zip asset_label: wasm version, best runtime performance, smaller assets, requires configuration asset_content_type: application/zip - - name: Upload Release Asset (asm) + - name: Upload Release Asset (inline wasm) uses: lovasoa/upload-release-asset@851d9cc59fe8113912edffbd8fddaa09470a5ac0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/sql-asm.js - asset_name: sql.js - asset_label: asm.js version, slower, easy to integrate and compatible with old browsers + asset_path: dist/sql-wasm-inline.js + asset_name: sql-wasm-inline.js + asset_label: single JavaScript file with embedded WebAssembly, no configuration required asset_content_type: text/javascript - run: cd dist && zip sqljs-worker-wasm.zip worker.sql-wasm.js sql-wasm.wasm - name: Upload Release Asset (worker wasm) @@ -60,15 +60,15 @@ jobs: asset_name: sqljs-worker-wasm.zip asset_label: webworker wasm version, to be loaded as a web worker asset_content_type: application/zip - - name: Upload Release Asset (worker asm) + - name: Upload Release Asset (worker inline wasm) uses: lovasoa/upload-release-asset@851d9cc59fe8113912edffbd8fddaa09470a5ac0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/worker.sql-asm.js - asset_name: worker.sql-asm.js - asset_label: webworker asm version, to be loaded as a web worker + asset_path: dist/worker.sql-wasm-inline.js + asset_name: worker.sql-wasm-inline.js + asset_label: single-file WebAssembly version, to be loaded as a web worker asset_content_type: text/javascript - run: cd dist && zip sqljs-all.zip *.{js,wasm} - name: Upload Release Asset (all) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be4d6451..4d9d6939 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,3 +64,15 @@ CFLAGS = \ + -DSQLITE_ENABLE_FTS5 \ -DSQLITE_THREADSAFE=0 ``` + +## Building and testing distribution variants + +`npm run build` produces the default, browser-only, and inline WebAssembly builds, their debug variants, and worker bundles. The inline variants use Emscripten's [`-sSINGLE_FILE=1`](https://emscripten.org/docs/tools_reference/settings_reference.html#single-file) to embed the binary in JavaScript. + +To build only the inline variants: + +```sh +make dist/sql-wasm-inline.js dist/sql-wasm-inline-debug.js dist/worker.sql-wasm-inline.js dist/worker.sql-wasm-inline-debug.js +``` + +`npm test` runs the API suite against the WebAssembly variants and checks the distribution behavior, including single-file initialization without fetching a companion asset. `npm run doc` generates the API documentation. diff --git a/Makefile b/Makefile index 9b29aa5b..3d1315ef 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,6 @@ EMFLAGS = \ -s ALLOW_TABLE_GROWTH=1 \ -s EXPORTED_FUNCTIONS=@src/exported_functions.json \ -s EXPORTED_RUNTIME_METHODS=@src/exported_runtime_methods.json \ - -s SINGLE_FILE=0 \ -s NODEJS_CATCH_EXIT=0 \ -s NODEJS_CATCH_REJECTION=0 \ -s STACK_SIZE=5MB @@ -50,6 +49,9 @@ EMFLAGS_WASM = \ -s WASM=1 \ -s ALLOW_MEMORY_GROWTH=1 +# Base64 embedding works even when a page does not declare UTF-8 encoding. +EMFLAGS_WASM_INLINE = $(EMFLAGS_WASM) -s SINGLE_FILE=1 -s SINGLE_FILE_BINARY_ENCODE=0 + EMFLAGS_WASM_BROWSER = \ -s WASM=1 \ -s ALLOW_MEMORY_GROWTH=1 \ @@ -78,12 +80,12 @@ EXPORTED_METHODS_JSON_FILES = src/exported_functions.json src/exported_runtime_m all: optimized debug worker .PHONY: debug -debug: dist/sql-asm-debug.js dist/sql-wasm-debug.js dist/sql-wasm-browser-debug.js +debug: dist/sql-asm-debug.js dist/sql-wasm-debug.js dist/sql-wasm-browser-debug.js dist/sql-wasm-inline-debug.js -dist/sql-asm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) +dist/sql-asm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) src/asm-deprecation.js $(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ mv $@ out/tmp-raw.js - cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ + cat src/shell-pre.js src/asm-deprecation.js out/tmp-raw.js src/shell-post.js > $@ rm out/tmp-raw.js dist/sql-wasm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) @@ -98,13 +100,19 @@ dist/sql-wasm-browser-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURC cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ rm out/tmp-raw.js +dist/sql-wasm-inline-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) Makefile + $(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_WASM_INLINE) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ + mv $@ out/tmp-raw.js + cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ + rm out/tmp-raw.js + .PHONY: optimized -optimized: dist/sql-asm.js dist/sql-wasm.js dist/sql-wasm-browser.js dist/sql-asm-memory-growth.js +optimized: dist/sql-asm.js dist/sql-wasm.js dist/sql-wasm-browser.js dist/sql-wasm-inline.js dist/sql-asm-memory-growth.js -dist/sql-asm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) +dist/sql-asm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) src/asm-deprecation.js $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ mv $@ out/tmp-raw.js - cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ + cat src/shell-pre.js src/asm-deprecation.js out/tmp-raw.js src/shell-post.js > $@ rm out/tmp-raw.js dist/sql-wasm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) @@ -119,15 +127,21 @@ dist/sql-wasm-browser.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_ cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ rm out/tmp-raw.js -dist/sql-asm-memory-growth.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) - $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM_MEMORY_GROWTH) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ +dist/sql-wasm-inline.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) Makefile + $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_WASM_INLINE) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ mv $@ out/tmp-raw.js cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ rm out/tmp-raw.js +dist/sql-asm-memory-growth.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) src/asm-deprecation.js + $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM_MEMORY_GROWTH) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ + mv $@ out/tmp-raw.js + cat src/shell-pre.js src/asm-deprecation.js out/tmp-raw.js src/shell-post.js > $@ + rm out/tmp-raw.js + # Web worker API .PHONY: worker -worker: dist/worker.sql-asm.js dist/worker.sql-asm-debug.js dist/worker.sql-wasm.js dist/worker.sql-wasm-debug.js +worker: dist/worker.sql-asm.js dist/worker.sql-asm-debug.js dist/worker.sql-wasm.js dist/worker.sql-wasm-debug.js dist/worker.sql-wasm-inline.js dist/worker.sql-wasm-inline-debug.js dist/worker.sql-asm.js: dist/sql-asm.js src/worker.js cat $^ > $@ @@ -141,6 +155,12 @@ dist/worker.sql-wasm.js: dist/sql-wasm.js src/worker.js dist/worker.sql-wasm-debug.js: dist/sql-wasm-debug.js src/worker.js cat $^ > $@ +dist/worker.sql-wasm-inline.js: dist/sql-wasm-inline.js src/worker.js + cat $^ > $@ + +dist/worker.sql-wasm-inline-debug.js: dist/sql-wasm-inline-debug.js src/worker.js + cat $^ > $@ + # Building it this way gets us a wrapper that _knows_ it's in worker mode, which is nice. # However, since we can't tell emcc that we don't need the wasm generated, and just want the wrapper, we have to pay to have the .wasm generated # even though we would have already generated it with our sql-wasm.js target above. diff --git a/README.md b/README.md index a42cfa8c..161b5cf7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ *sql.js* is a javascript SQL database. It allows you to create a relational database and query it entirely in the browser. You can try it in [this online demo](https://sql.js.org/examples/GUI/). It uses a [virtual database file stored in memory](https://emscripten.org/docs/porting/files/file_systems_overview.html), and thus **doesn't persist the changes** made to the database. However, it allows you to **import** any existing sqlite file, and to **export** the created database as a [JavaScript typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays). -*sql.js* uses [emscripten](https://emscripten.org/docs/introducing_emscripten/about_emscripten.html) to compile [SQLite](http://sqlite.org/about.html) to webassembly (or to javascript code for compatibility with older browsers). It includes [contributed math and string extension functions](https://www.sqlite.org/contrib?orderby=date). +*sql.js* uses [emscripten](https://emscripten.org/docs/introducing_emscripten/about_emscripten.html) to compile [SQLite](http://sqlite.org/about.html) to WebAssembly. It includes [contributed math and string extension functions](https://www.sqlite.org/contrib?orderby=date). sql.js can be used like any traditional JavaScript library. If you are building a native application in JavaScript (using Electron for instance), or are working in node.js, you will likely prefer to use [a native binding of SQLite to JavaScript](https://www.npmjs.com/package/sqlite3). A native binding will not only be faster because it will run native code, but it will also be able to work on database files directly instead of having to load the entire database in memory, avoiding out of memory errors and further improving performances. @@ -20,6 +20,16 @@ It is generated from comments inside the source code, and is thus always up to d ## Usage +For a single-file setup, use **`sql-wasm-inline.js`**. It embeds the WebAssembly binary in the JavaScript file, so there is no separate `.wasm` asset to serve and no `locateFile` configuration: + +```javascript +const initSqlJs = require('sql.js/dist/sql-wasm-inline.js'); +const SQL = await initSqlJs(); +const db = new SQL.Database(); +``` + +In a browser, load `` and call `initSqlJs()` in the same way. This build requires WebAssembly support and uses the same asynchronous API as the default build. Embedding the binary makes the JavaScript file larger; the default build keeps it separate for independent caching and streaming compilation. + By default, *sql.js* uses [wasm](https://developer.mozilla.org/en-US/docs/WebAssembly), and thus needs to load a `.wasm` file in addition to the javascript library. You can find this file in `./node_modules/sql.js/dist/sql-wasm.wasm` after installing sql.js from npm, and instruct your bundler to add it to your static assets or load it from [a CDN](https://cdnjs.com/libraries/sql.js). Then use the [`locateFile`](https://emscripten.org/docs/api_reference/module.html#Module.locateFile) property of the configuration object passed to `initSqlJs` to indicate where the file is. If you use an asset builder such as webpack, you can automate this. See [this demo of how to integrate sql.js with webpack (and react)](https://github.com/sql-js/react-sqljs-demo). ```javascript @@ -205,7 +215,7 @@ Alternatively, you can simply download `sql-wasm.js` and `sql-wasm.wasm`, from t #### read a database from the disk: ```javascript const fs = require('fs'); -const initSqlJs = require('sql-wasm.js'); +const initSqlJs = require('sql.js'); const filebuffer = fs.readFileSync('test.sqlite'); initSqlJs().then(function(SQL){ @@ -231,7 +241,9 @@ See : https://github.com/sql-js/sql.js/blob/master/test/test_node_file.js If you don't want to run CPU-intensive SQL queries in your main application thread, you can use the *more limited* WebWorker API. -You will need to download `worker.sql-wasm.js` and `worker.sql-wasm.wasm` from the [release page](https://github.com/sql-js/sql.js/releases). +You will need to download `worker.sql-wasm.js` and `sql-wasm.wasm` from the [release page](https://github.com/sql-js/sql.js/releases). + +For a single-file worker, use `worker.sql-wasm-inline.js`; it includes the WebAssembly binary and needs no companion file. Example: ```html @@ -291,11 +303,11 @@ See [examples/GUI/gui.js](examples/GUI/gui.js) for a full working example. ## Flavors/versions Targets/Downloads -This library includes both WebAssembly and asm.js versions of Sqlite. (WebAssembly is the newer, preferred way to compile to JavaScript, and has superceded asm.js. It produces smaller, faster code.) Asm.js versions are included for compatibility. +Choose between the default WebAssembly build, which loads a separate binary, and the inline build, which embeds it in one JavaScript file. ## Upgrading from 0.x to 1.x -Version 1.0 of sql.js must be loaded asynchronously, whereas asm.js was able to be loaded synchronously. +Version 1.0 and later load asynchronously, whereas version 0.x loaded synchronously. So in the past, you would: ```html @@ -324,7 +336,7 @@ Version 1.x: ``` or: ```javascript -const initSqlJs = require('sql-wasm.js'); +const initSqlJs = require('sql.js'); initSqlJs().then(function(SQL){ const db = new SQL.Database(); //... @@ -333,22 +345,26 @@ initSqlJs().then(function(SQL){ `NOTHING` is now a reserved word in SQLite, whereas previously it was not. This could cause errors like `Error: near "nothing": syntax error` -### Downloading/Using: ### -Although asm.js files were distributed as a single Javascript file, WebAssembly libraries are most efficiently distributed as a pair of files, the `.js` loader and the `.wasm` file, like `sql-wasm.js` and `sql-wasm.wasm`. The `.js` file is responsible for loading the `.wasm` file. You can find these files on our [release page](https://github.com/sql-js/sql.js/releases) - +### Downloading and using builds +The [release page](https://github.com/sql-js/sql.js/releases/latest) provides `sql-wasm-inline.js` and `worker.sql-wasm-inline.js` as standalone downloads. The `sqljs-wasm.zip` archive contains the default JavaScript loader and WebAssembly binary; `sqljs-worker-wasm.zip` contains the worker loader and its binary. +The `sqljs-all.zip` archive and npm package include the following WebAssembly builds: -## Versions of sql.js included in the distributed artifacts -You can always find the latest published artifacts on https://github.com/sql-js/sql.js/releases/latest. +| Build | Companion file | Use | +| --- | --- | --- | +| `sql-wasm.js` | `sql-wasm.wasm` | Default production build for browsers and Node.js. | +| `sql-wasm-debug.js` | `sql-wasm-debug.wasm` | Development build with assertions. | +| `sql-wasm-browser.js` | `sql-wasm-browser.wasm` | Browser-only production build, selected by the npm browser export. | +| `sql-wasm-browser-debug.js` | `sql-wasm-browser-debug.wasm` | Browser-only development build. | +| `sql-wasm-inline.js` | None | Production build with the WebAssembly binary embedded. | +| `sql-wasm-inline-debug.js` | None | Inline development build with assertions. | +| `worker.sql-wasm.js` | `sql-wasm.wasm` | Production Web Worker build. | +| `worker.sql-wasm-debug.js` | `sql-wasm-debug.wasm` | Development Web Worker build. | +| `worker.sql-wasm-inline.js` | None | Single-file production Web Worker build. | +| `worker.sql-wasm-inline-debug.js` | None | Single-file development Web Worker build. | -For each [release](https://github.com/sql-js/sql.js/releases/), you will find a file called `sqljs.zip` in the *release assets*. It will contain: - - `sql-wasm.js` : The Web Assembly version of Sql.js. Minified and suitable for production. Use this. If you use this, you will need to include/ship `sql-wasm.wasm` as well. - - `sql-wasm-debug.js` : The Web Assembly, Debug version of Sql.js. Larger, with assertions turned on. Useful for local development. You will need to include/ship `sql-wasm-debug.wasm` if you use this. - - `sql-asm.js` : The older asm.js version of Sql.js. Slower and larger. Provided for compatibility reasons. - - `sql-asm-memory-growth.js` : Asm.js doesn't allow for memory to grow by default, because it is slower and de-optimizes. If you are using sql-asm.js and you see this error (`Cannot enlarge memory arrays`), use this file. - - `sql-asm-debug.js` : The _Debug_ asm.js version of Sql.js. Use this for local development. - - `worker.*` - Web Worker versions of the above libraries. More limited API. See [examples/GUI/gui.js](examples/GUI/gui.js) for a good example of this. +Workers offer a more limited API. See [examples/GUI/gui.js](examples/GUI/gui.js) for an example. ## Compiling/Contributing diff --git a/documentation_index.md b/documentation_index.md index 9f7a0152..3546928e 100644 --- a/documentation_index.md +++ b/documentation_index.md @@ -2,20 +2,34 @@ ## Introduction -If you need a quick intoduction with code samples that you can copy-and-paste, +If you need a quick introduction with code samples that you can copy-and-paste, head over to [sql.js.org](https://sql.js.org/) +## Loading sql.js + +The default `sql-wasm.js` build loads a separate `sql-wasm.wasm` binary. In browsers, use the `locateFile` configuration to specify its location. + +To keep deployment in one JavaScript file, use `sql-wasm-inline.js`, which embeds the WebAssembly binary and needs no `locateFile` configuration: + +```javascript +const initSqlJs = require("sql.js/dist/sql-wasm-inline.js"); +const SQL = await initSqlJs(); +const db = new SQL.Database(); +``` + +In a browser, load `sql-wasm-inline.js` with a script tag and call `initSqlJs()`. For a single-file Web Worker, use `worker.sql-wasm-inline.js`. All builds require WebAssembly support and initialize asynchronously. Debug variants are also available; see the [build list](https://sql.js.org/#/README?id=downloading-and-using-builds). + ## API ### The initSqlJs function The root object in the API is the [`initSqlJs`](./global.html#initSqlJs) function, that takes an [`SqlJsConfig`](./global.html#SqlJsConfig) parameter, -and returns an [SqlJs](./global.html#SqlJs) object +and returns a Promise that resolves to an [SqlJs](./global.html#SqlJs) object ### The SqlJs object -`initSqlJs` returns the main sql.js object, the [**`SqlJs`**](./module-SqlJs.html) module, which contains : +`initSqlJs` resolves to the main sql.js object, the [**`SqlJs`**](./module-SqlJs.html) module, which contains : #### Database diff --git a/examples/requireJS.html b/examples/requireJS.html index bc1f6b2b..cb85b62b 100644 --- a/examples/requireJS.html +++ b/examples/requireJS.html @@ -8,8 +8,8 @@ baseUrl: baseUrl }); - // Options: 'sql-wasm', 'sql-asm', 'sql-asm-memory-growth.js', 'sql-wasm-debug', 'sql-asm-debug' - require(['sql-wasm'], + // The inline build includes WebAssembly in the JavaScript file. + require(['sql-wasm-inline'], function success(initSqlJs) { console.log(typeof initSqlJs); if (typeof initSqlJs !== 'function') { @@ -18,13 +18,7 @@ alert("Failed to require sql.js through AMD"); return; } - // The `initSqlJs` function is globally provided by all of the main dist files if loaded in the browser. - // We must specify this locateFile function if we are loading a wasm file from anywhere other than the current html page's folder. - - var config = { - locateFile: filename => `${baseUrl}/${filename}` - } - initSqlJs(config).then(function (SQL) { + initSqlJs().then(function (SQL) { //Create the database var db = new SQL.Database(); // Run a query without reading the results diff --git a/package.json b/package.json index 88d4fd96..d2ad8acd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sql.js", "version": "1.14.2", - "description": "SQLite library with support for opening and writing databases, prepared statements, and more. This SQLite library is in pure javascript (compiled with emscripten).", + "description": "SQLite library with support for opening and writing databases, prepared statements, and more. Compiled to WebAssembly with Emscripten, with JavaScript bindings.", "keywords": [ "sql", "sqlite", @@ -13,8 +13,8 @@ "query", "statement", "emscripten", - "asm", - "asm.js" + "wasm", + "webassembly" ], "license": "MIT", "main": "./dist/sql-wasm.js", @@ -29,15 +29,15 @@ "build": "make", "rebuild": "npm run clean && npm run build", "clean": "make clean", - "test": "npm run lint && npm run test-asm && npm run test-asm-debug && npm run test-wasm && npm run test-wasm-debug && npm run test-wasm-browser && npm run test-asm-memory-growth", + "test": "npm run lint && npm run test-wasm && npm run test-wasm-debug && npm run test-wasm-browser && npm run test-wasm-inline && npm run test-wasm-inline-debug && npm run test-builds", "lint": "eslint .", "prettify": "eslint . --fix", - "test-asm": "node --unhandled-rejections=strict test/all.js asm", - "test-asm-debug": "node --unhandled-rejections=strict test/all.js asm-debug", - "test-asm-memory-growth": "node --unhandled-rejections=strict test/all.js asm-memory-growth", "test-wasm": "node --unhandled-rejections=strict test/all.js wasm", "test-wasm-debug": "node --unhandled-rejections=strict test/all.js wasm-debug", "test-wasm-browser": "node --unhandled-rejections=strict test/all.js wasm-browser", + "test-wasm-inline": "node --unhandled-rejections=strict test/all.js wasm-inline", + "test-wasm-inline-debug": "node --unhandled-rejections=strict test/all.js wasm-inline-debug", + "test-builds": "node --unhandled-rejections=strict test/builds.js", "doc": "jsdoc -c .jsdoc.config.json" }, "homepage": "http://github.com/sql-js/sql.js", diff --git a/src/asm-deprecation.js b/src/asm-deprecation.js new file mode 100644 index 00000000..071a92e0 --- /dev/null +++ b/src/asm-deprecation.js @@ -0,0 +1,9 @@ +if (typeof console !== "undefined" && typeof console.warn === "function") { + console.warn( + "sql.js: the asm.js build is deprecated. " + + "Use sql-wasm-inline.js (worker.sql-wasm-inline.js for workers) " + + "for a single JavaScript file with embedded WebAssembly. " + + "WebAssembly support is required. If you cannot migrate, please " + + "tell us at https://github.com/sql-js/sql.js/issues/635." + ); +} diff --git a/test/builds.js b/test/builds.js new file mode 100644 index 00000000..349c6097 --- /dev/null +++ b/test/builds.js @@ -0,0 +1,116 @@ +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const vm = require("node:vm"); +const { execFileSync } = require("node:child_process"); + +function noAssetLoading() { + throw new Error("The inline build must not load a companion asset"); +} + +async function testBrowserBuild(file, deprecated) { + const warnings = []; + const messages = []; + const worker = file.startsWith("worker."); + const context = vm.createContext({ + console: { ...console, warn: (warning) => warnings.push(warning) }, + WebAssembly, + TextDecoder, + TextEncoder, + atob, + setTimeout, + clearTimeout, + fetch: noAssetLoading, + XMLHttpRequest: noAssetLoading, + location: { href: "file:///sqljs/" + file }, + postMessage: (message) => messages.push(message) + }); + context.self = context; + if (worker) { + context.WorkerGlobalScope = function WorkerGlobalScope() {}; + context.importScripts = noAssetLoading; + } else { + context.window = context; + context.document = { currentScript: { src: context.location.href } }; + } + vm.runInContext(fs.readFileSync(path.join(__dirname, "../dist", file), "utf8"), context); + + const first = context.initSqlJs({ locateFile: noAssetLoading }); + assert.equal(first, context.initSqlJs(), "Initialization is cached"); + const SQL = await first; + const db = new SQL.Database(); + assert.equal(db.exec("SELECT 42 AS answer")[0].values[0][0], 42); + db.close(); + + if (worker) { + await context.self.onmessage({ data: { id: 1, action: "open" } }); + await context.self.onmessage({ data: { id: 2, action: "exec", sql: "SELECT 42" } }); + assert.equal(messages[0].ready, true); + assert.equal(messages[1].results[0].values[0][0], 42); + await context.self.onmessage({ data: { id: 3, action: "close" } }); + } + + if (deprecated) { + assert.equal(warnings.length, 1, "Warn once when initializing a deprecated build"); + assert.match(warnings[0], /asm\.js build is deprecated/); + assert.match(warnings[0], /sql-wasm-inline\.js/); + assert.match(warnings[0], /https:\/\/github\.com\/sql-js\/sql\.js\/issues\/635/); + } else { + assert.equal(warnings.length, 0, "WebAssembly builds do not warn"); + } + console.log("OK browser distribution " + file); +} + +function testIsolatedNodeBuild(file) { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "sqljs-inline-")); + try { + const bundle = path.join(dir, file); + fs.copyFileSync(path.join(__dirname, "../dist", file), bundle); + execFileSync(process.execPath, ["--unhandled-rejections=strict", "-e", ` + const assert = require("node:assert/strict"); + const initSqlJs = require(process.argv[1]); + let completed = false; + process.on("beforeExit", () => assert.ok(completed, "Initialization must finish")); + global.fetch = () => { throw new Error("Unexpected fetch"); }; + initSqlJs({ locateFile() { throw new Error("Unexpected locateFile"); } }).then(SQL => { + const db = new SQL.Database(); + assert.equal(db.exec("SELECT 42")[0].values[0][0], 42); + db.close(); + completed = true; + }); + `, bundle], { timeout: 20000, stdio: "inherit" }); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } + console.log("OK isolated Node.js distribution " + file); +} + +async function main() { + for (const suffix of ["", "-debug"]) { + const file = "sql-wasm-inline" + suffix + ".js"; + assert.equal(fs.existsSync(path.join(__dirname, "../dist", "sql-wasm-inline" + suffix + ".wasm")), false); + testIsolatedNodeBuild(file); + await testBrowserBuild(file, false); + await testBrowserBuild("worker." + file, false); + } + for (const file of [ + "sql-asm.js", "sql-asm-debug.js", "sql-asm-memory-growth.js", + "worker.sql-asm.js", "worker.sql-asm-debug.js" + ]) { + await testBrowserBuild(file, true); + } +} + +const timeout = setTimeout(() => { + console.error("Distribution checks timed out"); + process.exit(1); +}, 30000); + +main().then(() => { + clearTimeout(timeout); +}, (error) => { + clearTimeout(timeout); + console.error(error); + process.exitCode = 1; +}); diff --git a/test/test_workers.html b/test/test_workers.html index f0596a36..05b4af63 100644 --- a/test/test_workers.html +++ b/test/test_workers.html @@ -5,8 +5,8 @@

\ No newline at end of file + From da30e968187631f038164baf6be0ceeb119f4eb5 Mon Sep 17 00:00:00 2001 From: Ophir Lojkine Date: Fri, 9 Oct 2026 19:12:50 +0000 Subject: [PATCH 2/2] Remove automated coverage of deprecated asm.js builds --- test/builds.js | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/test/builds.js b/test/builds.js index 349c6097..f61013dc 100644 --- a/test/builds.js +++ b/test/builds.js @@ -9,7 +9,7 @@ function noAssetLoading() { throw new Error("The inline build must not load a companion asset"); } -async function testBrowserBuild(file, deprecated) { +async function testBrowserBuild(file) { const warnings = []; const messages = []; const worker = file.startsWith("worker."); @@ -51,14 +51,7 @@ async function testBrowserBuild(file, deprecated) { await context.self.onmessage({ data: { id: 3, action: "close" } }); } - if (deprecated) { - assert.equal(warnings.length, 1, "Warn once when initializing a deprecated build"); - assert.match(warnings[0], /asm\.js build is deprecated/); - assert.match(warnings[0], /sql-wasm-inline\.js/); - assert.match(warnings[0], /https:\/\/github\.com\/sql-js\/sql\.js\/issues\/635/); - } else { - assert.equal(warnings.length, 0, "WebAssembly builds do not warn"); - } + assert.equal(warnings.length, 0, "WebAssembly builds do not warn"); console.log("OK browser distribution " + file); } @@ -91,14 +84,8 @@ async function main() { const file = "sql-wasm-inline" + suffix + ".js"; assert.equal(fs.existsSync(path.join(__dirname, "../dist", "sql-wasm-inline" + suffix + ".wasm")), false); testIsolatedNodeBuild(file); - await testBrowserBuild(file, false); - await testBrowserBuild("worker." + file, false); - } - for (const file of [ - "sql-asm.js", "sql-asm-debug.js", "sql-asm-memory-growth.js", - "worker.sql-asm.js", "worker.sql-asm-debug.js" - ]) { - await testBrowserBuild(file, true); + await testBrowserBuild(file); + await testBrowserBuild("worker." + file); } }