mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 09:25:54 +00:00
feat: serveStatic (#47)
This commit is contained in:
parent
b010e83008
commit
a9b9d19e66
@ -24,6 +24,7 @@ export interface SigmaContext {
|
||||
preset: string
|
||||
rollupConfig?: any
|
||||
renderer: string
|
||||
serveStatic: boolean
|
||||
middleware: ServerMiddleware[]
|
||||
hooks: configHooksT
|
||||
nuxtHooks: configHooksT
|
||||
@ -72,6 +73,7 @@ export function getsigmaContext (nuxtOptions: NuxtOptions, input: SigmaInput): S
|
||||
preset: undefined,
|
||||
rollupConfig: undefined,
|
||||
renderer: undefined,
|
||||
serveStatic: false,
|
||||
middleware: [],
|
||||
ignore: [],
|
||||
env: {},
|
||||
|
@ -1,64 +1,21 @@
|
||||
import replace from '@rollup/plugin-replace'
|
||||
import archiver from 'archiver'
|
||||
import consola from 'consola'
|
||||
import createEtag from 'etag'
|
||||
import { createWriteStream, readdirSync, readFileSync, statSync } from 'fs-extra'
|
||||
import mime from 'mime'
|
||||
import { join, relative, resolve } from 'upath'
|
||||
|
||||
import { createWriteStream } from 'fs-extra'
|
||||
import { join, resolve } from 'upath'
|
||||
import { prettyPath, writeFile } from '../utils'
|
||||
import { SigmaPreset, SigmaContext } from '../context'
|
||||
|
||||
export const azure: SigmaPreset = {
|
||||
inlineChunks: false,
|
||||
serveStatic: true,
|
||||
entry: '{{ _internal.runtimeDir }}/entries/azure',
|
||||
hooks: {
|
||||
'sigma:rollup:before' (ctx: SigmaContext) {
|
||||
const manifest = JSON.stringify(getStaticManifest(ctx)).replace(/\\"/g, '\\\\"')
|
||||
ctx.rollupConfig.plugins.push(replace({
|
||||
values: {
|
||||
'process.env.STATIC_MANIFEST': `\`${manifest}\``
|
||||
}
|
||||
}))
|
||||
},
|
||||
async 'sigma:compiled' (ctx: SigmaContext) {
|
||||
await writeRoutes(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getStaticManifest ({ output: { dir } }: SigmaContext) {
|
||||
const files = []
|
||||
const staticRoot = resolve(dir, 'public')
|
||||
|
||||
const addFiles = (directory: string) => {
|
||||
const listing = readdirSync(directory)
|
||||
listing.forEach((filename) => {
|
||||
const fullPath = resolve(directory, filename)
|
||||
if (statSync(fullPath).isDirectory()) {
|
||||
return addFiles(fullPath)
|
||||
}
|
||||
files.push('/' + relative(staticRoot, fullPath))
|
||||
})
|
||||
}
|
||||
|
||||
addFiles(staticRoot)
|
||||
const metadata = files.reduce((metadata, filename) => {
|
||||
let mimeType = mime.getType(filename) || 'text/plain'
|
||||
if (mimeType.startsWith('text')) {
|
||||
mimeType += '; charset=utf-8'
|
||||
}
|
||||
const etag = createEtag(readFileSync(join(staticRoot, filename)))
|
||||
metadata[filename] = [mimeType, etag]
|
||||
return metadata
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
return {
|
||||
files,
|
||||
metadata
|
||||
}
|
||||
}
|
||||
|
||||
function zipDirectory (dir: string, outfile: string): Promise<undefined> {
|
||||
const archive = archiver('zip', { zlib: { level: 9 } })
|
||||
const stream = createWriteStream(outfile)
|
||||
|
@ -7,7 +7,8 @@ export const server: SigmaPreset = extendPreset(node, {
|
||||
entry: '{{ _internal.runtimeDir }}/entries/server',
|
||||
externals: false,
|
||||
inlineChunks: false,
|
||||
timing: true,
|
||||
serveStatic: true,
|
||||
minify: false,
|
||||
hooks: {
|
||||
'sigma:compiled' ({ output }: SigmaContext) {
|
||||
consola.success('Ready to run', hl('node ' + prettyPath(output.serverDir)))
|
||||
|
@ -12,15 +12,16 @@ import analyze from 'rollup-plugin-analyzer'
|
||||
import type { Preset } from '@nuxt/un'
|
||||
import * as un from '@nuxt/un'
|
||||
|
||||
import hasha from 'hasha'
|
||||
import { SigmaContext } from '../context'
|
||||
import { resolvePath, MODULE_DIR } from '../utils'
|
||||
|
||||
import { dynamicRequire } from './dynamic-require'
|
||||
import { externals } from './externals'
|
||||
import { timing } from './timing'
|
||||
import { autoMock } from './automock'
|
||||
import esbuild from './esbuild'
|
||||
import { dynamicRequire } from './plugins/dynamic-require'
|
||||
import { externals } from './plugins/externals'
|
||||
import { timing } from './plugins/timing'
|
||||
import { autoMock } from './plugins/automock'
|
||||
import { staticAssets } from './plugins/static'
|
||||
import { middleware } from './plugins/middleware'
|
||||
import { esbuild } from './plugins/esbuild'
|
||||
|
||||
export type RollupConfig = InputOptions & { output: OutputOptions }
|
||||
|
||||
@ -125,28 +126,17 @@ export const getRollupConfig = (sigmaContext: SigmaContext) => {
|
||||
}
|
||||
}))
|
||||
|
||||
// https://github.com/rollup/plugins/tree/master/packages/replace
|
||||
// TODO: better fix for node-fetch issue
|
||||
rollupConfig.plugins.push(replace({
|
||||
delimiters: ['', ''],
|
||||
values: {
|
||||
'require(\'encoding\')': '{}'
|
||||
}
|
||||
}))
|
||||
// Static
|
||||
if (sigmaContext.serveStatic) {
|
||||
rollupConfig.plugins.push(staticAssets(sigmaContext))
|
||||
}
|
||||
|
||||
// Provide serverMiddleware
|
||||
const getImportId = p => '_' + hasha(p).substr(0, 6)
|
||||
rollupConfig.plugins.push(virtual({
|
||||
'~serverMiddleware': `
|
||||
${sigmaContext.middleware.filter(m => m.lazy === false).map(m => `import ${getImportId(m.handle)} from '${m.handle}';`).join('\n')}
|
||||
|
||||
${sigmaContext.middleware.filter(m => m.lazy !== false).map(m => `const ${getImportId(m.handle)} = () => import('${m.handle}');`).join('\n')}
|
||||
|
||||
export default [
|
||||
${sigmaContext.middleware.map(m => `{ route: '${m.route}', handle: ${getImportId(m.handle)}, lazy: ${m.lazy || true}, promisify: ${m.promisify !== undefined ? m.promisify : true} }`).join(',\n')}
|
||||
];
|
||||
`
|
||||
}))
|
||||
// Middleware
|
||||
const _middleware = [...sigmaContext.middleware]
|
||||
if (sigmaContext.serveStatic) {
|
||||
_middleware.unshift({ route: '/', handle: '~runtime/server/static' })
|
||||
}
|
||||
rollupConfig.plugins.push(middleware(_middleware))
|
||||
|
||||
// Polyfill
|
||||
rollupConfig.plugins.push(virtual({
|
||||
|
@ -34,7 +34,7 @@ export type Options = {
|
||||
}
|
||||
}
|
||||
|
||||
export default (options: Options = {}): Plugin => {
|
||||
export function esbuild (options: Options = {}): Plugin {
|
||||
let target: string | string[]
|
||||
|
||||
const loaders = {
|
21
packages/nitro/src/rollup/plugins/middleware.ts
Normal file
21
packages/nitro/src/rollup/plugins/middleware.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import hasha from 'hasha'
|
||||
import virtual from '@rollup/plugin-virtual'
|
||||
import type { ServerMiddleware } from '../../context'
|
||||
|
||||
export function middleware (middleware: ServerMiddleware[]) {
|
||||
const getImportId = p => '_' + hasha(p).substr(0, 6)
|
||||
|
||||
return virtual({
|
||||
'~serverMiddleware': `
|
||||
${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
|
||||
`
|
||||
})
|
||||
}
|
47
packages/nitro/src/rollup/plugins/static.ts
Normal file
47
packages/nitro/src/rollup/plugins/static.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import createEtag from 'etag'
|
||||
import { readFileSync, statSync } from 'fs-extra'
|
||||
import mime from 'mime'
|
||||
import { relative, resolve } from 'upath'
|
||||
import virtual from '@rollup/plugin-virtual'
|
||||
import globby from 'globby'
|
||||
import type { SigmaContext } from '../../context'
|
||||
|
||||
export function staticAssets (context: SigmaContext) {
|
||||
const assets: Record<string, { type: string, etag: string, mtime: string, path: string }> = {}
|
||||
|
||||
const files = globby.sync('**/*.*', { cwd: context.output.publicDir, absolute: false })
|
||||
|
||||
for (const id of files) {
|
||||
let type = mime.getType(id) || 'text/plain'
|
||||
if (type.startsWith('text')) { type += '; charset=utf-8' }
|
||||
const fullPath = resolve(context.output.publicDir, id)
|
||||
const etag = createEtag(readFileSync(fullPath))
|
||||
const stat = statSync(fullPath)
|
||||
|
||||
assets[id] = {
|
||||
type,
|
||||
etag,
|
||||
mtime: stat.mtime.toJSON(),
|
||||
path: relative(context.output.serverDir, fullPath)
|
||||
}
|
||||
}
|
||||
|
||||
return virtual({
|
||||
'~static-assets': `export default ${JSON.stringify(assets, null, 2)};`,
|
||||
'~static': `
|
||||
import { readFile } from 'fs/promises'
|
||||
import { resolve, dirname } from 'path'
|
||||
import assets from '~static-assets'
|
||||
|
||||
const mainDir = dirname(require.main.filename)
|
||||
|
||||
export function readAsset (id) {
|
||||
return readFile(resolve(mainDir, getAsset(id).path))
|
||||
}
|
||||
|
||||
export function getAsset (id) {
|
||||
return assets[id]
|
||||
}
|
||||
`
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user