<script type=worker>: the worker element

The <script type=worker> element holds the code of a worker: a fetch() handler that answers requests for your page. The playground joins the text of every worker script and runs it in the service worker of the output, so a page and its API develop together. With the edge attribute, the script is also deployed to RTEdge.net as the worker of your route.

Try it

html
<iframe src=:hello></iframe>
<script type=worker edge>
  export default {
    fetch: request => new Response(`Hello from ${new URL(request.url).pathname}`)
  }
</script>

The iframe asks for :hello. The worker sees /hello and answers Hello from /hello. In the playground, GET / always returns your page, and the : prefix reaches the worker for any path, the root included, in the playground and on RTEdge.net. See Calling the worker.

Attributes

This element includes the global attributes. The attributes below control how the worker runs. edge, fetch, io:host and io:fail are read from the first worker script only, so put them there; the copies on later worker scripts are ignored.

type

Must be worker. Browsers do not execute this type, so the element stays an inert part of the output document.

edge

A boolean attribute, accepted with any value. It deploys the script to RTEdge.net as the worker of the route. Worker scripts without edge run only in the playground, and a deployment with no edge script has no worker. In the playground, edge does not change how the code runs: edge and non-edge scripts run together.

fetch Deprecated Playground only

The name of the top-level binding that is the handler of a classic-script worker. The default is response. Use export default { fetch } instead; see the legacy form.

io:host Playground only

A space-separated list of hosts whose requests from the output the worker answers, usually to mock a third-party API. * means every host. RTEdge.net ignores it. See Mocking third-party APIs.

io:fail Playground only

What happens when the worker fails. open forwards the original request to the network. Any other value, or no value, is closed, the default. RTEdge.net ignores it. See Failing open or closed.

io:guest

Keeps the source of the deployment public. A deployment with an edge worker has a private source, which only you, your editors and io:user permits may open with ?. The source stays public only if every edge script carries io:guest and nothing else restricts it. See io:guest.

io:user

A list of email addresses, domains or * that may open the source with ?. It is read from every edge script. See io:user.

copy:redact Playground only

An editor feature: the script is masked in the editor, and copying it puts a REDACTED comment on the clipboard. It has no effect on a deployment: the element is served as you wrote it. See copy:redact.

pure Experimental

A boolean attribute that keeps edits to this script from reloading the output. The edit patches the page only, and the service worker keeps the old code until the next full load.

Note: pure is experimental and may change.

src

Never read. Worker code cannot be loaded from a file: write it inside the element, and use static imports for libraries.

Content

JavaScript text and no child elements. The text of every worker script is one program, whether the script has edge or not: the playground joins them with a newline, in document order. A worker script nested inside a <template> is not found.

Usage notes

Several worker scripts are one program

Because the scripts are joined, they must still parse and compile as one program. In particular, two export default statements, even in two different scripts, break every request: only the last one is rewritten as the handler, and the first stays an export statement, which the worker cannot run. Keep one handler, and make the first worker script the edge script.

On RTEdge.net, only the edge scripts are merged, in document order, into the worker of the route. The edge value and the fetch attribute come from the first edge script, while io:user permits are collected from all of them.

In the playground

On RTEdge.net

The rest of the deployed runtime is in The edge worker runtime.

Pitfalls

Examples

An API called from the page

Requests made with fetch() keep their method, headers and query. request.rt.code is true in the playground.

html
<pre id=api></pre>
<script type=module>
  api.textContent = JSON.stringify(await fetch(':api/now?tz=UTC').then(r => r.json()), null, 2)
</script>
<script type=worker edge>
  export default {
    fetch: async request => {
      const { pathname, searchParams } = new URL(request.url)
      if (pathname !== '/api/now') return new Response('Not found', { status: 404 })
      return Response.json({ now: new Date().toISOString(), tz: searchParams.get('tz'), playground: request.rt.code === true })
    }
  }
</script>

A playground-only mock

Without edge, the script runs only in the playground. io:host sends the requests for api.example.com to it, and returning nothing lets other requests reach the real host.

html
<pre id=profile></pre>
<script type=module>
  profile.textContent = JSON.stringify(await fetch('https://api.example.com/v1/users/7').then(r => r.json()))
</script>
<script type=worker io:host=api.example.com>
  export default {
    fetch: async request => {
      const { pathname } = new URL(request.url)
      if (pathname.startsWith('/v1/users/')) return Response.json({ id: +pathname.split('/').at(-1), name: 'Ada' })
    }
  }
</script>

A worker with a public source

With io:guest, anyone can open the source of the deployment with ?, provided no io:user or edge:user restricts it. Without it, an edge worker makes the source private.

html
<iframe src=:x></iframe>
<script type=worker edge io:guest>
  export default { fetch: r => new Response(r.url) }
</script>

Technical summary

Permitted contentJavaScript text only, no child elements. Usually export default { fetch }.
Read fromThe playground input: every script[type=worker] in document order, except those inside a <template>. Their textContent is joined with a newline. src is never read.
Deployed HTMLBlanked: every <script type=worker> is replaced by line breaks. Only the edge scripts become the worker of the route.
Applies inThe playground (all worker scripts) and RTEdge.net (edge scripts).
DOM interfaceHTMLScriptElement. Browsers do not run the type worker.

Specifications

Not part of any specification. <script type=worker> is an RTCode.io and RTEdge.net feature. It builds on a script element with an unknown type, which browsers treat as a data block and do not run, on service workers in the playground, and on the Cloudflare Workers runtime on RTEdge.net.

Availability

FeaturePlaygroundRTEdge.netNotes
<script type=worker edge>YesYesDeployed as the worker of the route.
<script type=worker> without edgeYesNoBlanked from the deployed page and not deployed.
io:host, io:failYesNoRTEdge.net ignores them.
fetch attributeYesNoDeprecated.
io:guest, io:userNoYesRead at deploy. The playground does not enforce access rules.
copy:redactYesNoAn editor feature.
pureYesNoExperimental.

See also