sveltekit-adapter-chrome-extension
sveltekit-adapter-chrome-extension copied to clipboard
Question about accessing chrome APIs correctly
Hi! I'm trying to write an extension which accesses the chrome bookmarks API, but I'm having some trouble understanding how to use it correctly in the context of sveltekit. I started from this template repository.
To start with I wanted to just display a BookmarkTreeNode
, so I edited src/routes/+page.svelte
with the following:
(here's the docs for chrome.bookmarks.getTree)
<script lang='ts'>
import { onMount } from 'svelte';
let bookmarksPromise: Promise<chrome.bookmarks.BookmarkTreeNode[]>;
onMount(() => {
if (window.chrome && chrome.runtime && chrome.runtime.id) {
bookmarksPromise = chrome.bookmarks.getTree();
}
});
</script>
<div class="container h-full mx-auto flex justify-center items-center">
<div class="space-y-10 text-center flex flex-col items-center">
<h2 class="h2 font-bold">Welcome to Skeleton.</h2>
<div class="space-y-2">
<p>hello, world!</p>
{#await bookmarksPromise}
<p>loading bookmarks...</p>
{:then bookmarks}
<p>bookmarks loaded!</p>
<pre>{JSON.stringify(bookmarks, null, 2)}</pre>
{:catch error}
<p>error loading bookmarks: {error.message}</p>
{/await}
</div>
</div>
</div>
This works as expected, displaying this JSON:
[
{
"children": [
{
"children": [],
"dateAdded": 1702963434117,
"id": "1",
"index": 0,
"parentId": "0",
"title": "Bookmarks bar"
},
{
"children": [],
"dateAdded": 1702963434117,
"id": "2",
"index": 1,
"parentId": "0",
"title": "Other bookmarks"
}
],
"dateAdded": 1702963434117,
"id": "0",
"title": ""
}
]
The problem comes in when I try to actually access the node. When I edit the html with the following instead:
{#await bookmarksPromise}
<p>loading bookmarks...</p>
{:then bookmarks}
<p>bookmarks loaded!</p>
<!-- for some reason getTree returns an array containing the single root `BookmarkTreeNode` -->
<!-- so we need to index it to access the node -->
<pre>{JSON.stringify(bookmarks[0], null, 2)}</pre>
{:catch error}
<p>error loading bookmarks: {error.message}</p>
{/await}
I get a compile error:
TypeError: Cannot read properties of undefined (reading '0')
at file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/entries/pages/_page.svelte.js:16:112
at file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/entries/pages/_page.svelte.js:17:6
at file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/entries/pages/_page.svelte.js:18:4
at Object.$$render (file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/chunks/ssr.js:104:18)
at Object.default (file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/chunks/internal.js:68:98)
at Object.default (file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/entries/pages/_layout.svelte.js:167:47)
at file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/entries/pages/_layout.svelte.js:147:909
at Object.$$render (file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/chunks/ssr.js:104:18)
at file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/entries/pages/_layout.svelte.js:152:55
at Object.$$render (file:///home/james/dev/popmark-svelte/.svelte-kit/output/server/chunks/ssr.js:104:18)
node:internal/event_target:1083
process.nextTick(() => { throw err; });
^
Error: 500 /
To suppress or handle this error, implement `handleHttpError` in https://kit.svelte.dev/docs/configuration#prerender
at file:///home/james/dev/popmark-svelte/node_modules/@sveltejs/kit/src/core/config/options.js:212:13
at file:///home/james/dev/popmark-svelte/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:64:25
at save (file:///home/james/dev/popmark-svelte/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:403:4)
at visit (file:///home/james/dev/popmark-svelte/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:236:3)
Emitted 'error' event on Worker instance at:
at [kOnErrorMessage] (node:internal/worker:326:10)
at [kOnMessage] (node:internal/worker:337:37)
at MessagePort.<anonymous> (node:internal/worker:232:57)
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:807:20)
at exports.emitMessage (node:internal/per_context/messageport:23:28)
Node.js v20.6.1
ELIFECYCLE Command failed with exit code 1.
referring to the bookmarks[0]
in the html. I'm a bit hazy on how sveltekit works, but my intuition says the error is to do with SSR and the bookmarks not being available when the page is being prerendered? Is that right?
How do I do this correctly?
The best solution for this would be to add typing for the chrome api with this package. I'm looking into ways to add it for intellisense to also pick up and use it correctly
I am also using chrome API (chrome.storage.local). Because this API can only be accessed from the client, I set prerender = true
and ssr = false
in +layout.ts
. While developing, I use localStorage to mock the behavior of chrome.storage.local
, and it works fine.
But when I build the app and unpack it, then open the extension, it shows 404 not found. The console error says Error: Not found: /index.html
, even though the index.html
file is present on the build folder. I suspect the problem comes from the script tag inside index.html
.
If i remove ssr = false
, the extension works fine, but I have to make a lot of adjustment (like using onMount
and browser
variable) to make sure chrome.storage.local
only called in the browser, which is a lot of hassle and not very clean, because I have to do this in multiple files.
My question is, does this adapter doesn't work for ssr = false
? or maybe there is something wrong my implementation? Thankyou in advance!
HEy @ahanprojects
yes this adapter won't work for ssr = false
the reason being that it needs to have fully resolved and injectable html and js to package it as an extension.
Without ssr = false
the svelte compiler will create a server package that will need to run on another environment than the browser, and the resulting html and js will require a connection to that server to load and render.