From ebd494abd32052b4f0c113459334f42738b5ab23 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 18 Mar 2025 15:46:03 +0100 Subject: [PATCH 1/3] feat(core): Don't name bundles after debug IDs for upload --- .../src/debug-id-upload.ts | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/packages/bundler-plugin-core/src/debug-id-upload.ts b/packages/bundler-plugin-core/src/debug-id-upload.ts index d201b3a0..0df52249 100644 --- a/packages/bundler-plugin-core/src/debug-id-upload.ts +++ b/packages/bundler-plugin-core/src/debug-id-upload.ts @@ -213,7 +213,7 @@ export async function prepareBundleForDebugIdUpload( logger: Logger, rewriteSourcesHook: RewriteSourcesHook ) { - let bundleContent; + let bundleContent: string; try { bundleContent = await promisify(fs.readFile)(bundleFilePath, "utf8"); } catch (e) { @@ -232,14 +232,21 @@ export async function prepareBundleForDebugIdUpload( return; } - const uniqueUploadName = `${debugId}-${chunkIndex}`; - - bundleContent += `\n//# debugId=${debugId}`; - const writeSourceFilePromise = fs.promises.writeFile( - path.join(uploadFolder, `${uniqueUploadName}.js`), - bundleContent, - "utf-8" + const uniqueSourceFileUploadPath = path.join( + uploadFolder, + `${chunkIndex}`, + path.normalize( + path + .relative(process.cwd(), bundleFilePath) + .split(path.sep) + .filter((segment) => segment !== ".." && segment !== ".") + .join(path.sep) + ) ); + bundleContent += `\n//# debugId=${debugId}`; + const writeSourceFilePromise = fs.promises + .mkdir(path.dirname(uniqueSourceFileUploadPath), { recursive: true }) + .then(() => fs.promises.writeFile(uniqueSourceFileUploadPath, bundleContent, "utf-8")); const writeSourceMapFilePromise = determineSourceMapPathFromBundle( bundleFilePath, @@ -249,7 +256,13 @@ export async function prepareBundleForDebugIdUpload( if (sourceMapPath) { await prepareSourceMapForDebugIdUpload( sourceMapPath, - path.join(uploadFolder, `${uniqueUploadName}.js.map`), + path.normalize( + path + .join(uploadFolder, `${chunkIndex}`, path.relative(process.cwd(), sourceMapPath)) + .split(path.sep) + .filter((segment) => segment !== ".." && segment !== ".") + .join(path.sep) + ), debugId, rewriteSourcesHook, logger @@ -379,7 +392,8 @@ async function prepareSourceMapForDebugIdUpload( } try { - await util.promisify(fs.writeFile)(targetPath, JSON.stringify(map), { + await fs.promises.mkdir(path.dirname(targetPath), { recursive: true }); + await fs.promises.writeFile(targetPath, JSON.stringify(map), { encoding: "utf8", }); } catch (e) { From b17b44aa5ce67c3dd9a4fb3a1768802ebcd08f79 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 24 Mar 2025 11:41:20 +0100 Subject: [PATCH 2/3] Add explanations --- packages/bundler-plugin-core/src/debug-id-upload.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/bundler-plugin-core/src/debug-id-upload.ts b/packages/bundler-plugin-core/src/debug-id-upload.ts index 0df52249..1f1ecdfe 100644 --- a/packages/bundler-plugin-core/src/debug-id-upload.ts +++ b/packages/bundler-plugin-core/src/debug-id-upload.ts @@ -234,11 +234,18 @@ export async function prepareBundleForDebugIdUpload( const uniqueSourceFileUploadPath = path.join( uploadFolder, + // We add a "chunk index" segment to the path that is a simple incrementing number to avoid name collisions. + // Name collisions can happen when files are located "outside" of the current working directory, at different levels but they share a subpath. + // Example: + // - CWD: /root/foo/cwd + // - File 1: /root/foo/index.js -> ../foo/index.js -> foo/index.js + // - File 2: /foo/index.js -> ../../foo/index.js -> foo/index.js `${chunkIndex}`, path.normalize( path .relative(process.cwd(), bundleFilePath) .split(path.sep) + // We filter out these "navigation" segments because a) they look ugly b) they will cause us to break out of the upload folder. .filter((segment) => segment !== ".." && segment !== ".") .join(path.sep) ) @@ -260,6 +267,7 @@ export async function prepareBundleForDebugIdUpload( path .join(uploadFolder, `${chunkIndex}`, path.relative(process.cwd(), sourceMapPath)) .split(path.sep) + // We filter out these "navigation" segments because a) they look ugly b) they will cause us to break out of the upload folder. .filter((segment) => segment !== ".." && segment !== ".") .join(path.sep) ), From 139eb7c1e9cf7fda6ca73f1786824536a411b8a4 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 24 Mar 2025 11:54:56 +0100 Subject: [PATCH 3/3] extract common functionality --- .../src/debug-id-upload.ts | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/packages/bundler-plugin-core/src/debug-id-upload.ts b/packages/bundler-plugin-core/src/debug-id-upload.ts index 1f1ecdfe..3c458388 100644 --- a/packages/bundler-plugin-core/src/debug-id-upload.ts +++ b/packages/bundler-plugin-core/src/debug-id-upload.ts @@ -232,24 +232,7 @@ export async function prepareBundleForDebugIdUpload( return; } - const uniqueSourceFileUploadPath = path.join( - uploadFolder, - // We add a "chunk index" segment to the path that is a simple incrementing number to avoid name collisions. - // Name collisions can happen when files are located "outside" of the current working directory, at different levels but they share a subpath. - // Example: - // - CWD: /root/foo/cwd - // - File 1: /root/foo/index.js -> ../foo/index.js -> foo/index.js - // - File 2: /foo/index.js -> ../../foo/index.js -> foo/index.js - `${chunkIndex}`, - path.normalize( - path - .relative(process.cwd(), bundleFilePath) - .split(path.sep) - // We filter out these "navigation" segments because a) they look ugly b) they will cause us to break out of the upload folder. - .filter((segment) => segment !== ".." && segment !== ".") - .join(path.sep) - ) - ); + const uniqueSourceFileUploadPath = getUniqueUploadPath(uploadFolder, chunkIndex, bundleFilePath); bundleContent += `\n//# debugId=${debugId}`; const writeSourceFilePromise = fs.promises .mkdir(path.dirname(uniqueSourceFileUploadPath), { recursive: true }) @@ -263,14 +246,7 @@ export async function prepareBundleForDebugIdUpload( if (sourceMapPath) { await prepareSourceMapForDebugIdUpload( sourceMapPath, - path.normalize( - path - .join(uploadFolder, `${chunkIndex}`, path.relative(process.cwd(), sourceMapPath)) - .split(path.sep) - // We filter out these "navigation" segments because a) they look ugly b) they will cause us to break out of the upload folder. - .filter((segment) => segment !== ".." && segment !== ".") - .join(path.sep) - ), + getUniqueUploadPath(uploadFolder, chunkIndex, sourceMapPath), debugId, rewriteSourcesHook, logger @@ -282,6 +258,27 @@ export async function prepareBundleForDebugIdUpload( await writeSourceMapFilePromise; } +function getUniqueUploadPath(uploadFolder: string, chunkIndex: number, filePath: string) { + return path.join( + uploadFolder, + // We add a "chunk index" segment to the path that is a simple incrementing number to avoid name collisions. + // Name collisions can happen when files are located "outside" of the current working directory, at different levels but they share a subpath. + // Example: + // - CWD: /root/foo/cwd + // - File 1: /root/foo/index.js -> ../foo/index.js -> foo/index.js + // - File 2: /foo/index.js -> ../../foo/index.js -> foo/index.js + `${chunkIndex}`, + path.normalize( + path + .relative(process.cwd(), filePath) + .split(path.sep) + // We filter out these "navigation" segments because a) they look ugly b) they will cause us to break out of the upload folder. + .filter((segment) => segment !== ".." && segment !== ".") + .join(path.sep) + ) + ); +} + /** * Looks for a particular string pattern (`sdbid-[debug ID]`) in the bundle * source and extracts the bundle's debug ID from it.