Skip to content

Commit 650b858

Browse files
rdhyeeclaude
andcommitted
Fix DuckDB-WASM import for GitHub Pages deployment
- Replace @observablehq/duckdb with direct @duckdb/duckdb-wasm import - Use dynamic import pattern to avoid CORS proxy issues - Add runQuery helper with BigInt conversion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 26dbfde commit 650b858

1 file changed

Lines changed: 41 additions & 11 deletions

File tree

tutorials/isamples_explorer.qmd

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ This app queries a 282 MB Parquet file directly in your browser using DuckDB-WAS
1919

2020
```{ojs}
2121
//| code-fold: true
22-
// Imports
23-
import { DuckDBClient } from "https://cdn.jsdelivr.net/npm/@observablehq/duckdb@0.7.1/+esm"
22+
// Imports - use dynamic import to avoid CORS issues
23+
duckdbModule = import("https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@1.28.0/+esm")
2424
```
2525

2626
```{ojs}
@@ -221,12 +221,45 @@ html`<div style="margin-bottom: 16px;">
221221

222222
```{ojs}
223223
//| code-fold: true
224-
// Initialize DuckDB
224+
// Initialize DuckDB-WASM
225225
db = {
226-
const instance = await DuckDBClient.of();
227-
await instance.query(`CREATE VIEW samples AS SELECT * FROM read_parquet('${parquet_url}')`);
226+
const bundle = await duckdbModule.selectBundle(duckdbModule.getJsDelivrBundles());
227+
228+
const worker_url = URL.createObjectURL(
229+
new Blob([`importScripts("${bundle.mainWorker}");`], {type: 'text/javascript'})
230+
);
231+
const worker = new Worker(worker_url);
232+
const logger = new duckdbModule.ConsoleLogger(duckdbModule.LogLevel.WARNING);
233+
234+
const instance = new duckdbModule.AsyncDuckDB(logger, worker);
235+
await instance.instantiate(bundle.mainModule, bundle.pthreadWorker);
236+
URL.revokeObjectURL(worker_url);
237+
238+
// Create view for convenience
239+
const conn = await instance.connect();
240+
await conn.query(`CREATE VIEW samples AS SELECT * FROM read_parquet('${parquet_url}')`);
241+
await conn.close();
242+
228243
return instance;
229244
}
245+
246+
// Helper function to run queries
247+
async function runQuery(sql) {
248+
const conn = await db.connect();
249+
try {
250+
const result = await conn.query(sql);
251+
return result.toArray().map(row => {
252+
const obj = row.toJSON();
253+
// Convert BigInt to Number
254+
for (const key in obj) {
255+
if (typeof obj[key] === 'bigint') obj[key] = Number(obj[key]);
256+
}
257+
return obj;
258+
});
259+
} finally {
260+
await conn.close();
261+
}
262+
}
230263
```
231264

232265
```{ojs}
@@ -283,8 +316,7 @@ sourceCounts = {
283316
`;
284317
285318
try {
286-
const result = await db.query(query);
287-
return Array.from(result);
319+
return await runQuery(query);
288320
} catch (e) {
289321
console.error("Facet query error:", e);
290322
return [];
@@ -298,8 +330,7 @@ sourceCounts = {
298330
totalCount = {
299331
const query = `SELECT COUNT(*) as count FROM samples WHERE ${whereClause}`;
300332
try {
301-
const result = await db.query(query);
302-
const rows = Array.from(result);
333+
const rows = await runQuery(query);
303334
return rows[0]?.count || 0;
304335
} catch (e) {
305336
return 0;
@@ -334,8 +365,7 @@ sampleData = {
334365
LIMIT ${maxSamples}
335366
`;
336367
337-
const result = await db.query(query);
338-
const data = Array.from(result);
368+
const data = await runQuery(query);
339369
340370
if (statusDiv) {
341371
statusDiv.textContent = `Loaded ${data.length.toLocaleString()} samples`;

0 commit comments

Comments
 (0)