cloudflare / cloudflare/workers-sdk

Workers & Routes & SPAs - assets not resolving

Open
#9,885 7 comments 1 reaction 0 assignees View on GitHub
feature:workers-assets package:vite-plugin
Dominant language
TypeScript
Stars
4.5k
Forks
1.5k
Avg merge
3d 8h
Merged PRs (30d)
186

Description

### What versions & operating system are you using?

Node 22, wrangler4.22, viteplugin: 1.7.5

### Please provide a link to a minimal reproduction

_No response_

### Describe the Bug

I have a worker, using Vite plugin, and it is bound to route: `*.domain.com/auth/*`. Note the sub-path, that's the key issue here.

In vite, my base is set to : /auth/

wrangler asset config:

```
"assets": {
"not_found_handling": "single-page-application",
"run_worker_first": ["/auth/api/*"],
"html_handling": "drop-trailing-slash"
},
```

My dist folder after build:
```
├── auth_svc
│ ├── assets
│ │ ├── bun-sqlite-dialect-BA34DVYO.js
│ │ ├── index-DS8CXNKO.js
│ │ └── server.edge-CMi7F8Zj.js
│ ├── index.js
│ └── wrangler.json
└── client
├── assets
│ ├── index-C6_7OQDu.js
│ └── etc....
├── images
│ └── favicon.ico
├── index.html
└── manifest.json
```

Cloudflare will correctly invoke my worker only when the route matches, ie, a url with `/auth/*`, however, the app is "mounted" at the root `/`, which creates a conflict that is tricky to solve.

With the config above, we get:
✅ curl test.domain.com/auth/login - OK - returns index.html page
✅ curl test.domain.com/auth/api - OK, worker gets invoked successfully
❓ the index.html file has the following:
- public urls: ``
- chunks: ``
❌ curl https://test.domain.com/auth/images/favicon.ico - returns index.html ( from public folder)
❌ curl https://test.domain.com/auth/assets/index-C6_7OQDu.js - returns index.html page (bundled assets)

The requests fail because the files are actually not under `/auth`, but under `/`. the `dist/client` folder is mounted to `/`.

We can proove this by

## Attempt 1
.. adding this to the vite config:
```
build: {
assetsDir: 'auth/assets'
}
```

now, `dist` builds like this:
```
./dist
├── auth_svc
│   └── auth
│   └── assets
└── client
├── auth
│   └── assets
└── images
```
and these now work:
https://test.domain.com/auth/images/favicon.ico
https://test.domain.com/auth/assets/index-C6_7OQDu.js

but we have a different problem; the index.html page has bad URLs:
- public URLs are OK: `<link rel="icon" href="/auth/images/favicon.ico" />`
- chunks are not: `<script type="module" crossorigin src="/auth/auth/assets/index-C6_7OQDu.js" />`

## Attempt 2
Another attempt to fix this with Vite is using an experimental config that gives you full control over the URLs generated:

```
build: {
assetsDir: 'auth/assets'
},
experimental: {
renderBuiltUrl(filename, { hostId, hostType, type }) {
if (type === 'public') {
return `/auth/${filename}`;
}
return `/${filename}`;
},
},
```
This produces:
- ✅ file system ( dist/client/auth )
- ❌ public import URLS:
` <link rel="apple-touch-icon" sizes="180x180" href="/auth/images/apple-touch-icon.png">`
- ✅ chunk import URLS

We could fix this by editing the original index.html and hard coding the /auth prefix there, but not clean.

## Attempt 3
Looking deeper into the plugin code, at how it builds the output paths:
https://github.com/cloudflare/workers-sdk/blob/main/packages/vite-plugin-cloudflare/src/utils.ts#L10-L20
We can see that maybe we can set the outDir for the environment:

```
environments: {
client: {
build: {
outDir: 'dist/client/auth/'
}
}
},
```
This gives us:
- ✅ file system ( dist/client/auth )
- ✅ public imports (they start with /auth), ex: ` <link rel="icon" href="/auth/images/favicon.ico" />`
- ✅ chunk imports (start with /auth/assets) ex: <script type="module" crossorigin src="/auth/assets/index-C6_7OQDu.js">
but..
- ❌ wrong `assets.directory` in the generated wrangler config: ` "directory": "../client/auth"`.

The wrangler assets.directory should've remained `../client` to make everything work.

## TLDR
There is no clean way to align the following:
- Vite `base` setting
- Vite build folder structure
- Wrangler assets.directory

IMO, the correct thing to do would be to have the Vite plugin respect the `base` config, and append that to the build output, but keep the assets.directory as `client`

### Please provide any relevant error logs

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.