Skip to content
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

feat!: remove support for JavaScript bundles #224

Merged
merged 1 commit into from
Nov 24, 2022
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
61 changes: 4 additions & 57 deletions node/bundler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { BundleError } from './bundle_error.js'
import { bundle, BundleOptions } from './bundler.js'
import { isNodeError } from './utils/error.js'

test('Produces a JavaScript bundle and a manifest file', async () => {
test('Produces an ESZIP bundle', async () => {
const sourceDirectory = resolve(fixturesDir, 'with_import_maps', 'functions')
const tmpDir = await tmp.dir()
const declarations = [
Expand All @@ -34,39 +34,6 @@ test('Produces a JavaScript bundle and a manifest file', async () => {
const manifest = JSON.parse(manifestFile)
const { bundles } = manifest

expect(bundles.length).toBe(1)
expect(bundles[0].format).toBe('js')
expect(generatedFiles.includes(bundles[0].asset)).toBe(true)
expect(result.manifest).toEqual(manifest)

await fs.rmdir(tmpDir.path, { recursive: true })
})

test('Produces only a ESZIP bundle when the `edge_functions_produce_eszip` feature flag is set', async () => {
const sourceDirectory = resolve(fixturesDir, 'with_import_maps', 'functions')
const tmpDir = await tmp.dir()
const declarations = [
{
function: 'func1',
path: '/func1',
},
]
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
basePath: fixturesDir,
configPath: join(sourceDirectory, 'config.json'),
featureFlags: {
edge_functions_produce_eszip: true,
},
})
const generatedFiles = await fs.readdir(tmpDir.path)

expect(result.functions.length).toBe(1)
expect(generatedFiles.length).toBe(2)

const manifestFile = await fs.readFile(resolve(tmpDir.path, 'manifest.json'), 'utf8')
const manifest = JSON.parse(manifestFile)
const { bundles } = manifest

expect(bundles.length).toBe(1)
expect(bundles[0].format).toBe('eszip2')
expect(generatedFiles.includes(bundles[0].asset)).toBe(true)
Expand All @@ -86,9 +53,6 @@ test('Uses the vendored eszip module instead of fetching it from deno.land', asy
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
basePath: fixturesDir,
configPath: join(sourceDirectory, 'config.json'),
featureFlags: {
edge_functions_produce_eszip: true,
},
})
const generatedFiles = await fs.readdir(tmpDir.path)

Expand Down Expand Up @@ -124,7 +88,7 @@ test('Adds a custom error property to user errors during bundling', async () =>
expect(error).toBeInstanceOf(BundleError)
expect((error as BundleError).customErrorInfo).toEqual({
location: {
format: 'javascript',
format: 'eszip',
runtime: 'deno',
},
type: 'functionsBundling',
Expand All @@ -145,11 +109,7 @@ test('Prints a nice error message when user tries importing NPM module', async (
]

try {
await bundle([sourceDirectory], tmpDir.path, declarations, {
featureFlags: {
edge_functions_produce_eszip: true,
},
})
await bundle([sourceDirectory], tmpDir.path, declarations)
} catch (error) {
expect(error).toBeInstanceOf(BundleError)
expect((error as BundleError).message).toEqual(
Expand All @@ -170,7 +130,7 @@ test('Does not add a custom error property to system errors during bundling', as
})

test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_cache_deno_dir` feature flag is set', async () => {
expect.assertions(7)
expect.assertions(6)

const sourceDirectory = resolve(fixturesDir, 'with_import_maps', 'functions')
const outDir = await tmp.dir()
Expand Down Expand Up @@ -214,7 +174,6 @@ test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_ca

const denoDir2 = await fs.readdir(join(cacheDir.path, 'deno_dir'))

expect(denoDir2.includes('deps')).toBe(true)
expect(denoDir2.includes('gen')).toBe(true)

await fs.rmdir(outDir.path, { recursive: true })
Expand All @@ -232,9 +191,6 @@ test('Supports import maps with relative paths', async () => {
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
basePath: fixturesDir,
configPath: join(sourceDirectory, 'config.json'),
featureFlags: {
edge_functions_produce_eszip: true,
},
})
const generatedFiles = await fs.readdir(tmpDir.path)

Expand Down Expand Up @@ -300,9 +256,6 @@ test('Ignores any user-defined `deno.json` files', async () => {
bundle([join(fixtureDir, 'functions')], tmpDir.path, declarations, {
basePath: fixturesDir,
configPath: join(fixtureDir, 'functions', 'config.json'),
featureFlags: {
edge_functions_produce_eszip: true,
},
}),
).not.toThrow()

Expand All @@ -322,9 +275,6 @@ test('Processes a function that imports a custom layer', async () => {
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
basePath: fixturesDir,
configPath: join(sourceDirectory, 'config.json'),
featureFlags: {
edge_functions_produce_eszip: true,
},
})
const generatedFiles = await fs.readdir(tmpDir.path)

Expand Down Expand Up @@ -357,9 +307,6 @@ test('Loads declarations and import maps from the deploy configuration', async (
const result = await bundle(directories, tmpDir.path, declarations, {
basePath: fixtureDir,
configPath: join(fixtureDir, '.netlify', 'edge-functions', 'config.json'),
featureFlags: {
edge_functions_produce_eszip: true,
},
})
const generatedFiles = await fs.readdir(tmpDir.path)

Expand Down
48 changes: 1 addition & 47 deletions node/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import type { Bundle } from './bundle.js'
import { FunctionConfig, getFunctionConfig } from './config.js'
import { Declaration, getDeclarationsFromConfig } from './declaration.js'
import { load as loadDeployConfig } from './deploy_config.js'
import { EdgeFunction } from './edge_function.js'
import { FeatureFlags, getFlags } from './feature_flags.js'
import { findFunctions } from './finder.js'
import { bundle as bundleESZIP } from './formats/eszip.js'
import { bundle as bundleJS } from './formats/javascript.js'
import { ImportMap } from './import_map.js'
import { getLogger, LogFunction } from './logger.js'
import { writeManifest } from './manifest.js'
Expand All @@ -31,50 +29,6 @@ interface BundleOptions {
systemLogger?: LogFunction
}

interface BundleFormatOptions {
buildID: string
debug?: boolean
deno: DenoBridge
distDirectory: string
functions: EdgeFunction[]
featureFlags: FeatureFlags
importMap: ImportMap
basePath: string
}

const createBundle = ({
basePath,
buildID,
debug,
deno,
distDirectory,
functions,
importMap,
featureFlags,
}: BundleFormatOptions) => {
if (featureFlags.edge_functions_produce_eszip) {
return bundleESZIP({
basePath,
buildID,
debug,
deno,
distDirectory,
featureFlags,
functions,
importMap,
})
}

return bundleJS({
buildID,
debug,
deno,
distDirectory,
functions,
importMap,
})
}

const bundle = async (
sourceDirectories: string[],
distDirectory: string,
Expand Down Expand Up @@ -126,7 +80,7 @@ const bundle = async (
}

const functions = await findFunctions(sourceDirectories)
const functionBundle = await createBundle({
const functionBundle = await bundleESZIP({
basePath,
buildID,
debug,
Expand Down
4 changes: 0 additions & 4 deletions node/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,6 @@ test('Ignores function paths from the in-source `config` function if the feature
const result = await bundle([internalDirectory, userDirectory], tmpDir.path, declarations, {
basePath: fixturesDir,
configPath: join(internalDirectory, 'config.json'),
featureFlags: {
edge_functions_produce_eszip: true,
},
})
const generatedFiles = await fs.readdir(tmpDir.path)

Expand Down Expand Up @@ -194,7 +191,6 @@ test('Loads function paths from the in-source `config` function', async () => {
configPath: join(internalDirectory, 'config.json'),
featureFlags: {
edge_functions_config_export: true,
edge_functions_produce_eszip: true,
},
})
const generatedFiles = await fs.readdir(tmpDir.path)
Expand Down
1 change: 0 additions & 1 deletion node/feature_flags.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const defaultFlags: Record<string, boolean> = {
edge_functions_cache_deno_dir: false,
edge_functions_config_export: false,
edge_functions_produce_eszip: false,
}

type FeatureFlag = keyof typeof defaultFlags
Expand Down
74 changes: 2 additions & 72 deletions node/formats/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,11 @@ import { pathToFileURL } from 'url'

import { deleteAsync } from 'del'

import { DenoBridge } from '../bridge.js'
import { Bundle, BundleFormat } from '../bundle.js'
import { wrapBundleError } from '../bundle_error.js'
import { EdgeFunction } from '../edge_function.js'
import { ImportMap } from '../import_map.js'
import { wrapNpmImportError } from '../npm_import_error.js'
import type { FormatFunction } from '../server/server.js'
import { getFileHash } from '../utils/sha256.js'

const BOOTSTRAP_LATEST = 'https://637cf7ce9214b300099b3aa8--edge.netlify.com/bootstrap/index-combined.ts'

interface BundleJSOptions {
buildID: string
debug?: boolean
deno: DenoBridge
distDirectory: string
functions: EdgeFunction[]
importMap: ImportMap
}

const bundleJS = async ({
buildID,
debug,
deno,
distDirectory,
functions,
importMap,
}: BundleJSOptions): Promise<Bundle> => {
const stage2Path = await generateStage2({ distDirectory, functions, fileName: `${buildID}-pre.js` })
const extension = '.js'
const jsBundlePath = join(distDirectory, `${buildID}${extension}`)
const flags = [`--import-map=${importMap.toDataURL()}`, '--no-config']

if (!debug) {
flags.push('--quiet')
}

try {
await deno.run(['bundle', ...flags, stage2Path, jsBundlePath], { pipeOutput: true })
} catch (error: unknown) {
throw wrapBundleError(wrapNpmImportError(error), { format: 'javascript' })
}

await fs.unlink(stage2Path)

const hash = await getFileHash(jsBundlePath)

return { extension, format: BundleFormat.JS, hash }
}

const defaultFormatExportTypeError: FormatFunction = (name) =>
`The Edge Function "${name}" has failed to load. Does it have a function as the default export?`

Expand All @@ -66,7 +21,6 @@ interface GenerateStage2Options {
formatExportTypeError?: FormatFunction
formatImportError?: FormatFunction
functions: EdgeFunction[]
type?: 'local' | 'production'
}

const generateStage2 = async ({
Expand All @@ -75,15 +29,11 @@ const generateStage2 = async ({
formatExportTypeError,
formatImportError,
functions,
type = 'production',
}: GenerateStage2Options) => {
await deleteAsync(distDirectory, { force: true })
await fs.mkdir(distDirectory, { recursive: true })

const entryPoint =
type === 'local'
? getLocalEntryPoint(functions, { formatExportTypeError, formatImportError })
: getProductionEntryPoint(functions)
const entryPoint = getLocalEntryPoint(functions, { formatExportTypeError, formatImportError })
const stage2Path = join(distDirectory, fileName)

await fs.writeFile(stage2Path, entryPoint)
Expand Down Expand Up @@ -137,24 +87,4 @@ const getLocalEntryPoint = (
return [bootImport, declaration, ...imports, bootCall].join('\n\n')
}

const getProductionEntryPoint = (functions: EdgeFunction[]) => {
const bootImport = `import { boot } from "${getBootstrapURL()}";`
const lines = functions.map((func, index) => {
const importName = `func${index}`
const exportLine = `"${func.name}": ${importName}`
const url = pathToFileURL(func.path)

return {
exportLine,
importLine: `import ${importName} from "${url}";`,
}
})
const importLines = lines.map(({ importLine }) => importLine).join('\n')
const exportLines = lines.map(({ exportLine }) => exportLine).join(', ')
const exportDeclaration = `const functions = {${exportLines}};`
const defaultExport = 'boot(functions);'

return [bootImport, importLines, exportDeclaration, defaultExport].join('\n\n')
}

export { bundleJS as bundle, generateStage2, getBootstrapURL, getLocalEntryPoint }
export { generateStage2, getBootstrapURL, getLocalEntryPoint }
1 change: 0 additions & 1 deletion node/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ const prepareServer = ({
functions,
formatExportTypeError,
formatImportError,
type: 'local',
})

try {
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/invalid_functions/functions/func1.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export default async () => new NotAResponse('Hello')
export default async () =>
6 changes: 1 addition & 5 deletions test/integration/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,7 @@ const bundleFunction = async (bundlerDir) => {

console.log(`Bundling functions at '${functionsDir}'...`)

return await bundle([functionsDir], destPath, [{ function: 'func1', path: '/func1' }], {
featureFlags: {
edge_functions_produce_eszip: true,
},
})
return await bundle([functionsDir], destPath, [{ function: 'func1', path: '/func1' }])
}

const runAssertions = (bundleOutput) => {
Expand Down