Closed sabrinaluohk01 closed 5 years ago
Hi @sabrinaluohk01! Sorry to see that you're having issues.
I went to put together a small next.js example at to play around with things, and I had to fix a few issues with this library (#4). I've published that as v1.1.1
.
Unfortunately that won't solve the issues you're having, though. The problem stems from the fact that the next bundles are not served with the same paths that they exist with on the filesystem…
The next router does this – mapping paths like /_next/xxxxxxxxxxxxxxx/page/index.js
onto /.next/bundles/pages/index.js
. In order to support this kind of dynamic serving we'd need to add a feature to this library. At the moment we just join the publicPath
with the location of the bundle on disk…
… assuming that the result of a webpack build is served from the filesystem statically – as it usually is.
Until we get around to supporting your use case, may I suggest an alternative. Rather than uploading sourcemaps to Bugsnag, you should leave the //# sourceMappingURL=index.js.map
annotations in your JS, and allow Bugsnag's servers to retrieve the source map when we process an error. If your application isn't publicly available, you'll need to whitelist our IPs.
N.B. you should also add this config if you haven't already, to ensure source maps are created for all of your JS.
Hey @bengourley, thanks for the help. What do you suggest to upload server sourcemaps?
webpack(config, { dev, isServer }) {
if (!dev) {
config.devtool = 'source-map'
const appVersion = gitRev.short()
const BUGSNAG_API = isServer
? dotenv.parsed.BUGSNAG_API_SERVER
: dotenv.parsed.BUGSNAG_API_CLIENT
config.plugins.push(
new BugsnagBuildReporterPlugin(
{
apiKey: BUGSNAG_API,
appVersion: appVersion,
releaseStage: dotenv.parsed.BUGSNAG_ENV
}
)
)
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: BUGSNAG_API,
appVersion: appVersion,
releaseStage: dotenv.parsed.BUGSNAG_ENV
})
)
}
}
I started with something like this but came accross this issue. So now if I can upload only server side sourcemaps, that would be enough. I'll figure something else and comment for client side.
@azizhk we don't currently support source maps for server-side javascript – however we do plan to support it soon.
Hey, so here's my script to upload client side sourcemaps after a build. Works with next.js v6. Does not work with next.js v7. Thought would share.
const fs = require('fs')
const _ = require('lodash')
const { resolve } = require('path')
const { promisify } = require('util')
const { upload: _uploadToBugsnag } = require('bugsnag-sourcemaps')
const { config: loadEnv } = require('dotenv')
const { short: gitRevShort } = require('git-rev-sync')
loadEnv({
path: resolve(__dirname, '../.env')
})
const readFile = promisify(fs.readFile)
const uploadToBugsnag = promisify(_uploadToBugsnag)
const DASHBOARD_URL = process.env.DASHBOARD_URL
module.exports = async function uploadClientSourcemapTask(): Promise<void> {
if (!process.env.BUGSNAG_API_CLIENT) {
return
}
const BUILD_ID = await readFile(
resolve(__dirname, '../.next/BUILD_ID'),
'utf8'
)
const manifest = JSON.parse(
await readFile(resolve(__dirname, '../.next/build-manifest.json'), 'utf8')
)
const baseConfig = {
apiKey: process.env.BUGSNAG_API_CLIENT,
appVersion: gitRevShort(),
overwrite: true,
uploadSources: true
}
const pageBundles = Object.keys(manifest)
.filter(p => p.startsWith('bundles/pages'))
.map(p => p.replace(/^bundles\/pages\//, ''))
await Promise.all(
pageBundles.map(p =>
uploadToBugsnag({
...baseConfig,
minifiedUrl: `${DASHBOARD_URL}_next/${BUILD_ID}/page/${p}`,
minifiedFile: resolve(__dirname, `../.next/bundles/pages/${p}`),
sourceMap: resolve(__dirname, `../.next/bundles/pages/${p}.map`)
})
)
)
const chunkBundles = _.entries(manifest).filter(([k, _]) =>
k.startsWith('chunks')
)
await Promise.all(
chunkBundles.map(([_, v]) =>
uploadToBugsnag({
...baseConfig,
minifiedUrl: `${DASHBOARD_URL}_next/webpack/${v[0]}`,
minifiedFile: resolve(__dirname, `../.next/${v[0]}`),
sourceMap: resolve(__dirname, `../.next/${v[0]}.map`)
})
)
)
await uploadToBugsnag({
...baseConfig,
minifiedUrl: `${DASHBOARD_URL}_next/${manifest['main.js']}`,
minifiedFile: resolve(__dirname, `../.next/${manifest['main.js']}`),
sourceMap: resolve(__dirname, `../.next/${manifest['main.js']}.map`)
})
}
Upgrading to next 7 soon, will share if successful.
With Next 7, this plugin works as is and does not need much modifications. As next now stores the files in the same path that their served to the client.
Just you need to turn on sourcemaps. For that you can use @zeit/next-source-maps
next.config.js:
const withSourceMaps = require('@zeit/next-source-maps')()
module.exports = withSourceMaps({
webpack(config, options) {
const { dev, isServer, defaultLoaders } = options
if (!dev && !isServer) {
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: BUGSNAG_API_KEY, // replace this
publicPath: `http*://*.example.com/_next/` // replace this
})
)
}
}
})
Above code is for @zeit/next-source-maps
version "0.0.4-canary.0"
You should be able to close this issue now.
@bengourley Follow up question from earlier in the thread. Is there now support for source maps for server-side javascript?
@bengourley could we reopen this issue?
I think we need a way to define a wildcard in place of next BUILD_ID.
For example minifiedUrl
like this one:
https://example.com/_next/static/L0eJ6XV0Hw9IEdAUlJFh5/pages/example.js
should be:
https://example.com/_next/static/*/pages/example.js
I'm thinking to add an additional transformSource
option to plugin setting that will allow transforming of a source string, e.g. static/L0eJ6XV0Hw9IEdAUlJFh5/pages/example.js
to static/*/pages/example.js
.
@bnisbett yes we support server side source maps now! You should upload your source maps -> https://docs.bugsnag.com/platforms/javascript/source-maps/#source-map-upload
So here is my next.config.js to upload client and server sourcemaps.
Next.js version 8
@zeit/next-source-maps version 0.0.4-canary.1
const fp = require("lodash/fp");
const enhance = fp.compose(
require("@zeit/next-source-maps")({ devtool: "hidden-source-map" }),
// Add other plugins here
);
module.exports = enhance({
webpack(config, { isServer, dev }) {
if (isServer) {
config.devtool = "source-map";
}
const BUGSNAG_API = isServer
? BUGSNAG_API_SERVER_KEY // replace here
: BUGSNAG_API_CLIENT_KEY; // replace here
if (!dev) {
const { BugsnagSourceMapUploaderPlugin } = require("webpack-bugsnag-plugins");
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: BUGSNAG_API,
overwrite: true,
releaseStage: "production",
publicPath: isServer
? ".next/server/"
: "*/_next/"
})
);
}
return config;
}
});
@bengourley do you think you could share how to integrate this into nextjs? the example doesn't talk about how to get sourcemaps working.
@azizhk @lifeiscontent Our docs describe how to get source maps applied to any js project.
This can be done using either our bugsnag-sourcemaps
tool:
https://docs.bugsnag.com/build-integrations/js/#uploading-source-maps
or using our webpack plugin: https://docs.bugsnag.com/build-integrations/webpack/#uploading-source-maps
Our FAQs cover the common reasons why source maps may not be applied: https://docs.bugsnag.com/api/js-source-map-upload/#frequently-asked-questions
If you're still having issues getting this to work can you contact support@bugsnag.com or raise a support request via the Bugsnag dashboard with details of which Bugsnag project this relates to? We can then take a look at your account / project and help to diagnose the reason.
My solution above works for me. @lifeiscontent can you mention your next.js version and I can point you accordingly.
@lifeiscontent the following is my config for Next 7 that successfully loads source maps to Bugsnag. It is based off the work @azizhk already shared.
const {
bugsnagApiKeyServer,
bugsnagApiKeyClient,
} = require("./env-config.js");
const {
BugsnagBuildReporterPlugin,
BugsnagSourceMapUploaderPlugin
} = require("webpack-bugsnag-plugins");
const DEPLOY_ENV = process.env.DEPLOY_ENV || "development";
module.exports = {
serverRuntimeConfig: { bugsnagApiKey: bugsnagApiKeyServer },
publicRuntimeConfig: { bugsnagApiKey: bugsnagApiKeyClient },
webpack: (config, { buildId, isServer }) => {
if (DEPLOY_ENV !== "development") {
config.plugins.push(
new BugsnagBuildReporterPlugin({
apiKey: isServer ? bugsnagApiKeyServer : bugsnagApiKeyClient,
appVersion: buildId,
releaseStage: DEPLOY_ENV,
sourceControl: {
provider: "<PROVIDER_NAME>",
repository: "<PROVIDER_URL>",
revision: "$Format:%H$"
}
})
);
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: isServer ? bugsnagApiKeyServer : bugsnagApiKeyClient,
appVersion: buildId,
overwrite: true,
publicPath: isServer ? ".next/server" : `<DOMAIN>/_next/`
})
);
}
return config;
}
};
@azizhk here's my config that is currently not working
const fs = require('fs');
const path = require('path');
const withSass = require('@zeit/next-sass');
const withSourceMaps = require('@zeit/next-source-maps');
const {
BugsnagBuildReporterPlugin,
BugsnagSourceMapUploaderPlugin,
} = require('webpack-bugsnag-plugins');
const RELEASE_STAGE = process.env.RELEASE_STAGE || 'development';
function getRevision() {
if (fs.existsSync('.git')) {
const rev = fs
.readFileSync('.git/HEAD')
.toString()
.trim()
.split(/.*[: ]/)
.slice(-1)[0];
if (rev.indexOf('/') === -1) {
return rev;
} else {
return fs
.readFileSync(`.git/${rev}`)
.toString()
.trim();
}
}
}
module.exports = withSourceMaps(
withSass({
publicRuntimeConfig: {
BUGSNAG_API_KEY: process.env.BUGSNAG_BROWSER_API_KEY,
},
serverRuntimeConfig: {
BUGSNAG_API_KEY: process.env.BUGSNAG_SERVER_API_KEY,
},
sassLoaderOptions: {
includePaths: ['styles', 'node_modules'].map(d =>
path.join(__dirname, d)
),
sourceMap: true,
},
cssLoaderOptions: {
sourceMap: true,
},
webpack(config, { buildId, isServer }) {
if (RELEASE_STAGE !== 'development') {
config.plugins.push(
new BugsnagBuildReporterPlugin({
apiKey: isServer
? process.env.BUGSNAG_SERVER_API_KEY
: process.env.BUGSNAG_BROWSER_API_KEY,
appVersion: process.env.HEROKU_RELEASE_VERSION || buildId,
releaseStage: RELEASE_STAGE,
notifyReleaseStages: ['staging', 'production'],
sourceControl: {
provider: 'github',
repository: 'https://github.com/redacted/redacted',
revision: getRevision(),
},
})
);
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: isServer
? process.env.BUGSNAG_SERVER_API_KEY
: process.env.BUGSNAG_BROWSER_API_KEY,
appVersion: process.env.HEROKU_RELEASE_VERSION || buildId,
overwrite: true,
publicPath: isServer ? '.next/server' : '*/_next/',
releaseStage: RELEASE_STAGE,
notifyReleaseStages: ['staging', 'production'],
})
);
}
return config;
},
})
);
Can you share the version of next.js that you are using?
Hi @lifeiscontent
Thanks for raising the related support request. As mentioned on the response, looking at your account I can see that your uploaded source maps have an app version specified but the error reports we're receiving from your application don't, so setting the appVersion
when initializing Bugsnag in your application should resolve this.
@azizhk I'm using next 8 and it seems source maps are not being uploaded on the browser end of things
@mattdyoung do I need to map over the outputs in webpack with the plugin? it seems to only be uploading the server js source maps.
This ended up being resolved under a Bugsnag support request.
For anyone else with this issue, it looks to be an issue with Next, but we've found a workaround.
You would need to apply this package:
https://github.com/zeit/next-plugins/tree/master/packages/next-source-maps
but you'll need the latest pre-release version:
@zeit/next-source-maps@0.0.4-canary.1
Next doesn't output source maps by default. This plugin enables source map generation, but with versions before this one it had a bug where it didn't output for browser, only for Node.js. Here's the related issue: https://github.com/zeit/next-plugins/issues/377#issuecomment-513604330
Is someone still here?)
I have an issue with this. I loaded my sourcemaps
to bugsnag but when i tried to start my server locally with now dev is seems that something went wrong:
Preparing next.config.js for build: [BugsnagSourceMapUploaderPlugin] uploading sourcemap for "*/static/runtime/webpack.js"
It just keep spinning forever. Can someone tell what is going on?
const path = require('path');
const webpack = require('webpack')
const withSass = require('@zeit/next-sass');
const {
WebpackBundleSizeAnalyzerPlugin
} = require('webpack-bundle-size-analyzer');
const { ANALYZE_SIZE } = process.env;
const {
BugsnagBuildReporterPlugin,
BugsnagSourceMapUploaderPlugin
} = require("webpack-bugsnag-plugins");
const withSourceMaps = require('@zeit/next-source-maps')
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === 'true',
});
const globalSass = [
path.resolve(__dirname, 'styles/_mixins.scss'),
path.resolve(__dirname, 'styles/_variables.scss'),
path.resolve(__dirname, 'styles/_functions.scss'),
path.resolve(__dirname, 'styles/_placeholders.scss')
]
module.exports = withBundleAnalyzer(withSass(withSourceMaps({
sassLoaderOptions: {
includePaths: ['public/assets/styles']
},
webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
config.module.rules.push({
enforce: "pre",
test: /\.scss$/,
loader: "sass-resources-loader",
options: {
resources: globalSass
}
});
config.plugins.push(
new webpack.IgnorePlugin(/^encoding$/, /node-fetch/)
);
if (ANALYZE_SIZE) {
config.plugins.push(new WebpackBundleSizeAnalyzerPlugin('stats.txt'))
}
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: '********',
appVersion: buildId,
publicPath: '*/',
override: true,
uploadSource: true,
})
);
return config
}
})));
module.exports.target = 'serverless'
You just need to add an if condition to add BugsnagSourceMapUploaderPlugin in production mode.
if (!dev) {
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: '********',
appVersion: buildId,
publicPath: '*/',
override: true,
uploadSource: true,
})
);
}
Oh my, thank you)
But i have another question) It seems that my source maps is ignored for now
What can i do about this?
Do you set appVersion
as the buildId when initializing bugsnag client? https://github.com/bugsnag/webpack-bugsnag-plugins/issues/3#issuecomment-512822605
(Even after setting appVersion, you will see sourcemaps only for new errors)
You mean here?
import React from 'react';
import bugsnag from '@bugsnag/js';
import bugsnagReact from '@bugsnag/plugin-react';
const bugsnagClient = bugsnag({
apiKey: 'd0a59e8349ee3e1ba609cdbd2ecaecc5',
notifyReleaseStages: ['production', 'staging'],
appVersion: '1.0.0' <---- is this it?
});
bugsnagClient.use(bugsnagReact, React);
export default bugsnagClient;
as I understand it buildId and this version must be the same, but how to know buildID?
if (typeof window !== "undefined" && window.__NEXT_DATA__ && window.__NEXT_DATA__.buildId) {
const bugsnagClient = bugsnag({
apiKey: 'd0a59e8349ee3e1ba609cdbd2ecaecc5',
notifyReleaseStages: ['production', 'staging'],
appVersion: window.__NEXT_DATA__.buildId
});
}
You should initialize this in browser.
Similarly on the server also you would get global.__NEXT_DATA__.buildId
. For that you would have to upload server side sourcemaps as well.
Ok, sorry but it seems that i cant understand something, this is our global:
global ->>> Object [global] {
global: [Circular],
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] { [Symbol(util.promisify.custom)]: [Function] },
queueMicrotask: [Function: queueMicrotask],
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(util.promisify.custom)]: [Function]
},
'__core-js_shared__': {
versions: [ [Object] ],
wks: {
toStringTag: Symbol(Symbol.toStringTag),
_hidden: Symbol(Symbol._hidden),
toPrimitive: Symbol(Symbol.toPrimitive),
hasInstance: Symbol(Symbol.hasInstance),
isConcatSpreadable: Symbol(Symbol.isConcatSpreadable),
iterator: Symbol(Symbol.iterator),
match: Symbol(Symbol.match),
replace: Symbol(Symbol.replace),
search: Symbol(Symbol.search),
species: Symbol(Symbol.species),
split: Symbol(Symbol.split),
unscopables: Symbol(Symbol.unscopables),
asyncIterator: Symbol(Symbol.asyncIterator),
observable: Symbol(Symbol.observable)
},
keys: { IE_PROTO: 'Symbol(IE_PROTO)_2.5e9ufk9ygw' },
'symbol-registry': {},
symbols: {},
'op-symbols': {}
},
__DEBUG__: false,
__extends: [Function: __extends],
__assign: [Function: assign],
__rest: [Function: __rest],
__decorate: [Function: __decorate],
__param: [Function: __param],
__metadata: [Function: __metadata],
__awaiter: [Function: __awaiter],
__generator: [Function: __generator],
__exportStar: [Function: __exportStar],
__values: [Function: __values],
__read: [Function: __read],
__spread: [Function: __spread],
__spreadArrays: [Function: __spreadArrays],
__await: [Function: __await],
__asyncGenerator: [Function: __asyncGenerator],
__asyncDelegator: [Function: __asyncDelegator],
__asyncValues: [Function: __asyncValues],
__makeTemplateObject: [Function: __makeTemplateObject],
__importStar: [Function: __importStar],
__importDefault: [Function: __importDefault],
fetch: [Function]
}
It seems our global has not _NEXTDATA on server, but on client it seems that we have it and
when i starting it locally it buildId: "development"
when i starting it locally it buildId: "development" Yeah when you build in production mode, it will generate and populate a buildId.
Regarding the buildId on server, you can use webpack's define plugin:
// next.config.js
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
config.plugins.push(
new webpack.DefinePlugin({
"process.env.APP_VERSION": JSON.stringify(buildId),
})
);
}
}
This will give you the buildId in process.env.APP_VERSION
Sorry but it seems that it`s all the same(
Now in config:
config.plugins.push(
new webpack.DefinePlugin({
"process.env.APP_VERSION": JSON.stringify(buildId),
})
);
if (!dev) {
config.plugins.push(
new BugsnagSourceMapUploaderPlugin({
apiKey: '**************',
appVersion: process.env.APP_VERSION,
publicPath: '*/',
override: true,
uploadSource: true
})
);
}
and in bugsnag config is
import React from 'react';
import bugsnag from '@bugsnag/js';
import bugsnagReact from '@bugsnag/plugin-react';
import config from '../config';
const bugsnagClient = bugsnag({
apiKey: config.apiKey,
notifyReleaseStages: ['production', 'staging'],
appVersion: process.browser
? global.__NEXT_DATA__.buildId
: process.env.APP_VERSION
});
bugsnagClient.use(bugsnagReact, React);
export default bugsnagClient;
No need to do
appVersion: process.browser
? global.__NEXT_DATA__.buildId
: process.env.APP_VERSION
Now you can directly use process.env.APP_VERSION
for both client and server.
@VadymBoguslavsky I'd suggest if you're still having issues you contact support@bugsnag.com with full details of your config and a link to an example of an error in your dashboard which hasn't correctly mapped which will enable us to analyze the root cause much more quickly.
@mattdyoung seems a recent version of next.js broke sourcemaps again. Should I reach out to support@bugsnag.com?
Hey @lifeiscontent if you're ever experiencing any issues, please don't hesitate to reach out to support@bugsnag.com!
same problem exists in nextjs 14 with server pages sourcemaps. looking inside the compilation stats
object, i found that page chunk files and auxiliary files are resolved relative to outputPath
which is set to .next/server/chunks
:
{
"publicPath": "/_next/",
"outputPath": "/path/to/project/.next/server/chunks",
"chunks": [
{
"names": ["pages/hello"],
"files": ["../pages/hello.js"],
"auxiliaryFiles": ["../pages/hello.js.map"],
// ...
},
{
"reason": "split chunk (cache group: default)",
"names": [],
"files": ["123.js"],
"auxiliaryFiles": ["123.js.map"],
// ...
},
// ...
],
// ...
}
this causes sourcemaps to be uploaded with ".."
in the url and bugsnag cannot match them to the actual pages that report issues:
<i> [BugsnagSourceMapUploaderPlugin] uploading sourcemap for ".next/server/chunks/../pages/hello.js"
<i> [BugsnagSourceMapUploaderPlugin] uploading sourcemap for ".next/server/chunks/123.js"
i was able to "fix" this by deleting parent directory reference (/chunks/../
-> /
). this simple change worked for my problem but i couldn't think of a more general solution.
PS: i also needed to pass publicPath
to the plugin config (as @azizhk pointed out here) and use different value for server builds
new BugsnagSourceMapUploaderPlugin({
// ...
publicPath: isServer ? ".next/server/chunks/" : "*/_next/"
})
Hello :) bugsnag requires the publicPath, but in nextjs generated project, the public path is always with chunkhash, but the file is under
.next/bundle
.So when I upload the sourcemap under
./next/bundle
, it wont work with the caught error in minified production code.is there any other way to fix this issue? thanks!
website:
error in bugsnag
uploaded source map