Skip to content

Commit 3060126

Browse files
committed
Revamp sourcemap upload instructions with latest plugin and deletion
1 parent b62e316 commit 3060126

File tree

1 file changed

+190
-44
lines changed
  • src/app/reference/replay-cli/source-maps

1 file changed

+190
-44
lines changed

src/app/reference/replay-cli/source-maps/page.md

+190-44
Original file line numberDiff line numberDiff line change
@@ -8,89 +8,235 @@ Source maps exist to try and preserve the original debugging experience as best
88

99
## Upload Process
1010

11-
For production use cases where sourcemaps may not be exposed publicly, we provide tooling for preemptively uploading sourcemaps to our servers so that when replays are made, they can make use of these maps. We provide both a CLI command, and a Webpack plugin to make integrating this into your build process as easy as possible.
11+
For production use cases where sourcemaps may not be exposed publicly, we provide tooling for preemptively uploading sourcemaps to our servers so that when replays are made, they can make use of these maps and you can still debug the recordings with the original source code. We provide both a CLI command and a Webpack plugin to make integrating this into your build process as easy as possible.
1212

1313
### API Keys
1414

1515
We recommend using the `REPLAY_API_KEY` environment variable to set up the API for use in all of our following examples, but each also allows passing the key directly as an argument. API Keys are available in the [Team Settings](/reference/ci-workflows/generate-api-key) modal.
1616

17-
### CLI
17+
**Be sure to add the `REPLAY_API_KEY` for the workspace to the build and deployment settings for your project**, such as in Vercel or Github Actions - it needs to be available during the build step in order for the upload logic to upload successfully.
1818

19-
You can upload source maps using the `upload-sourcemaps` command in the Replay CLI.
19+
## CLI
20+
21+
You can upload source maps using the `replayio upload-source-maps` command in the [Replay CLI](/reference/replay-cli/commands).
2022

2123
The simplest usage will be running the following after your production JS build has finished.
2224

2325
```sh
24-
npx replayio upload-sourcemaps --group <Version or SHA> <buildOutputDir>
26+
npx replayio upload-source-maps --group <Version or SHA> <buildOutputDir>
2527
```
2628

2729
You must ensure that your build tool is configured to output sourcemaps into the build directory you provide.
2830

29-
### Webpack
31+
### CLI Options
32+
33+
The `replayio upload-source-maps` command has options available to help locate and filter which sourcemaps are available. Currently, those options are:
34+
35+
```bash
36+
-g, --group <name> The name to group this source map into, e.g. A commit SHA or release version.
37+
-x, --extensions <exts> A comma-separated list of file extensions to process; default ".js,.map"
38+
-i, --ignore <pattern> Ignore files that match this pattern
39+
--root <dirname> The base directory to use when computing relative paths
40+
```
3041

31-
The `sourcemap-upload` Webpack plugin is available on npm at `@replayio/sourcemap-upload-webpack-plugin` and you can explore the available options at [sourcemap-upload-webpack-plugin](https://github.com/replayio/replay-cli/tree/main/packages/sourcemap-upload-webpack-plugin) and [sourcemap-upload](https://github.com/replayio/replay-cli/tree/main/packages/sourcemap-upload).
42+
## Webpack
3243

33-
The simplest usage will be to edit your `webpack.config.js` to include a new entry in the `plugins` array at the top level of the file, e.g.
44+
We have a Webpack plugin that can upload sourcemaps, available on NPM as [`@replayio/sourcemap-upload-webpack-plugin`](https://npmjs.com/package/@replayio/sourcemap-upload-webpack-plugin).
3445

35-
```javascript
36-
const ReplaySourceMapUploadWebpackPlugin = require("@replayio/sourcemap-upload-webpack-plugin");
46+
To use the plugin, edit your `webpack.config.js` to include a new entry in the `plugins` array at the top level of the file, e.g.
47+
48+
```js
49+
const ReplaySourceMapUploadWebpackPlugin = require('@replayio/sourcemap-upload-webpack-plugin')
3750

3851
module.exports = {
3952
// Ensure that Webpack has been configured to output sourcemaps.
40-
devtool: "source-map",
41-
// ... plugins:
42-
[
43-
// Enable our plugin to upload the sourcemaps once the build has completed.
44-
// This assumes NODE_ENV is how you distinguish production builds. If that
45-
// is not the case for you, you will have to tweak this logic.
46-
process.env.NODE_ENV === "production"
47-
? [new ReplaySourceMapUploadWebpackPlugin({
48-
filepaths: ["outputDir/"],
49-
group: "<A unique version string or git SHA>"
50-
})]
51-
: []
53+
devtool: 'source-map',
54+
// ...
55+
plugins: [
56+
// Enable our plugin to upload the sourcemaps once the build has completed.
57+
// This assumes NODE_ENV is how you distinguish production builds. If that
58+
// is not the case for you, you will have to tweak this logic.
59+
process.env.NODE_ENV === 'production'
60+
? [
61+
new ReplaySourceMapUploadWebpackPlugin({
62+
filepaths: ['outputDir/'],
63+
group: '<A unique version string or git SHA>',
64+
}),
65+
]
66+
: [],
67+
],
68+
}
69+
```
70+
71+
### Webpack Upload Plugin Options
72+
73+
The Webpack plugin accepts several options to configure searching for sourcemaps and build artifacts on disk, excluding them from upload, and configuring deletion.
74+
75+
```ts
76+
// Exported from `@replayio/sourcemap-upload`
77+
export interface UploadOptions {
78+
/**
79+
* The files/directories to search for sourcemaps. All files that match the
80+
* 'extensions' list and fail to match 'ignore' will be searched for
81+
* sourcemap JSON or `//#sourceMappingURL=` coments in order to find pairs
82+
* of generated-file + sourcemap, and the sourcemap will be uploaded.
83+
*/
84+
filepaths: Array<string> | string
85+
/**
86+
* To allow for tracking and browsing of maps that have been uploaded, we
87+
* require uploaded sourcemaps to have an overall group name associated with
88+
* them. This could for instance be a version number, or commit hash.
89+
*/
90+
group: string
91+
/**
92+
* The API key to use when connecting to Replay's servers.
93+
* Defaults to `process.env.REPLAY_API_KEY`.
94+
*/
95+
key?: string
96+
/**
97+
* Run all of the local processing and searching for maps, but skip uploading them.
98+
*/
99+
dryRun?: boolean
100+
/**
101+
* Delete all found sourcemap files after they have been uploaded.
102+
*/
103+
deleteAfterUpload?: boolean
104+
/**
105+
* If sourcemaps can't be matched to generated files by their sourceMappingURL, try matching by filenames on disk
106+
*/
107+
matchSourcemapsByFilename?: boolean
108+
/**
109+
* The set of file extensions to search for sourcemap-related data.
110+
* Defaults to [".js", ".map"].
111+
*/
112+
extensions?: Array<string>
113+
/**
114+
* The set of pattern for files to ignore when searching for sourcemap-related data.
115+
*/
116+
ignore?: Array<string>
117+
/**
118+
* Set the directory that relative paths should be computed with respect to.
119+
* The relative path of sourcemaps is included in the uploaded entry, and will be
120+
* visible in the UI, so this can be used to strip off unimportant directories in
121+
* the build path. Defaults to `process.cwd()`.
122+
*/
123+
root?: string
124+
/**
125+
* A callback function that will be called with log messages.
126+
*/
127+
log?: LogCallback
128+
/**
129+
* URL of the Replay server to upload to. Defaults to `https://api.replay.io`.
130+
*/
131+
server?: string
132+
/**
133+
* The number of concurrent uploads to perform. Defaults to 25.
134+
*/
135+
concurrency?: number
136+
/**
137+
* A string to append to the User-Agent header when making requests to the Replay API.
138+
*/
139+
userAgentAddition?: string
140+
}
141+
142+
// Exported from `@replayio/sourcemap-upload-webpack-plugin`
143+
export interface PluginOptions extends UploadOptions {
144+
// Choose how verbose the plugin should be when logging.
145+
logLevel?: 'quiet' | 'normal' | 'verbose'
146+
147+
// Normally failure to upload the sourcemaps will result
148+
// in a build error. If you'd like to simply warn instead
149+
// of failing in this case, you can set this to true.
150+
warnOnFailure?: boolean
151+
}
152+
```
153+
154+
### Sourcemap Visibility in Production
155+
156+
Keep in mind that your build output will now contain sourcemaps, and so your app source code will be viewable in the browser devtools for anyone viewing your production site.
157+
158+
If this is a concern for you, you can keep your sourcemaps hidden from end users by deleting them from the build output directory. The Replay Webpack plugin has a `deleteAfterUpload` option to allow this. You can also configure Webpack's sourcemap generation settings to use [`devtool: "hidden-source-map"`](https://webpack.js.org/configuration/devtool/#production), which skips adding a `sourceMappingURL` reference to the generated JS build artifacts to keep the browser from trying to download and view sourcemaps. If you enable that, you should also enable the Webpack plugin's `matchSourcemapsByFilename` option, to ensure the plugin still correctly finds the right sourcemaps:
159+
160+
```js
161+
const ReplaySourceMapUploadWebpackPlugin = require('@replayio/sourcemap-upload-webpack-plugin')
162+
163+
module.exports = {
164+
// Ensure that Webpack has been configured to output sourcemaps,
165+
// but without the `sourceMappingURL` references in buidl artifacts.
166+
devtool: 'hidden-source-map',
167+
// ...
168+
plugins: [
169+
// Enable our plugin to upload the sourcemaps once the build has completed.
170+
// This assumes NODE_ENV is how you distinguish production builds. If that
171+
// is not the case for you, you will have to tweak this logic.
172+
process.env.NODE_ENV === 'production'
173+
? [
174+
new ReplaySourceMapUploadWebpackPlugin({
175+
filepaths: ['outputDir/'],
176+
group: '<A unique version string or git SHA>',
177+
deleteAfterUpload: true,
178+
matchSourcemapsByFilename: true,
179+
}),
180+
]
181+
: [],
52182
],
53183
}
54184
```
55185

56-
Keep in mind that your build output will now contain sourcemaps, so you should take care to ensure that these maps aren't also exposed on your production site.
186+
The Replay Webpack plugin uploads sourcemaps to the workspace associated with your API key, and automatically matches up sourcemaps with the build artifacts in a recorded replay when you debug it. This way, you can avoid having sourcemaps visible on your production site, but still debug replays with the original source code.
57187

58188
### NextJS
59189

60190
NextJS uses Webpack internally, so the plugin above will also be used for NextJS, but the config that needs editing is `next.config.js` instead. NextJS's [own documentation](https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config) is a good place to start and shows how to add Webpack plugins to your build process. You'll also need to enable [production sourcemaps](https://nextjs.org/docs/advanced-features/source-maps), so you'll end up with the following additional config in your `next.config.js` file:
61191

62-
```javascript
63-
module.exports = {
192+
```ts
193+
/** @type {import('next').NextConfig} */
194+
const nextConfig = {
64195
productionBrowserSourceMaps: true,
65-
webpack: (config, { buildId, dev, isServer }) => {
196+
197+
webpack: (config, { isServer, dev, buildId }) => {
198+
/** @type {import('webpack').Configuration} */
199+
const webpackConfig = config
200+
201+
// This configures Webpack to generate sourcemaps, but not include
202+
// the `sourceMappingURL` reference in generated JS bundles.
203+
// This keeps the sourcemaps hidden from users, but still available
204+
webpackConfig.devtool = 'hidden-source-map'
205+
66206
if (!dev && !isServer) {
67-
config.plugins.push(
68-
new ReplaySourceMapUploadWebpackPlugin({
69-
// If you've configured a custom build directory, this should
70-
// point to that directory. filepaths: [".next/"],
71-
// Potentially the 'buildId' argument here could be used.
72-
group: '<A unique version string or git SHA>',
73-
}),
74-
)
75-
// 'productionBrowserSourceMaps' will output your sourcemaps
76-
// into the build directory, which can expose them from your
77-
// production server as well, so you will likely want to delete
78-
// the .map files once they have been uploaded.
79-
80-
config.plugins.push((compiler) =>
81-
compiler.hooks.afterEmit.tapPromise('DeleteSourceMaps', () =>
82-
findAndDeleteSourceMaps(),
83-
),
84-
)
207+
/** @type {import('@replayio/sourcemap-upload-webpack-plugin').PluginOptions} */
208+
const uploadOptions = {
209+
// If you've configured a custom build directory, this should point to that directory.
210+
filepaths: ['.next/'],
211+
// You can use `buildId` here to differentiate sourcemaps between different builds.
212+
group: buildId,
213+
214+
// Don't upload or delete server-related sourcemaps
215+
ignore: ['**/server/**'],
216+
// You can configure the plugin to automatically delete sourcemaps from the local build
217+
// output folder after they've been uploaded, to keep them from being visible to users.
218+
deleteAfterUpload: true,
219+
// When `devtool: "hidden-source-map"` is used, the upload plugin can't match up
220+
// sourcemaps with bundles automatically because there's no `sourceMappingURL`.
221+
// Set this to true to match them up by similar filenames instead.
222+
matchSourcemapsByFilename: true,
223+
// The plugin will look for the API key as `process.env.REPLAY_API_KEY` by default.
224+
// You can provide it here if it's stored in a different environment variable.
225+
// key: process.env.REPLAY_API_KEY,
226+
}
227+
config.plugins.push(new ReplaySourceMapUploadWebpackPlugin(uploadOptions))
85228
}
229+
86230
return config
87231
},
88232
}
233+
234+
module.exports = nextConfig
89235
```
90236

91237
As mentioned, NextJS's `buildId` can be useful, but please [see their docs](https://nextjs.org/docs/api-reference/next.config.js/configuring-the-build-id) to ensure verify if it is a good fit for your application.
92238

93-
### Debugging problems
239+
## Debugging problems
94240

95241
Each of these approaches will log the sourcemaps as they are uploaded so that you can validate that all of the files you expect are being detected. They each also have a verbose mode, either `logLevel: "verbose"` for the JS plugins, and `--verbose` for the CLI.
96242

0 commit comments

Comments
 (0)