@sentry/browser
^5.11.0@sentry/node
^5.11.0node
v12.7.0๋๋ nextjs ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๊ณ nextjs ์ปค๋ฎค๋ํฐ์์ ์ ๊ณตํ๋ ์ด ํํ ๋ฆฌ์ผ์ ๋ฐ๋์ต๋๋ค. ๋ฌธ์ ๋ ๋ด ์ฑ์ ๋น๋ํ๊ณ ์คํํ ํ ๋ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๋ ๊ฒ์ ๋๋ค.
[ error ] ./node_modules/@sentry/node/esm/integrations/console.js
Module not found: Can't resolve 'console' in '/.../node_modules/@sentry/node/esm/integrations'
์ฑ์ ๋ค์ ๋น๋ํ๊ณ ์์ฌ ์ ๊ธ์ ์ ๊ฑฐํ๊ณ ํด๋๋ฅผ ๋น๋ํ์ง๋ง ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์์์ต๋๋ค! ๋ด node_modules์ ๋๋ ํ ๋ฆฌ๊ฐ ์์ง๋ง!
์ค๋ฅ๋ ๋ค์๊ณผ ๊ฐ์ด Sentry๋ฅผ ๊ฐ์ ธ์ค๋ ค๊ณ ํ ๋ ๋ฐ์ํฉ๋๋ค.
import * as Sentry from '@sentry/node';
๋ฌธ์ ๋ @zeit/next-source-maps
์ ๋ฒ์ ์ด ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ๋์๋ค๊ณ ์๊ฐํฉ๋๋ค.
@zeit/next-source-maps": "0.0.4-canary.1
.
๊ทธ๋ผ ์ฒญ์ node_modules
์ ๊ฑฐ yarn.lock
์ ์ฌ๊ฑด์! ์ง๊ธ ์๋ ์ค์
๋๋ค!
@afsanefda node_modules
yarn.lock
node_modules
์ ๊ฑฐํ๊ณ @zeit/next-source-maps": "0.0.4-canary.1
๋ฅผ ์ข
์์ฑ์ผ๋ก ๊ฐ์ง ํ์๋ ์ฌ์ ํ ์ด ๋ฌธ์ ๊ฐ ์์ต๋๋ค... ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๋ค๋ฅธ ์กฐ์น๋ฅผ ์ทจํ ์
จ์ต๋๊น?
์ถ๊ฐํ๋ค:
if (!options.isServer) {
config.resolve.alias['@sentry/node'] = '@sentry/browser'
}
next.config.js
์ด์ ๋ํ ํด๊ฒฐ์ฑ ์ด ์์ต๋๊น?
์ด์ ๋ํ ํด๊ฒฐ์ฑ ์ด ์์ต๋๊น?
๋ถ๋ช ํ ๋ฒ์ ๋ถ์ผ์น ๋๋ฌธ์ ๋๋ค. ์์์ ์ค๋ช ํ ๋๋ก ๋ฒ์ ์ ํ์ธํ์ญ์์ค.
์ ์์ ์ ํํ ๋ฐ๋์ง๋ง ์ฌ์ ํ ์ด ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
@5tormTrooper ์ด๊ฒ์ด ๋์์ด ๋ ์ง ํ์คํ์ง ์์ง๋ง require ๋ฌธ์ ()๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์์ต๋๋ค.
const withSourceMaps = require('@zeit/next-source-maps')()
๋๋ ์ฌ์ ํ์ด ๋ฌธ์ ์ ์ง๋ฉดํ๊ณ ์์ต๋๋ค.
@sentry/node^5.11.0
๋๊ตฌ๋ ์ง ๋์ธ ์ ์์ต๋๊น?
@philkeys ๋ ์ด๋ฏธ ์๋ํ์ต๋๋ค. ๋ถ์ด.
Next.js๋ฅผ ' 9.1.6 '์์ ' 9.3.5 '๋ก ์ ๊ทธ๋ ์ด๋ํ ํ์๋ ๋์ผํ ๋ฌธ์ ์ ์ง๋ฉดํ์ต๋๋ค. ์ผ๋ถ ๋๋ฒ๊น ํ์ ' @sentry/node '๊ฐ ์ด๋ป๊ฒ๋ ํด๋ผ์ด์ธํธ ๋ฒ๋ค์์ ๋๋ฌ๋ค๊ณ ์๊ฐํ์ต๋๋ค. ์ด ๋ผ์ธ์ด ๊ฐ์๊ธฐ ์๋์ ๋ฉ์ถ ๊ฒ ๊ฐ์ต๋๋ค.
if (!isServer) {
config.resolve.alias['@sentry/node'] = '@sentry/browser';
}
์ด ๋ฌธ์ ๋ฅผ ๋ค์ ์ด ์ ์์ต๋๊น? ๋ชจ๋ ํจํค์ง๋ฅผ ์ ๋ฐ์ดํธํ๋ ค๊ณ ์๋ํ์ง๋ง ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ ์ ์์ต๋๋ค.
์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ด ์์ต๋๊น? ๋ชจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํด์ผ ํ๋ ์ผ๋ฐ์ ์ธ ๊ธฐ๋ฅ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
์ ์ ์๋ฏ์ด ์ฐธ์กฐ๋ ๋ชจ๋ ๋ฌธ์ ๋ ์ด๋ฏธ ๊ฐ๋ฐ ๊ตฌ์ฑ์ ๋ณ๊ฒฝํ์ฌ ์ด๋ป๊ฒ๋ ํด๊ฒฐ๋์์ต๋๋ค. ๊ตฌ์ฒด์ ์ธ ๋ฌธ์ ๋ฐ ์ฌํ ์ฌ๋ก๊ฐ ์ ๊ณต๋์ง ์์ผ๋ฉด ํน์ ์์ ์ฌํญ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
์ ๋ณด๋ฅผ ์ํด @kamilogorek thx. ๊ด๋ จ์ด ์๋ ๊ฒ์ผ๋ก ๋ณด์ด๋ ๋ฌธ์ ์ ๋ํ ์ฐธ์กฐ๊ฐ ํ๋๋ง ํ์๋ฉ๋๋ค. OP๋ @zeit/next-source-maps
์
๋ฐ์ดํธ๋ฅผ ์ ์ํ์ต๋๋ค(์ฌ์ฉํ์ง ์์)
์ผํธ๋ฆฌ ํ ํฐ์ด ํฌํจ๋ .env
ํ์ผ์ ์ง์ ์ ๊ณตํด์ผ ํ์ง๋ง ๋ณต์ ์ ์ฅ์๋ฅผ ๋ง๋ค๋ ค๊ณ ํฉ๋๋ค.
์ด๋ค ํด๊ฒฐ์ฑ ?
์ ๊ณต๋ ์์ ๋ฅผ ๋ฐ์ ํ๊ฒ ๋ณต์ next export
)๋ก ์ ํํ ๋ ์ด ๋ฌธ์ ๊ฐ ๋ค์ ๋ฐ์ํ์ต๋๋ค. SSG์ ๋ํ ์๋ฒ ๋ณด๊ณ ์๊ฐ ํ์ํ์ง ์๊ธฐ ๋๋ฌธ์ webpack ๋ณ์นญ(+ @sentry/node
์ฐธ์กฐํ๋ ๋ชจ๋ ํญ๋ชฉ)์ ์ ๊ฑฐํ๊ณ ๋ค์ ์๋ํ์ต๋๋ค. . ์ด์ @sentry/browser
๋ง ์ฌ์ฉํฉ๋๋ค.
๋ค์ ์ค์ด ์๋ ๊ฒฝ์ฐ:
if (!isServer) { config.resolve.alias['@sentry/node'] = '@sentry/browser'; }
๊ทธ๋ฐ ๋ค์ @sentry/browser
๋ ์ค์นํด์ผ ํฉ๋๋ค. ์ค๋ฅ๊ฐ ์ข ์ฌํ๋ค์...
๋ด next.config.js์์ ๋๋ ์ด๋ฏธ fs: "empty" ๋ฉ์๋๋ฅผ ์ํํ๊ณ ์์๊ณ !isServer ๋ ๋ธ๋ผ์ฐ์ ๋ก sentry/node ๋ณ์นญ๋ ์ง์ ํ์ง๋ง ๊ฑฐ๊ธฐ์ console.log๋ฅผ ์ถ๊ฐํ๋ฉด ๋ก๊ทธ๊ฐ ์ฝ์์ ์ธ์๋์ง ์๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๋ด๊ฐ ๊ฐ์ง ํ๋ฌ๊ทธ์ธ(withSourceMaps, withSass, withOptimizedImages)์ ์์ค ์ฝ๋๋ฅผ ํํค์น๊ณ ๊ฐ๊ฐ์ console.log๋ฅผ ์ถ๊ฐํ ๊ฒฐ๊ณผ, ๋ด ๊ธฐ๋ณธ ๊ตฌ์ฑ์ด ์ด ์ฐ๊ฒฐ ๋ฐฉ๋ฒ์ผ๋ก ์ธ๋ถ ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ ์ก๋์ง ์๋๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ต๋๋ค. ๊ตฌ์ฑ ์์ฒด๊ฐ ์์ง๋ง ๋ฌด์ธ๊ฐ๊ฐ ์ฌ์ ํ ๊บผ์ ธ ์์):
module.exports = withBundleAnalyzer(
withSourceMaps(
withSass(
withOptimizedImages(baseConfig)
)
)
๋ฐ๋ผ์ fs: "empty"๋ ์ ๋ ์กด์ค๋์ง ์์ต๋๋ค.
๋ด๊ฐ ์ฐพ์ ํด๊ฒฐ์ฑ ์ next-compose-plugins ํจํค์ง๋ฅผ ์ค์นํ ๋ค์ ๋ด๋ณด๋ด๊ธฐ๋ฅผ ๋ค์์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ๋๋ค.
module.exports = withPlugins(
[
[withOptimizedImages],
[withSass],
[withSourceMaps],
[withBundleAnalyzer],
],
baseConfig
);
๋ค์ ์ค์ด ์๋ ๊ฒฝ์ฐ:
if (!isServer) { config.resolve.alias['@sentry/node'] = '@sentry/browser'; }
๊ทธ๋ฐ ๋ค์
@sentry/browser
๋ ์ค์นํด์ผ ํฉ๋๋ค. ์ค๋ฅ๊ฐ ์ข ์ฌํ๋ค์...
@vpontis , ์ด๊ฒ์ ๋๋ฅผ ์ํด ์๋ํ์ง ์์์ต๋๋ค. Vue.js์ ํจ๊ป Sentry๋ฅผ ์ฌ์ฉํ๊ณ ์์ผ๋ฉฐ ์ด๊ฒ์ vue.config.js์ ์ถ๊ฐํ์ต๋๋ค.
chainWebpack: (config) => {
config.resolve.alias['@sentry/node'] = '@sentry/browser'
}
๋๊ตฐ๊ฐ๊ฐ ์ฌ์ ํ ๋ฌธ์ ๊ฐ ์๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ์ถ๊ฐํ๊ณ ์ถ์ต๋๋ค.
๋ค์ ์์ค ๋งต์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ @zeit/next-source-maps
ํจํค์ง๊ฐ 0.0.4-canary.1
์ค์ ๋์ด ์๋์ง ํ์ธํ์ญ์์ค.
๋๋ next.config.js๊ฐ ํ์ํ์ง ์์ผ๋ฉฐ next-source-maps
์ ํจ๊ป sentry๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฏ๋ก ์๋ฃจ์
์ด ๋ฌด์์ธ์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
if (process.env.NEXT_PUBLIC_SENTRY_DSN) {
Sentry.init({
enabled: true,
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
});
}
@sentry/node @sentry/browser @sentry/react
์ค์นํ ํ _app.js
์
๋ ฅํ๋๋ฐ ์ฌ์ ํ ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
@zeit/next-source-maps": "0.0.4-canary.1๋ ์ฌ์ฉํ๊ธฐ ์์ํ์ ๋ ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค!
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํ๋ฌ๊ทธ์ธ์ ์ ๊ฑฐํ ๋ค์ ์ฝ๋์ ์ค์ํ ๋ถ๋ถ์ ๋ค์ ๊ตฌ์ฑ์ ์ถ๊ฐํ์ต๋๋ค.
const { dev } = options
if (!dev) {
config.devtool = options.devtool || 'source-map'
for (const plugin of config.plugins) {
if (plugin.constructor.name === 'UglifyJsPlugin') {
plugin.options.sourceMap = true
break
}
}
if (config.optimization && config.optimization.minimizer) {
for (const plugin of config.optimization.minimizer) {
if (plugin.constructor.name === 'TerserPlugin') {
plugin.options.sourceMap = true
break
}
}
}
}
์ผํธ๋ฆฌ์๋ ๋ฌธ์ ๊ฐ ์์ง๋ง ๋ค์ ์์ค ๋งต ํ๋ฌ๊ทธ์ธ์๋
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
@5tormTrooper ์ด๊ฒ์ด ๋์์ด ๋ ์ง ํ์คํ์ง ์์ง๋ง require ๋ฌธ์ ()๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์์ต๋๋ค.
const withSourceMaps = require('@zeit/next-source-maps')()