Skip to content

chore: convert remaining source files to TypeScript #939

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"watch": "tsc --watch"
},
"config": {
"eslint": "--cache --format=codeframe --max-warnings=0 \"{src,scripts,tests,.github}/**/*.{js,md,html}\" \"*.{js,md,html}\" \".*.{js,md,html}\"",
"prettier": "--loglevel=warn \"{src,scripts,tests,.github}/**/*.{js,md,yml,json,html}\" \"*.{js,yml,json,html}\" \".*.{js,yml,json,html}\" \"!package-lock.json\""
"eslint": "--cache --format=codeframe --max-warnings=0 \"{src,scripts,tests,.github}/**/*.{ts,js,md,html}\" \"*.{ts,js,md,html}\" \".*.{ts,js,md,html}\"",
"prettier": "--loglevel=warn \"{src,scripts,tests,.github}/**/*.{ts,js,md,yml,json,html}\" \"*.{ts,js,yml,json,html}\" \".*.{ts,js,yml,json,html}\" \"!package-lock.json\""
},
"repository": {
"type": "git",
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export const CATCH_ALL_REGEX = /\/\[\.{3}(.*)](.json)?$/
export const OPTIONAL_CATCH_ALL_REGEX = /\/\[{2}\.{3}(.*)]{2}(.json)?$/
export const DYNAMIC_PARAMETER_REGEX = /\/\[(.*?)]/g
export const MINIMUM_REVALIDATE_SECONDS = 60
// 50MB, which is the documented max, though the hard max seems to be higher
export const LAMBDA_MAX_SIZE = 1024 * 1024 * 50

export const DIVIDER = `
────────────────────────────────────────────────────────────────
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ export const saveCache = async ({ cache, publish }) => {
} else {
console.log('No Next.js cache to save.')
}
}
}
108 changes: 65 additions & 43 deletions src/helpers/files.js → src/helpers/files.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,54 @@
/* eslint-disable max-lines */
const { cpus } = require('os')

const { yellowBright } = require('chalk')
const {
existsSync,
readJson,
move,
copy,
writeJson,
readFile,
writeFile,
ensureDir,
readFileSync,
} = require('fs-extra')
const globby = require('globby')
const { outdent } = require('outdent')
const pLimit = require('p-limit')
const { join } = require('pathe')
const slash = require('slash')

const { MINIMUM_REVALIDATE_SECONDS, DIVIDER } = require('../constants')
import { cpus } from 'os'

import { NetlifyConfig } from '@netlify/build'
import { yellowBright } from 'chalk'
import { existsSync, readJson, move, copy, writeJson, readFile, writeFile, ensureDir, readFileSync } from 'fs-extra'
import globby from 'globby'
import { PrerenderManifest } from 'next/dist/build'
import { Redirect as NextRedirect } from 'next/dist/lib/load-custom-routes'
import { outdent } from 'outdent'
import pLimit from 'p-limit'
import { join } from 'pathe'
import slash from 'slash'

import { MINIMUM_REVALIDATE_SECONDS, DIVIDER } from '../constants'

import { NextConfig } from './config'

interface Redirect extends NextRedirect {
regex: string
internal?: boolean
}

type Rewrites =
| {
fallback?: Array<Redirect>
afterFiles?: Array<Redirect>
beforeFiles?: Array<Redirect>
}
| Array<Redirect>

const TEST_ROUTE = /(|\/)\[[^/]+?](\/|\.html|$)/

const isDynamicRoute = (route) => TEST_ROUTE.test(route)
export const isDynamicRoute = (route) => TEST_ROUTE.test(route)

const stripLocale = (rawPath, locales = []) => {
export const stripLocale = (rawPath: string, locales: Array<string> = []) => {
const [locale, ...segments] = rawPath.split('/')
if (locales.includes(locale)) {
return segments.join('/')
}
return rawPath
}

const matchMiddleware = (middleware, filePath) =>
export const matchMiddleware = (middleware: Array<string>, filePath: string): string | boolean =>
middleware?.includes('') ||
middleware?.find(
(middlewarePath) =>
filePath === middlewarePath || filePath === `${middlewarePath}.html` || filePath.startsWith(`${middlewarePath}/`),
)

const matchesRedirect = (file, redirects) => {
export const matchesRedirect = (file: string, redirects: Rewrites): boolean => {
if (!Array.isArray(redirects)) {
return false
}
Expand All @@ -53,7 +61,7 @@ const matchesRedirect = (file, redirects) => {
})
}

const matchesRewrite = (file, rewrites) => {
export const matchesRewrite = (file: string, rewrites: Rewrites): boolean => {
if (Array.isArray(rewrites)) {
return matchesRedirect(file, rewrites)
}
Expand All @@ -63,14 +71,16 @@ const matchesRewrite = (file, rewrites) => {
return matchesRedirect(file, rewrites.beforeFiles)
}

exports.matchesRedirect = matchesRedirect
exports.matchesRewrite = matchesRewrite
exports.matchMiddleware = matchMiddleware
exports.stripLocale = stripLocale
exports.isDynamicRoute = isDynamicRoute

// eslint-disable-next-line max-lines-per-function
exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
export const moveStaticPages = async ({
netlifyConfig,
target,
i18n,
}: {
netlifyConfig: NetlifyConfig
target: 'server' | 'serverless' | 'experimental-serverless-trace'
Copy link

Choose a reason for hiding this comment

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

[sand] Could have a type for this instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Next might have one actually

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👏🏻
image

i18n: NextConfig['i18n']
}): Promise<void> => {
console.log('Moving static page files to serve from CDN...')
const outputDir = join(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless')
const root = join(outputDir, 'pages')
Expand All @@ -87,12 +97,16 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
}
}

const prerenderManifest = await readJson(join(netlifyConfig.build.publish, 'prerender-manifest.json'))
const { redirects, rewrites } = await readJson(join(netlifyConfig.build.publish, 'routes-manifest.json'))
const prerenderManifest: PrerenderManifest = await readJson(
join(netlifyConfig.build.publish, 'prerender-manifest.json'),
)
const { redirects, rewrites }: { redirects: Array<Redirect>; rewrites: Rewrites } = await readJson(
join(netlifyConfig.build.publish, 'routes-manifest.json'),
)

const isrFiles = new Set()
const isrFiles = new Set<string>()

const shortRevalidateRoutes = []
const shortRevalidateRoutes: Array<{ Route: string; Revalidate: number }> = []

Object.entries(prerenderManifest.routes).forEach(([route, { initialRevalidateSeconds }]) => {
if (initialRevalidateSeconds) {
Expand All @@ -106,8 +120,8 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
}
})

const files = []
const filesManifest = {}
const files: Array<string> = []
const filesManifest: Record<string, string> = {}
const moveFile = async (file) => {
const isData = file.endsWith('.json')
const source = join(root, file)
Expand Down Expand Up @@ -268,7 +282,7 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
}
}

const patchFile = async ({ file, from, to }) => {
const patchFile = async ({ file, from, to }: { file: string; from: string; to: string }): Promise<void> => {
if (!existsSync(file)) {
return
}
Expand Down Expand Up @@ -299,7 +313,7 @@ const getServerFile = (root) => {
return serverFile
}

exports.patchNextFiles = async (root) => {
export const patchNextFiles = async (root: string): Promise<void> => {
const serverFile = getServerFile(root)
console.log(`Patching ${serverFile}`)
if (serverFile) {
Expand All @@ -311,15 +325,23 @@ exports.patchNextFiles = async (root) => {
}
}

exports.unpatchNextFiles = async (root) => {
export const unpatchNextFiles = async (root: string): Promise<void> => {
const serverFile = getServerFile(root)
const origFile = `${serverFile}.orig`
if (existsSync(origFile)) {
await move(origFile, serverFile, { overwrite: true })
}
}

exports.movePublicFiles = async ({ appDir, outdir, publish }) => {
export const movePublicFiles = async ({
appDir,
outdir,
publish,
}: {
appDir: string
outdir?: string
publish: string
}): Promise<void> => {
// `outdir` is a config property added when using Next.js with Nx. It's typically
// a relative path outside of the appDir, e.g. '../../dist/apps/<app-name>', and
// the parent directory of the .next directory.
Expand Down
55 changes: 38 additions & 17 deletions src/helpers/verification.js → src/helpers/verification.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
const { existsSync, promises } = require('fs')
const path = require('path')
const { relative } = require('path')
import { existsSync, promises } from 'fs'
import path, { relative } from 'path'

const { yellowBright, greenBright, blueBright, redBright, reset } = require('chalk')
const { async: StreamZip } = require('node-stream-zip')
const outdent = require('outdent')
const prettyBytes = require('pretty-bytes')
const { satisfies } = require('semver')
import { NetlifyPluginUtils } from '@netlify/build'
import { yellowBright, greenBright, blueBright, redBright, reset } from 'chalk'
import { async as StreamZip } from 'node-stream-zip'
import { outdent } from 'outdent'
import prettyBytes from 'pretty-bytes'
import { satisfies } from 'semver'

import { LAMBDA_MAX_SIZE } from '../constants'

// This is when nft support was added
const REQUIRED_BUILD_VERSION = '>=18.16.0'

exports.verifyNetlifyBuildVersion = ({ IS_LOCAL, NETLIFY_BUILD_VERSION, failBuild }) => {
type FailBuild = NetlifyPluginUtils['build']['failBuild']

export const verifyNetlifyBuildVersion = ({
IS_LOCAL,
NETLIFY_BUILD_VERSION,
failBuild,
}: {
IS_LOCAL: boolean
NETLIFY_BUILD_VERSION: string
failBuild: FailBuild
}): void | never => {
// We check for build version because that's what's available to us, but prompt about the cli because that's what they can upgrade
if (IS_LOCAL && !satisfies(NETLIFY_BUILD_VERSION, REQUIRED_BUILD_VERSION, { includePrerelease: true })) {
return failBuild(outdent`
Expand All @@ -21,7 +33,7 @@ exports.verifyNetlifyBuildVersion = ({ IS_LOCAL, NETLIFY_BUILD_VERSION, failBuil
}
}

exports.checkForOldFunctions = async ({ functions }) => {
export const checkForOldFunctions = async ({ functions }: Pick<NetlifyPluginUtils, 'functions'>): Promise<void> => {
const allOldFunctions = await functions.list()
const oldFunctions = allOldFunctions.filter(({ name }) => name.startsWith('next_'))
if (oldFunctions.length !== 0) {
Expand All @@ -41,7 +53,13 @@ exports.checkForOldFunctions = async ({ functions }) => {
}
}

exports.checkNextSiteHasBuilt = ({ publish, failBuild }) => {
export const checkNextSiteHasBuilt = ({
publish,
failBuild,
}: {
publish: string
failBuild: FailBuild
}): void | never => {
if (!existsSync(path.join(publish, 'BUILD_ID'))) {
return failBuild(outdent`
The directory "${path.relative(
Expand All @@ -61,7 +79,13 @@ exports.checkNextSiteHasBuilt = ({ publish, failBuild }) => {
}
}

exports.checkForRootPublish = ({ publish, failBuild }) => {
export const checkForRootPublish = ({
publish,
failBuild,
}: {
publish: string
failBuild: FailBuild
}): void | never => {
if (path.resolve(publish) === path.resolve('.')) {
failBuild(outdent`
Your publish directory is pointing to the base directory of your site. This is not supported for Next.js sites, and is probably a mistake.
Expand All @@ -70,10 +94,7 @@ exports.checkForRootPublish = ({ publish, failBuild }) => {
}
}

// 50MB, which is the documented max, though the hard max seems to be higher
const LAMBDA_MAX_SIZE = 1024 * 1024 * 50

exports.checkZipSize = async (file, maxSize = LAMBDA_MAX_SIZE) => {
export const checkZipSize = async (file: string, maxSize: number = LAMBDA_MAX_SIZE): Promise<void> => {
if (!existsSync(file)) {
console.warn(`Could not check zip size because ${file} does not exist`)
return
Expand Down Expand Up @@ -111,7 +132,7 @@ exports.checkZipSize = async (file, maxSize = LAMBDA_MAX_SIZE) => {
)
}

exports.logBetaMessage = () =>
export const logBetaMessage = () =>
console.log(
greenBright(
outdent`
Expand Down
38 changes: 24 additions & 14 deletions src/index.js → src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
const { join, relative } = require('path')

const { ODB_FUNCTION_NAME } = require('./constants')
const { restoreCache, saveCache } = require('./helpers/cache')
const { getNextConfig, configureHandlerFunctions } = require('./helpers/config')
const { moveStaticPages, movePublicFiles, patchNextFiles, unpatchNextFiles } = require('./helpers/files')
const { generateFunctions, setupImageFunction, generatePagesResolver } = require('./helpers/functions')
const { generateRedirects } = require('./helpers/redirects')
const {
import { join, relative } from 'path'

import { NetlifyPlugin } from '@netlify/build'

import { ODB_FUNCTION_NAME } from './constants'
import { restoreCache, saveCache } from './helpers/cache'
import { getNextConfig, configureHandlerFunctions } from './helpers/config'
import { moveStaticPages, movePublicFiles, patchNextFiles, unpatchNextFiles } from './helpers/files'
import { generateFunctions, setupImageFunction, generatePagesResolver } from './helpers/functions'
import { generateRedirects } from './helpers/redirects'
import {
verifyNetlifyBuildVersion,
checkNextSiteHasBuilt,
checkForRootPublish,
logBetaMessage,
checkZipSize,
checkForOldFunctions,
} = require('./helpers/verification')
} from './helpers/verification'

/** @type import("@netlify/build").NetlifyPlugin */
module.exports = {
const plugin: NetlifyPlugin = {
async onPreBuild({
constants,
netlifyConfig,
Expand Down Expand Up @@ -71,7 +72,7 @@ module.exports = {
}

if (!process.env.SERVE_STATIC_FILES_FROM_ORIGIN) {
await moveStaticPages({ target, failBuild, netlifyConfig, i18n })
await moveStaticPages({ target, netlifyConfig, i18n })
}

await setupImageFunction({ constants, imageconfig: images, netlifyConfig, basePath })
Expand All @@ -82,7 +83,15 @@ module.exports = {
})
},

async onPostBuild({ netlifyConfig, utils: { cache, functions, failBuild }, constants: { FUNCTIONS_DIST } }) {
async onPostBuild({
netlifyConfig,
utils: {
cache,
functions,
build: { failBuild },
},
constants: { FUNCTIONS_DIST },
}) {
await saveCache({ cache, publish: netlifyConfig.build.publish })
await checkForOldFunctions({ functions })
await checkZipSize(join(FUNCTIONS_DIST, `${ODB_FUNCTION_NAME}.zip`))
Expand All @@ -93,3 +102,4 @@ module.exports = {
logBetaMessage()
},
}
module.exports = plugin
2 changes: 1 addition & 1 deletion src/templates/handlerUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export const augmentFsModule = ({
return readfileOrig(file, options)
}) as typeof promises.readFile

promises.stat = (async (file, options) => {
promises.stat = ((file, options) => {
// We only care about page files
if (file.startsWith(pageRoot)) {
// We only want the part after `pages/`
Expand Down