Skip to content

Commit

Permalink
feat: use import maps for internal Netlify identifier (#5)
Browse files Browse the repository at this point in the history
* chore: doh

* refactor: fix merge conflict

* chore: remove workspace file
  • Loading branch information
eduardoboucas committed Mar 15, 2022
1 parent d27184a commit c5fa05e
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 8 deletions.
27 changes: 21 additions & 6 deletions src/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { Declaration } from './declaration.js'
import { getESZIPBundler } from './eszip.js'
import { findHandlers } from './finder.js'
import { Handler } from './handler.js'
import { ImportMap } from './import_map.js'
import { generateManifest } from './manifest.js'
import { getFileHash } from './utils/sha256.js'

Expand All @@ -20,15 +21,24 @@ interface HandlerLine {
}

interface BundleOptions {
importMapPath?: string
onAfterDownload?: LifecycleHook
onBeforeDownload?: LifecycleHook
}

interface BundleAlternateOptions {
buildID: string
deno: DenoBridge
distDirectory: string
importMap: ImportMap
preBundlePath: string
}

const bundle = async (
sourceDirectories: string[],
distDirectory: string,
declarations: Declaration[] = [],
{ onAfterDownload, onBeforeDownload }: BundleOptions = {},
{ importMapPath, onAfterDownload, onBeforeDownload }: BundleOptions = {},
) => {
const deno = new DenoBridge({
onAfterDownload,
Expand All @@ -39,13 +49,14 @@ const bundle = async (
// compute until we run the bundle process. For now, we'll use a random ID
// to create the bundle artifacts and rename them later.
const buildID = uuidv4()
const importMap = new ImportMap()
const { handlers, preBundlePath } = await preBundle(sourceDirectories, distDirectory, `${buildID}-pre.js`)
const bundleAlternates: BundleAlternate[] = ['js']
const bundleOps = [bundleJS(deno, preBundlePath, distDirectory, buildID)]
const bundleOps = [bundleJS({ buildID, deno, distDirectory, importMap, preBundlePath })]

if (env.BUNDLE_ESZIP) {
bundleAlternates.push('eszip2')
bundleOps.push(bundleESZIP(deno, preBundlePath, distDirectory, buildID))
bundleOps.push(bundleESZIP({ buildID, deno, distDirectory, importMap, preBundlePath }))
}

const bundleHash = await createFinalBundles(bundleOps, distDirectory, buildID)
Expand All @@ -59,10 +70,14 @@ const bundle = async (

await fs.unlink(preBundlePath)

if (importMapPath) {
await importMap.writeToFile(importMapPath)
}

return { handlers, manifest, preBundlePath }
}

const bundleESZIP = async (deno: DenoBridge, preBundlePath: string, distDirectory: string, buildID: string) => {
const bundleESZIP = async ({ buildID, deno, distDirectory, preBundlePath }: BundleAlternateOptions) => {
const extension = '.eszip2'
const preBundleFileURL = pathToFileURL(preBundlePath).toString()
const eszipBundlePath = join(distDirectory, `${buildID}${extension}`)
Expand All @@ -73,11 +88,11 @@ const bundleESZIP = async (deno: DenoBridge, preBundlePath: string, distDirector
return extension
}

const bundleJS = async (deno: DenoBridge, preBundlePath: string, distDirectory: string, buildID: string) => {
const bundleJS = async ({ buildID, deno, distDirectory, importMap, preBundlePath }: BundleAlternateOptions) => {
const extension = '.js'
const jsBundlePath = join(distDirectory, `${buildID}${extension}`)

await deno.run(['bundle', preBundlePath, jsBundlePath])
await deno.run(['bundle', `--import-map=${importMap.toDataURL()}`, preBundlePath, jsBundlePath])

return extension
}
Expand Down
39 changes: 39 additions & 0 deletions src/import_map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Buffer } from 'buffer'
import { promises as fs } from 'fs'
import { dirname } from 'path'

const DEFAULT_IMPORTS = {
'netlify:edge': 'https://dinosaurs:are-the-future!@edge-bootstrap.netlify.app/v1/index.ts',
}

class ImportMap {
imports: Record<string, string>

constructor() {
this.imports = DEFAULT_IMPORTS
}

getContents() {
const contents = {
imports: this.imports,
}

return JSON.stringify(contents)
}

toDataURL() {
const encodedImportMap = Buffer.from(this.getContents()).toString('base64')

return `data:application/json;base64,${encodedImportMap}`
}

async writeToFile(path: string) {
await fs.mkdir(dirname(path), { recursive: true })

const contents = this.getContents()

await fs.writeFile(path, contents)
}
}

export { ImportMap }
11 changes: 9 additions & 2 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import { tmpName } from 'tmp-promise'
import { DenoBridge, LifecycleHook } from './bridge.js'
import { preBundle } from './bundler.js'
import type { Declaration } from './declaration.js'
import { ImportMap } from './import_map.js'
import { generateManifest } from './manifest.js'

interface ServeOptions {
importMapPath?: string
onAfterDownload?: LifecycleHook
onBeforeDownload?: LifecycleHook
}

const serve = async (
port: number,
sourceDirectories: string[],
{ onAfterDownload, onBeforeDownload }: ServeOptions = {},
{ importMapPath, onAfterDownload, onBeforeDownload }: ServeOptions = {},
) => {
const deno = new DenoBridge({
onAfterDownload,
Expand All @@ -27,10 +29,15 @@ const serve = async (
// Wait for the binary to be downloaded if needed.
await deno.getBinaryPath()

const flags = ['-A', '--unstable', '--no-clear-screen', '--watch', '--no-prompt']
const importMap = new ImportMap()
const flags = ['-A', '--unstable', '--no-clear-screen', '--watch', `--import-map=${importMap.toDataURL()}`]

deno.run(['run', ...flags, preBundlePath, port.toString()], { wait: false })

if (importMapPath) {
await importMap.writeToFile(importMapPath)
}

return {
getManifest,
}
Expand Down

0 comments on commit c5fa05e

Please sign in to comment.