michmich112 / sveltekit-adapter-chrome-extension

Sveltekit adapter for making chrome extensions
MIT License
108 stars 17 forks source link

Question about accessing chrome APIs correctly #32

Open sullyj3 opened 6 months ago

sullyj3 commented 6 months ago

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?

michmich112 commented 3 months ago

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

ahanprojects commented 4 weeks ago

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!