diff --git a/packages/nitro/src/presets/azure.ts b/packages/nitro/src/presets/azure.ts new file mode 100644 index 0000000000..14bd9f4ced --- /dev/null +++ b/packages/nitro/src/presets/azure.ts @@ -0,0 +1,117 @@ +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 { prettyPath, writeFile } from '../utils' +import { SigmaPreset, SigmaContext } from '../context' + +export const azure: SigmaPreset = { + inlineChunks: false, + 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) + + return { + files, + metadata + } +} + +function zipDirectory (dir: string, outfile: string): Promise { + const archive = archiver('zip', { zlib: { level: 9 } }) + const stream = createWriteStream(outfile) + + return new Promise((resolve, reject) => { + archive + .directory(dir, false) + .on('error', (err: Error) => reject(err)) + .pipe(stream) + + stream.on('close', () => resolve(undefined)) + archive.finalize() + }) +} + +async function writeRoutes ({ output: { dir, serverDir } }: SigmaContext) { + const host = { + version: '2.0', + extensions: { http: { routePrefix: '' } } + } + + const functionDefinition = { + entryPoint: 'handle', + bindings: [ + { + authLevel: 'anonymous', + type: 'httpTrigger', + direction: 'in', + name: 'req', + route: '{*url}', + methods: [ + 'delete', + 'get', + 'head', + 'options', + 'patch', + 'post', + 'put' + ] + }, + { + type: 'http', + direction: 'out', + name: 'res' + } + ] + } + + await writeFile(resolve(serverDir, 'function.json'), JSON.stringify(functionDefinition)) + await writeFile(resolve(dir, 'host.json'), JSON.stringify(host)) + + await zipDirectory(dir, join(dir, 'deploy.zip')) + const zipPath = prettyPath(resolve(dir, 'deploy.zip')) + + consola.success(`Ready to run \`az functionapp deployment source config-zip -g -n --src ${zipPath}\``) +} diff --git a/packages/nitro/src/presets/index.ts b/packages/nitro/src/presets/index.ts index be1e44a1a7..ea589398c8 100644 --- a/packages/nitro/src/presets/index.ts +++ b/packages/nitro/src/presets/index.ts @@ -1,3 +1,4 @@ +export * from './azure' export * from './browser' export * from './cloudflare' export * from './lambda'