Skip to content

Commit 7d4f3ea

Browse files
committed
chore: use v4 compat. in playground
chore: cleanup playground chore: export server utils subpackage instead using nitro imports
1 parent c6ca138 commit 7d4f3ea

File tree

15 files changed

+382
-356
lines changed

15 files changed

+382
-356
lines changed

package.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,19 @@
2525
"types": "./dist/types.d.mts",
2626
"default": "./dist/module.mjs"
2727
},
28+
"./server-utils": {
29+
"types": "./dist/runtime/server/utils.d.ts",
30+
"default": "./dist/runtime/server/utils.js"
31+
},
2832
"./package.json": "./package.json"
2933
},
3034
"main": "./dist/module.mjs",
3135
"types": "./dist/types.d.ts",
36+
"typesVersions": {
37+
"*": {
38+
"server-utils": ["./dist/runtime/server/utils.d.ts"]
39+
}
40+
},
3241
"files": [
3342
"dist"
3443
],
@@ -44,10 +53,10 @@
4453
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
4554
},
4655
"dependencies": {
47-
"@nuxt/kit": "^3.13.2",
4856
"detect-browser-es": "^0.1.1"
4957
},
5058
"devDependencies": {
59+
"@nuxt/kit": "^3.13.2",
5160
"@nuxt/devtools": "^1.5.0",
5261
"@nuxt/eslint-config": "^0.5.7",
5362
"@nuxt/module-builder": "^0.8.4",
@@ -62,6 +71,9 @@
6271
"vitest": "^2.1.1",
6372
"vue-tsc": "^2.1.6"
6473
},
74+
"build": {
75+
"externals": ["h3"]
76+
},
6577
"stackblitz": {
6678
"installDependencies": false,
6779
"startCommand": "pnpm install && pnpm dev:prepare && pnpm dev"
File renamed without changes.

playground/modules/image.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { addDevServerHandler, defineNuxtModule } from '@nuxt/kit'
2+
3+
export default defineNuxtModule({
4+
async setup(_, nuxt) {
5+
if (nuxt.options.dev) {
6+
addDevServerHandler({
7+
route: '',
8+
handler: await import('../server/dev-image').then(m => m.default),
9+
})
10+
}
11+
else {
12+
nuxt.hook('nitro:build:before', async (nitro) => {
13+
nitro.options.handlers.unshift({
14+
route: '',
15+
handler: '~~/server/image',
16+
middleware: true,
17+
})
18+
})
19+
}
20+
},
21+
})

playground/nuxt.config.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import DevImage from './server/dev-image'
2-
31
export default defineNuxtConfig({
42
compatibilityDate: '2024-10-11',
53
devtools: { enabled: true },
64
modules: ['../src/module'],
75

6+
future: {
7+
compatibilityVersion: 4,
8+
},
9+
810
httpClientHints: {
911
detectBrowser: true,
1012
detectOS: 'windows-11',
@@ -20,17 +22,17 @@ export default defineNuxtConfig({
2022
},
2123

2224
nitro: {
23-
handlers: [
25+
/* handlers: [
2426
{
2527
middleware: true,
2628
// route: '',
27-
handler: '~/server/image',
29+
handler: './server/image',
2830
},
29-
],
30-
devHandlers: [{
31+
], */
32+
/* devHandlers: [{
3133
route: '',
3234
handler: DevImage,
33-
}],
35+
}], */
3436
},
3537

3638
})

playground/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
},
1010
"dependencies": {
1111
"nuxt": "^3.13.2",
12-
"nuxt-http-client-hints": "workspace:*",
1312
"sharp": "^0.33.5"
1413
},
1514
"devDependencies": {

playground/server/dev-image.ts

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,71 @@
11
import { lstat, readFile } from 'node:fs/promises'
22
import { resolve } from 'node:path'
3-
import { eventHandler } from 'h3'
4-
import { useNitro } from '@nuxt/kit'
3+
import { Readable } from 'node:stream'
4+
import { lazyEventHandler, eventHandler, sendStream } from 'h3'
55
import sharp from 'sharp'
6-
import type { HttpClientHintsState } from '../../src/runtime/shared-types/types'
7-
import { extractHTTPClientHints } from './utils/image'
6+
import { useNitro } from '@nuxt/kit'
7+
import { extractImageClientHints } from '../../src/runtime/server/utils'
8+
import type { ResolvedHttpClientHintsOptions, ServerHttpClientHintsOptions } from '../../src/runtime/server/utils'
89

9-
export default eventHandler(async (event) => {
10-
console.log('dev-image:', event.path)
11-
await extractHTTPClientHints(event)
12-
const httpClientHintsState: HttpClientHintsState | undefined = event.context.httpClientHints
13-
const { widthAvailable = false, width = -1 } = httpClientHintsState?.critical ?? {}
14-
if (widthAvailable && width > -1) {
15-
const image = await convertImage(event.path, width)
16-
if (image) {
17-
console.log('dev-image:Sec-CH-Width:', width)
18-
event.node.res.setHeader('Vary', 'Sec-CH-Width')
19-
event.node.res.end(image)
20-
}
10+
export default lazyEventHandler(async () => {
11+
const nitroOptions = useNitro().options
12+
const {
13+
serverImages,
14+
...rest
15+
} = nitroOptions.appConfig.httpClientHints as ServerHttpClientHintsOptions
16+
const options: ResolvedHttpClientHintsOptions = {
17+
...rest,
18+
serverImages: serverImages.map(r => new RegExp(r)),
2119
}
22-
})
2320

24-
async function convertImage(path: string, width: number) {
25-
if (path.startsWith('/')) {
26-
path = path.slice(1)
27-
}
28-
const nitro = useNitro()
29-
const folders = nitro.options.publicAssets
30-
let image: string
31-
for (const folder of folders) {
32-
try {
33-
console.log(folder.dir)
34-
image = resolve(folder.dir, path)
35-
const stats = await lstat(image)
36-
if (stats.isFile()) {
37-
return sharp(await readFile(image)).resize({ width }).toBuffer()
21+
return eventHandler(async (event) => {
22+
console.log('dev-image', event.path)
23+
const clientHints = await extractImageClientHints(event, options)
24+
console.log('dev-image', event.path, clientHints?.httpClientHints.critical)
25+
if (clientHints) {
26+
const {
27+
widthAvailable = false,
28+
width = -1,
29+
} = clientHints.httpClientHints.critical ?? {}
30+
if (widthAvailable && width > -1) {
31+
const image = await convertImage(event.path, width)
32+
if (image) {
33+
console.log('dev-image:Sec-CH-Width:', width)
34+
event.node.res.setHeader('Vary', 'Sec-CH-Width')
35+
return sendStream(event, Readable.from(image))
36+
}
37+
}
38+
}
39+
})
40+
async function convertImage(path: string, width: number) {
41+
/* try {
42+
const image = await readAsset(path)
43+
if (image) {
44+
return await sharp(image).resize({ width }).toBuffer()
45+
}
46+
}
47+
catch {
48+
// just ignore
49+
}
50+
51+
// return undefined */
52+
if (path.startsWith('/')) {
53+
path = path.slice(1)
54+
}
55+
const folders = nitroOptions.publicAssets
56+
let image: string
57+
for (const folder of folders) {
58+
try {
59+
console.log(folder.dir)
60+
image = resolve(folder.dir, path)
61+
const stats = await lstat(image)
62+
if (stats.isFile()) {
63+
return await sharp(await readFile(image)).resize({ width }).toBuffer()
64+
}
65+
}
66+
catch {
67+
// just ignore
3868
}
3969
}
40-
catch (_) {}
4170
}
42-
}
71+
})

playground/server/image.ts

Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,83 @@
1-
import { useAppConfig } from 'nitropack/runtime'
2-
import { parseUserAgent } from 'detect-browser-es'
3-
import type {
4-
HttpClientHintsState,
5-
ResolvedHttpClientHintsOptions,
6-
ServerHttpClientHintsOptions,
7-
} from '../../src/runtime/shared-types/types'
8-
import { extractBrowser } from '../../src/runtime/utils/detect'
9-
import { extractDeviceHints } from '../../src/runtime/utils/device'
10-
import { extractNetworkHints } from '../../src/runtime/utils/network'
11-
import { extractCriticalHints } from '../../src/runtime/utils/critical'
1+
import { lstat, readFile } from 'node:fs/promises'
2+
import { resolve } from 'node:path'
3+
import { Readable } from 'node:stream'
4+
import { fileURLToPath } from 'node:url'
5+
import { lazyEventHandler, eventHandler, sendStream } from 'h3'
6+
import sharp from 'sharp'
7+
import { extractImageClientHints } from '../../src/runtime/server/utils'
8+
import type { ResolvedHttpClientHintsOptions, ServerHttpClientHintsOptions } from '../../src/runtime/server/utils'
9+
// import { readAsset } from '#internal/nitro/virtual/public-assets-data'
1210

13-
export default defineEventHandler(async (event) => {
14-
console.log('request', useAppConfig().httpClientHints)
11+
export default lazyEventHandler(() => {
12+
const appConfig = useAppConfig()
13+
const nitroApp = useNitroApp()
1514
const {
1615
serverImages,
1716
...rest
18-
} = useAppConfig().httpClientHints as ServerHttpClientHintsOptions
17+
} = appConfig.httpClientHints as ServerHttpClientHintsOptions
1918
const options: ResolvedHttpClientHintsOptions = {
2019
...rest,
2120
serverImages: serverImages.map(r => new RegExp(r)),
2221
}
23-
const critical = !!options.critical
24-
const device = options.device.length > 0
25-
const network = options.network.length > 0
26-
const detect = options.detectOS || options.detectBrowser || options.userAgent.length > 0
2722

28-
try {
29-
// expose the client hints in the context
30-
const url = event.path
31-
console.log('request', { url, match: options.serverImages?.some(r => url.match(r)) })
32-
if (options.serverImages?.some(r => url.match(r))) {
33-
const userAgentHeader = event.headers.get('user-agent')
34-
const requestHeaders: { [key in Lowercase<string>]?: string } = {}
35-
for (const [key, value] of event.headers.entries()) {
36-
requestHeaders[key.toLowerCase() as Lowercase<string>] = value
37-
}
38-
const userAgent = userAgentHeader
39-
? parseUserAgent(userAgentHeader)
40-
: null
41-
const clientHints: HttpClientHintsState = {}
42-
if (detect) {
43-
clientHints.browser = await extractBrowser(options, requestHeaders as Record<string, string>, userAgentHeader ?? undefined)
44-
}
45-
if (device) {
46-
clientHints.device = extractDeviceHints(options, requestHeaders, userAgent)
23+
const publicFolder = resolve(fileURLToPath(import.meta.url), '../../public')
24+
25+
const handler = eventHandler(async (event) => {
26+
console.log('dev-image', event.path)
27+
const clientHints = await extractImageClientHints(event, options)
28+
console.log('dev-image', event.path, clientHints?.httpClientHints.critical)
29+
if (clientHints) {
30+
const {
31+
widthAvailable = false,
32+
width = -1,
33+
} = clientHints.httpClientHints.critical ?? {}
34+
if (widthAvailable && width > -1) {
35+
const image = await convertImage(event.path, width)
36+
if (image) {
37+
console.log('dev-image:Sec-CH-Width:', width)
38+
event.node.res.setHeader('Vary', 'Sec-CH-Width')
39+
return sendStream(event, Readable.from(image))
40+
}
4741
}
48-
if (network) {
49-
clientHints.network = extractNetworkHints(options, requestHeaders, userAgent)
42+
}
43+
})
44+
45+
async function convertImage(path: string, width: number) {
46+
/* try {
47+
const image = await readAsset(path)
48+
if (image) {
49+
return await sharp(image).resize({ width }).toBuffer()
5050
}
51-
if (critical) {
52-
clientHints.critical = extractCriticalHints(options, requestHeaders, userAgent)
51+
}
52+
catch (e) {
53+
// just ignore
54+
console.error('WTF', e)
55+
} */
56+
57+
// return undefined
58+
if (path.startsWith('/')) {
59+
path = path.slice(1)
60+
}
61+
// const folders = appConfig.publicAssets
62+
// let image: string
63+
// for (const folder of folders) {
64+
try {
65+
const image = resolve(publicFolder, path)
66+
const stats = await lstat(image)
67+
if (stats.isFile()) {
68+
return await sharp(await readFile(image)).resize({ width }).toBuffer()
5369
}
54-
event.context.httpClientHintsOptions = options
55-
event.context.httpClientHints = clientHints
70+
}
71+
catch {
72+
// just ignore
5673
}
5774
}
58-
catch (err) {
59-
console.error(err)
60-
}
75+
// }
76+
77+
nitroApp.h3App.stack.unshift({
78+
route: '',
79+
handler,
80+
})
81+
82+
return eventHandler(() => {})
6183
})

0 commit comments

Comments
 (0)