sveltekit-adapter-chrome-extension icon indicating copy to clipboard operation
sveltekit-adapter-chrome-extension copied to clipboard

Question about accessing chrome APIs correctly

Open sullyj3 opened this issue 1 year ago • 3 comments

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?

sullyj3 avatar Dec 19 '23 05:12 sullyj3

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

michmich112 avatar Mar 24 '24 21:03 michmich112

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!

ahanprojects avatar Jun 06 '24 08:06 ahanprojects

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.

michmich112 avatar Jul 06 '24 16:07 michmich112