From f0ac6d050ce31566045cbf8339b6f2a556b484df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Wed, 7 Dec 2022 15:20:50 +0000 Subject: [PATCH] fix: add guard for import map with extraneous dist directory (#243) --- node/bundler.test.ts | 38 ++++++++++++++++++++++++++++++++++++++ node/formats/eszip.ts | 14 ++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/node/bundler.test.ts b/node/bundler.test.ts index 73699f13..3405712f 100644 --- a/node/bundler.test.ts +++ b/node/bundler.test.ts @@ -1,6 +1,7 @@ import { promises as fs } from 'fs' import { join, resolve } from 'path' import process from 'process' +import { pathToFileURL } from 'url' import { deleteAsync } from 'del' import tmp from 'tmp-promise' @@ -345,3 +346,40 @@ test('Loads declarations and import maps from the deploy configuration', async ( await cleanup() }) + +test('Uses an absolute URL for the import map when the dist directory is not a child of the base path', async () => { + const { basePath, cleanup } = await useFixture('with_import_maps') + const { path: distPath } = await tmp.dir() + const declarations = [ + { + function: 'func1', + path: '/func1', + }, + ] + const sourceDirectory = join(basePath, 'functions') + const result = await bundle([sourceDirectory], distPath, declarations, { + basePath, + configPath: join(sourceDirectory, 'config.json'), + }) + const generatedFiles = await fs.readdir(distPath) + + expect(result.functions.length).toBe(1) + + // ESZIP, manifest and import map. + expect(generatedFiles.length).toBe(3) + + const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8') + const manifest = JSON.parse(manifestFile) + expect(() => validateManifest(manifest)).not.toThrowError() + const { bundles, import_map: importMapURL } = manifest + + expect(bundles.length).toBe(1) + expect(bundles[0].format).toBe('eszip2') + expect(generatedFiles.includes(bundles[0].asset)).toBe(true) + + const importMapPath = join(distPath, 'import_map.json') + expect(importMapURL).toBe(pathToFileURL(importMapPath).toString()) + + await cleanup() + await fs.rm(distPath, { recursive: true }) +}) diff --git a/node/formats/eszip.ts b/node/formats/eszip.ts index a98a5f67..83a32190 100644 --- a/node/formats/eszip.ts +++ b/node/formats/eszip.ts @@ -69,8 +69,18 @@ const createUserImportMap = async (importMap: ImportMap, basePath: string, distD await importMap.writeToFile(destPath) - const relativePath = relative(basePath, destPath) - const importMapURL = new URL(relativePath, virtualRoot) + let virtualPath = relative(basePath, destPath) + + // If the dist directory is not a child of the base path, we can't represent + // the relative path as a file URL (because something like 'file://../foo' is + // not valid). This should never happen, but it's best to leave the absolute + // path untransformed to avoid getting a build error due to a missing import + // map. + if (virtualPath.startsWith('..')) { + virtualPath = destPath + } + + const importMapURL = new URL(virtualPath, virtualRoot) return importMapURL.toString() }