feat(nitro): assets driver (#511)

This commit is contained in:
pooya parsa 2021-09-08 22:01:21 +02:00 committed by GitHub
parent e363ed5853
commit 820a9d0b57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 98 deletions

View File

@ -64,7 +64,7 @@
"table": "^6.7.1",
"ufo": "^0.7.9",
"unenv": "^0.3.3",
"unstorage": "^0.2.3",
"unstorage": "^0.2.5",
"upath": "^2.0.1",
"vue": "3.2.10",
"vue-bundle-renderer": "^0.3.0",

View File

@ -1,9 +1,9 @@
import { promises as fsp } from 'fs'
import type { Plugin } from 'rollup'
import createEtag from 'etag'
import mime from 'mime'
import { resolve } from 'upath'
import globby from 'globby'
import type { Plugin } from 'rollup'
import virtual from './virtual'
export interface AssetOptions {
@ -16,60 +16,26 @@ export interface AssetOptions {
}
}
export function assets (opts: AssetOptions): Plugin {
type Asset = {
interface Asset {
fsPath: string,
meta: {
type?: string,
etag?: string,
mtime?: string
}
}
const assetUtils = `
export function readAsset (id) {
return getAsset(id).read()
}
export function statAsset (id) {
return getAsset(id).meta
}
`
export function assets (opts: AssetOptions): Plugin {
if (!opts.inline) {
return virtual({
'#assets': `
import { statSync, promises as fsp } from 'fs'
import { resolve } from 'path'
const dirs = ${JSON.stringify(opts.dirs)}
${assetUtils}
export function getAsset (id) {
for (const dirname in dirs) {
if (id.startsWith(dirname + '/')) {
const dirOpts = dirs[dirname]
const path = resolve(dirOpts.dir, id.substr(dirname.length + 1))
let stat = statSync(path)
const asset = {
read: () => fsp.readFile(path, 'utf-8'),
meta: {
mtime: stat.mtime
}
}
return asset
}
}
throw new Error('Asset dir not found: ' + id)
}
`
})
// 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]
@ -88,17 +54,55 @@ export function getAsset (id) {
}
}
}
const inlineAssets = `const assets = {\n${Object.keys(assets).map(id =>
` ['${id}']: {\n read: () => import('${assets[id].fsPath}').then(r => r.default || r),\n meta: ${JSON.stringify(assets[id].meta)}\n }`
).join(',\n')}\n}`
return `${inlineAssets}\n${assetUtils}
export function getAsset (id) {
if (!assets[id]) {
throw new Error('Asset not found : ' + id)
}
return assets[id]
}`
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 = {\n${Object.entries(assets).map(([id, asset]) =>
` ['${normalizeKey(id)}']: {\n import: () => import('${asset.fsPath}').then(r => r.default || r),\n meta: ${JSON.stringify(asset.meta)}\n }`
).join(',\n')}\n}
${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 : {}
}
}
`
}

View File

@ -32,10 +32,14 @@ export function storage (opts: StorageOptions) {
return virtual({
'#storage': `
import { createStorage } from 'unstorage'
import { assets } from '#assets'
${driverImports.map(i => `import ${getImportName(i)} from '${i}'`).join('\n')}
export const storage = createStorage({})
storage.mount('/assets', assets)
${mounts.map(m => `storage.mount('${m.path}', ${getImportName(m.driver)}(${JSON.stringify(m.opts)}))`).join('\n')}
`
})

View File

@ -1,7 +1,6 @@
import type { $Fetch } from 'ohmyfetch'
import type { Storage } from 'unstorage'
declare global {
import type { $Fetch } from 'ohmyfetch'
// eslint-disable-next-line no-var
var $fetch: $Fetch
namespace NodeJS {
@ -12,6 +11,7 @@ declare global {
}
declare module '#storage' {
import type { Storage } from 'unstorage'
export const storage: Storage
}
@ -19,5 +19,7 @@ declare module '#assets' {
export interface AssetMeta { type?: string, etag?: string, mtime?: string }
export function readAsset<T=any>(id: string): Promise<T>
export function statAsset(id: string): Promise<AssetMeta>
export function getAsset<T=any>(id: string): { read: () => Promise<T>, meta: AssetMeta }
export function getKeys() : Promise<string[]>
}
export default {}

View File

@ -1523,7 +1523,7 @@ __metadata:
ufo: ^0.7.9
unbuild: ^0.4.2
unenv: ^0.3.3
unstorage: ^0.2.3
unstorage: ^0.2.5
upath: ^2.0.1
vue: 3.2.10
vue-bundle-renderer: ^0.3.0
@ -4532,7 +4532,7 @@ __metadata:
languageName: node
linkType: hard
"chokidar@npm:3.5.2, chokidar@npm:^3.5.1, chokidar@npm:^3.5.2":
"chokidar@npm:3.5.2, chokidar@npm:^3.5.2":
version: 3.5.2
resolution: "chokidar@npm:3.5.2"
dependencies:
@ -7732,9 +7732,9 @@ fsevents@~2.3.2:
languageName: node
linkType: hard
"ioredis@npm:^4.27.3":
version: 4.27.7
resolution: "ioredis@npm:4.27.7"
"ioredis@npm:^4.27.9":
version: 4.27.9
resolution: "ioredis@npm:4.27.9"
dependencies:
cluster-key-slot: ^1.1.0
debug: ^4.3.1
@ -7747,7 +7747,7 @@ fsevents@~2.3.2:
redis-errors: ^1.2.0
redis-parser: ^3.0.0
standard-as-callback: ^2.1.0
checksum: 42c2f242b3c91202578415dc39fbc9e9ecff58f19acbd91b654cbe12877181e18dbeb6c12b3e71225a7cc928cc4e34f536953375978093c7c1a6f7417a9dfd84
checksum: 0472f20366759fe17c71c42105869dbaba99ad54e3fc14428cd6e1d28f8767ff1aea03bfc0228b29bf6030d7ae1ac856941ab6698c850a9b27fd8a17328e7f9f
languageName: node
linkType: hard
@ -9990,17 +9990,6 @@ fsevents@~2.3.2:
languageName: node
linkType: hard
"ohmyfetch@npm:^0.2.0":
version: 0.2.0
resolution: "ohmyfetch@npm:0.2.0"
dependencies:
destr: ^1.1.0
node-fetch: ^2.6.1
ufo: ^0.6.10
checksum: 58afffe238610d2b8829d1f90949cdc776a0d531cd4b9f88f7d0c4ab82550179b810e9b0e0197212216a1722e630149421b4e2b710fa92ed72fa739c28f935cb
languageName: node
linkType: hard
"ohmyfetch@npm:^0.3.1":
version: 0.3.1
resolution: "ohmyfetch@npm:0.3.1"
@ -13418,14 +13407,7 @@ fsevents@~2.3.2:
languageName: node
linkType: hard
"ufo@npm:^0.6.10":
version: 0.6.11
resolution: "ufo@npm:0.6.11"
checksum: cf73c7f3e62413237cb8b763b2ae39ec9b83a630644a9ceac721c6394c62d562f1d7deb117e7b0c35f5a29a4c88b5e67a8c1ebf0d41543b8acc4c44e5dd607df
languageName: node
linkType: hard
"ufo@npm:^0.7.5, ufo@npm:^0.7.9":
"ufo@npm:^0.7.9":
version: 0.7.9
resolution: "ufo@npm:0.7.9"
checksum: 8a141889382dfe9fe42af625316ea0bc60e287ed81275befa699d3c099af44232720ea7b72d5ea738e4766e79adb8dc901bd7f788f9c2057d0ec2389d9f06df5
@ -13603,21 +13585,21 @@ fsevents@~2.3.2:
languageName: node
linkType: hard
"unstorage@npm:^0.2.3":
version: 0.2.3
resolution: "unstorage@npm:0.2.3"
"unstorage@npm:^0.2.5":
version: 0.2.5
resolution: "unstorage@npm:0.2.5"
dependencies:
anymatch: ^3.1.1
chokidar: ^3.5.1
chokidar: ^3.5.2
destr: ^1.1.0
h3: ^0.2.10
ioredis: ^4.27.3
ioredis: ^4.27.9
listhen: ^0.2.4
mri: ^1.1.6
ohmyfetch: ^0.2.0
ufo: ^0.7.5
ws: ^7.4.5
checksum: 88996f454624a8da10c140f28441376ceee84047bff7aad7c9df7b8bfd8f4768042ce97c63713bad1c5d42c66c1fad367c7e9727b7241260ec75e04350f5b785
ohmyfetch: ^0.3.1
ufo: ^0.7.9
ws: ^8.2.1
checksum: 214042a12eaf4ac9b17ee35058681330f57c7d9570f0e30cb46fd96b9d0952ff73296e6bf43c40162d7f4f86df29b249d2d1df7db0d7c1d9d98b72c2a0b50ed8
languageName: node
linkType: hard
@ -14327,7 +14309,7 @@ fsevents@~2.3.2:
languageName: node
linkType: hard
"ws@npm:^7.3.1, ws@npm:^7.4.5, ws@npm:^7.4.6":
"ws@npm:^7.3.1, ws@npm:^7.4.6":
version: 7.5.3
resolution: "ws@npm:7.5.3"
peerDependencies:
@ -14342,6 +14324,21 @@ fsevents@~2.3.2:
languageName: node
linkType: hard
"ws@npm:^8.2.1":
version: 8.2.1
resolution: "ws@npm:8.2.1"
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
checksum: 22906903c7952790a911627f99e3419d8f251a6a540d9ba4f334a7e0865d7ea7026d8ad23829c3c0f2843a9f15bdb91c646e7f8853a5a5ba25a57dea2cf7d416
languageName: node
linkType: hard
"xml-name-validator@npm:^3.0.0":
version: 3.0.0
resolution: "xml-name-validator@npm:3.0.0"