mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 13:45:18 +00:00
feat: add support for Azure static web apps (#92)
This commit is contained in:
parent
97efab4270
commit
31a9bc2d18
@ -1,14 +1,16 @@
|
||||
import archiver from 'archiver'
|
||||
import consola from 'consola'
|
||||
import { createWriteStream } from 'fs-extra'
|
||||
import fse from 'fs-extra'
|
||||
import globby from 'globby'
|
||||
import { join, resolve } from 'upath'
|
||||
import { prettyPath, writeFile } from '../utils'
|
||||
import { writeFile } from '../utils'
|
||||
import { NitroPreset, NitroContext } from '../context'
|
||||
|
||||
export const azure: NitroPreset = {
|
||||
inlineChunks: false,
|
||||
serveStatic: true,
|
||||
entry: '{{ _internal.runtimeDir }}/entries/azure',
|
||||
output: {
|
||||
serverDir: '{{ output.dir }}/server/functions'
|
||||
},
|
||||
hooks: {
|
||||
async 'nitro:compiled' (ctx: NitroContext) {
|
||||
await writeRoutes(ctx)
|
||||
@ -16,27 +18,64 @@ export const azure: NitroPreset = {
|
||||
}
|
||||
}
|
||||
|
||||
function zipDirectory (dir: string, outfile: string): Promise<undefined> {
|
||||
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 } }: NitroContext) {
|
||||
async function writeRoutes ({ output: { serverDir, publicDir } }: NitroContext) {
|
||||
const host = {
|
||||
version: '2.0',
|
||||
extensions: { http: { routePrefix: '' } }
|
||||
version: '2.0'
|
||||
}
|
||||
|
||||
const routes = [
|
||||
{
|
||||
route: '/*',
|
||||
serve: '/api/server'
|
||||
}
|
||||
]
|
||||
|
||||
const indexPath = resolve(publicDir, 'index.html')
|
||||
const indexFileExists = fse.existsSync(indexPath)
|
||||
if (!indexFileExists) {
|
||||
routes.unshift(
|
||||
{
|
||||
route: '/',
|
||||
serve: '/api/server'
|
||||
},
|
||||
{
|
||||
route: '/index.html',
|
||||
serve: '/api/server'
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const folderFiles = await globby([
|
||||
join(publicDir, 'index.html'),
|
||||
join(publicDir, '**/index.html')
|
||||
])
|
||||
const prefix = publicDir.length
|
||||
const suffix = '/index.html'.length
|
||||
folderFiles.forEach(file =>
|
||||
routes.unshift({
|
||||
route: file.slice(prefix, -suffix) || '/',
|
||||
serve: file.slice(prefix)
|
||||
})
|
||||
)
|
||||
|
||||
const otherFiles = await globby([join(publicDir, '**/*.html'), join(publicDir, '*.html')])
|
||||
otherFiles.forEach((file) => {
|
||||
if (file.endsWith('index.html')) {
|
||||
return
|
||||
}
|
||||
const route = file.slice(prefix, -5)
|
||||
const existingRouteIndex = routes.findIndex(_route => _route.route === route)
|
||||
if (existingRouteIndex > -1) {
|
||||
routes.splice(existingRouteIndex, 1)
|
||||
}
|
||||
routes.unshift(
|
||||
{
|
||||
route,
|
||||
serve: file.slice(prefix)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const functionDefinition = {
|
||||
entryPoint: 'handle',
|
||||
bindings: [
|
||||
@ -46,15 +85,7 @@ async function writeRoutes ({ output: { dir, serverDir } }: NitroContext) {
|
||||
direction: 'in',
|
||||
name: 'req',
|
||||
route: '{*url}',
|
||||
methods: [
|
||||
'delete',
|
||||
'get',
|
||||
'head',
|
||||
'options',
|
||||
'patch',
|
||||
'post',
|
||||
'put'
|
||||
]
|
||||
methods: ['delete', 'get', 'head', 'options', 'patch', 'post', 'put']
|
||||
},
|
||||
{
|
||||
type: 'http',
|
||||
@ -65,10 +96,11 @@ async function writeRoutes ({ output: { dir, serverDir } }: NitroContext) {
|
||||
}
|
||||
|
||||
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 <resource-group> -n <app-name> --src ${zipPath}\``)
|
||||
await writeFile(resolve(serverDir, '../host.json'), JSON.stringify(host))
|
||||
await writeFile(resolve(publicDir, 'routes.json'), JSON.stringify({ routes }))
|
||||
if (!indexFileExists) {
|
||||
await writeFile(indexPath, '')
|
||||
}
|
||||
|
||||
consola.success('Ready to deploy.')
|
||||
}
|
||||
|
75
packages/nitro/src/presets/azure_functions.ts
Normal file
75
packages/nitro/src/presets/azure_functions.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import archiver from 'archiver'
|
||||
import consola from 'consola'
|
||||
import { createWriteStream } from 'fs-extra'
|
||||
import { join, resolve } from 'upath'
|
||||
import { prettyPath, writeFile } from '../utils'
|
||||
import { NitroPreset, NitroContext } from '../context'
|
||||
|
||||
// eslint-disable-next-line
|
||||
export const azure_functions: NitroPreset = {
|
||||
inlineChunks: false,
|
||||
serveStatic: true,
|
||||
entry: '{{ _internal.runtimeDir }}/entries/azure_functions',
|
||||
hooks: {
|
||||
async 'nitro:compiled' (ctx: NitroContext) {
|
||||
await writeRoutes(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function zipDirectory (dir: string, outfile: string): Promise<undefined> {
|
||||
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 } }: NitroContext) {
|
||||
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 <resource-group> -n <app-name> --src ${zipPath}\``)
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
export * from './azure_functions'
|
||||
export * from './azure'
|
||||
export * from './browser'
|
||||
export * from './cloudflare'
|
||||
|
@ -1,8 +1,17 @@
|
||||
import '~polyfill'
|
||||
import { parseURL } from 'ufo'
|
||||
import { localCall } from '../server'
|
||||
|
||||
export default async function handle (context, req) {
|
||||
const url = '/' + (req.params.url || '')
|
||||
let url: string
|
||||
if (req.headers['x-ms-original-url']) {
|
||||
// This URL has been proxied as there was no static file matching it.
|
||||
url = parseURL(req.headers['x-ms-original-url']).pathname
|
||||
} else {
|
||||
// Because Azure SWA handles /api/* calls differently they
|
||||
// never hit the proxy and we have to reconstitute the URL.
|
||||
url = '/api/' + (req.params.url || '')
|
||||
}
|
||||
|
||||
const { body, status, statusText, headers } = await localCall({
|
||||
url,
|
||||
|
19
packages/nitro/src/runtime/entries/azure_functions.ts
Normal file
19
packages/nitro/src/runtime/entries/azure_functions.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import '~polyfill'
|
||||
import { localCall } from '../server'
|
||||
|
||||
export default async function handle (context, req) {
|
||||
const url = '/' + (req.params.url || '')
|
||||
|
||||
const { body, status, statusText, headers } = await localCall({
|
||||
url,
|
||||
headers: req.headers,
|
||||
method: req.method,
|
||||
body: req.body
|
||||
})
|
||||
|
||||
context.res = {
|
||||
status,
|
||||
headers,
|
||||
body: body ? body.toString() : statusText
|
||||
}
|
||||
}
|
@ -74,6 +74,10 @@ export function detectTarget () {
|
||||
if (process.env.NOW_BUILDER) {
|
||||
return 'vercel'
|
||||
}
|
||||
|
||||
if (process.env.INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN) {
|
||||
return 'azure'
|
||||
}
|
||||
}
|
||||
|
||||
export async function isDirectory (path: string) {
|
||||
|
Loading…
Reference in New Issue
Block a user