Closed jasperf closed 2 years ago
Testing
...
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'source-map',
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: process.env.BUGSNAG_API_KEY,
appVersion: process.env.BUGSNAG_APP_VERSION,
publicPath: '*/js'
...
now
Hi @jasperf,
publicPath
should be the path to your bundled assets as it appears in the stacktrace. If your app is running in the browser this is normally the base URL of your app, e.g. https://site.com/public/
. This should have a trailing slash, but the plugin will add one if not present so it's not required.publicPath
if your JS is being served at multiple URLs, e.g. https://*.site.com/public/
@yousif-bugsnag Thanks for getting back on this. As I posted we are now using a wildcard as part of publicPath
and we did see feedback in terminal on running npm run prod
. Feedback that source maps were being uploaded.
Only we do not have new errors yet in which the source maps are loaded. Old errors still show that source maps do not load. Is there a way to check uploaded sourcemaps besides their usage in error reports?
Also it seems now that this setup I shared
...
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'source-map',
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: process.env.BUGSNAG_API_KEY,
appVersion: process.env.BUGSNAG_APP_VERSION,
publicPath: '*/js'
})
],
output: {
chunkFilename: 'js/components/[name].js?id=[contenthash]',
},
})
} else {
mix.webpackConfig({
output: {
chunkFilename: 'js/components/[name].js',
},
});
}
...
is causing production request for source maps also which are not on the server.. and should not be. Any ideas how we can avoid that @yousif-bugsnag? Perhaps I should have a separate block?
We will by doing things with hidden-source-map
https://webpack.js.org/configuration/devtool/#production
Using hidden-source-map
got me errors
<i> [BugsnagSourceMapUploaderPlugin] uploading sourcemap for "*/js/js/components/editor/smt-i.js?id=6bf8cf2a14c0ec3b"
<i> [BugsnagSourceMapUploaderPlugin] uploading sourcemap for "*/js/js/components/editor/smt-contact-module.js?id=a24b946c0ba7fdca"
<i> [BugsnagSourceMapUploaderPlugin] uploading sourcemap for "*/js/main.js"
<i> [BugsnagSourceMapUploaderPlugin] uploading sourcemap for "*/js/js/components/editor/smt-image-module.js?id=5bc33caddd1bcfe2"
....
<i> [BugsnagSourceMapUploaderPlugin] uploading sourcemap for "*/js/js/components/publish/smt-diagonal-line-module.js?id=9c2a74b58dd93f85"
[webpack-cli] NetworkError: HTTP status 409 received from upload API
at /Users/jasper/code/site.com/site.com/node_modules/@bugsnag/source-maps/dist/Request.js:105:33
at ConcatStream.<anonymous> (/Users/jasper/code/site.com/site.com/node_modules/concat-stream/index.js:37:43)
at ConcatStream.emit (node:events:402:35)
at finishMaybe (/Users/jasper/code/site.com/site.com/node_modules/readable-stream/lib/_stream_writable.js:624:14)
at afterWrite (/Users/jasper/code/site.com/site.com/node_modules/readable-stream/lib/_stream_writable.js:470:3)
at processTicksAndRejections (node:internal/process/task_queues:85:21) {
isRetryable: false,
code: 1,
cause: null,
responseText: 'duplicate source map file for */js/main.js version 1.11.8'
Never mind, I needed a new version.
I just had another error but was told no sourcemap was located, but they were uploaded. How to debug this?
Generate source maps to see the original source file and line numbers. No link to a source map was found in your minified JavaScript file. Either include the link when generating source maps or upload them to us. (Note that events are not reprocessed after source maps are uploaded.)
Here is what we are using:
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'hidden-source-map',
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: process.env.BUGSNAG_API_KEY,
appVersion: process.env.BUGSNAG_APP_VERSION,
publicPath: '*/js'
})
],
output: {
chunkFilename: 'js/components/[name].js?id=[contenthash]',
},
})
} else {
mix.webpackConfig({
output: {
chunkFilename: 'js/components/[name].js',
},
});
We chose hidden-source-map
to have the source maps only uploaded and not shown to end users. But we still need Bugsnag to be able to read the sourcemaps. How do we do this?
NB we we had source-map
only we had 404s as well so perhaps we need to do something still to refer to sourcemaps?
Also possibly related https://github.com/laravel-mix/laravel-mix/issues/1651 and https://github.com/laravel-mix/laravel-mix/issues/1793
@jasperf By default, we look for uploaded-to-Bugsnag maps first, then if no matches are found there, we look for a //# sourceMappingURL
(or X-SourceMap
header). The error message you've quoted above suggests that:
//# sourceMappingURL
exists on this webpage, which figures as you're using hidden-source-map
which removes this comment from your output bundle.If you could drop us a link to an event that's failing to map but that you would expect it to map, we can take a look into that specific example and help explain why. You can message us at support@bugsnag.com or drop the link here.
We chose hidden-source-map to have the source maps only uploaded and not shown to end users. But we still need Bugsnag to be able to read the sourcemaps. How do we do this?
You would need to upload the sourcemaps to Bugsnag, which it looks like you're already doing according the Webpack snippet.
Will email de link to the even to you @xander-jones . Hope we can work out what is missing. Setup was kind of tricky for us and we really want to make it work so debugging becomes easier then it is without source maps.
email sent but link here once more https://app.bugsnag.com/smart48/smart48/errors/61a0b97d9abbc10007c35b6e?filters[event.since]=7d&filters[app.release_stage]=production&sort=events
Thanks for the link @jasperf! I'm going to close this issue as we are communicating via the support ticket, but for the benefit of future travellers:
Bugsnag uses both the frame URL and the app version to match uploaded source maps to events, so if you are specifying an appVersion
in your webpack config you will need to ensure the same value is used for the appVersion
config value when initialising Bugsnag in your JS app.
Also good to mention this which was mentioned by Bugsnag in email
So to summarize, you should:
- Specify an appVersion when initializing Bugsnag in your app
- Set the publicPath to '*' in your webpack config as js
was mentioned twice in path
Had to leave this be for a while but I am afraid I am still seeing
Missing JavaScript files:Provide JavaScript files for improved grouping and better stack traces
Ensure uploaded source maps match this version or make your JavaScript files accessible from our servers. (Note that events are not reprocessed after source maps are uploaded.)
--
[Ensure uploaded source maps match this version or make your JavaScript files accessible from our servers. (Note that events are not reprocessed after source maps are uploaded.)]()
--
and we do use
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'hidden-source-map',
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: process.env.BUGSNAG_API_KEY,
appVersion: process.env.BUGSNAG_APP_VERSION,
publicPath: '*'
})
],
and we update BUGSNAG_APP_VERSION=1.15.13
in .env every
npm run prod` . And the files are uploaded.
Hey @jasperf at a glance it looks like source maps are being applied correctly to recent events in your project - is this still an issue you're experiencing? If please share a link again with support@bugsnag.com and we can take a look.
I have zero JS error events currently. Guess we are deploying well to production. But before that I never had sourcemaps loading properly for JS. Will be testing some more with staging
added as environment.
@yousif-bugsnag Saw the latest files built getting uploaded on npm run prod
but still I see:
TypeError/editor
u.left.replace is not a function
12 minutes ago
Apr 7th, 12:11:08 GMT+7
production
unhandled
Missing JavaScript files: Provide JavaScript files for improved grouping and better stack traces View Details Source maps guide
TypeError · u.left.replace is not a function
https://site.test/js/editor.js:2:141391 n.value
https://site.test/js/components/editor/module.js:1:20167 a.positionObject
https://site.test/js/editor.js:2:1889012 hn.get
https://site.test/js/editor.js:2:1890152 hn.evaluate
https://site.test/js/editor.js:2:1890917 a.positionObject
https://site.test/js/components/editor/module.js:1:23890 a.<anonymous>
https://site.test/js/editor.js:2:1896989 a.t._render
https://site.test/js/editor.js:2:1930681 a.r
https://site.test/js/editor.js:2:1889012 hn.get
https://site.test/js/editor.js:2:1888930 new hn
Hi @jasperf - I've had a look at your dashboard and it appears that your events are missing an app version, whereas your sourcemaps have an app version set. The app versions must match in order for source maps to be applied correctly. You can read about setting app version in our docs.
If you're still having trouble please feel free to write back into support@bugsnag.com.
@luke-belton our Laravel Vue app has the app version set in .env
using BUGSNAG_APP_VERSION=1.19
which is loaded from webpack.mix.js
:
const mix = require('laravel-mix')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const { BugsnagSourceMapUploaderPlugin } = require('webpack-bugsnag-plugins')
....
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'hidden-source-map',
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: process.env.BUGSNAG_API_KEY,
appVersion: process.env.BUGSNAG_APP_VERSION,
publicPath: '*'
})
],
output: {
chunkFilename: 'js/components/[name].js?id=[contenthash]',
},
})
} else {
mix.webpackConfig({
output: {
chunkFilename: 'js/components/[name].js',
},
});
}
....
And in main js files for app we use
....
import bugsnag from '@bugsnag/js'
import bugsnagVue from '@bugsnag/plugin-vue'
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
let bugsnagClient = bugsnag({
apiKey: 'key',
interactionBreadcrumbsEnabled: false
})
bugsnagClient.use(bugsnagVue, Vue)
}
...
So what else are we missing here?
Hi @jasperf,
Setting the appVersion
in the webpack plugin means that your source maps will be uploaded with an appVersion set, but this is separate to the Bugsnag client. In order for events to be sent with an appVersion (which is necessary for matching with uploaded source maps) you will also need to set the appVersion
config option when initialising Bugsnag in main.js
.
You should also be calling Bugsnag.start()
passing in the Vue plugin to initialise the client - please see our Vue integration guide for how to initialise Bugsnag in your Vue app: https://docs.bugsnag.com/platforms/javascript/vue/
import Bugsnag from '@bugsnag/js'
import BugsnagPluginVue from '@bugsnag/plugin-vue'
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
Bugsnag.start({
apiKey: 'YOUR_API_KEY',
appVersion: process.env.BUGSNAG_APP_VERSION
plugins: [new BugsnagPluginVue()]
})
}
@yousif-bugsnag Thanks a lot for explaining this in more detail. Seems I was missing Bugsnag.start()
to initialize the client. this to allow the appVersion
to be sent alone with events, not just in the uploaded source maps.
We now have
import Bugsnag from '@bugsnag/js'
import BugsnagVue from '@bugsnag/plugin-vue'
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
Bugsnag.start({
apiKey: 'key',
appVersion: process.env.BUGSNAG_APP_VERSION,
plugins: [new BugsnagPluginVue()]
})
}
BugsnagVue
is not being used here in this setup. So perhaps you meant plugins: [new BugsnagVue()]
instead of BugsnagPluginVue()
?
also wonder if we should use
const bugsnagVue = Bugsnag.getPlugin('vue')
bugsnagVue.installVueErrorHandler(Vue)
Hi @jasperf - apologies, the import statement above should have been:
import BugsnagPluginVue from '@bugsnag/plugin-vue'
I've edited our last comment to reflect that.
Are you using Vue 2 or Vue 3? The way you install the error handler will depend on which version of Vue you are using, as described in our docs: https://docs.bugsnag.com/platforms/javascript/vue/#basic-configuration.
@luke-belton Thanks for the edit. We are using Vue 2 so that would mean
const bugsnagVue = Bugsnag.getPlugin('vue')
bugsnagVue.installVueErrorHandler(Vue)
Should this be added before or after imports at
import Bugsnag from '@bugsnag/js'
import BugsnagPluginVue from '@bugsnag/plugin-vue'
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
Bugsnag.start({
apiKey: 'key',
appVersion: process.env.BUGSNAG_APP_VERSION,
plugins: [new BugsnagPluginVue()]
})
}
?
Version
import Bugsnag from '@bugsnag/js'
import BugsnagPluginVue from '@bugsnag/plugin-vue'
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
const bugsnagClient = Bugsnag.start({
apiKey: 'key',
appVersion: process.env.BUGSNAG_APP_VERSION,
plugins: [new BugsnagPluginVue()]
})
Vue.use(bugsnagClient) // // this is also important
}
did cause errors on build mentioning BugsnagPluginVue()
is not a constructor . If I am still missing something please let me know.
Hi @jasperf,
@luke-belton Thanks for the edit. We are using Vue 2 so that would mean
const bugsnagVue = Bugsnag.getPlugin('vue') bugsnagVue.installVueErrorHandler(Vue)
This is the correct way to initialise Bugsnag in Vue 2. Note that this should be added after the call to Bugsnag.start()
@yousif-bugsnag thanks for getting back to me. Previously added code with different Vue.use
call still had the error that BugsnagPluginVue()
was not a constructor.
When we tested:
import Bugsnag from '@bugsnag/js'
import BugsnagPluginVue from '@bugsnag/plugin-vue'
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
Bugsnag.start({
apiKey: 'key',
appVersion: process.env.BUGSNAG_APP_VERSION,
plugins: [new BugsnagPluginVue()]
})
const bugsnagVue = Bugsnag.getPlugin('vue')
bugsnagVue.installVueErrorHandler(Vue)
}
in app.js
(not webpack.mix.js
) we still have the same error Uncaught TypeError: BugsnagPluginVue(...) is not a constructor
or locally built Uncaught TypeError: _bugsnag_plugin_vue__WEBPACK_IMPORTED_MODULE_46___default(...) is not a constructor
Added
{
"compilerOptions": {
"baseUrl": ".",
"module": "CommonJS",
"resolveJsonModule": true,
"strictNullChecks": true,
"esModuleInterop": true,
...
with "esModuleInterop": true,
to jsconfig.json
but it did not help either
Perhaps something off with the import here. But if I use require
instead I still get Uncaught TypeError: BugsnagPluginVue is not a constructor
. Import with {}
does not solve the issue either so something else must be the problem.
fyi
npm view @bugsnag/js
@bugsnag/js@7.16.2 | MIT | deps: 2 | versions: 109
Universal Javascript error reporting. Automatically detect JavaScript errors in the browser and Node.js, with plugins for React, Vue, Angular, Express, Restify and Koa.
https://www.bugsnag.com/
...
npm view @bugsnag/plugin-vue
@bugsnag/plugin-vue@7.16.2 | MIT | deps: none | versions: 84
Vue.js integration for bugsnag-js
https://www.bugsnag.com/
....
@jasperf Please update to the latest version (7.16.*) for @bugsnag/js and @bugsnag/plugin-vue, everything will work fine.
Built locally now with latest versions but did get
bugsnag] installVueErrorHandler() was called unnecessarily
installVueErrorHandler @ file.js?id=cb0bf50710bd2e81dc36:2
so made it
import Bugsnag from '@bugsnag/js'
import BugsnagPluginVue from '@bugsnag/plugin-vue'
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
Bugsnag.start({
apiKey: 'key',
appVersion: process.env.BUGSNAG_APP_VERSION,
plugins: [new BugsnagPluginVue()]
})
// call not needed
// const bugsnagVue = Bugsnag.getPlugin('vue')
// bugsnagVue.installVueErrorHandler(Vue)
}
Unfortunately I am still getting
Source mapping failed:Missing source map linkHide DetailsSource maps guideGenerate source maps to see the original source file and line numbers. No link to a source map was found in your minified JavaScript file. Either include the link when generating source maps or upload them to us. (Note that events are not reprocessed after source maps are uploaded.)
--
Missing source map link
Hide Details
[Source maps guide](https://docs.bugsnag.com/platforms/browsers/js/source-maps/)
Generate source maps to see the original source file and line numbers. No link to a source map was found in your minified JavaScript file. Either include the link when generating source maps or upload them to us. (Note that events are not reprocessed after source maps are uploaded.)
On npm run prod
we do generate sourcemaps and these are uploaded.
We do use devtool: 'hidden-source-map'
Do we need to include source maps links in our production code to have this work @yousif-bugsnag ?
we now have
...
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'hidden-source-map',
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: process.env.BUGSNAG_API_KEY,
appVersion: process.env.BUGSNAG_APP_VERSION,
publicPath: '*'
})
],
...
should it be
...
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'source-map',
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
],
...
Or...?
Hi @jasperf - you should be able to use the hidden-source-map
devtool option if you're uploading source maps to Bugsnag. We have guidance on uploading source maps in our docs: https://docs.bugsnag.com/platforms/javascript/source-maps/#uploading-source-maps-recommended.
If you're still having trouble, please can you write into support@bugsnag.com referencing this GitHub issue and sharing links to events in your dashboard that aren't being mapped, as well as the command you're using to upload source maps. Thanks!
@luke-belton we tested
appVersion: `'${process.env.BUGSNAG_APP_VERSION}'`,
in
if (process.env.NODE_ENV == 'production' || process.env.NODE_ENV == 'staging') {
Bugsnag.start({
apiKey: 'redacted',
appVersion: `'${process.env.BUGSNAG_APP_VERSION}'`,
plugins: [new BugsnagPluginVue()]
})
// call installVueErrorHandler not needed
// const bugsnagVue = Bugsnag.getPlugin('vue')
// bugsnagVue.installVueErrorHandler(Vue)
}
to have appVersion
uploaded as a string as well. Seems it was rejected by Bugsnag because it was not sent in as a string like the API key.
However, it does not work yet
Mi().start({
apiKey: "key",
appVersion: "'".concat(Fi.env.BUGSNAG_APP_VERSION, "'"),
plugins: [new (Bi())]
}),
Seems process.env
does not work. Not inside Bugsnag.start
nor defined as const
before the if statement. Hardcoded version as string for now. But not happy about it.
Are you using https://webpack.js.org/plugins/define-plugin/? If you want process.env.x
to be available in the bundle at runtime you need to "export" it by using DefinePlugin
@djskinner Thanks for the tip. We do use Webpack/Laravel Mix with some plugins already. No we are not using Define Plugin yet. Looks like something we should use. The code loading the appVersion
is in two .js files now and hard coded.
But I guess if we add:
new webpack.DefinePlugin({
'process.env.BUGSNAG_APP_VERSION': JSON.stringify(process.env.BUGSNAG_APP_VERSION),
});
and perhaps api key too inside webpack.mix.js.
:
if (mix.inProduction()) {
mix.webpackConfig({
devtool: 'hidden-source-map',
plugins: [
new DefinePlugin({
'process.env.BUGSNAG_APP_VERSION': JSON.stringify(process.env.BUGSNAG_APP_VERSION),
'process.env.BUGSNAG_API_KEY': JSON.stringify(process.env.BUGSNAG_API_KEY),
}),
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
protectWebpackAssets: true,
cleanOnceBeforeBuildPatterns: ['js/components/*'],
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: process.env.BUGSNAG_API_KEY,
appVersion: process.env.BUGSNAG_APP_VERSION,
publicPath: '*'
})
],
output: {
chunkFilename: 'js/components/[name].js?id=[contenthash]',
},
})
} else {
mix.webpackConfig({
output: {
chunkFilename: 'js/components/[name].js',
},
});
}
The values should be available at runtime. Perhaps not for usage in the webpack file, but for inside the editor.js
and preview.js
. Perhaps I should then also remove
BugsnagSourceMapUploaderPlugin
I think you should keep BugsnagSourceMapUploaderPlugin
so that your source maps get uploaded for production builds
@djskinner True. Need to keep it for uploading with path. Thank you for your feedback. Much appreciated. Will test all out soon. Hope it will all work once and for all.
In the end I realized Laravel Mix does have its own implementation of Define Plugin. But it blocks loading in .env
values unless you prefix them with MIX_
like MIX_BUGSNAG_APP_VERSION=
. Version loading now. Checked source code on staging. Just need to test on Bugsnag side.
Been reading on adding / uploading source maps for easier debugging JavaScript/Vue. That besides PHP debugging . So found your documentation on using the webpack plugin https://docs.bugsnag.com/build-integrations/webpack/ .
Not clear however on the integration into
webpack.mix.js
. Miss that at https://github.com/bugsnag/webpack-bugsnag-plugins and in documentation https://docs.bugsnag.com/platforms/php/laravel/ .If we use this in
webpack.mix.js
:publicPath
here? Should it behttps://site.com/public
? Or do I need to add a slash?inProduction
, but different domains(staging.domain.com
anddomain.com
)?NB Reading https://github.com/bugsnag/webpack-bugsnag-plugins/issues/11 some now as well, but not quite clear yet and would appreciate some feedback.