This repository has been archived by the owner on Apr 6, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
assets.ts
112 lines (100 loc) · 2.75 KB
/
assets.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { promises as fsp } from 'fs'
import type { Plugin } from 'rollup'
import createEtag from 'etag'
import mime from 'mime'
import { resolve } from 'pathe'
import { globby } from 'globby'
import { genDynamicImport, genObjectFromRawEntries } from 'knitwork'
import virtual from './virtual'
export interface AssetOptions {
inline: boolean
dirs: {
[assetdir: string]: {
dir: string
meta?: boolean
}
}
}
interface Asset {
fsPath: string
meta: {
type?: string
etag?: string
mtime?: string
}
}
export function assets (opts: AssetOptions): Plugin {
if (!opts.inline) {
// Development: Use filesystem
return virtual({ '#assets': getAssetsDev(opts.dirs) })
}
// Production: Bundle assets
return virtual({
'#assets': {
async load () {
// Scan all assets
const assets: Record<string, Asset> = {}
for (const assetdir in opts.dirs) {
const dirOpts = opts.dirs[assetdir]
const files = await globby('**/*.*', { cwd: dirOpts.dir, absolute: false })
for (const _id of files) {
const fsPath = resolve(dirOpts.dir, _id)
const id = assetdir + '/' + _id
assets[id] = { fsPath, meta: {} }
if (dirOpts.meta) {
// @ts-ignore TODO: Use mime@2 types
let type = mime.getType(id) || 'text/plain'
if (type.startsWith('text')) { type += '; charset=utf-8' }
const etag = createEtag(await fsp.readFile(fsPath))
const mtime = await fsp.stat(fsPath).then(s => s.mtime.toJSON())
assets[id].meta = { type, etag, mtime }
}
}
}
return getAssetProd(assets)
}
}
})
}
function getAssetsDev (dirs) {
return `
import { createStorage } from 'unstorage'
import fsDriver from 'unstorage/drivers/fs'
const dirs = ${JSON.stringify(dirs)}
export const assets = createStorage()
for (const [dirname, dirOpts] of Object.entries(dirs)) {
assets.mount(dirname, fsDriver({ base: dirOpts.dir }))
}
`
}
function normalizeKey (key) {
return key.replace(/[/\\]/g, ':').replace(/^:|:$/g, '')
}
function getAssetProd (assets: Record<string, Asset>) {
return `
const _assets = ${genObjectFromRawEntries(
Object.entries(assets).map(([id, asset]) => [normalizeKey(id), {
import: genDynamicImport(asset.fsPath, { interopDefault: true }),
meta: asset.meta
}])
)}
${normalizeKey.toString()}
export const assets = {
getKeys() {
return Object.keys(_assets)
},
hasItem (id) {
id = normalizeKey(id)
return id in _assets
},
getItem (id) {
id = normalizeKey(id)
return _assets[id] ? _assets[id].import() : null
},
getMeta (id) {
id = normalizeKey(id)
return _assets[id] ? _assets[id].meta : {}
}
}
`
}