@honeybadger-io/nextjs 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/dist/copy-config-files.d.ts +5 -0
- package/dist/copy-config-files.js +25 -0
- package/dist/copy-config-files.js.map +1 -0
- package/dist/honeybadger-nextjs.cjs.js +152 -0
- package/dist/honeybadger-nextjs.cjs.js.map +1 -0
- package/dist/honeybadger-nextjs.esm.js +142 -0
- package/dist/honeybadger-nextjs.esm.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/types.d.ts +21 -0
- package/package.json +61 -0
- package/src/copy-config-files.ts +29 -0
- package/src/index.ts +169 -0
- package/src/types.ts +23 -0
- package/templates/honeybadger.browser.config.js +11 -0
- package/templates/honeybadger.edge.config.js +12 -0
- package/templates/honeybadger.server.config.js +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Honeybadger Next.js Integration
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://badge.fury.io/js/%40honeybadger-io%2Fnextjs)
|
|
5
|
+
[](https://www.npmjs.com/package/@honeybadger-io/nextjs)
|
|
6
|
+
[](https://www.npmjs.com/package/@honeybadger-io/nextjs)
|
|
7
|
+
|
|
8
|
+
## Documentation and Support
|
|
9
|
+
|
|
10
|
+
For comprehensive documentation and support, [check out our documentation site](https://docs.honeybadger.io/lib/javascript).
|
|
11
|
+
|
|
12
|
+
The documentation includes a detailed [Next.js integration guide](https://docs.honeybadger.io/lib/javascript/integration/nextjs).
|
|
13
|
+
|
|
14
|
+
## Project Goals
|
|
15
|
+
|
|
16
|
+
The goal is to provide an idiomatic, simple integration of Honeybadger's
|
|
17
|
+
exception monitoring service with Next.js applications.
|
|
18
|
+
|
|
19
|
+
## Project Status
|
|
20
|
+
|
|
21
|
+
This version is considered suitable for preview.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- Automatic reporting of uncaught exceptions (see [Limitations](#limitations))
|
|
26
|
+
- Breadcrumbs
|
|
27
|
+
- Source map upload to Honeybadger
|
|
28
|
+
- CLI command to generate Honeybadger configuration files for Next.js runtimes
|
|
29
|
+
|
|
30
|
+
## Limitations
|
|
31
|
+
|
|
32
|
+
The following limitations are known to exist and will be tackled in future releases:
|
|
33
|
+
|
|
34
|
+
- [Issue link](https://github.com/honeybadger-io/honeybadger-js/issues/1055): A custom `_error.js` component is used to report uncaught exceptions to Honeybadger.
|
|
35
|
+
This is necessary because Next.js does not provide a way to hook into the error handler.
|
|
36
|
+
This is not a catch-all errors solution. There are some caveats to this approach, as reported [here](https://nextjs.org/docs/advanced-features/custom-error-page#caveats).
|
|
37
|
+
This is a limitation of Next.js, not Honeybadger's Next.js integration.
|
|
38
|
+
Errors thrown in middlewares or API routes will not be reported to Honeybadger, since when they reach _error.js, the response status code is 404 and no error information is available.
|
|
39
|
+
Additionally, there is an open [issue](https://github.com/vercel/next.js/issues/45535) about 404 being reported with Next.js apps deployed on Vercel, when they should be reported as 500.
|
|
40
|
+
- [Issue link](https://github.com/honeybadger-io/honeybadger-js/issues/1056):Source maps for the [Edge runtime](https://vercel.com/docs/concepts/functions/edge-functions/edge-runtime) are not supported yet.
|
|
41
|
+
|
|
42
|
+
## Example app
|
|
43
|
+
|
|
44
|
+
A separate repository, [nextjs-with-honeybadger](https://github.com/honeybadger-io/nextjs-with-honeybadger) exists with an example app using this package.
|
|
45
|
+
Follow the README instructions to run the example app.
|
|
46
|
+
|
|
47
|
+
## Development
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# install dependencies
|
|
51
|
+
npm install
|
|
52
|
+
|
|
53
|
+
# build for production
|
|
54
|
+
npm run build
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### License
|
|
58
|
+
|
|
59
|
+
This package is MIT licensed. See the [MIT-LICENSE](./MIT-LICENSE) file in this folder for details.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const debug = process.env.HONEYBADGER_DEBUG === 'true';
|
|
6
|
+
async function copyConfigFiles() {
|
|
7
|
+
if (debug) {
|
|
8
|
+
console.debug('cwd', process.cwd());
|
|
9
|
+
}
|
|
10
|
+
const templateDir = path.resolve(__dirname, '../templates');
|
|
11
|
+
const files = await fs.promises.readdir(templateDir);
|
|
12
|
+
const copyPromises = files.map((file) => {
|
|
13
|
+
if (debug) {
|
|
14
|
+
console.debug('copying', file);
|
|
15
|
+
}
|
|
16
|
+
return fs.promises.copyFile(path.join(templateDir, file), file);
|
|
17
|
+
});
|
|
18
|
+
await Promise.all(copyPromises);
|
|
19
|
+
console.log('Done copying config files.');
|
|
20
|
+
}
|
|
21
|
+
copyConfigFiles().catch((err) => {
|
|
22
|
+
console.error(err);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=copy-config-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-config-files.js","sourceRoot":"","sources":["../src/copy-config-files.ts"],"names":[],"mappings":";;AAEA,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;AAC5B,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAExB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,CAAA;AAEtD,KAAK,UAAU,eAAe;IAC5B,IAAI,KAAK,EAAE;QACT,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;KACpC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACtC,IAAI,KAAK,EAAE;YACT,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;SAC/B;QACD,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAEhC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAA;AAC3C,CAAC;AAED,eAAe,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA","sourcesContent":["#!/usr/bin/env node\n\nconst path = require('path')\nconst fs = require('fs')\n\nconst debug = process.env.HONEYBADGER_DEBUG === 'true'\n\nasync function copyConfigFiles() {\n if (debug) {\n console.debug('cwd', process.cwd())\n }\n\n const templateDir = path.resolve(__dirname, '../templates');\n const files = await fs.promises.readdir(templateDir);\n const copyPromises = files.map((file) => {\n if (debug) {\n console.debug('copying', file)\n }\n return fs.promises.copyFile(path.join(templateDir, file), file);\n });\n await Promise.all(copyPromises);\n\n console.log('Done copying config files.')\n}\n\ncopyConfigFiles().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"]}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var fs = require('fs');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var HoneybadgerSourceMapPlugin = require('@honeybadger-io/webpack');
|
|
8
|
+
|
|
9
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
10
|
+
|
|
11
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
12
|
+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
13
|
+
var HoneybadgerSourceMapPlugin__default = /*#__PURE__*/_interopDefaultLegacy(HoneybadgerSourceMapPlugin);
|
|
14
|
+
|
|
15
|
+
let _silent = true;
|
|
16
|
+
function log(type, msg) {
|
|
17
|
+
if (type === 'error' || !_silent) {
|
|
18
|
+
console[type]('[HoneybadgerNextJs]', msg);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function shouldUploadSourceMaps(honeybadgerNextJsConfig, context) {
|
|
22
|
+
const { dev } = context;
|
|
23
|
+
if (honeybadgerNextJsConfig.disableSourceMapUpload) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (dev || process.env.NODE_ENV === 'development') {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
function setupHoneybadger(config, honeybadgerNextJsConfig) {
|
|
32
|
+
var _a;
|
|
33
|
+
_silent = (_a = honeybadgerNextJsConfig === null || honeybadgerNextJsConfig === void 0 ? void 0 : honeybadgerNextJsConfig.silent) !== null && _a !== void 0 ? _a : true;
|
|
34
|
+
return {
|
|
35
|
+
...config,
|
|
36
|
+
webpack: mergeWithExistingWebpackConfig(config.webpack, honeybadgerNextJsConfig)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function mergeWithExistingWebpackConfig(nextJsWebpackConfig, honeybadgerNextJsConfig) {
|
|
40
|
+
return function webpackFunctionMergedWithHb(webpackConfig, context) {
|
|
41
|
+
const { isServer, dir: projectDir, nextRuntime } = context;
|
|
42
|
+
const configType = isServer ? (nextRuntime === 'edge' ? 'edge' : 'server') : 'browser';
|
|
43
|
+
log('debug', `reached webpackFunctionMergedWithHb isServer[${isServer}] configType[${configType}]`);
|
|
44
|
+
let result = { ...webpackConfig };
|
|
45
|
+
if (typeof nextJsWebpackConfig === 'function') {
|
|
46
|
+
result = nextJsWebpackConfig(result, context);
|
|
47
|
+
}
|
|
48
|
+
const originalEntry = result.entry;
|
|
49
|
+
result.entry = async () => injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType);
|
|
50
|
+
if (shouldUploadSourceMaps(honeybadgerNextJsConfig, context)) {
|
|
51
|
+
// `result.devtool` must be 'hidden-source-map' or 'source-map' to properly pass sourcemaps.
|
|
52
|
+
// Next.js uses regular `source-map` which doesnt pass its sourcemaps to Webpack.
|
|
53
|
+
// https://github.com/vercel/next.js/blob/89ec21ed686dd79a5770b5c669abaff8f55d8fef/packages/next/build/webpack/config/blocks/base.ts#L40
|
|
54
|
+
// Use the hidden-source-map option when you don't want the source maps to be
|
|
55
|
+
// publicly available on the servers, only to the error reporting
|
|
56
|
+
result.devtool = 'hidden-source-map';
|
|
57
|
+
if (!result.plugins) {
|
|
58
|
+
result.plugins = [];
|
|
59
|
+
}
|
|
60
|
+
const options = getWebpackPluginOptions(honeybadgerNextJsConfig);
|
|
61
|
+
if (options) {
|
|
62
|
+
result.plugins.push(new HoneybadgerSourceMapPlugin__default["default"](options));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType) {
|
|
69
|
+
const hbConfigFile = getHoneybadgerConfigFile(projectDir, configType);
|
|
70
|
+
if (!hbConfigFile) {
|
|
71
|
+
return originalEntry;
|
|
72
|
+
}
|
|
73
|
+
const hbConfigFileRelativePath = `./${hbConfigFile}`;
|
|
74
|
+
const result = typeof originalEntry === 'function' ? await originalEntry() : { ...originalEntry };
|
|
75
|
+
if (!Object.keys(result).length) {
|
|
76
|
+
log('debug', `no entry points for configType[${configType}]`);
|
|
77
|
+
}
|
|
78
|
+
for (const entryName in result) {
|
|
79
|
+
addHoneybadgerConfigToEntry(result, entryName, hbConfigFileRelativePath, configType);
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
function addHoneybadgerConfigToEntry(entry, entryName, hbConfigFile, configType) {
|
|
84
|
+
log('debug', `adding entry[${entryName}] to configType[${configType}]`);
|
|
85
|
+
switch (configType) {
|
|
86
|
+
case 'server':
|
|
87
|
+
if (!entryName.startsWith('pages/')) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
case 'browser':
|
|
92
|
+
if (!['pages/_app', 'main-app'].includes(entryName)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
const currentEntryPoint = entry[entryName];
|
|
98
|
+
let newEntryPoint = currentEntryPoint;
|
|
99
|
+
if (typeof currentEntryPoint === 'string') {
|
|
100
|
+
newEntryPoint = [hbConfigFile, currentEntryPoint];
|
|
101
|
+
}
|
|
102
|
+
else if (Array.isArray(currentEntryPoint)) {
|
|
103
|
+
newEntryPoint = [hbConfigFile, ...currentEntryPoint];
|
|
104
|
+
} // descriptor object (webpack 5+)
|
|
105
|
+
else if (typeof currentEntryPoint === 'object' && currentEntryPoint && 'import' in currentEntryPoint) {
|
|
106
|
+
const currentImportValue = currentEntryPoint['import'];
|
|
107
|
+
const newImportValue = [hbConfigFile];
|
|
108
|
+
if (typeof currentImportValue === 'string') {
|
|
109
|
+
newImportValue.push(currentImportValue);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
newImportValue.push(...(currentImportValue));
|
|
113
|
+
}
|
|
114
|
+
newEntryPoint = {
|
|
115
|
+
...currentEntryPoint,
|
|
116
|
+
import: newImportValue,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
log('error', 'Could not inject Honeybadger config to entry point: ' + JSON.stringify(currentEntryPoint, null, 2));
|
|
121
|
+
}
|
|
122
|
+
entry[entryName] = newEntryPoint;
|
|
123
|
+
}
|
|
124
|
+
function getHoneybadgerConfigFile(projectDir, configType) {
|
|
125
|
+
const possibilities = [`honeybadger.${configType}.config.ts`, `honeybadger.${configType}.config.js`];
|
|
126
|
+
for (const filename of possibilities) {
|
|
127
|
+
if (fs__default["default"].existsSync(path__default["default"].resolve(projectDir, filename))) {
|
|
128
|
+
return filename;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
log('debug', `could not find config file in ${projectDir} for ${configType}`);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
function getWebpackPluginOptions(honeybadgerNextJsConfig) {
|
|
135
|
+
var _a, _b, _c;
|
|
136
|
+
const apiKey = ((_a = honeybadgerNextJsConfig.webpackPluginOptions) === null || _a === void 0 ? void 0 : _a.apiKey) || process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY;
|
|
137
|
+
const assetsUrl = ((_b = honeybadgerNextJsConfig.webpackPluginOptions) === null || _b === void 0 ? void 0 : _b.assetsUrl) || process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL;
|
|
138
|
+
if (!apiKey || !assetsUrl) {
|
|
139
|
+
log('error', 'Missing Honeybadger required configuration for webpack plugin. Source maps will not be uploaded to Honeybadger.');
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
...honeybadgerNextJsConfig.webpackPluginOptions,
|
|
144
|
+
apiKey,
|
|
145
|
+
assetsUrl,
|
|
146
|
+
revision: ((_c = honeybadgerNextJsConfig.webpackPluginOptions) === null || _c === void 0 ? void 0 : _c.revision) || process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
|
|
147
|
+
silent: _silent,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
exports.setupHoneybadger = setupHoneybadger;
|
|
152
|
+
//# sourceMappingURL=honeybadger-nextjs.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"honeybadger-nextjs.cjs.js","sources":["../../build/index.js"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport HoneybadgerSourceMapPlugin from '@honeybadger-io/webpack';\nlet _silent = true;\nfunction log(type, msg) {\n if (type === 'error' || !_silent) {\n console[type]('[HoneybadgerNextJs]', msg);\n }\n}\nfunction shouldUploadSourceMaps(honeybadgerNextJsConfig, context) {\n const { dev } = context;\n if (honeybadgerNextJsConfig.disableSourceMapUpload) {\n return false;\n }\n if (dev || process.env.NODE_ENV === 'development') {\n return false;\n }\n return true;\n}\nexport function setupHoneybadger(config, honeybadgerNextJsConfig) {\n var _a;\n _silent = (_a = honeybadgerNextJsConfig === null || honeybadgerNextJsConfig === void 0 ? void 0 : honeybadgerNextJsConfig.silent) !== null && _a !== void 0 ? _a : true;\n return {\n ...config,\n webpack: mergeWithExistingWebpackConfig(config.webpack, honeybadgerNextJsConfig)\n };\n}\nfunction mergeWithExistingWebpackConfig(nextJsWebpackConfig, honeybadgerNextJsConfig) {\n return function webpackFunctionMergedWithHb(webpackConfig, context) {\n const { isServer, dir: projectDir, nextRuntime } = context;\n const configType = isServer ? (nextRuntime === 'edge' ? 'edge' : 'server') : 'browser';\n log('debug', `reached webpackFunctionMergedWithHb isServer[${isServer}] configType[${configType}]`);\n let result = { ...webpackConfig };\n if (typeof nextJsWebpackConfig === 'function') {\n result = nextJsWebpackConfig(result, context);\n }\n const originalEntry = result.entry;\n result.entry = async () => injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType);\n if (shouldUploadSourceMaps(honeybadgerNextJsConfig, context)) {\n // `result.devtool` must be 'hidden-source-map' or 'source-map' to properly pass sourcemaps.\n // Next.js uses regular `source-map` which doesnt pass its sourcemaps to Webpack.\n // https://github.com/vercel/next.js/blob/89ec21ed686dd79a5770b5c669abaff8f55d8fef/packages/next/build/webpack/config/blocks/base.ts#L40\n // Use the hidden-source-map option when you don't want the source maps to be\n // publicly available on the servers, only to the error reporting\n result.devtool = 'hidden-source-map';\n if (!result.plugins) {\n result.plugins = [];\n }\n const options = getWebpackPluginOptions(honeybadgerNextJsConfig);\n if (options) {\n result.plugins.push(new HoneybadgerSourceMapPlugin(options));\n }\n }\n return result;\n };\n}\nasync function injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType) {\n const hbConfigFile = getHoneybadgerConfigFile(projectDir, configType);\n if (!hbConfigFile) {\n return originalEntry;\n }\n const hbConfigFileRelativePath = `./${hbConfigFile}`;\n const result = typeof originalEntry === 'function' ? await originalEntry() : { ...originalEntry };\n if (!Object.keys(result).length) {\n log('debug', `no entry points for configType[${configType}]`);\n }\n for (const entryName in result) {\n addHoneybadgerConfigToEntry(result, entryName, hbConfigFileRelativePath, configType);\n }\n return result;\n}\nfunction addHoneybadgerConfigToEntry(entry, entryName, hbConfigFile, configType) {\n log('debug', `adding entry[${entryName}] to configType[${configType}]`);\n switch (configType) {\n case 'server':\n if (!entryName.startsWith('pages/')) {\n return;\n }\n break;\n case 'browser':\n if (!['pages/_app', 'main-app'].includes(entryName)) {\n return;\n }\n break;\n case 'edge':\n // nothing?\n break;\n }\n const currentEntryPoint = entry[entryName];\n let newEntryPoint = currentEntryPoint;\n if (typeof currentEntryPoint === 'string') {\n newEntryPoint = [hbConfigFile, currentEntryPoint];\n }\n else if (Array.isArray(currentEntryPoint)) {\n newEntryPoint = [hbConfigFile, ...currentEntryPoint];\n } // descriptor object (webpack 5+)\n else if (typeof currentEntryPoint === 'object' && currentEntryPoint && 'import' in currentEntryPoint) {\n const currentImportValue = currentEntryPoint['import'];\n const newImportValue = [hbConfigFile];\n if (typeof currentImportValue === 'string') {\n newImportValue.push(currentImportValue);\n }\n else {\n newImportValue.push(...(currentImportValue));\n }\n newEntryPoint = {\n ...currentEntryPoint,\n import: newImportValue,\n };\n }\n else {\n log('error', 'Could not inject Honeybadger config to entry point: ' + JSON.stringify(currentEntryPoint, null, 2));\n }\n entry[entryName] = newEntryPoint;\n}\nfunction getHoneybadgerConfigFile(projectDir, configType) {\n const possibilities = [`honeybadger.${configType}.config.ts`, `honeybadger.${configType}.config.js`];\n for (const filename of possibilities) {\n if (fs.existsSync(path.resolve(projectDir, filename))) {\n return filename;\n }\n }\n log('debug', `could not find config file in ${projectDir} for ${configType}`);\n return null;\n}\nfunction getWebpackPluginOptions(honeybadgerNextJsConfig) {\n var _a, _b, _c;\n const apiKey = ((_a = honeybadgerNextJsConfig.webpackPluginOptions) === null || _a === void 0 ? void 0 : _a.apiKey) || process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY;\n const assetsUrl = ((_b = honeybadgerNextJsConfig.webpackPluginOptions) === null || _b === void 0 ? void 0 : _b.assetsUrl) || process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL;\n if (!apiKey || !assetsUrl) {\n log('error', 'Missing Honeybadger required configuration for webpack plugin. Source maps will not be uploaded to Honeybadger.');\n return null;\n }\n return {\n ...honeybadgerNextJsConfig.webpackPluginOptions,\n apiKey,\n assetsUrl,\n revision: ((_c = honeybadgerNextJsConfig.webpackPluginOptions) === null || _c === void 0 ? void 0 : _c.revision) || process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,\n silent: _silent,\n };\n}\n//# sourceMappingURL=index.js.map"],"names":["HoneybadgerSourceMapPlugin","fs","path"],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import HoneybadgerSourceMapPlugin from '@honeybadger-io/webpack';
|
|
4
|
+
|
|
5
|
+
let _silent = true;
|
|
6
|
+
function log(type, msg) {
|
|
7
|
+
if (type === 'error' || !_silent) {
|
|
8
|
+
console[type]('[HoneybadgerNextJs]', msg);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function shouldUploadSourceMaps(honeybadgerNextJsConfig, context) {
|
|
12
|
+
const { dev } = context;
|
|
13
|
+
if (honeybadgerNextJsConfig.disableSourceMapUpload) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (dev || process.env.NODE_ENV === 'development') {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
function setupHoneybadger(config, honeybadgerNextJsConfig) {
|
|
22
|
+
var _a;
|
|
23
|
+
_silent = (_a = honeybadgerNextJsConfig === null || honeybadgerNextJsConfig === void 0 ? void 0 : honeybadgerNextJsConfig.silent) !== null && _a !== void 0 ? _a : true;
|
|
24
|
+
return {
|
|
25
|
+
...config,
|
|
26
|
+
webpack: mergeWithExistingWebpackConfig(config.webpack, honeybadgerNextJsConfig)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function mergeWithExistingWebpackConfig(nextJsWebpackConfig, honeybadgerNextJsConfig) {
|
|
30
|
+
return function webpackFunctionMergedWithHb(webpackConfig, context) {
|
|
31
|
+
const { isServer, dir: projectDir, nextRuntime } = context;
|
|
32
|
+
const configType = isServer ? (nextRuntime === 'edge' ? 'edge' : 'server') : 'browser';
|
|
33
|
+
log('debug', `reached webpackFunctionMergedWithHb isServer[${isServer}] configType[${configType}]`);
|
|
34
|
+
let result = { ...webpackConfig };
|
|
35
|
+
if (typeof nextJsWebpackConfig === 'function') {
|
|
36
|
+
result = nextJsWebpackConfig(result, context);
|
|
37
|
+
}
|
|
38
|
+
const originalEntry = result.entry;
|
|
39
|
+
result.entry = async () => injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType);
|
|
40
|
+
if (shouldUploadSourceMaps(honeybadgerNextJsConfig, context)) {
|
|
41
|
+
// `result.devtool` must be 'hidden-source-map' or 'source-map' to properly pass sourcemaps.
|
|
42
|
+
// Next.js uses regular `source-map` which doesnt pass its sourcemaps to Webpack.
|
|
43
|
+
// https://github.com/vercel/next.js/blob/89ec21ed686dd79a5770b5c669abaff8f55d8fef/packages/next/build/webpack/config/blocks/base.ts#L40
|
|
44
|
+
// Use the hidden-source-map option when you don't want the source maps to be
|
|
45
|
+
// publicly available on the servers, only to the error reporting
|
|
46
|
+
result.devtool = 'hidden-source-map';
|
|
47
|
+
if (!result.plugins) {
|
|
48
|
+
result.plugins = [];
|
|
49
|
+
}
|
|
50
|
+
const options = getWebpackPluginOptions(honeybadgerNextJsConfig);
|
|
51
|
+
if (options) {
|
|
52
|
+
result.plugins.push(new HoneybadgerSourceMapPlugin(options));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async function injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType) {
|
|
59
|
+
const hbConfigFile = getHoneybadgerConfigFile(projectDir, configType);
|
|
60
|
+
if (!hbConfigFile) {
|
|
61
|
+
return originalEntry;
|
|
62
|
+
}
|
|
63
|
+
const hbConfigFileRelativePath = `./${hbConfigFile}`;
|
|
64
|
+
const result = typeof originalEntry === 'function' ? await originalEntry() : { ...originalEntry };
|
|
65
|
+
if (!Object.keys(result).length) {
|
|
66
|
+
log('debug', `no entry points for configType[${configType}]`);
|
|
67
|
+
}
|
|
68
|
+
for (const entryName in result) {
|
|
69
|
+
addHoneybadgerConfigToEntry(result, entryName, hbConfigFileRelativePath, configType);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
function addHoneybadgerConfigToEntry(entry, entryName, hbConfigFile, configType) {
|
|
74
|
+
log('debug', `adding entry[${entryName}] to configType[${configType}]`);
|
|
75
|
+
switch (configType) {
|
|
76
|
+
case 'server':
|
|
77
|
+
if (!entryName.startsWith('pages/')) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
case 'browser':
|
|
82
|
+
if (!['pages/_app', 'main-app'].includes(entryName)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
const currentEntryPoint = entry[entryName];
|
|
88
|
+
let newEntryPoint = currentEntryPoint;
|
|
89
|
+
if (typeof currentEntryPoint === 'string') {
|
|
90
|
+
newEntryPoint = [hbConfigFile, currentEntryPoint];
|
|
91
|
+
}
|
|
92
|
+
else if (Array.isArray(currentEntryPoint)) {
|
|
93
|
+
newEntryPoint = [hbConfigFile, ...currentEntryPoint];
|
|
94
|
+
} // descriptor object (webpack 5+)
|
|
95
|
+
else if (typeof currentEntryPoint === 'object' && currentEntryPoint && 'import' in currentEntryPoint) {
|
|
96
|
+
const currentImportValue = currentEntryPoint['import'];
|
|
97
|
+
const newImportValue = [hbConfigFile];
|
|
98
|
+
if (typeof currentImportValue === 'string') {
|
|
99
|
+
newImportValue.push(currentImportValue);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
newImportValue.push(...(currentImportValue));
|
|
103
|
+
}
|
|
104
|
+
newEntryPoint = {
|
|
105
|
+
...currentEntryPoint,
|
|
106
|
+
import: newImportValue,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
log('error', 'Could not inject Honeybadger config to entry point: ' + JSON.stringify(currentEntryPoint, null, 2));
|
|
111
|
+
}
|
|
112
|
+
entry[entryName] = newEntryPoint;
|
|
113
|
+
}
|
|
114
|
+
function getHoneybadgerConfigFile(projectDir, configType) {
|
|
115
|
+
const possibilities = [`honeybadger.${configType}.config.ts`, `honeybadger.${configType}.config.js`];
|
|
116
|
+
for (const filename of possibilities) {
|
|
117
|
+
if (fs.existsSync(path.resolve(projectDir, filename))) {
|
|
118
|
+
return filename;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
log('debug', `could not find config file in ${projectDir} for ${configType}`);
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function getWebpackPluginOptions(honeybadgerNextJsConfig) {
|
|
125
|
+
var _a, _b, _c;
|
|
126
|
+
const apiKey = ((_a = honeybadgerNextJsConfig.webpackPluginOptions) === null || _a === void 0 ? void 0 : _a.apiKey) || process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY;
|
|
127
|
+
const assetsUrl = ((_b = honeybadgerNextJsConfig.webpackPluginOptions) === null || _b === void 0 ? void 0 : _b.assetsUrl) || process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL;
|
|
128
|
+
if (!apiKey || !assetsUrl) {
|
|
129
|
+
log('error', 'Missing Honeybadger required configuration for webpack plugin. Source maps will not be uploaded to Honeybadger.');
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
...honeybadgerNextJsConfig.webpackPluginOptions,
|
|
134
|
+
apiKey,
|
|
135
|
+
assetsUrl,
|
|
136
|
+
revision: ((_c = honeybadgerNextJsConfig.webpackPluginOptions) === null || _c === void 0 ? void 0 : _c.revision) || process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
|
|
137
|
+
silent: _silent,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export { setupHoneybadger };
|
|
142
|
+
//# sourceMappingURL=honeybadger-nextjs.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"honeybadger-nextjs.esm.js","sources":["../../build/index.js"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport HoneybadgerSourceMapPlugin from '@honeybadger-io/webpack';\nlet _silent = true;\nfunction log(type, msg) {\n if (type === 'error' || !_silent) {\n console[type]('[HoneybadgerNextJs]', msg);\n }\n}\nfunction shouldUploadSourceMaps(honeybadgerNextJsConfig, context) {\n const { dev } = context;\n if (honeybadgerNextJsConfig.disableSourceMapUpload) {\n return false;\n }\n if (dev || process.env.NODE_ENV === 'development') {\n return false;\n }\n return true;\n}\nexport function setupHoneybadger(config, honeybadgerNextJsConfig) {\n var _a;\n _silent = (_a = honeybadgerNextJsConfig === null || honeybadgerNextJsConfig === void 0 ? void 0 : honeybadgerNextJsConfig.silent) !== null && _a !== void 0 ? _a : true;\n return {\n ...config,\n webpack: mergeWithExistingWebpackConfig(config.webpack, honeybadgerNextJsConfig)\n };\n}\nfunction mergeWithExistingWebpackConfig(nextJsWebpackConfig, honeybadgerNextJsConfig) {\n return function webpackFunctionMergedWithHb(webpackConfig, context) {\n const { isServer, dir: projectDir, nextRuntime } = context;\n const configType = isServer ? (nextRuntime === 'edge' ? 'edge' : 'server') : 'browser';\n log('debug', `reached webpackFunctionMergedWithHb isServer[${isServer}] configType[${configType}]`);\n let result = { ...webpackConfig };\n if (typeof nextJsWebpackConfig === 'function') {\n result = nextJsWebpackConfig(result, context);\n }\n const originalEntry = result.entry;\n result.entry = async () => injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType);\n if (shouldUploadSourceMaps(honeybadgerNextJsConfig, context)) {\n // `result.devtool` must be 'hidden-source-map' or 'source-map' to properly pass sourcemaps.\n // Next.js uses regular `source-map` which doesnt pass its sourcemaps to Webpack.\n // https://github.com/vercel/next.js/blob/89ec21ed686dd79a5770b5c669abaff8f55d8fef/packages/next/build/webpack/config/blocks/base.ts#L40\n // Use the hidden-source-map option when you don't want the source maps to be\n // publicly available on the servers, only to the error reporting\n result.devtool = 'hidden-source-map';\n if (!result.plugins) {\n result.plugins = [];\n }\n const options = getWebpackPluginOptions(honeybadgerNextJsConfig);\n if (options) {\n result.plugins.push(new HoneybadgerSourceMapPlugin(options));\n }\n }\n return result;\n };\n}\nasync function injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType) {\n const hbConfigFile = getHoneybadgerConfigFile(projectDir, configType);\n if (!hbConfigFile) {\n return originalEntry;\n }\n const hbConfigFileRelativePath = `./${hbConfigFile}`;\n const result = typeof originalEntry === 'function' ? await originalEntry() : { ...originalEntry };\n if (!Object.keys(result).length) {\n log('debug', `no entry points for configType[${configType}]`);\n }\n for (const entryName in result) {\n addHoneybadgerConfigToEntry(result, entryName, hbConfigFileRelativePath, configType);\n }\n return result;\n}\nfunction addHoneybadgerConfigToEntry(entry, entryName, hbConfigFile, configType) {\n log('debug', `adding entry[${entryName}] to configType[${configType}]`);\n switch (configType) {\n case 'server':\n if (!entryName.startsWith('pages/')) {\n return;\n }\n break;\n case 'browser':\n if (!['pages/_app', 'main-app'].includes(entryName)) {\n return;\n }\n break;\n case 'edge':\n // nothing?\n break;\n }\n const currentEntryPoint = entry[entryName];\n let newEntryPoint = currentEntryPoint;\n if (typeof currentEntryPoint === 'string') {\n newEntryPoint = [hbConfigFile, currentEntryPoint];\n }\n else if (Array.isArray(currentEntryPoint)) {\n newEntryPoint = [hbConfigFile, ...currentEntryPoint];\n } // descriptor object (webpack 5+)\n else if (typeof currentEntryPoint === 'object' && currentEntryPoint && 'import' in currentEntryPoint) {\n const currentImportValue = currentEntryPoint['import'];\n const newImportValue = [hbConfigFile];\n if (typeof currentImportValue === 'string') {\n newImportValue.push(currentImportValue);\n }\n else {\n newImportValue.push(...(currentImportValue));\n }\n newEntryPoint = {\n ...currentEntryPoint,\n import: newImportValue,\n };\n }\n else {\n log('error', 'Could not inject Honeybadger config to entry point: ' + JSON.stringify(currentEntryPoint, null, 2));\n }\n entry[entryName] = newEntryPoint;\n}\nfunction getHoneybadgerConfigFile(projectDir, configType) {\n const possibilities = [`honeybadger.${configType}.config.ts`, `honeybadger.${configType}.config.js`];\n for (const filename of possibilities) {\n if (fs.existsSync(path.resolve(projectDir, filename))) {\n return filename;\n }\n }\n log('debug', `could not find config file in ${projectDir} for ${configType}`);\n return null;\n}\nfunction getWebpackPluginOptions(honeybadgerNextJsConfig) {\n var _a, _b, _c;\n const apiKey = ((_a = honeybadgerNextJsConfig.webpackPluginOptions) === null || _a === void 0 ? void 0 : _a.apiKey) || process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY;\n const assetsUrl = ((_b = honeybadgerNextJsConfig.webpackPluginOptions) === null || _b === void 0 ? void 0 : _b.assetsUrl) || process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL;\n if (!apiKey || !assetsUrl) {\n log('error', 'Missing Honeybadger required configuration for webpack plugin. Source maps will not be uploaded to Honeybadger.');\n return null;\n }\n return {\n ...honeybadgerNextJsConfig.webpackPluginOptions,\n apiKey,\n assetsUrl,\n revision: ((_c = honeybadgerNextJsConfig.webpackPluginOptions) === null || _c === void 0 ? void 0 : _c.revision) || process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,\n silent: _silent,\n };\n}\n//# sourceMappingURL=index.js.map"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type NextJsRuntime = 'server' | 'browser' | 'edge';
|
|
2
|
+
export type HoneybadgerNextJsConfig = {
|
|
3
|
+
disableSourceMapUpload: boolean;
|
|
4
|
+
silent: boolean;
|
|
5
|
+
webpackPluginOptions: Omit<HoneybadgerWebpackPluginOptions, 'silent'>;
|
|
6
|
+
};
|
|
7
|
+
export type HoneybadgerWebpackPluginOptions = {
|
|
8
|
+
apiKey: string;
|
|
9
|
+
assetsUrl: string;
|
|
10
|
+
revision?: string;
|
|
11
|
+
endpoint?: string;
|
|
12
|
+
silent?: boolean;
|
|
13
|
+
ignoreErrors?: boolean;
|
|
14
|
+
retries?: number;
|
|
15
|
+
workerCount?: number;
|
|
16
|
+
deploy?: false | {
|
|
17
|
+
repository?: string;
|
|
18
|
+
environment?: string;
|
|
19
|
+
localUsername?: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@honeybadger-io/nextjs",
|
|
3
|
+
"version": "5.3.0",
|
|
4
|
+
"description": "Next.js integration for Honeybadger",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"nextjs",
|
|
7
|
+
"honeybadger",
|
|
8
|
+
"vercel",
|
|
9
|
+
"react"
|
|
10
|
+
],
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "Pangratios Cosma",
|
|
13
|
+
"email": "pangratios.cosma@honeybadger.io"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/honeybadger-io/honeybadger-js/packages/nextjs#readme",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"main": "dist/honeybadger-nextjs.cjs.js",
|
|
18
|
+
"module": "dist/honeybadger-nextjs.esm.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"src",
|
|
23
|
+
"templates"
|
|
24
|
+
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"honeybadger-copy-config-files": "dist/copy-config-files.js"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/honeybadger-io/honeybadger-js.git"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc --build tsconfig.json && rollup -c && tsc --build tsconfig.types.json"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/honeybadger-io/honeybadger-js/issues"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@honeybadger-io/react": "5.x",
|
|
40
|
+
"next": "13.x"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@honeybadger-io/js": "^5.3.0",
|
|
44
|
+
"@honeybadger-io/webpack": "5.1.7"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@honeybadger-io/react": "5.1.3",
|
|
48
|
+
"@rollup/plugin-commonjs": "^22.0.0",
|
|
49
|
+
"next": "^13.2.3",
|
|
50
|
+
"rollup": "^2.70.2",
|
|
51
|
+
"rollup-plugin-copy": "^3.4.0",
|
|
52
|
+
"typescript": "^4.6.3"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=14"
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"gitHead": "1a6914ba49db1854bba26833074e59aea53ec04c"
|
|
61
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
|
|
6
|
+
const debug = process.env.HONEYBADGER_DEBUG === 'true'
|
|
7
|
+
|
|
8
|
+
async function copyConfigFiles() {
|
|
9
|
+
if (debug) {
|
|
10
|
+
console.debug('cwd', process.cwd())
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const templateDir = path.resolve(__dirname, '../templates');
|
|
14
|
+
const files = await fs.promises.readdir(templateDir);
|
|
15
|
+
const copyPromises = files.map((file) => {
|
|
16
|
+
if (debug) {
|
|
17
|
+
console.debug('copying', file)
|
|
18
|
+
}
|
|
19
|
+
return fs.promises.copyFile(path.join(templateDir, file), file);
|
|
20
|
+
});
|
|
21
|
+
await Promise.all(copyPromises);
|
|
22
|
+
|
|
23
|
+
console.log('Done copying config files.')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
copyConfigFiles().catch((err) => {
|
|
27
|
+
console.error(err)
|
|
28
|
+
process.exit(1)
|
|
29
|
+
})
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import HoneybadgerSourceMapPlugin from '@honeybadger-io/webpack'
|
|
4
|
+
import type { WebpackConfigContext } from 'next/dist/server/config-shared';
|
|
5
|
+
import { HoneybadgerNextJsConfig, NextJsRuntime, HoneybadgerWebpackPluginOptions } from './types'
|
|
6
|
+
|
|
7
|
+
let _silent = true
|
|
8
|
+
function log(type: 'error' | 'debug', msg: string): void {
|
|
9
|
+
if (type === 'error' || !_silent) {
|
|
10
|
+
console[type]('[HoneybadgerNextJs]', msg)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function shouldUploadSourceMaps(honeybadgerNextJsConfig: HoneybadgerNextJsConfig, context: WebpackConfigContext): boolean {
|
|
15
|
+
const { dev } = context
|
|
16
|
+
|
|
17
|
+
if (honeybadgerNextJsConfig.disableSourceMapUpload) {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (dev || process.env.NODE_ENV === 'development') {
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function setupHoneybadger(config, honeybadgerNextJsConfig: HoneybadgerNextJsConfig) {
|
|
29
|
+
_silent = honeybadgerNextJsConfig?.silent ?? true
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...config,
|
|
33
|
+
webpack: mergeWithExistingWebpackConfig(config.webpack, honeybadgerNextJsConfig)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function mergeWithExistingWebpackConfig(nextJsWebpackConfig, honeybadgerNextJsConfig: HoneybadgerNextJsConfig) {
|
|
38
|
+
return function webpackFunctionMergedWithHb(webpackConfig, context: WebpackConfigContext) {
|
|
39
|
+
|
|
40
|
+
const { isServer, dir: projectDir, nextRuntime } = context
|
|
41
|
+
const configType = isServer ? (nextRuntime === 'edge' ? 'edge' : 'server') : 'browser'
|
|
42
|
+
log('debug', `reached webpackFunctionMergedWithHb isServer[${isServer}] configType[${configType}]`)
|
|
43
|
+
|
|
44
|
+
let result = { ...webpackConfig }
|
|
45
|
+
if (typeof nextJsWebpackConfig === 'function') {
|
|
46
|
+
result = nextJsWebpackConfig(result, context)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const originalEntry = result.entry
|
|
50
|
+
result.entry = async () => injectHoneybadgerConfigToEntry(originalEntry, projectDir, configType)
|
|
51
|
+
|
|
52
|
+
if (shouldUploadSourceMaps(honeybadgerNextJsConfig, context)) {
|
|
53
|
+
// `result.devtool` must be 'hidden-source-map' or 'source-map' to properly pass sourcemaps.
|
|
54
|
+
// Next.js uses regular `source-map` which doesnt pass its sourcemaps to Webpack.
|
|
55
|
+
// https://github.com/vercel/next.js/blob/89ec21ed686dd79a5770b5c669abaff8f55d8fef/packages/next/build/webpack/config/blocks/base.ts#L40
|
|
56
|
+
// Use the hidden-source-map option when you don't want the source maps to be
|
|
57
|
+
// publicly available on the servers, only to the error reporting
|
|
58
|
+
result.devtool = 'hidden-source-map'
|
|
59
|
+
if (!result.plugins) {
|
|
60
|
+
result.plugins = []
|
|
61
|
+
}
|
|
62
|
+
const options = getWebpackPluginOptions(honeybadgerNextJsConfig)
|
|
63
|
+
if (options) {
|
|
64
|
+
result.plugins.push(new HoneybadgerSourceMapPlugin(options))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function injectHoneybadgerConfigToEntry(originalEntry, projectDir: string, configType: NextJsRuntime) {
|
|
73
|
+
const hbConfigFile = getHoneybadgerConfigFile(projectDir, configType)
|
|
74
|
+
if (!hbConfigFile) {
|
|
75
|
+
return originalEntry
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const hbConfigFileRelativePath = `./${hbConfigFile}`
|
|
79
|
+
const result = typeof originalEntry === 'function' ? await originalEntry() : { ...originalEntry }
|
|
80
|
+
if (!Object.keys(result).length) {
|
|
81
|
+
log('debug', `no entry points for configType[${configType}]`)
|
|
82
|
+
}
|
|
83
|
+
for (const entryName in result) {
|
|
84
|
+
addHoneybadgerConfigToEntry(result, entryName, hbConfigFileRelativePath, configType)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function addHoneybadgerConfigToEntry(entry, entryName: string, hbConfigFile: string, configType: NextJsRuntime) {
|
|
91
|
+
|
|
92
|
+
log('debug', `adding entry[${entryName}] to configType[${configType}]`)
|
|
93
|
+
|
|
94
|
+
switch (configType) {
|
|
95
|
+
case 'server':
|
|
96
|
+
if (!entryName.startsWith('pages/')) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
break
|
|
101
|
+
case 'browser':
|
|
102
|
+
if (!['pages/_app', 'main-app'].includes(entryName)) {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
break
|
|
107
|
+
case 'edge':
|
|
108
|
+
// nothing?
|
|
109
|
+
|
|
110
|
+
break
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const currentEntryPoint = entry[entryName]
|
|
114
|
+
let newEntryPoint = currentEntryPoint
|
|
115
|
+
|
|
116
|
+
if (typeof currentEntryPoint === 'string') {
|
|
117
|
+
newEntryPoint = [hbConfigFile, currentEntryPoint]
|
|
118
|
+
} else if (Array.isArray(currentEntryPoint)) {
|
|
119
|
+
newEntryPoint = [hbConfigFile, ...currentEntryPoint]
|
|
120
|
+
} // descriptor object (webpack 5+)
|
|
121
|
+
else if (typeof currentEntryPoint === 'object' && currentEntryPoint && 'import' in currentEntryPoint) {
|
|
122
|
+
const currentImportValue = currentEntryPoint['import']
|
|
123
|
+
const newImportValue = [hbConfigFile]
|
|
124
|
+
if (typeof currentImportValue === 'string') {
|
|
125
|
+
newImportValue.push(currentImportValue)
|
|
126
|
+
} else {
|
|
127
|
+
newImportValue.push(...(currentImportValue))
|
|
128
|
+
}
|
|
129
|
+
newEntryPoint = {
|
|
130
|
+
...currentEntryPoint,
|
|
131
|
+
import: newImportValue,
|
|
132
|
+
};
|
|
133
|
+
} else {
|
|
134
|
+
log('error', 'Could not inject Honeybadger config to entry point: ' + JSON.stringify(currentEntryPoint, null, 2))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
entry[entryName] = newEntryPoint
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getHoneybadgerConfigFile(projectDir: string, configType: NextJsRuntime): string | null {
|
|
141
|
+
const possibilities = [`honeybadger.${configType}.config.ts`, `honeybadger.${configType}.config.js`]
|
|
142
|
+
|
|
143
|
+
for (const filename of possibilities) {
|
|
144
|
+
if (fs.existsSync(path.resolve(projectDir, filename))) {
|
|
145
|
+
return filename;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
log('debug', `could not find config file in ${projectDir} for ${configType}`)
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getWebpackPluginOptions(honeybadgerNextJsConfig: HoneybadgerNextJsConfig): HoneybadgerWebpackPluginOptions | null {
|
|
154
|
+
const apiKey = honeybadgerNextJsConfig.webpackPluginOptions?.apiKey || process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY
|
|
155
|
+
const assetsUrl = honeybadgerNextJsConfig.webpackPluginOptions?.assetsUrl || process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL
|
|
156
|
+
if (!apiKey || !assetsUrl) {
|
|
157
|
+
log('error', 'Missing Honeybadger required configuration for webpack plugin. Source maps will not be uploaded to Honeybadger.')
|
|
158
|
+
|
|
159
|
+
return null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
...honeybadgerNextJsConfig.webpackPluginOptions,
|
|
164
|
+
apiKey,
|
|
165
|
+
assetsUrl,
|
|
166
|
+
revision: honeybadgerNextJsConfig.webpackPluginOptions?.revision || process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
|
|
167
|
+
silent: _silent,
|
|
168
|
+
}
|
|
169
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type NextJsRuntime = 'server' | 'browser' | 'edge'
|
|
2
|
+
export type HoneybadgerNextJsConfig = {
|
|
3
|
+
disableSourceMapUpload: boolean
|
|
4
|
+
silent: boolean
|
|
5
|
+
webpackPluginOptions: Omit<HoneybadgerWebpackPluginOptions, 'silent'>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// this should be in @honeybadger-io/webpack
|
|
9
|
+
export type HoneybadgerWebpackPluginOptions = {
|
|
10
|
+
apiKey: string
|
|
11
|
+
assetsUrl: string
|
|
12
|
+
revision?: string
|
|
13
|
+
endpoint?: string
|
|
14
|
+
silent?: boolean
|
|
15
|
+
ignoreErrors?: boolean
|
|
16
|
+
retries?: number
|
|
17
|
+
workerCount?: number
|
|
18
|
+
deploy?: false | {
|
|
19
|
+
repository?: string,
|
|
20
|
+
environment?: string,
|
|
21
|
+
localUsername?: string,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Honeybadger } from '@honeybadger-io/react'
|
|
2
|
+
|
|
3
|
+
Honeybadger.configure({
|
|
4
|
+
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
|
|
5
|
+
environment: process.env.NEXT_PUBLIC_VERCEL_ENV || process.env.VERCEL_ENV || process.env.NODE_ENV,
|
|
6
|
+
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
|
|
7
|
+
projectRoot: 'webpack://_N_E/./',
|
|
8
|
+
// debug: true,
|
|
9
|
+
// reportData: true,
|
|
10
|
+
})
|
|
11
|
+
Honeybadger.logger.debug('Honeybadger configured for browser')
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Honeybadger } from '@honeybadger-io/react'
|
|
2
|
+
|
|
3
|
+
Honeybadger.configure({
|
|
4
|
+
|
|
5
|
+
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
|
|
6
|
+
environment: process.env.NEXT_PUBLIC_VERCEL_ENV || process.env.VERCEL_ENV || process.env.NODE_ENV,
|
|
7
|
+
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
|
|
8
|
+
projectRoot: 'webpack://_N_E/./',
|
|
9
|
+
// debug: true,
|
|
10
|
+
// reportData: true,
|
|
11
|
+
})
|
|
12
|
+
Honeybadger.logger.debug('Honeybadger configured for edge')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Honeybadger } from '@honeybadger-io/react'
|
|
2
|
+
|
|
3
|
+
const projectRoot = process.cwd()
|
|
4
|
+
Honeybadger
|
|
5
|
+
.configure({
|
|
6
|
+
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
|
|
7
|
+
environment: process.env.NEXT_PUBLIC_VERCEL_ENV || process.env.VERCEL_ENV || process.env.NODE_ENV,
|
|
8
|
+
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
|
|
9
|
+
projectRoot: 'webpack:///./',
|
|
10
|
+
// debug: true,
|
|
11
|
+
// reportData: true,
|
|
12
|
+
})
|
|
13
|
+
.beforeNotify((notice) => {
|
|
14
|
+
notice.backtrace.forEach((line) => {
|
|
15
|
+
if (line.file) {
|
|
16
|
+
line.file = line.file.replace(`${projectRoot}/.next/server`, `${process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL}/..`)
|
|
17
|
+
}
|
|
18
|
+
return line
|
|
19
|
+
})
|
|
20
|
+
})
|
|
21
|
+
Honeybadger.logger.debug('Honeybadger configured for server')
|