dfinity / agent-js

A collection of libraries and tools for building software around the Internet Computer, in JavaScript.
https://agent-js.icp.xyz
Apache License 2.0
155 stars 96 forks source link

Cannot use 'import.meta' outside a module when building a ServiceWorker script #930

Open zensh opened 2 months ago

zensh commented 2 months ago

https://github.com/dfinity/agent-js/blob/main/packages/agent/src/agent/http/index.ts#L1106

await import is incompatible with the ServiceWorker script. This can cause the error: "Uncaught SyntaxError: Cannot use 'import.meta' outside a module."

We encountered this issue while building the ICPanda frontend application. Removing the await import here resolved the ServiceWorker script build.

https://github.com/ldclabs/ic-panda/blob/main/src/ic_panda_frontend/src/service-worker.ts#L11

peterpeterparker commented 2 months ago

await import is incompatible with the ServiceWorker script.

I randomly had a look at the line of code you are referencing. Are you bundling your SW using ES modules?

zensh commented 2 months ago

await import is incompatible with the ServiceWorker script.

I randomly had a look at the line of code you are referencing. Are you bundling your SW using ES modules?

Yes, I used the ES module for packaging. I spent half a day resolving the issue and was only able to package successfully after modifying the agent file in node_modules. https://github.com/ldclabs/ic-panda/blob/main/src/ic_panda_frontend/vite.config.js#L99

peterpeterparker commented 2 months ago

Yes, I used the ES module for packaging.

Maybe it's specific to service worker? We do use the agent in web workers in Oisy for example and we do not have issue. That's why I was asking about ES modules.

zensh commented 2 months ago

Thank you for following up.
I created a test project using pnpm create @vite-pwa/pwa agent-sw --template svelte-ts and didn't encounter any issues. The generated sw file has slight differences from my previous project, but I haven't yet identified the cause. I tried using the same tsconfig and package versions. Currently, the key difference is that the test project doesn't use SvelteKitPWA.

from template project: iShot_2024-09-16_22 04 55

from ICPanda, import.meta.url appears: iShot_2024-09-16_22 04 23

zensh commented 2 months ago

It's clear that if the await import in the agent-js source code is removed, there won't be any issues.

peterpeterparker commented 2 months ago

import.meta.url

Oh yeah we had that issue in Oisy too - i.e. import.meta is incompatible with web workers. To overcome the issue we pass the variable to the web worker (UI -> web worker through postMessage) and then pay attention to use those values instead of import.meta in any piece of code used by the workers.

Did you check if import.meta.url is injected by agent-js or your code?

zensh commented 2 months ago

import.meta.url

Oh yeah we had that issue in Oisy too - i.e. import.meta is incompatible with web workers. To overcome the issue we pass the variable to the web worker (UI -> web worker through postMessage) and then pay attention to use those values instead of import.meta in any piece of code used by the workers.

Did you check if import.meta.url is injected by agent-js or your code?

It is injected by agent-js:

image image
peterpeterparker commented 2 months ago

Are you using use-auth-client? The only reference in src I find about import.meta is in its demo.

That would explain why we do not face the issue in Oisy.

zensh commented 2 months ago

We use agent-js in service worker to fetch latest data for notifications, some code like this:

/// <reference lib="webworker" />
import { cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute } from 'workbox-precaching'
import { NavigationRoute, registerRoute } from 'workbox-routing'
import {
  HttpAgent,
} from '@dfinity/agent'

declare let self: ServiceWorkerGlobalScope

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING')
    self.skipWaiting()
})

// self.__WB_MANIFEST is the default injection point
precacheAndRoute(self.__WB_MANIFEST)

// clean old assets
cleanupOutdatedCaches()

let allowlist: RegExp[] | undefined
// in dev mode, we disable precaching to avoid caching issues
if (import.meta.env.DEV)
  allowlist = [/^\/$/]

// to allow work offline
registerRoute(new NavigationRoute(
  createHandlerBoundToURL('index.html'),
  { allowlist },
))

console.log('Service worker is active.')

const agent = new HttpAgent({ host: 'https://ic0.app' })

async function testLoop() {
  while (true) {
    await agent.syncTime()
    console.log('@dfinity/agent', 'syncTime')
    await new Promise((resolve) => setTimeout(resolve, 10000))
  }
}

testLoop()
peterpeterparker commented 2 months ago

Weird, I’m a bit out of ideas...

peterpeterparker commented 2 months ago

In which of your repo are you facing the issue? Can I give it a try?

peterpeterparker commented 2 months ago

I spent last hour trying to reproduce the issue with your repo, but I'm having trouble loading the SW. I try to mock and remove some data to achieve the goal but, always ends facing some issue with bundling. I'll stop here for now, but if you're able to reproduce the issue with a sample repo, I'd be happy to give it another try.

zensh commented 2 months ago

Sorry to take up your time @peterpeterparker

I’ve created a test project that can reproduce the issue. It’s confirmed that after introducing SvelteKit, the service-worker.js generated during the build contains the import.meta.url snippet from agent-js.

I’m not sure what configuration causes this issue. My current workaround is to delete the await import line in @dfinity/agent within the local node_modules before building.

This seems to be a specific issue and it’s probably not worth taking more of your time to diagnose it. Merging #931 should fully resolve it.

Working branch:

git clone https://github.com/zensh/agent-sw
cd agent-sw
pnpm i
pnpm build
pnpm preview

Branch with the issue after introducing SvelteKit:

git checkout feat/kit
pnpm i
pnpm dev // and then stop to generate the .svelte-kit directory
pnpm build
pnpm preview
peterpeterparker commented 2 months ago

Thanks, @zensh, for the repo. I can reproduce the issue as well and couldn't find any configuration option to resolve it.

While the issue is not addressed yet, I may have a workaround to suggest. Instead of letting the bundler pick the appropriate module, you can try forcing the import to point to cjs. Based on my quick test, this seems to avoid the issue. Of course, it's not a clean solution, and the worker might be too heavy because of this, but I thought I'd share it in case it helps unblock you.

import { HttpAgent } from '@dfinity/agent/lib/cjs'

As for your PR, I can't say for sure and still unsure about the root cause. I also don't collaborate to agent-js, just jumped in because I use worker in Oisy Wallet or Juno. I guess @krpeacock, who's currently on PTO, will take a look when they return.