-
Notifications
You must be signed in to change notification settings - Fork 253
/
generate.ts
64 lines (57 loc) · 2.39 KB
/
generate.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { createWriteStream } from 'fs'
import { promisify } from 'util'
import stream from 'stream'
import { mkdirp } from 'fs-extra'
import { dirname, join, relative, basename, trimExt } from 'upath'
import fetch from 'node-fetch'
import { joinURL, hasProtocol, parseURL, withoutTrailingSlash } from 'ufo'
import pLimit from 'p-limit'
import { ModuleOptions, MapToStatic, ResolvedImage } from './types'
import { hash, logger, guessExt } from './utils'
const pipeline = promisify(stream.pipeline)
export function setupStaticGeneration (nuxt: any, options: ModuleOptions) {
const staticImages: Record<string, string> = {} // url ~> hashed file name
nuxt.hook('vue-renderer:ssr:prepareContext', (renderContext: any) => {
renderContext.image = renderContext.image || {}
renderContext.image.mapToStatic = <MapToStatic> function ({ url, format }: ResolvedImage, input: string) {
if (!staticImages[url]) {
const { pathname } = parseURL(input)
const params: any = {
name: trimExt(basename(pathname)),
ext: (format && `.${format}`) || guessExt(input),
hash: hash(url),
// TODO: pass from runtimeConfig to mapStatic as param
publicPath: nuxt.options.app.cdnURL ? '/' : withoutTrailingSlash(nuxt.options.build.publicPath)
}
staticImages[url] = options.staticFilename.replace(/\[(\w+)]/g, (match, key) => params[key] || match)
}
return joinURL(nuxt.options.app.cdnURL || nuxt.options.app.basePath, staticImages[url])
}
})
nuxt.hook('generate:done', async () => {
const limit = pLimit(8)
const downloads = Object.entries(staticImages).map(([url, name]) => {
if (!hasProtocol(url)) {
url = joinURL(options.internalUrl, url)
}
return limit(() => downloadImage({
url,
name,
outDir: nuxt.options.generate.dir
}))
})
await Promise.all(downloads)
})
}
async function downloadImage ({ url, name, outDir }: { url: string, name: string, outDir: string }) {
try {
const response = await fetch(url)
if (!response.ok) { throw new Error(`Unexpected response ${response.statusText}`) }
const dstFile = join(outDir, name)
await mkdirp(dirname(dstFile))
await pipeline(response.body, createWriteStream(dstFile))
logger.success('Generated static image ' + relative(process.cwd(), dstFile))
} catch (error) {
logger.error(error.message)
}
}