mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
feat(nitro): server assets (#83)
This commit is contained in:
parent
31f06e9f69
commit
babb70a4bd
@ -7,6 +7,7 @@ import { tryImport, resolvePath, detectTarget, extendPreset } from './utils'
|
||||
import * as PRESETS from './presets'
|
||||
import type { NodeExternalsOptions } from './rollup/plugins/externals'
|
||||
import type { StorageOptions } from './rollup/plugins/storage'
|
||||
import type { AssetOptions } from './rollup/plugins/assets'
|
||||
import type { ServerMiddleware } from './server/middleware'
|
||||
|
||||
export interface NitroContext {
|
||||
@ -34,6 +35,7 @@ export interface NitroContext {
|
||||
publicDir: string
|
||||
}
|
||||
storage: StorageOptions,
|
||||
assets: AssetOptions,
|
||||
_nuxt: {
|
||||
majorVersion: number
|
||||
dev: boolean
|
||||
@ -88,6 +90,10 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
||||
publicDir: '{{ output.dir }}/public'
|
||||
},
|
||||
storage: { mounts: { } },
|
||||
assets: {
|
||||
inline: !nuxtOptions.dev,
|
||||
dirs: {}
|
||||
},
|
||||
_nuxt: {
|
||||
majorVersion: nuxtOptions._majorVersion || 2,
|
||||
dev: nuxtOptions.dev,
|
||||
@ -148,6 +154,11 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
||||
}
|
||||
}
|
||||
|
||||
// Assets
|
||||
nitroContext.assets.dirs.server = {
|
||||
dir: resolve(nitroContext._nuxt.rootDir, 'server/assets'), meta: true
|
||||
}
|
||||
|
||||
// console.log(nitroContext)
|
||||
// process.exit(1)
|
||||
|
||||
|
@ -21,6 +21,7 @@ import { externals } from './plugins/externals'
|
||||
import { timing } from './plugins/timing'
|
||||
import { autoMock } from './plugins/automock'
|
||||
import { staticAssets, dirnames } from './plugins/static'
|
||||
import { assets } from './plugins/assets'
|
||||
import { middleware } from './plugins/middleware'
|
||||
import { esbuild } from './plugins/esbuild'
|
||||
import { raw } from './plugins/raw'
|
||||
@ -81,8 +82,10 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
||||
prefix = 'nuxt'
|
||||
} else if (lastModule.startsWith(nitroContext._internal.runtimeDir)) {
|
||||
prefix = 'nitro'
|
||||
} else if (!prefix && nitroContext.middleware.find(m => lastModule.startsWith(m.handle))) {
|
||||
} else if (!prefix && nitroContext.middleware.find(m => lastModule.startsWith(m.handle as string))) {
|
||||
prefix = 'middleware'
|
||||
} else if (lastModule.includes('assets')) {
|
||||
prefix = 'assets'
|
||||
}
|
||||
return join('chunks', prefix, '[name].js')
|
||||
},
|
||||
@ -148,7 +151,11 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
||||
}
|
||||
}))
|
||||
|
||||
// Assets
|
||||
rollupConfig.plugins.push(assets(nitroContext.assets))
|
||||
|
||||
// Static
|
||||
// TODO: use assets plugin
|
||||
if (nitroContext.serveStatic) {
|
||||
rollupConfig.plugins.push(dirnames())
|
||||
rollupConfig.plugins.push(staticAssets(nitroContext))
|
||||
|
103
packages/nitro/src/rollup/plugins/assets.ts
Normal file
103
packages/nitro/src/rollup/plugins/assets.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { readFile, stat } from 'fs/promises'
|
||||
import type { Plugin } from 'rollup'
|
||||
import createEtag from 'etag'
|
||||
import mime from 'mime'
|
||||
import { resolve } from 'upath'
|
||||
import globby from 'globby'
|
||||
import virtual from './virtual'
|
||||
|
||||
export interface AssetOptions {
|
||||
inline: Boolean
|
||||
dirs: {
|
||||
[assetdir: string]: {
|
||||
dir: string
|
||||
meta?: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function assets (opts: AssetOptions): Plugin {
|
||||
type 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
|
||||
}
|
||||
`
|
||||
|
||||
if (!opts.inline) {
|
||||
return virtual({
|
||||
'~nitro/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)
|
||||
}
|
||||
`
|
||||
})
|
||||
}
|
||||
|
||||
return virtual({
|
||||
'~nitro/assets': {
|
||||
async load () {
|
||||
const assets: Record<string, Asset> = {}
|
||||
for (const assetdir in opts.dirs) {
|
||||
const dirOpts = opts.dirs[assetdir]
|
||||
const files = globby.sync('**/*.*', { 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) {
|
||||
let type = mime.getType(id) || 'text/plain'
|
||||
if (type.startsWith('text')) { type += '; charset=utf-8' }
|
||||
const etag = createEtag(await readFile(fsPath))
|
||||
const mtime = await stat(fsPath).then(s => s.mtime.toJSON())
|
||||
assets[id].meta = { type, etag, mtime }
|
||||
}
|
||||
}
|
||||
}
|
||||
const inlineAssets = `const assets = {\n${Object.keys(assets).map(id =>
|
||||
` ['${id}']: {\n read: () => import('${assets[id].fsPath}'),\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]
|
||||
}`
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
@ -12,30 +12,32 @@ export function middleware (getMiddleware: () => ServerMiddleware[]) {
|
||||
let lastDump = ''
|
||||
|
||||
return virtual({
|
||||
'~serverMiddleware': () => {
|
||||
const middleware = getMiddleware()
|
||||
'~serverMiddleware': {
|
||||
load: () => {
|
||||
const middleware = getMiddleware()
|
||||
|
||||
if (!stdenv.test) {
|
||||
const dumped = dumpMiddleware(middleware)
|
||||
if (dumped !== lastDump) {
|
||||
lastDump = dumped
|
||||
if (middleware.length) {
|
||||
console.log(dumped)
|
||||
if (!stdenv.test) {
|
||||
const dumped = dumpMiddleware(middleware)
|
||||
if (dumped !== lastDump) {
|
||||
lastDump = dumped
|
||||
if (middleware.length) {
|
||||
console.log(dumped)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `
|
||||
${middleware.filter(m => m.lazy === false).map(m => `import ${getImportId(m.handle)} from '${m.handle}';`).join('\n')}
|
||||
|
||||
${middleware.filter(m => m.lazy !== false).map(m => `const ${getImportId(m.handle)} = () => import('${m.handle}');`).join('\n')}
|
||||
|
||||
const middleware = [
|
||||
${middleware.map(m => `{ route: '${m.route}', handle: ${getImportId(m.handle)}, lazy: ${m.lazy || true}, promisify: ${m.promisify !== undefined ? m.promisify : true} }`).join(',\n')}
|
||||
];
|
||||
|
||||
export default middleware
|
||||
`
|
||||
}
|
||||
|
||||
return `
|
||||
${middleware.filter(m => m.lazy === false).map(m => `import ${getImportId(m.handle)} from '${m.handle}';`).join('\n')}
|
||||
|
||||
${middleware.filter(m => m.lazy !== false).map(m => `const ${getImportId(m.handle)} = () => import('${m.handle}');`).join('\n')}
|
||||
|
||||
const middleware = [
|
||||
${middleware.map(m => `{ route: '${m.route}', handle: ${getImportId(m.handle)}, lazy: ${m.lazy || true}, promisify: ${m.promisify !== undefined ? m.promisify : true} }`).join(',\n')}
|
||||
];
|
||||
|
||||
export default middleware
|
||||
`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -13,7 +13,10 @@ export function raw (opts: RawOptions = {}): Plugin {
|
||||
name: 'raw',
|
||||
transform (code, id) {
|
||||
if (id[0] !== '\0' && extensions.has(extname(id))) {
|
||||
return `// ${id}\nexport default ${JSON.stringify(code)}`
|
||||
return {
|
||||
code: `// ${id}\nexport default ${JSON.stringify(code)}`,
|
||||
map: null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,21 +3,21 @@ import * as path from 'path'
|
||||
|
||||
import { Plugin } from 'rollup'
|
||||
|
||||
type UnresolvedModule = string | (() => string)
|
||||
type VirtualModule = string | { load: () => string | Promise<string> }
|
||||
|
||||
export interface RollupVirtualOptions {
|
||||
[id: string]: UnresolvedModule;
|
||||
[id: string]: VirtualModule;
|
||||
}
|
||||
|
||||
const PREFIX = '\0virtual:'
|
||||
|
||||
const resolveModule = (m: UnresolvedModule) => typeof m === 'function' ? m() : m
|
||||
|
||||
export default function virtual (modules: RollupVirtualOptions): Plugin {
|
||||
const resolvedIds = new Map<string, string |(() => string)>()
|
||||
const _modules = new Map<string, VirtualModule>()
|
||||
|
||||
Object.keys(modules).forEach((id) => {
|
||||
resolvedIds.set(path.resolve(id), modules[id])
|
||||
})
|
||||
for (const [id, mod] of Object.entries(modules)) {
|
||||
_modules.set(id, mod)
|
||||
_modules.set(path.resolve(id), mod)
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'virtual',
|
||||
@ -30,20 +30,29 @@ export default function virtual (modules: RollupVirtualOptions): Plugin {
|
||||
? importer.slice(PREFIX.length)
|
||||
: importer
|
||||
const resolved = path.resolve(path.dirname(importerNoPrefix), id)
|
||||
if (resolvedIds.has(resolved)) { return PREFIX + resolved }
|
||||
if (_modules.has(resolved)) { return PREFIX + resolved }
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
|
||||
load (id) {
|
||||
if (!id.startsWith(PREFIX)) {
|
||||
return null
|
||||
}
|
||||
async load (id) {
|
||||
if (!id.startsWith(PREFIX)) { return null }
|
||||
|
||||
const idNoPrefix = id.slice(PREFIX.length)
|
||||
return idNoPrefix in modules
|
||||
? resolveModule(modules[idNoPrefix])
|
||||
: resolveModule(resolvedIds.get(idNoPrefix))
|
||||
if (!_modules.has(idNoPrefix)) { return null }
|
||||
|
||||
let m = _modules.get(idNoPrefix)
|
||||
if (typeof m !== 'string' && typeof m.load === 'function') {
|
||||
m = await m.load()
|
||||
}
|
||||
|
||||
// console.log('[virtual]', idNoPrefix, '\n', m)
|
||||
|
||||
return {
|
||||
code: m as string,
|
||||
map: null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user