@hawk.so/nextjs 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +218 -2
- package/dist/index.cjs +533 -0
- package/dist/index.d.cts +75 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +496 -0
- package/global.d.ts +16 -0
- package/package.json +67 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CodeX
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,219 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Hawk Next.js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Sends releases with source maps from Next.js builds to [Hawk](https://hawk.so), so errors from the browser show the original source code instead of minified chunks.
|
|
4
|
+
|
|
5
|
+
- 🌟 Client source maps sending
|
|
6
|
+
- ⚡ Turbopack and webpack support
|
|
7
|
+
- 🏷️ Automatic release id from CI, git or build time
|
|
8
|
+
- 💬 Recent commits sending
|
|
9
|
+
- 🙈 Source maps removal after sending, so the source code is not published
|
|
10
|
+
- 🧩 One-line setup in `next.config`
|
|
11
|
+
- 🛡️ Build never fails because of sending errors
|
|
12
|
+
|
|
13
|
+
The package only sends releases, it doesn't catch errors. Use Hawk catchers for that, see [Error tracking](#error-tracking).
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
yarn add @hawk.so/nextjs
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Install it as a regular dependency, not with `-D`: `next start` loads `next.config` too, and fails with `Cannot find module '@hawk.so/nextjs'` when production installs skip dev dependencies.
|
|
22
|
+
|
|
23
|
+
## Connect
|
|
24
|
+
|
|
25
|
+
Wrap your Next.js config with `withHawkConfig`:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
// next.config.ts
|
|
29
|
+
import type { NextConfig } from 'next';
|
|
30
|
+
import { withHawkConfig } from '@hawk.so/nextjs';
|
|
31
|
+
|
|
32
|
+
const nextConfig: NextConfig = {
|
|
33
|
+
// your config
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default withHawkConfig(nextConfig, {
|
|
37
|
+
token: process.env.HAWK_TOKEN, // Your project's Integration Token
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Config functions are supported as well: `withHawkConfig((phase, { defaultConfig }) => ({ ... }), options)`.
|
|
42
|
+
|
|
43
|
+
On `next build` the plugin:
|
|
44
|
+
|
|
45
|
+
1. resolves the release id and exposes it to your code as `process.env.HAWK_RELEASE`
|
|
46
|
+
2. enables client source maps (`productionBrowserSourceMaps`) unless you set it yourself
|
|
47
|
+
3. after compilation sends recent commits and client source maps to Hawk
|
|
48
|
+
4. removes client source maps and `sourceMappingURL` comments from `.next/static`, so the source code is not published
|
|
49
|
+
|
|
50
|
+
`next dev` sends nothing.
|
|
51
|
+
|
|
52
|
+
### Plugin options
|
|
53
|
+
|
|
54
|
+
| name | type | required | description |
|
|
55
|
+
| -- | -- | -- | -- |
|
|
56
|
+
| `token` | string | optional | Your project's Integration Token. Default is the `HAWK_TOKEN` environment variable. Without a token the release is not sent |
|
|
57
|
+
| `release` | string/number | optional | Unique identifier of the release. See [Release id](#release-id) |
|
|
58
|
+
| `removeSourceMaps` | boolean | optional | Shows if the plugin should remove client source maps after sending. Default is `true` |
|
|
59
|
+
| `commits` | boolean/object | optional | Sends recent commits with the release. Default is `true`. Pass `false` to disable or `{ repo, number }` to set the path to the git repository (default is the project directory) and the number of commits (default is `5`) |
|
|
60
|
+
|
|
61
|
+
### Release id
|
|
62
|
+
|
|
63
|
+
Release id links error events to the source maps and commits sent from the build. The plugin picks it once per build, in this order:
|
|
64
|
+
|
|
65
|
+
1. `release` option
|
|
66
|
+
2. `HAWK_RELEASE` environment variable
|
|
67
|
+
3. commit SHA from the CI environment: GitHub Actions (`GITHUB_SHA`), GitLab CI (`CI_COMMIT_SHA`), Vercel (`VERCEL_GIT_COMMIT_SHA`), Netlify, Cloudflare Pages, CircleCI and [others](./src/release.ts)
|
|
68
|
+
4. current commit: `git rev-parse HEAD`
|
|
69
|
+
5. build start time, e.g. `2026-10-27T18:30:00.000Z`
|
|
70
|
+
|
|
71
|
+
Whatever is picked, the source maps and your code get the same value: the plugin inlines it into the build as `process.env.HAWK_RELEASE`. You don't need to set this variable when the app runs, just pass it to the catchers, see [Error tracking](#error-tracking).
|
|
72
|
+
|
|
73
|
+
Production builds often run without git and CI variables, for example in a Docker build or a separate Kubernetes pod. Then the release is the build time. Source maps still work, but commits are not sent and the release name tells nothing about the deployed version. To get meaningful releases, pass the id from your pipeline with the `HAWK_RELEASE` environment variable:
|
|
74
|
+
|
|
75
|
+
```dockerfile
|
|
76
|
+
ARG HAWK_RELEASE
|
|
77
|
+
RUN yarn build
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```shell
|
|
81
|
+
docker build --build-arg HAWK_RELEASE=$(git rev-parse HEAD) .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or set the `release` option, for example to the version from `package.json`, which package managers expose while running `yarn build` or `npm run build`:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
export default withHawkConfig(nextConfig, {
|
|
88
|
+
release: process.env.npm_package_version,
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
A version is unique only if you bump it for every deploy, otherwise errors of different builds get into the same release.
|
|
93
|
+
|
|
94
|
+
## Error tracking
|
|
95
|
+
|
|
96
|
+
To catch errors, use the Hawk catchers with the release id from the plugin:
|
|
97
|
+
|
|
98
|
+
- [@hawk.so/browser](https://github.com/codex-team/hawk.javascript/tree/master/packages/browser) in the browser. Hawk applies the sent source maps to these errors.
|
|
99
|
+
- [@hawk.so/nodejs](https://github.com/codex-team/hawk.nodejs) on the server. Hawk doesn't apply source maps to server errors, so their stack traces point to the compiled files in `.next/server`.
|
|
100
|
+
|
|
101
|
+
```shell
|
|
102
|
+
yarn add @hawk.so/browser @hawk.so/nodejs
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Both catchers below take the Integration Token from `NEXT_PUBLIC_HAWK_TOKEN`. The browser catcher has the token in the client code anyway, and Next.js inlines `NEXT_PUBLIC_` variables during the build like `HAWK_RELEASE`, so the running app needs no Hawk variables.
|
|
106
|
+
|
|
107
|
+
### Browser
|
|
108
|
+
|
|
109
|
+
Create the catcher in `instrumentation-client.ts` in the project root (or in `src`). Next.js runs this file before the app starts, so the catcher gets errors from event handlers, effects and unhandled promise rejections.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
// instrumentation-client.ts
|
|
113
|
+
import HawkCatcher from '@hawk.so/browser';
|
|
114
|
+
|
|
115
|
+
const token = process.env.NEXT_PUBLIC_HAWK_TOKEN;
|
|
116
|
+
|
|
117
|
+
if (token) {
|
|
118
|
+
new HawkCatcher({
|
|
119
|
+
token,
|
|
120
|
+
release: process.env.HAWK_RELEASE,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Errors caught by your error boundaries (`error.tsx` and a custom `global-error.tsx`) are only logged to the console by Next.js. Report them with `reportError`, so the catcher gets them like uncaught errors:
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
// app/error.tsx
|
|
129
|
+
'use client';
|
|
130
|
+
|
|
131
|
+
import { useEffect } from 'react';
|
|
132
|
+
|
|
133
|
+
export default function ErrorPage({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
// Server errors have a digest and are sent by the Node.js catcher
|
|
136
|
+
if (error.digest === undefined) {
|
|
137
|
+
reportError(error);
|
|
138
|
+
}
|
|
139
|
+
}, [error]);
|
|
140
|
+
|
|
141
|
+
return <button type="button" onClick={reset}>Try again</button>;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Server
|
|
146
|
+
|
|
147
|
+
Initialize the catcher in `instrumentation.ts` and send request errors from the `onRequestError` hook:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
// instrumentation.ts
|
|
151
|
+
import type { Instrumentation } from 'next';
|
|
152
|
+
|
|
153
|
+
export async function register() {
|
|
154
|
+
const token = process.env.NEXT_PUBLIC_HAWK_TOKEN;
|
|
155
|
+
|
|
156
|
+
if (process.env.NEXT_RUNTIME === 'nodejs' && token) {
|
|
157
|
+
const { default: HawkCatcher } = await import('@hawk.so/nodejs');
|
|
158
|
+
|
|
159
|
+
HawkCatcher.init({
|
|
160
|
+
token,
|
|
161
|
+
release: process.env.HAWK_RELEASE,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export const onRequestError: Instrumentation.onRequestError = async (error, request, context) => {
|
|
167
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
168
|
+
const { default: HawkCatcher } = await import('@hawk.so/nodejs');
|
|
169
|
+
|
|
170
|
+
HawkCatcher.send(error as Error, {
|
|
171
|
+
method: request.method,
|
|
172
|
+
path: request.path,
|
|
173
|
+
routePath: context.routePath,
|
|
174
|
+
routeType: context.routeType,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- `register` runs once on server start. The catcher also handles `uncaughtException` and `unhandledRejection`.
|
|
181
|
+
- Next.js handles errors of server components, route handlers and server actions itself, so they reach the catcher only through `onRequestError`.
|
|
182
|
+
- `@hawk.so/nodejs` works only in the Node.js runtime. It is imported dynamically to keep it out of Edge bundles, so errors from the Edge runtime are not sent.
|
|
183
|
+
|
|
184
|
+
See the [example](./example) app with both catchers.
|
|
185
|
+
|
|
186
|
+
### TypeScript
|
|
187
|
+
|
|
188
|
+
`process.env.HAWK_RELEASE` is typed automatically when you import the plugin in `next.config.ts`. If your config is a JavaScript file, add the declaration to `tsconfig.json`:
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"compilerOptions": {
|
|
193
|
+
"types": ["@hawk.so/nextjs/global"]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Requirements
|
|
199
|
+
|
|
200
|
+
- Next.js 15.4.1 or newer: the plugin uses the `compiler.runAfterProductionCompile` build hook
|
|
201
|
+
- Node.js 20.9 or newer
|
|
202
|
+
|
|
203
|
+
## Notes
|
|
204
|
+
|
|
205
|
+
- Hawk applies source maps to errors from the browser, so only client source maps are sent. Server source maps in `.next/server` are left untouched.
|
|
206
|
+
- Releases are sent during the build. Make sure the build environment has the token and access to Hawk, and the build finishes before the new version gets traffic.
|
|
207
|
+
- When `experimental.sri` is enabled, `sourceMappingURL` comments are kept, since changing the files would break the integrity hashes.
|
|
208
|
+
- Sending errors never fail the build: they are printed to the build output.
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
```shell
|
|
213
|
+
yarn # install dependencies
|
|
214
|
+
yarn lint # ESLint
|
|
215
|
+
yarn test # unit tests
|
|
216
|
+
yarn e2e # build the example app and check what is sent to a mock collector
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`yarn e2e --debug-ids` checks indexed source maps produced with `turbopack.debugIds`, `yarn e2e --webpack` checks the webpack build.
|