diff --git a/.changeset/flat-wombats-sneeze.md b/.changeset/flat-wombats-sneeze.md new file mode 100644 index 000000000000..5141bd580c62 --- /dev/null +++ b/.changeset/flat-wombats-sneeze.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +Adds the Content-Type header when serving assets with `wrangler pages dev`. It guesses the mime-type based on the asset's file extension. diff --git a/package-lock.json b/package-lock.json index b2a0aa7e55e3..0d5a274d01ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13452,7 +13452,7 @@ "license": "ISC" }, "packages/wrangler": { - "version": "0.0.5", + "version": "0.0.6", "license": "MIT OR Apache-2.0", "dependencies": { "@cloudflare/pages-functions-compiler": "0.3.8", @@ -13466,6 +13466,7 @@ }, "devDependencies": { "@iarna/toml": "^2.2.5", + "@types/mime": "^2.0.3", "@types/react": "^17.0.37", "@types/serve-static": "^1.13.10", "@types/signal-exit": "^3.0.1", @@ -13483,6 +13484,7 @@ "ink-select-input": "^4.2.1", "ink-table": "^3.0.0", "ink-text-input": "^4.0.2", + "mime": "^3.0.0", "node-fetch": "^3.1.0", "open": "^8.4.0", "path-to-regexp": "^6.2.0", @@ -13502,6 +13504,12 @@ "fsevents": "~2.3.2" } }, + "packages/wrangler/node_modules/@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", + "dev": true + }, "packages/wrangler/node_modules/@types/yargs": { "version": "17.0.7", "integrity": "sha512-OvLKmpKdea1aWtqHv9bxVVcMoT6syAeK+198dfETIFkAevYRGwqh4H+KFxfjUETZuUuE5sQCAFwdOdoHUdo8eg==", @@ -13551,6 +13559,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/wrangler/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "packages/wrangler/node_modules/mimic-fn": { "version": "4.0.0", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", @@ -23249,6 +23269,7 @@ "requires": { "@cloudflare/pages-functions-compiler": "0.3.8", "@iarna/toml": "^2.2.5", + "@types/mime": "^2.0.3", "@types/react": "^17.0.37", "@types/serve-static": "^1.13.10", "@types/signal-exit": "^3.0.1", @@ -23268,6 +23289,7 @@ "ink-select-input": "^4.2.1", "ink-table": "^3.0.0", "ink-text-input": "^4.0.2", + "mime": "^3.0.0", "miniflare": "2.0.0-rc.4", "node-fetch": "^3.1.0", "open": "^8.4.0", @@ -23283,6 +23305,12 @@ "yargs": "^17.3.0" }, "dependencies": { + "@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", + "dev": true + }, "@types/yargs": { "version": "17.0.7", "integrity": "sha512-OvLKmpKdea1aWtqHv9bxVVcMoT6syAeK+198dfETIFkAevYRGwqh4H+KFxfjUETZuUuE5sQCAFwdOdoHUdo8eg==", @@ -23317,6 +23345,12 @@ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, "mimic-fn": { "version": "4.0.0", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index 103ca9bc8e80..4ddb93dc44de 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -46,6 +46,7 @@ }, "devDependencies": { "@iarna/toml": "^2.2.5", + "@types/mime": "^2.0.3", "@types/react": "^17.0.37", "@types/serve-static": "^1.13.10", "@types/signal-exit": "^3.0.1", @@ -63,6 +64,7 @@ "ink-select-input": "^4.2.1", "ink-table": "^3.0.0", "ink-text-input": "^4.0.2", + "mime": "^3.0.0", "node-fetch": "^3.1.0", "open": "^8.4.0", "path-to-regexp": "^6.2.0", diff --git a/packages/wrangler/src/pages.tsx b/packages/wrangler/src/pages.tsx index 4b36d97dd2e5..9385865fcf0c 100644 --- a/packages/wrangler/src/pages.tsx +++ b/packages/wrangler/src/pages.tsx @@ -6,6 +6,7 @@ import { execSync, spawn } from "child_process"; import { Headers, Request, Response } from "undici"; import type { MiniflareOptions } from "miniflare"; import type { RequestInfo, RequestInit } from "undici"; +import { getType } from "mime"; import open from "open"; import { watch } from "chokidar"; @@ -466,12 +467,20 @@ const generateAssetsFetch = async ( if ((asset = getAsset(`${cwd}/404.html`))) { deconstructedResponse.status = 404; deconstructedResponse.body = serveAsset(asset); + deconstructedResponse.headers.set( + "Content-Type", + getType(asset) || "application/octet-stream" + ); return deconstructedResponse; } } if ((asset = getAsset(`/index.html`))) { deconstructedResponse.body = serveAsset(asset); + deconstructedResponse.headers.set( + "Content-Type", + getType(asset) || "application/octet-stream" + ); return deconstructedResponse; } @@ -484,6 +493,10 @@ const generateAssetsFetch = async ( if (url.pathname.endsWith("/")) { if ((asset = getAsset(`${url.pathname}/index.html`))) { deconstructedResponse.body = serveAsset(asset); + deconstructedResponse.headers.set( + "Content-Type", + getType(asset) || "application/octet-stream" + ); return deconstructedResponse; } else if ( (asset = getAsset(`${url.pathname.replace(/\/$/, ".html")}`)) @@ -511,6 +524,10 @@ const generateAssetsFetch = async ( const extensionlessPath = url.pathname.slice(0, -".html".length); if (getAsset(extensionlessPath) || extensionlessPath === "/") { deconstructedResponse.body = serveAsset(asset); + deconstructedResponse.headers.set( + "Content-Type", + getType(asset) || "application/octet-stream" + ); return deconstructedResponse; } else { deconstructedResponse.status = 301; @@ -522,6 +539,10 @@ const generateAssetsFetch = async ( } } else { deconstructedResponse.body = serveAsset(asset); + deconstructedResponse.headers.set( + "Content-Type", + getType(asset) || "application/octet-stream" + ); return deconstructedResponse; } } else if (hasFileExtension(url.pathname)) { @@ -531,6 +552,10 @@ const generateAssetsFetch = async ( if ((asset = getAsset(`${url.pathname}.html`))) { deconstructedResponse.body = serveAsset(asset); + deconstructedResponse.headers.set( + "Content-Type", + getType(asset) || "application/octet-stream" + ); return deconstructedResponse; }