Skip to content

Commit 15b20a5

Browse files
authored
feat: add azure functions preset (#45)
1 parent 6e06711 commit 15b20a5

2 files changed

Lines changed: 118 additions & 0 deletions

File tree

src/presets/azure.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import replace from '@rollup/plugin-replace'
2+
import archiver from 'archiver'
3+
import consola from 'consola'
4+
import createEtag from 'etag'
5+
import { createWriteStream, readdirSync, readFileSync, statSync } from 'fs-extra'
6+
import mime from 'mime'
7+
import { join, relative, resolve } from 'upath'
8+
9+
import { prettyPath, writeFile } from '../utils'
10+
import { SigmaPreset, SigmaContext } from '../context'
11+
12+
export const azure: SigmaPreset = {
13+
inlineChunks: false,
14+
entry: '{{ _internal.runtimeDir }}/entries/azure',
15+
hooks: {
16+
'sigma:rollup:before' (ctx: SigmaContext) {
17+
const manifest = JSON.stringify(getStaticManifest(ctx)).replace(/\\"/g, '\\\\"')
18+
ctx.rollupConfig.plugins.push(replace({
19+
values: {
20+
'process.env.STATIC_MANIFEST': `\`${manifest}\``
21+
}
22+
}))
23+
},
24+
async 'sigma:compiled' (ctx: SigmaContext) {
25+
await writeRoutes(ctx)
26+
}
27+
}
28+
}
29+
30+
function getStaticManifest ({ output: { dir } }: SigmaContext) {
31+
const files = []
32+
const staticRoot = resolve(dir, 'public')
33+
34+
const addFiles = (directory: string) => {
35+
const listing = readdirSync(directory)
36+
listing.forEach((filename) => {
37+
const fullPath = resolve(directory, filename)
38+
if (statSync(fullPath).isDirectory()) {
39+
return addFiles(fullPath)
40+
}
41+
files.push('/' + relative(staticRoot, fullPath))
42+
})
43+
}
44+
45+
addFiles(staticRoot)
46+
const metadata = files.reduce((metadata, filename) => {
47+
let mimeType = mime.getType(filename) || 'text/plain'
48+
if (mimeType.startsWith('text')) {
49+
mimeType += '; charset=utf-8'
50+
}
51+
const etag = createEtag(readFileSync(join(staticRoot, filename)))
52+
metadata[filename] = [mimeType, etag]
53+
return metadata
54+
}, {} as Record<string, string>)
55+
56+
return {
57+
files,
58+
metadata
59+
}
60+
}
61+
62+
function zipDirectory (dir: string, outfile: string): Promise<undefined> {
63+
const archive = archiver('zip', { zlib: { level: 9 } })
64+
const stream = createWriteStream(outfile)
65+
66+
return new Promise((resolve, reject) => {
67+
archive
68+
.directory(dir, false)
69+
.on('error', (err: Error) => reject(err))
70+
.pipe(stream)
71+
72+
stream.on('close', () => resolve(undefined))
73+
archive.finalize()
74+
})
75+
}
76+
77+
async function writeRoutes ({ output: { dir, serverDir } }: SigmaContext) {
78+
const host = {
79+
version: '2.0',
80+
extensions: { http: { routePrefix: '' } }
81+
}
82+
83+
const functionDefinition = {
84+
entryPoint: 'handle',
85+
bindings: [
86+
{
87+
authLevel: 'anonymous',
88+
type: 'httpTrigger',
89+
direction: 'in',
90+
name: 'req',
91+
route: '{*url}',
92+
methods: [
93+
'delete',
94+
'get',
95+
'head',
96+
'options',
97+
'patch',
98+
'post',
99+
'put'
100+
]
101+
},
102+
{
103+
type: 'http',
104+
direction: 'out',
105+
name: 'res'
106+
}
107+
]
108+
}
109+
110+
await writeFile(resolve(serverDir, 'function.json'), JSON.stringify(functionDefinition))
111+
await writeFile(resolve(dir, 'host.json'), JSON.stringify(host))
112+
113+
await zipDirectory(dir, join(dir, 'deploy.zip'))
114+
const zipPath = prettyPath(resolve(dir, 'deploy.zip'))
115+
116+
consola.success(`Ready to run \`az functionapp deployment source config-zip -g <resource-group> -n <app-name> --src ${zipPath}\``)
117+
}

src/presets/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './azure'
12
export * from './browser'
23
export * from './cloudflare'
34
export * from './lambda'

0 commit comments

Comments
 (0)