Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion plugin/src/helpers/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import path from 'path'

import { existsSync, readdirSync } from 'fs-extra'

import { getGatsbyRoot } from './config'

function getCacheDirs(publish) {
return [publish, normalizedCacheDir(publish)]
}
Expand Down Expand Up @@ -37,5 +39,5 @@ export async function restoreCache({ publish, utils }): Promise<void> {
}

export function normalizedCacheDir(publish: string): string {
return path.normalize(`${publish}/../.cache`)
return path.join(getGatsbyRoot(publish), `.cache`)
}
16 changes: 13 additions & 3 deletions plugin/src/helpers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ export async function spliceConfig({
return fs.writeFile(fileName, out)
}

function loadGatsbyConfig(utils): GatsbyConfig | never {
const gatsbyConfigFile = path.resolve(process.cwd(), 'gatsby-config.js')
function loadGatsbyConfig({ utils, publish }): GatsbyConfig | never {
const gatsbyConfigFile = path.resolve(
getGatsbyRoot(publish),
'gatsby-config.js',
)
if (!existsSync(gatsbyConfigFile)) {
return {}
}
Expand All @@ -64,7 +67,10 @@ function hasPlugin(plugins: PluginRef[], pluginName: string): boolean {

export function checkGatsbyConfig({ utils, netlifyConfig }): void {
// warn if gatsby-plugin-netlify is missing
const gatsbyConfig = loadGatsbyConfig(utils)
const gatsbyConfig = loadGatsbyConfig({
utils,
publish: netlifyConfig.build.publish,
})

if (!hasPlugin(gatsbyConfig.plugins, 'gatsby-plugin-netlify')) {
console.error(
Expand Down Expand Up @@ -152,3 +158,7 @@ export function shouldSkipFunctions(cacheDir: string): boolean {

return false
}

export function getGatsbyRoot(publish: string): string {
return path.resolve(path.dirname(publish))
}
27 changes: 17 additions & 10 deletions plugin/src/helpers/functions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import process from 'process'

import { NetlifyPluginConstants } from '@netlify/build'
import { copy, copyFile, ensureDir, existsSync, rm, writeFile } from 'fs-extra'
import { resolve, join, relative } from 'pathe'

import { makeHandler } from '../templates/handlers'
import { makeApiHandler, makeHandler } from '../templates/handlers'

import { getGatsbyRoot } from './config'

const writeFunction = async ({
renderMode,
Expand All @@ -21,12 +21,22 @@ const writeFunction = async ({
)
}

const writeApiFunction = async ({ appDir, functionDir }) => {
const source = makeApiHandler(appDir)
// This is to ensure we're copying from the compiled js, not ts source
await copy(
join(__dirname, '..', '..', 'lib', 'templates', 'api'),
functionDir,
)
await writeFile(join(functionDir, '__api.js'), source)
}

export const writeFunctions = async ({
INTERNAL_FUNCTIONS_SRC,
PUBLISH_DIR,
}: NetlifyPluginConstants): Promise<void> => {
const siteRoot = resolve(process.cwd(), PUBLISH_DIR, '..')
const functionDir = join(process.cwd(), INTERNAL_FUNCTIONS_SRC, '__api')
const siteRoot = getGatsbyRoot(PUBLISH_DIR)
const functionDir = resolve(INTERNAL_FUNCTIONS_SRC, '__api')
const appDir = relative(functionDir, siteRoot)

await writeFunction({
Expand All @@ -43,17 +53,14 @@ export const writeFunctions = async ({
functionsSrc: INTERNAL_FUNCTIONS_SRC,
})

await copy(
join(__dirname, '..', '..', 'lib', 'templates', 'api'),
functionDir,
)
await writeApiFunction({ appDir, functionDir })
}

export const deleteFunctions = async ({
INTERNAL_FUNCTIONS_SRC,
}: NetlifyPluginConstants): Promise<void> => {
for (const func of ['__api', '__ssr', '__dsg']) {
const funcDir = join(process.cwd(), INTERNAL_FUNCTIONS_SRC, func)
const funcDir = resolve(INTERNAL_FUNCTIONS_SRC, func)
if (existsSync(funcDir)) {
await rm(funcDir, { recursive: true, force: true })
}
Expand Down
2 changes: 1 addition & 1 deletion plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export async function onPreBuild({
netlifyConfig,
}): Promise<void> {
// Print a helpful message if the publish dir is misconfigured
if (!PUBLISH_DIR || process.cwd() === PUBLISH_DIR) {
if (!PUBLISH_DIR || process.cwd() === path.resolve(PUBLISH_DIR)) {
utils.build.failBuild(
`Gatsby sites must publish the "public" directory, but your site’s publish directory is set to “${PUBLISH_DIR}”. Please set your publish directory to your Gatsby site’s "public" directory.`,
)
Expand Down
33 changes: 0 additions & 33 deletions plugin/src/templates/api/__api.ts

This file was deleted.

16 changes: 5 additions & 11 deletions plugin/src/templates/api/gatsbyFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ export async function gatsbyFunction(
req: AugmentedGatsbyFunctionRequest,
res: AugmentedGatsbyFunctionResponse,
event: HandlerEvent,
appDir: string,
) {
const functionsDir = path.join(appDir, '.cache', 'functions')

// Multipart form data middleware. because co-body can't handle it
await new Promise((resolve) => {
// As we're using a fake Express handler we need to ignore the type to keep multer happy
Expand All @@ -47,7 +50,7 @@ export async function gatsbyFunction(

let functions
try {
functions = require('../../../.cache/functions/manifest.json')
functions = require(path.join(functionsDir, 'manifest.json'))
} catch {
return {
statusCode: 404,
Expand Down Expand Up @@ -91,16 +94,7 @@ export async function gatsbyFunction(
// During develop, the absolute path is correct, otherwise we need to use a relative path, as we're in a lambda
const pathToFunction = process.env.NETLIFY_DEV
? functionObj.absoluteCompiledFilePath
: path.join(
__dirname,
'..',
'..',
'..',
// ...We got there in the end
'.cache',
'functions',
functionObj.relativeCompiledFilePath,
)
: path.join(functionsDir, functionObj.relativeCompiledFilePath)

if (process.env.NETLIFY_DEV && !existsSync(pathToFunction)) {
// Functions are sometimes lazily-compiled, so we check and proxy the request if needed
Expand Down
46 changes: 44 additions & 2 deletions plugin/src/templates/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { Handler, HandlerEvent } from '@netlify/functions'
import type {
Handler,
HandlerContext,
HandlerEvent,
HandlerResponse,
} from '@netlify/functions'
import { stripIndent as javascript } from 'common-tags'
import type { GatsbyFunctionRequest } from 'gatsby'
import type {
Expand All @@ -14,6 +19,8 @@ const { join } = require('path')

const etag = require('etag')

const { gatsbyFunction } = require('./api/gatsbyFunction')
const { createRequestObject, createResponseObject } = require('./api/utils')
const {
getPagePathFromPageDataPath,
getGraphQLEngine,
Expand Down Expand Up @@ -127,6 +134,32 @@ const getHandler = (renderMode: RenderMode, appDir: string): Handler => {
}
}

/**
* Generate an API handler
*/

const getApiHandler = (appDir: string): Handler =>
function handler(
event: HandlerEvent,
context: HandlerContext,
): Promise<HandlerResponse> {
// Create a fake Gatsby/Express Request object
const req = createRequestObject({ event, context })

return new Promise((resolve) => {
// Create a stubbed Gatsby/Express Response object
// onResEnd is the "resolve" cb for this Promise
const res = createResponseObject({ onResEnd: resolve })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this line be put inside the try block? Just in case it throws.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ehmicky Good spot!

try {
// Try to call the actual function
gatsbyFunction(req, res, event, appDir)
} catch (error) {
console.error(`Error executing ${event.path}`, error)
resolve({ statusCode: 500 })
}
})
}

export const makeHandler = (appDir: string, renderMode: RenderMode): string =>
// This is a string, but if you have the right editor plugin it should format as js
javascript`
Expand All @@ -141,6 +174,15 @@ export const makeHandler = (appDir: string, renderMode: RenderMode): string =>
? `builder((${getHandler.toString()})("${renderMode}", pageRoot))`
: `((${getHandler.toString()})("${renderMode}", pageRoot))`
}
`

export const makeApiHandler = (appDir: string): string =>
// This is a string, but if you have the right editor plugin it should format as js
javascript`
const { gatsbyFunction } = require('./gatsbyFunction')
const { createRequestObject, createResponseObject } = require('./utils')
const { resolve } = require("path");

const pageRoot = resolve(__dirname, "${appDir}");
exports.handler = ((${getApiHandler.toString()})(pageRoot))
`
getHandler.toString()