Running SQLite in the browser using NextJS
Why not?
- tags
- sqlite
- browser
- nextjs
Contents
End API
Our goal is to be able to load a sqlite3 database using useBinaryFile
,
load up the database engine using useDB
, and get the results using
useDBQuery
.
|
|
Lets walk though how to make that happen.
Install sql.js
First we install the wasm
files, and we serve them out of /public
.
|
|
/public/sql-loader.js
Now, outside of the NextJS managed javascript universe create a file
that will add the script tag to load up sql-wasm.js
and sql-wasm.wasm
into the browser.
|
|
lib/useDB.tsx
Now we create a custom react hook to use load up the database.
The first useEffect
runs once, and looks to see if there's a window
object. If there is, it's running on the browser, so it sets up an
interval to see if the loadSQL
function has been defined. If it has,
this means that the sql-loader.js
script has been evaluated. Once's
that's true, will call setWindowWatcher
which will cause the second
useEffect
to rerun.
The second useEffect
called the function setup by sql-loader.js
, which
loads the SQLite database engine. Once this is done ie called
setEngine
.
Once the engine
and data
are set, the third useEffect
is run, which
actually instantiates a new SQL.Database
(called engine.Database
in
the code.)
At this point, the db is set, so we can use useDBQuery
to get the
results. We pass in db
(which will change if we switch to a new
database file) and a query, and it returns the result.
|
|
Loading up a file
An easy way to load a binary file is:
useBinaryFile.tsx
|
|
Tying it all together
Now to trigger the loading of sql-loader.js
you just need to put a
script tag in the pages that you use useDB
on:
|
|
If you don't put this tag in, window.loadSQL
will never be define, and
setWindowWatcher
will never be true.
Generic ResultsTable
Here's a little starting point to show the results:
export function ResultTable( {results} ) {
if( !results ) {
return <div></div>
}
return (
<table className="w-full">
<thead>
<tr>
{results[0].columns.map( (c) => <th key={c}>{c}</th>)}
</tr>
</thead>
<tbody>
{results[0].values.map( (r) => <tr key={r}>
{r.map( (v) => <td key={v}>{v}</td> )}
</tr>)}
</tbody>
</table>
)
}
Previously
Next