Repository: Shopify/hydrogen (2025-07-08T18:51:55Z)

Issue:
Shopify Hydrogen Deploy deletes sourcemaps before Sentry Vite plugin runs
### What is the location of your example repository?

_No response_

### Which package or tool is having this issue?

CLI

### What version of that package or tool are you using?

3.72.1

### What version of Remix are you using?

2.11.2

### Steps to Reproduce

We use Sentry for server and client error monitoring and debugging. In August 2024, @frandiox helped us integrate Sentry's Vite plugin #2477  by giving us the flexibility to not have Shopify delete the sourcemaps and instead allow Sentry's plugin to upload the sourcemaps to their server and then the plugin deletes them before Shopify deploys to Oxygen. This flag `--force-client-sourcemap` was added to the `shopify hydrogen build` command that we were using at the time. We are now using `shopify hydrogen deploy` but this command does not forward the flag to the build command.

See Sentry docs [here](https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/vite/).

### Expected Behavior

We would expect that calling `shopify hydrogen deploy --force-client-sourcemap` would properly pass the flag to the build command so that the Sentry Vite plugin can successfully upload the source maps.

### Actual Behavior

The deploy command ignores the flag and the source maps are deleted before the Sentry Vite plugin can run.


Discussion:
@gugges , Did you come right with this ? currently having the same issue, have Sentry in prod but my quota is being filled issues we just cant get too without sourcemaps
Hi @gugges and @jasonloeve, apologies for the delay on this one

Could please share what version of the shopify/cli and or hydrogen-cli are you on?
Hi @juanpprieto we are on `3.72.1` 
Hi @juanpprieto we are using 3.77.1
Thanks looking into this today



Patch:
diff --git a/.changeset/hungry-tools-enjoy.md b/.changeset/hungry-tools-enjoy.md
new file mode 100644
index 0000000000..a189cb1b7f
--- /dev/null
+++ b/.changeset/hungry-tools-enjoy.md
@@ -0,0 +1,5 @@
+---
+"@shopify/cli-hydrogen": patch
+---
+
+Add `--force-client-sourcemap` flag support to the `deploy` command
diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json
index 139123e178..125231829c 100644
--- a/packages/cli/oclif.manifest.json
+++ b/packages/cli/oclif.manifest.json
@@ -503,6 +503,13 @@
           "required": false,
           "allowNo": false,
           "type": "boolean"
+        },
+        "force-client-sourcemap": {
+          "description": "Client sourcemapping is avoided by default because it makes backend code visible in the browser. Use this flag to force enabling it.",
+          "env": "SHOPIFY_HYDROGEN_FLAG_FORCE_CLIENT_SOURCEMAP",
+          "name": "force-client-sourcemap",
+          "allowNo": false,
+          "type": "boolean"
         }
       },
       "hasDynamicHelp": false,
diff --git a/packages/cli/src/commands/hydrogen/deploy.ts b/packages/cli/src/commands/hydrogen/deploy.ts
index 741f6bbe6b..5f72c8086f 100644
--- a/packages/cli/src/commands/hydrogen/deploy.ts
+++ b/packages/cli/src/commands/hydrogen/deploy.ts
@@ -10,7 +10,7 @@ import {
 } from '@shopify/cli-kit/node/output';
 import {readAndParseDotEnv} from '@shopify/cli-kit/node/dot-env';
 import {AbortError} from '@shopify/cli-kit/node/error';
-import {readFile, writeFile} from '@shopify/cli-kit/node/fs';
+import {writeFile} from '@shopify/cli-kit/node/fs';
 import {
   ensureIsClean,
   getLatestGitCommit,
@@ -19,6 +19,7 @@ import {
 import {joinPath, relativePath, resolvePath} from '@shopify/cli-kit/node/path';
 import {
   renderConfirmationPrompt,
+  renderInfo,
   renderSelectPrompt,
   renderSuccess,
   renderTasks,
@@ -161,6 +162,11 @@ export default class Deploy extends Command {
       hidden: true,
     }),
     ...commonFlags.diff,
+    'force-client-sourcemap': Flags.boolean({
+      description:
+        'Client sourcemapping is avoided by default because it makes backend code visible in the browser. Use this flag to force enabling it.',
+      env: 'SHOPIFY_HYDROGEN_FLAG_FORCE_CLIENT_SOURCEMAP',
+    }),
   };
 
   async run() {
@@ -203,6 +209,7 @@ interface OxygenDeploymentOptions {
   envBranch?: string;
   environmentFile?: string;
   force: boolean;
+  forceClientSourcemap?: boolean;
   noVerify: boolean;
   lockfileCheck: boolean;
   jsonOutput: boolean;
@@ -252,6 +259,7 @@ export async function runDeploy(
     envBranch,
     environmentFile,
     force: forceOnUncommitedChanges,
+    forceClientSourcemap = false,
     noVerify,
     lockfileCheck,
     jsonOutput,
@@ -584,6 +592,14 @@ Continue?`.value,
   };
 
   if (buildCommand) {
+    if (forceClientSourcemap) {
+      console.log('');
+      renderInfo({
+        headline:
+          'The `--force-client-sourcemap` flag is not supported with a custom build command',
+        body: 'Client sourcemaps will not be generated.',
+      });
+    }
     config.buildCommand = buildCommand;
   } else {
     hooks.buildFunction = async (
@@ -602,6 +618,7 @@ Continue?`.value,
         assetPath,
         lockfileCheck,
         sourcemap: true,
+        forceClientSourcemap,
         useCodegen: false,
         entry: ssrEntry,
       });


Test patch:
diff --git a/packages/cli/src/commands/hydrogen/deploy.test.ts b/packages/cli/src/commands/hydrogen/deploy.test.ts
index 21ab0730cc..658c2e8e60 100644
--- a/packages/cli/src/commands/hydrogen/deploy.test.ts
+++ b/packages/cli/src/commands/hydrogen/deploy.test.ts
@@ -627,6 +627,34 @@ describe('deploy', async () => {
       directory: params.path,
       lockfileCheck: false,
       sourcemap: true,
+      forceClientSourcemap: false,
+      useCodegen: false,
+    });
+  });
+
+  it('passes the forceClientSourcemap flag to the build command', async () => {
+    const params = {
+      ...deployParams,
+      lockfileCheck: false,
+      forceClientSourcemap: true,
+    };
+
+    vi.mocked(createDeploy).mockImplementationOnce((options) => {
+      options.hooks?.buildFunction?.('some-cool-asset-path');
+
+      return new Promise((resolve, _reject) => {
+        resolve({url: 'https://a-lovely-deployment.com'});
+      }) as Promise<CompletedDeployment | undefined>;
+    });
+
+    await runDeploy(params);
+
+    expect(vi.mocked(runBuild)).toHaveBeenCalledWith({
+      assetPath: 'some-cool-asset-path',
+      directory: params.path,
+      lockfileCheck: false,
+      sourcemap: true,
+      forceClientSourcemap: true,
       useCodegen: false,
     });
   });