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

Need a way to upload sourcemaps manually using command line #5

Closed
wasimTQ opened this issue Jun 22, 2023 · 1 comment
Closed

Need a way to upload sourcemaps manually using command line #5

wasimTQ opened this issue Jun 22, 2023 · 1 comment

Comments

@wasimTQ
Copy link

wasimTQ commented Jun 22, 2023

I was able to upload sourcemaps using the flareSourcemapUploader vite plugin in both local and ci (I'm using gitlab ci).

But what I need is to be able to upload the sourcemaps using custom code by using a command like yarn upload.

What I'm doing right now:

  1. Build the app. It's available in dist in base directory.
  2. The sourcemap custom code forked from this repo is in src/sourcemap.
  3. Currently how it's being running is cd src/sourcemap && yarn && yarn build && yarn upload // (calls node dist/index.js)

Here's the glimpse of the sourcemap code for context:

// src/sourcemap/src/index.ts

export type PluginConfig = {
    key: string;
    base?: string;
    apiEndpoint?: string;
    runInDevelopment?: boolean;
    version?: string;
    removeSourcemaps?: boolean;
};

export type Sourcemap = {
    original_file: string;
    content: string;
    sourcemap_url: string;
};

export default async function flareSourcemapUploader({
    key,
    base,
    apiEndpoint = 'https://flareapp.io/api/sourcemaps',
    runInDevelopment = false,
    version = uuid(),
    removeSourcemaps = false,
}: PluginConfig) {
    const dir = resolve(__dirname, '../../../')
    base = dir
    if (!key) {
        flareLog('No Flare API key was provided, not uploading sourcemaps to Flare.');
    }

    const flare = new FlareApi(apiEndpoint, key, version);

    const enableUploadingSourcemaps =
        key && (process.env.NODE_ENV !== 'development' || runInDevelopment) && process.env.SKIP_SOURCEMAPS !== 'true';

    if (!enableUploadingSourcemaps) {
        return;
    }

    const outputDir = resolve(dir, 'dist');

    const files = await glob('./**/*.map', { cwd: outputDir });
    console.log(files)
    const sourcemaps = files
        .map((file): Sourcemap | null => {
            const sourcePath = file.replace(/\.map$/, '');
            const sourceFilename = resolve(outputDir, sourcePath);

            if (!existsSync(sourceFilename)) {
                flareLog(`no corresponding source found for "${file}"`, true);
                return null;
            }

            const sourcemapLocation = resolve(outputDir, file);

            try {
                return {
                    content: readFileSync(sourcemapLocation, 'utf8'),
                    sourcemap_url: sourcemapLocation,
                    original_file: `${base}${sourcePath}`,
                };
            } catch (error) {
                flareLog('Error reading sourcemap file ' + sourcemapLocation + ': ' + error, true);
                return null;
            }
        })
        .filter((sourcemap) => sourcemap !== null) as Sourcemap[];

    if (!sourcemaps.length) {
        return;
    }

    flareLog(`Uploading ${sourcemaps.length} sourcemap files to Flare.`);

    const pendingUploads = sourcemaps.map((sourcemap) => () => flare.uploadSourcemap(sourcemap));

    try {
        while (pendingUploads.length) {
            await Promise.all(pendingUploads.splice(0, 10).map((f) => f()));
        }

        flareLog('Successfully uploaded sourcemaps to Flare.');
    } catch (error) {
        flareLog(`Something went wrong while uploading the sourcemaps to Flare: ${error}`, true);
    }

    if (removeSourcemaps) {
        sourcemaps.forEach(({ sourcemap_url }) => {
            try {
                unlinkSync(sourcemap_url);
            } catch (error) {
                console.error('Error removing sourcemap file', sourcemap_url, ': ', error);
            }
        });

        flareLog('Successfully removed sourcemaps.');
    }
}

// Calling point
flareSourcemapUploader({
    key: process.env.FLARE_PROJECT_KEY,
})
// src/sourcemap/src/flareApi.ts

import { deflateRawSync } from 'zlib';
import axios from 'axios';
import { Sourcemap } from './index';

export default class FlareApi {
    endpoint: string;
    key: string;
    version: string;

    constructor(endpoint: string, key: string, version: string) {
        this.endpoint = endpoint;
        this.key = key;
        this.version = version;
    }

    uploadSourcemap(sourcemap: Sourcemap) {
        return new Promise((resolve, reject) => {
            const base64GzipSourcemap = deflateRawSync(sourcemap.content).toString('base64');

            axios
                .post(this.endpoint, {
                    key: this.key,
                    version_id: this.version,
                    relative_filename: sourcemap.original_file,
                    sourcemap: base64GzipSourcemap,
                })
                .then(resolve)
                .catch((error) => {
                    return reject(`${error.response.status}: ${JSON.stringify(error.response.data)}`);
                });
        });
    }
}

The output is

@flareapp/vite-plugin-sourcemap-uploader: Uploading 3 sourcemap files to Flare.
@flareapp/vite-plugin-sourcemap-uploader: Successfully uploaded sourcemaps to Flare.

File structure:

dist
src/frontend
src/sourcemap // It's a standalone folder cloned from this repo
vite.config.ts // Config for the frontend

What I need in the gitlab ci is to be able to build the app once, cache the dist folder alone and use the custom code for sourcemap to manually upload the files in multiple environments without having to build it again and again.

But it doesn't seem like it uploaded it successfully as I can't inspect the code that throws error in flare dashboard.

Let me know if you'll need more details.

@Sam-Apostel
Copy link
Contributor

Per the console output you provided, it looks like your sourcemaps are successfully uploaded to Flare.

The sourcemap uploader generates a unique version id (defaults to uuid()). This version needs to match the sourcemap_version_id that the flare js client uses to send an error to Flare.

In the code snippets you provided, I don't see the FLARE_SOURCEMAP_VERSION being set. Our sourcemap uploader does that here.

You could achieve this in a number of ways:

  • set FLARE_SOURCEMAP_VERSION on your globalThis object
  • assign flare.beforeSubmit a function that set the sourcemap_version_id for each report
  • fork the js client to add a config option that passed the sourcmap version id.
  • ...

If each build has some unique id you could also use that to upload the sourcemaps to each project during the build step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants