æ¬çªç°å¢ã°ã¬ãŒãã®JavaScriptãšã©ãŒãã³ããªã³ã°ãç¿åŸãã°ããŒãã«ã¢ããªã§ãšã©ãŒãææããã°èšé²ã管çããå ç¢ãªã·ã¹ãã ãæ§ç¯ããUXãåäžãããæ¹æ³ã解説ããŸãã
JavaScriptã®ãšã©ãŒãã³ããªã³ã°ïŒã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³åãæ¬çªç°å¢å¯Ÿå¿æŠç¥
ãªããconsole.logãæŠç¥ã¯æ¬çªç°å¢ã§ã¯äžååãªã®ã
ããŒã«ã«éçºã®ç®¡çãããç°å¢ã§ã¯ãJavaScriptã®ãšã©ãŒåŠçã¯ç°¡åã ãšæããããããšãå€ãã§ããããææ©ã`console.log(error)`ãèšè¿°ãããã`debugger`ã¹ããŒãã¡ã³ãã䜿ã£ããããã°ãããã§è§£æ±ºã§ããããããã¢ããªã±ãŒã·ã§ã³ãæ¬çªç°å¢ã«ãããã€ãããäžçäžã®äœåãã®ãŠãŒã¶ãŒããç¡æ°ã®ããã€ã¹ããã©ãŠã¶ããããã¯ãŒã¯ã®çµã¿åããã§ã¢ã¯ã»ã¹ããããã«ãªããšããã®ã¢ãããŒãã¯å šãäžååã«ãªããŸããéçºè ã³ã³ãœãŒã«ã¯ãããªãããã¯èŠãããšã®ã§ããªããã©ãã¯ããã¯ã¹ãªã®ã§ãã
æ¬çªç°å¢ã§æªåŠçã®ãšã©ãŒã¯ãåãªã軜埮ãªäžå ·åã§ã¯ãããŸããããããã¯ãŠãŒã¶ãŒäœéšãéãã«ç Žå£ããŸããæ©èœã®ç ŽæããŠãŒã¶ãŒã®äžæºãã«ãŒãã®æŸæ£ããããŠæçµçã«ã¯ãã©ã³ãã®è©å€äœäžãšåçã®æå€±ã«ã€ãªããå¯èœæ§ããããŸããå ç¢ãªãšã©ãŒç®¡çã·ã¹ãã ã¯èŽ æ²¢åã§ã¯ãªãããããã§ãã·ã§ãã«ã§é«å質ãªãŠã§ãã¢ããªã±ãŒã·ã§ã³ã®åºç€ãšãªãæ±ã§ããããã¯ãæãããŠãŒã¶ãŒããå ±åããããã°ãåçŸããããšèºèµ·ã«ãªããåãèº«ã®æ¶é²å£«ãããããŠãŒã¶ãŒããŒã¹ã«é倧ãªåœ±é¿ãäžããåã«åé¡ãç¹å®ã解決ãããç©æ¥µçãªãšã³ãžãã¢ããžãšããªããå€é©ãããŸãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãåºæ¬çãªææã¡ã«ããºã ãããé«åºŠãªç£èŠããããŠã°ããŒãã«ãªå©çšè ã«é©ããæåçãªãã¹ããã©ã¯ãã£ã¹ãŸã§ãæ¬çªç°å¢ã«å¯Ÿå¿ããJavaScriptãšã©ãŒç®¡çæŠç¥ã®æ§ç¯æ¹æ³ã解説ããŸãã
JavaScriptãšã©ãŒã®æ§é ïŒæ±ã®æµãç¥ã
ãšã©ãŒãåŠçããåã«ããããäœã§ããããçè§£ããªããã°ãªããŸãããJavaScriptã§ã¯ãäœãåé¡ãçºçãããšãéåžž`Error`ãªããžã§ã¯ããã¹ããŒãããŸãããã®ãªããžã§ã¯ãã¯ãããã°ã®ããã®æ å ±ã®å®åº«ã§ãã
- name: ãšã©ãŒã®çš®é¡ïŒäŸïŒ`TypeError`, `ReferenceError`, `SyntaxError`ïŒã
- message: 人éãèªãã圢åŒã®ãšã©ãŒã®èª¬æã
- stack: ãšã©ãŒã«è³ã£ã颿°åŒã³åºãã®ã·ãŒã±ã³ã¹ã瀺ããã¹ã¿ãã¯ãã¬ãŒã¹ãå«ãæååãããã¯å€ãã®å Žåããããã°ã«ãããŠæãéèŠãªæ å ±ã§ãã
äžè¬çãªãšã©ãŒã®çš®é¡
- SyntaxError: JavaScriptãšã³ãžã³ãèšèªã®æ§æã«éåããã³ãŒãã«ééãããšãã«çºçããŸãããããã¯çæ³çã«ã¯ããªã³ã¿ãŒããã«ãããŒã«ã«ãã£ãŠãããã€åã«ãã£ãããããã¹ãã§ãã
- ReferenceError: 宣èšãããŠããªã倿°ã䜿çšããããšãããšãã«ã¹ããŒãããŸãã
- TypeError: äžé©åãªåã®å€ã«å¯ŸããŠæäœãå®è¡ããããšãã«çºçããŸããäŸãã°ã颿°ã§ãªããã®ãåŒã³åºãããã`null`ã`undefined`ã®ããããã£ã«ã¢ã¯ã»ã¹ãããããå Žåã§ããããã¯æ¬çªç°å¢ã§æãäžè¬çãªãšã©ãŒã®1ã€ã§ãã
- RangeError: æ°å€å€æ°ããã©ã¡ãŒã¿ãæå¹ãªç¯å²å€ã«ããå Žåã«ã¹ããŒãããŸãã
åæãšã©ãŒãšéåæãšã©ãŒ
éèŠãªåºå¥ã¯ãåæã³ãŒããšéåæã³ãŒãã§ãšã©ãŒãã©ã®ããã«æ¯ãèããã§ãã`try...catch`ãããã¯ã¯ããã®`try`ãããã¯å ã§åæçã«çºçãããšã©ãŒããåŠçã§ããŸããã`setTimeout`ãã€ãã³ããªã¹ããŒããŸãã¯ã»ãšãã©ã®PromiseããŒã¹ã®ããžãã¯ã®ãããªéåææäœã®ãšã©ãŒãåŠçããã«ã¯å šã广ããããŸããã
äŸïŒ
try {
setTimeout(() => {
throw new Error("This will not be caught!");
}, 100);
} catch (e) {
console.error("Caught error:", e); // ãã®è¡ã¯æ±ºããŠå®è¡ãããŸãã
}
ããããå€å±€çãªæææŠç¥ãäžå¯æ¬ ã§ããçç±ã§ããç°ãªãçš®é¡ã®ãšã©ãŒããã£ããããããã«ã¯ãç°ãªãããŒã«ãå¿ èŠã§ãã
äž»èŠãªãšã©ãŒææã¡ã«ããºã ïŒæåã®é²è¡ç·
å æ¬çãªã·ã¹ãã ãæ§ç¯ããããã«ã¯ãã¢ããªã±ãŒã·ã§ã³å šäœã§ã»ãŒããã£ããããšããŠæ©èœããããã€ãã®ãªã¹ããŒãé 眮ããå¿ èŠããããŸãã
1. `try...catch...finally`
`try...catch`ã¹ããŒãã¡ã³ãã¯ãåæã³ãŒãã®ããã®æãåºæ¬çãªãšã©ãŒãã³ããªã³ã°ã¡ã«ããºã ã§ãã倱æããå¯èœæ§ã®ããã³ãŒãã`try`ãããã¯ã§å²ã¿ããšã©ãŒãçºçãããšãå®è¡ã¯çŽã¡ã«`catch`ãããã¯ã«ãžã£ã³ãããŸãã
æé©ãªã±ãŒã¹ïŒ
- JSONã®ããŒã¹ãAPIåŒã³åºããªã©ãç¹å®ã®æäœããäºæ³ããããšã©ãŒãåŠçããã«ã¹ã¿ã ããžãã¯ãã°ã¬ãŒã¹ãã«ãªãã©ãŒã«ããã¯ãå®è£ ãããå Žåã
- ã¿ãŒã²ãããçµã£ããæèã«å¿ãããšã©ãŒãã³ããªã³ã°ãæäŸããå Žåã
äŸïŒ
function parseUserConfig(jsonString) {
try {
const config = JSON.parse(jsonString);
return config.userPreferences;
} catch (error) {
// ããã¯æ¢ç¥ã®ãæœåšçãªå€±æç¹ã§ãã
// ãã©ãŒã«ããã¯ãæäŸããåé¡ãå ±åã§ããŸãã
console.error("Failed to parse user config:", error);
reportError(error, { context: 'UserConfigParsing' });
return { theme: 'default', language: 'en' }; // ã°ã¬ãŒã¹ãã«ãªãã©ãŒã«ããã¯
}
}
2. `window.onerror`
ããã¯ã°ããŒãã«ãªãšã©ãŒãã³ãã©ã§ãããã¢ããªã±ãŒã·ã§ã³ã®ã©ããã§çºçããæªåŠçã®åæãšã©ãŒã«å¯Ÿããçã®ã»ãŒããã£ãããã§ãã`try...catch`ãããã¯ãååšããªãå Žåã®æåŸã®ç ŠãšããŠæ©èœããŸãã
5ã€ã®åŒæ°ãåããŸãïŒ
- `message`: ãšã©ãŒã¡ãã»ãŒãžã®æååã
- `source`: ãšã©ãŒãçºçããã¹ã¯ãªããã®URLã
- `lineno`: ãšã©ãŒãçºçããè¡çªå·ã
- `colno`: ãšã©ãŒãçºçããåçªå·ã
- `error`: `Error`ãªããžã§ã¯ãèªäœïŒæãæçšãªåŒæ°ïŒïŒã
å®è£ äŸïŒ
window.onerror = function(message, source, lineno, colno, error) {
// æªåŠçã®ãšã©ãŒãçºçããŸããïŒ
console.log('Global handler caught an error:', error);
reportError(error);
// trueãè¿ããšããã©ãŠã¶ã®ããã©ã«ãã®ãšã©ãŒåŠçïŒäŸïŒã³ã³ãœãŒã«ãžã®ãã°åºåïŒãé²ããŸãã
return true;
};
éèŠãªå¶éäºé ïŒã¯ãã¹ãªãªãžã³ãªãœãŒã¹å ±æïŒCORSïŒããªã·ãŒã«ãããç°ãªããã¡ã€ã³ïŒCDNãªã©ïŒã§ãã¹ããããŠããã¹ã¯ãªãããããšã©ãŒãçºçããå Žåããã©ãŠã¶ã¯ã»ãã¥ãªãã£äžã®çç±ãã詳现ãé£èªåããããšãå€ããçµæãšããŠåœ¹ã«ç«ããªã`"Script error."`ãšããã¡ãã»ãŒãžã衚瀺ãããŸãããããä¿®æ£ããã«ã¯ãã¹ã¯ãªããã¿ã°ã«`crossorigin="anonymous"`屿§ãå«ããã¹ã¯ãªããããã¹ããããµãŒããŒã`Access-Control-Allow-Origin` HTTPããããŒãå«ããããã«ããŠãã ããã
3. `window.onunhandledrejection`
Promiseã¯éåæJavaScriptãæ ¹æ¬çã«å€ããŸããããæ°ããªèª²é¡ããããããŸãããããã¯æªåŠçã®`rejection`ã§ããPromiseã`reject`ãããããã«`.catch()`ãã³ãã©ãã¢ã¿ãããããŠããªãå Žåãå€ãã®ç°å¢ã§ã¯ãšã©ãŒã¯ããã©ã«ãã§éãã«ç¡èŠãããŸããããã§`window.onunhandledrejection`ãæ¥µããŠéèŠã«ãªããŸãã
ãã®ã°ããŒãã«ã€ãã³ããªã¹ããŒã¯ãPromiseããã³ãã©ãªãã§`reject`ããããã³ã«çºç«ããŸããåãåãã€ãã³ããªããžã§ã¯ãã«ã¯`reason`ããããã£ãå«ãŸããŠãããããã¯éåžžãã¹ããŒããã`Error`ãªããžã§ã¯ãã§ãã
å®è£ äŸïŒ
window.addEventListener('unhandledrejection', function(event) {
// 'reason'ããããã£ã«ãšã©ãŒãªããžã§ã¯ããå«ãŸããŠããŸãã
console.log('Global handler caught a promise rejection:', event.reason);
reportError(event.reason || 'Unknown promise rejection');
// ããã©ã«ãã®åŠçïŒäŸïŒã³ã³ãœãŒã«ãžã®ãã°åºåïŒãé²ããŸãã
event.preventDefault();
});
4. ãšã©ãŒå¢çïŒã³ã³ããŒãã³ãããŒã¹ã®ãã¬ãŒã ã¯ãŒã¯åãïŒ
Reactã®ãããªãã¬ãŒã ã¯ãŒã¯ã¯ããšã©ãŒå¢çïŒError BoundariesïŒãšããæŠå¿µãå°å ¥ããŸããããããã¯ãåã³ã³ããŒãã³ãããªãŒã®ã©ããã§çºçããJavaScriptãšã©ãŒããã£ãããããããã®ãšã©ãŒããã°ã«èšé²ããã¯ã©ãã·ã¥ããã³ã³ããŒãã³ãããªãŒã®ä»£ããã«ãã©ãŒã«ããã¯UIã衚瀺ããã³ã³ããŒãã³ãã§ããããã«ãããåäžã³ã³ããŒãã³ãã®ãšã©ãŒãã¢ããªã±ãŒã·ã§ã³å šäœãããŠã³ãããã®ãé²ããŸãã
Reactã®ç°¡ç¥åãããäŸïŒ
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// ããã§ãšã©ãŒããã®ã³ã°ãµãŒãã¹ã«å ±åããŸã
reportError(error, { componentStack: errorInfo.componentStack });
}
render() {
if (this.state.hasError) {
return åé¡ãçºçããŸãããããŒãžããªãã¬ãã·ã¥ããŠãã ããã
;
}
return this.props.children;
}
}
å ç¢ãªãšã©ãŒç®¡çã·ã¹ãã ã®æ§ç¯ïŒææãã解決ãŸã§
ãšã©ãŒã®ææã¯æåã®ã¹ãããã«ãããŸãããå®å šãªã·ã¹ãã ã«ã¯ãè±å¯ãªã³ã³ããã¹ãã®åéãããŒã¿ã®ä¿¡é Œæ§ã®é«ãéä¿¡ããããŠãããçè§£ããããã®ãµãŒãã¹ã®å©çšãå«ãŸããŸãã
ã¹ããã1ïŒãšã©ãŒå ±åã®äžå å
`window.onerror`ã`onunhandledrejection`ããããŠæ§ã ãª`catch`ãããã¯ãããããç¬èªã®å ±åããžãã¯ãå®è£ ããã®ã§ã¯ãªããåäžã®äžå åããã颿°ãäœæããŸããããã«ããäžè²«æ§ã確ä¿ãããåŸã§ããå€ãã®ã³ã³ããã¹ãããŒã¿ã远å ããã®ã容æã«ãªããŸãã
function reportError(error, extraContext = {}) {
// 1. ãšã©ãŒãªããžã§ã¯ãã®æ£èŠå
const normalizedError = {
message: error.message || 'An unknown error occurred.',
stack: error.stack || (new Error()).stack,
name: error.name || 'Error',
...extraContext
};
// 2. ã³ã³ããã¹ãã®è¿œå ïŒã¹ããã2åç
§ïŒ
const payload = addGlobalContext(normalizedError);
// 3. ããŒã¿ã®éä¿¡ïŒã¹ããã3åç
§ïŒ
sendErrorToServer(payload);
}
ã¹ããã2ïŒè±å¯ãªã³ã³ããã¹ãã®åé - 解決å¯èœãªãã°ãžã®éµ
ã¹ã¿ãã¯ãã¬ãŒã¹ã¯ãšã©ãŒãã©ãã§èµ·ãã£ãããæããŠãããŸããã³ã³ããã¹ãã¯ãªãèµ·ãã£ãããæããŠãããŸããã³ã³ããã¹ãããªããã°ãå€ãã®å Žåãæšæž¬ã«é Œãããšã«ãªããŸããäžå åããã`reportError`颿°ã¯ããã¹ãŠã®ãšã©ãŒå ±åãå¯èœãªéãå€ãã®é¢é£æ å ±ã§å å®ãããã¹ãã§ãïŒ
- ã¢ããªã±ãŒã·ã§ã³ã®ããŒãžã§ã³ïŒGitã®ã³ãããSHAããªãªãŒã¹ããŒãžã§ã³çªå·ãããã¯ãã°ãæ°ãããã®ããå€ããã®ãããããã¯ç¹å®ã®ãããã€ã¡ã³ãã®äžéšã§ããããç¥ãããã«äžå¯æ¬ ã§ãã
- ãŠãŒã¶ãŒæ å ±ïŒäžæã®ãŠãŒã¶ãŒIDïŒæç€ºçãªåæãšé©åãªã»ãã¥ãªãã£ããªãéããã¡ãŒã«ã¢ãã¬ã¹ãååãªã©ã®å人ãç¹å®ã§ããæ å ±ã¯æ±ºããŠéä¿¡ããªãã§ãã ããïŒãããã«ããã圱é¿ç¯å²ïŒäŸïŒ1人ã®ãŠãŒã¶ãŒã圱é¿ãåããŠããã®ãã倿°ãïŒãçè§£ããã®ã«åœ¹ç«ã¡ãŸãã
- ç°å¢ã®è©³çްïŒãã©ãŠã¶åãšããŒãžã§ã³ããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ãããã€ã¹ã¿ã€ããç»é¢è§£å床ãèšèªèšå®ã
- ãã¬ããã¯ã©ã ïŒãšã©ãŒã«è³ããŸã§ã®äžé£ã®ãŠãŒã¶ãŒã¢ã¯ã·ã§ã³ãšã¢ããªã±ãŒã·ã§ã³ã€ãã³ãã®æç³»åãªã¹ããäŸïŒ`['ãŠãŒã¶ãŒã#login-buttonãã¯ãªãã¯', ' /dashboardãžããã²ãŒã', '/api/widgetsãžã®APIåŒã³åºã倱æ', 'ãšã©ãŒçºç']`ãããã¯æã匷åãªãããã°ããŒã«ã®1ã€ã§ãã
- ã¢ããªã±ãŒã·ã§ã³ã®ç¶æ ïŒãšã©ãŒçºçæã®ã¢ããªã±ãŒã·ã§ã³ã®ç¶æ ã®ãµãã¿ã€ãºãããã¹ãããã·ã§ããïŒäŸïŒçŸåšã®Redux/Vuexã¹ãã¢ã®ç¶æ ãã¢ã¯ãã£ããªURLïŒã
- ãããã¯ãŒã¯æ å ±ïŒãšã©ãŒãAPIåŒã³åºãã«é¢é£ããŠããå Žåããªã¯ãšã¹ãURLãã¡ãœãããã¹ããŒã¿ã¹ã³ãŒããå«ããŸãã
ã¹ããã3ïŒéä¿¡å±€ - ãšã©ãŒã確å®ã«éä¿¡ãã
è±å¯ãªãšã©ãŒãã€ããŒããäœæãããããããããã¯ãšã³ããŸãã¯ãµãŒãããŒãã£ã®ãµãŒãã¹ã«éä¿¡ããå¿ èŠããããŸããæšæºã®`fetch`åŒã³åºãããã®ãŸãŸäœ¿ãããšã¯ã§ããŸããããªããªãããŠãŒã¶ãŒãããŒãžããé¢ããéã«ãšã©ãŒãçºçããå Žåããã©ãŠã¶ããªã¯ãšã¹ããå®äºããåã«ãã£ã³ã»ã«ããŠããŸãå¯èœæ§ãããããã§ãã
ãã®äœæ¥ã«æé©ãªããŒã«ã¯`navigator.sendBeacon()`ã§ãã
`navigator.sendBeacon(url, data)`ã¯ãå°éã®åæããŒã¿ããã®ã³ã°ããŒã¿ãéä¿¡ããããã«èšèšãããŠããŸããããã¯ãããŒãžãã¢ã³ããŒããããåã«éå§ãããããšãä¿èšŒãããHTTP POSTãªã¯ãšã¹ããéåæã§éä¿¡ããä»ã®éèŠãªãããã¯ãŒã¯ãªã¯ãšã¹ããšç«¶åããŸããã
`sendErrorToServer`颿°ã®äŸïŒ
function sendErrorToServer(payload) {
const endpoint = 'https://api.yourapp.com/errors';
const blob = new Blob([JSON.stringify(payload)], { type: 'application/json' });
if (navigator.sendBeacon) {
navigator.sendBeacon(endpoint, blob);
} else {
// å€ããã©ãŠã¶åãã®ãã©ãŒã«ããã¯
fetch(endpoint, {
method: 'POST',
body: blob,
keepalive: true // ããŒãžã¢ã³ããŒãäžã®ãªã¯ãšã¹ãã§éèŠ
}).catch(console.error);
}
}
ã¹ããã4ïŒãµãŒãããŒãã£ã®ç£èŠãµãŒãã¹ã®æŽ»çš
ãããã®ãšã©ãŒãåã蟌ã¿ãä¿åããåæããããã«ç¬èªã®ããã¯ãšã³ããæ§ç¯ããããšãå¯èœã§ãããããã¯å€§ããªãšã³ãžãã¢ãªã³ã°ã®åŽåãèŠããŸããã»ãšãã©ã®ããŒã ã«ãšã£ãŠãå°éã®ãããã§ãã·ã§ãã«ãªãšã©ãŒç£èŠãµãŒãã¹ã掻çšããæ¹ãã¯ããã«å¹ççã§åŒ·åã§ãããããã®ãã©ãããã©ãŒã ã¯ããã®åé¡ãå€§èŠæš¡ã«è§£æ±ºããããã«ç¹åããŠäœãããŠããŸãã
äž»èŠãªãµãŒãã¹ïŒ
- Sentry: æã人æ°ã®ãããªãŒãã³ãœãŒã¹ããã³ãã¹ãåã®ãšã©ãŒç£èŠãã©ãããã©ãŒã ã®1ã€ããšã©ãŒã®ã°ã«ãŒãã³ã°ããªãªãŒã¹ã®è¿œè·¡ãã€ã³ãã°ã¬ãŒã·ã§ã³ã«åªããŠããŸãã
- LogRocket: ãšã©ãŒè¿œè·¡ãšã»ãã·ã§ã³ãªãã¬ã€ãçµã¿åããããŠãŒã¶ãŒããšã©ãŒãçºçãããããã«äœãããããæ£ç¢ºã«ãããªã§ç¢ºèªã§ããŸãã
- Datadog Real User Monitoring: ãã倧ããªç£èŠããŒã«ã¹ã€ãŒãã®äžéšãšããŠãšã©ãŒè¿œè·¡ãå«ããå æ¬çãªãªãã¶ãŒãããªãã£ãã©ãããã©ãŒã ã§ãã
- Bugsnag: å®å®æ§ã¹ã³ã¢ãšãæç¢ºã§å®è¡å¯èœãªãšã©ãŒã¬ããŒãã®æäŸã«éç¹ã眮ããŠããŸãã
ãªããµãŒãã¹ã䜿ãã®ãïŒ
- ã€ã³ããªãžã§ã³ããªã°ã«ãŒãã³ã°ïŒäœåãã®åå¥ã®ãšã©ãŒã€ãã³ãããåäžã®å¯ŸåŠå¯èœãªåé¡ã«èªåçã«ã°ã«ãŒãåããŸãã
- ãœãŒã¹ãããã®ãµããŒãïŒæ¬çªç°å¢ã®ã³ãŒããéãããã¡ã€ããŠãèªã¿ãããã¹ã¿ãã¯ãã¬ãŒã¹ã衚瀺ã§ããŸããïŒè©³çްã¯åŸè¿°ïŒã
- ã¢ã©ãŒããšéç¥ïŒSlackãPagerDutyãã¡ãŒã«ãªã©ãšé£æºããæ°ãããšã©ãŒããªã°ã¬ãã·ã§ã³ããŸãã¯ãšã©ãŒçã®æ¥å¢ãéç¥ããŸãã
- ããã·ã¥ããŒããšåæïŒãšã©ãŒã®åŸåãèŠèŠåãã圱é¿ãçè§£ããä¿®æ£ã®åªå é äœãä»ããããã®åŒ·åãªããŒã«ãæäŸããŸãã
- è±å¯ãªã€ã³ãã°ã¬ãŒã·ã§ã³ïŒJiraãªã©ã®ãããžã§ã¯ã管çããŒã«ãšé£æºããŠãã±ãããäœæããããGitHubãªã©ã®ããŒãžã§ã³ç®¡çãšé£æºããŠãšã©ãŒãç¹å®ã®ã³ãããã«ãªã³ã¯ãããããŸãã
ç§å¯å µåšïŒãããã¡ã€ãããã³ãŒãããããã°ããããã®ãœãŒã¹ããã
ããã©ãŒãã³ã¹ãæé©åãããããæ¬çªç°å¢ã®JavaScriptã¯ã»ãšãã©åžžã«ãããã¡ã€ïŒå€æ°åãççž®ãã空çœãåé€ïŒããã³ãã©ã³ã¹ãã€ã«ïŒäŸïŒTypeScriptãææ°ã®ESNextããES5ãžïŒãããŸããããã«ãããããªãã®çŸããèªã¿ãããã³ãŒãããå€èªäžèœãªæ··ä¹±ãããã®ã«å€ãã£ãŠããŸããŸãã
ãã®ãããã¡ã€ãããã³ãŒãã§ãšã©ãŒãçºçãããšãã¹ã¿ãã¯ãã¬ãŒã¹ã¯åœ¹ã«ç«ããã`app.min.js:1:15432`ã®ãããªå Žæãæã瀺ããŸãã
ããã§ãœãŒã¹ããããæäžäž»ãšãªããŸãã
ãœãŒã¹ãããã¯ããããã¡ã€ãããæ¬çªã³ãŒããšå ã®ãœãŒã¹ã³ãŒããšã®éã®ãããã³ã°ãäœæãããã¡ã€ã«ïŒ`.map`ïŒã§ããWebpackãViteãRollupãªã©ã®çŸä»£ã®ãã«ãããŒã«ã¯ããã«ãããã»ã¹äžã«ããããèªåçã«çæã§ããŸãã
ãšã©ãŒç£èŠãµãŒãã¹ã¯ãããã®ãœãŒã¹ãããã䜿çšããŠãäžå¯è§£ãªæ¬çªç°å¢ã®ã¹ã¿ãã¯ãã¬ãŒã¹ããå ã®ãœãŒã¹ãã¡ã€ã«ã®è¡ãšåãçŽæ¥æã瀺ããçŸããèªã¿ããããã®ã«ç¿»èš³ã§ããŸããããã¯ééããªããçŸä»£ã®ãšã©ãŒç£èŠã·ã¹ãã ã®æãéèŠãªæ©èœã§ãã
ã¯ãŒã¯ãããŒïŒ
- ãã«ãããŒã«ãèšå®ããŠãœãŒã¹ããããçæããŸãã
- ãããã€ã¡ã³ãããã»ã¹äžã«ããããã®ãœãŒã¹ããããã¡ã€ã«ããšã©ãŒç£èŠãµãŒãã¹ïŒäŸïŒSentry, BugsnagïŒã«ã¢ããããŒãããŸãã
- éèŠãªããšãšããŠããœãŒã¹ã³ãŒããå ¬éãããŠãåé¡ãªãå Žåãé€ãã`.map`ãã¡ã€ã«ããŠã§ããµãŒããŒã«å ¬éã§ãããã€ããªãã§ãã ãããç£èŠãµãŒãã¹ããã©ã€ããŒãã«ãããã³ã°ãåŠçããŸãã
ç©æ¥µçãªãšã©ãŒç®¡çæåã®éžæ
ãã¯ãããžãŒã¯æŠãã®ååã«ãããŸãããçã«å¹æçãªæŠç¥ã«ã¯ããšã³ãžãã¢ãªã³ã°ããŒã å ã§ã®æåçãªå€é©ãå¿ èŠã§ãã
ããªã¢ãŒãžãšåªå é äœä»ã
ç£èŠãµãŒãã¹ã¯ããã«ãšã©ãŒã§ãã£ã±ãã«ãªããŸãããã¹ãŠãä¿®æ£ããããšã¯ã§ããŸãããããªã¢ãŒãžããã»ã¹ã確ç«ããŠãã ããïŒ
- 圱é¿ïŒäœäººã®ãŠãŒã¶ãŒã圱é¿ãåããŠããŸããïŒãã§ãã¯ã¢ãŠãããµã€ã³ã¢ããã®ãããªéèŠãªããžãã¹ãããŒã«åœ±é¿ãäžããŸããïŒ
- é »åºŠïŒãã®ãšã©ãŒã¯ã©ã®ãããã®é »åºŠã§çºçããŠããŸããïŒ
- æ°èŠæ§ïŒããã¯ææ°ã®ãªãªãŒã¹ã§å°å ¥ãããæ°ãããšã©ãŒïŒãªã°ã¬ãã·ã§ã³ïŒã§ããïŒ
ãã®æ å ±ã䜿çšããŠãã©ã®ãã°ãæåã«ä¿®æ£ãããã®åªå é äœãä»ããŸããéèŠãªãŠãŒã¶ãŒãžã£ãŒããŒã«ããã圱é¿ã倧ãããé »åºŠã®é«ããšã©ãŒããªã¹ãã®æäžäœã«æ¥ãã¹ãã§ãã
ã€ã³ããªãžã§ã³ããªã¢ã©ãŒãèšå®
ã¢ã©ãŒãç²ããé¿ããŠãã ããããã¹ãŠã®ãšã©ãŒã«å¯ŸããŠSlackéç¥ãéããªãã§ãã ãããã¢ã©ãŒããæŠç¥çã«èšå®ããŸãïŒ
- ãããŸã§ã«èŠãããšã®ãªãæ°ãããšã©ãŒã«å¯ŸããŠã¢ã©ãŒããåºãã
- ãªã°ã¬ãã·ã§ã³ïŒä»¥åã«è§£æ±ºæžã¿ãšããŒã¯ããããåçºãããšã©ãŒïŒã«å¯ŸããŠã¢ã©ãŒããåºãã
- æ¢ç¥ã®ãšã©ãŒã®çºççãèããæ¥å¢ããå Žåã«ã¢ã©ãŒããåºãã
ãã£ãŒãããã¯ã«ãŒããéãã
ãšã©ãŒç£èŠããŒã«ããããžã§ã¯ã管çã·ã¹ãã ãšçµ±åããŸããæ°ããé倧ãªãšã©ãŒãç¹å®ãããããJiraãAsanaã§èªåçã«ãã±ãããäœæããé¢é£ããŒã ã«å²ãåœãŠãŸããéçºè ããã°ãä¿®æ£ããŠã³ãŒããããŒãžããããã³ãããããã±ããã«ãªã³ã¯ããŸããæ°ããããŒãžã§ã³ããããã€ããããšãç£èŠããŒã«ã¯ãšã©ãŒãçºçããªããªã£ãããšãèªåçã«æ€åºãã解決æžã¿ãšããŠããŒã¯ããã¹ãã§ãã
çµè«ïŒåã身ã®ç«æ¶ãããç©æ¥µçãªåè¶æ§ãž
æ¬çªç°å¢ã°ã¬ãŒãã®JavaScriptãšã©ãŒç®¡çã·ã¹ãã ã¯ãç®çå°ã§ã¯ãªãæ ã§ããããã¯ã`try...catch`ã`window.onerror`ã`window.onunhandledrejection`ãšãã£ãäž»èŠãªææã¡ã«ããºã ãå®è£ ãããã¹ãŠãäžå åãããå ±å颿°ãéããŠéçŽããããšããå§ãŸããŸãã
ããããçã®åã¯ããããã®å ±åãæ·±ãã³ã³ããã¹ãã§å å®ãããå°éã®ç£èŠãµãŒãã¹ã䜿ã£ãŠããŒã¿ãçè§£ãããœãŒã¹ããããæŽ»çšããŠãããã°ãã·ãŒã ã¬ã¹ãªäœéšã«ããããšããçãŸããŸãããã®æè¡çåºç€ããç©æ¥µçãªããªã¢ãŒãžãã€ã³ããªãžã§ã³ããªã¢ã©ãŒãããããŠéãããã£ãŒãããã¯ã«ãŒãã«çŠç¹ãåœãŠãããŒã æåãšçµã¿åãããããšã§ããœãããŠã§ã¢å質ãžã®ã¢ãããŒããå€é©ã§ããŸãã
ãŠãŒã¶ãŒããã°ãå ±åããã®ãåŸ ã€ã®ã¯ãããŸããããäœãå£ããŠããã®ãã誰ã«åœ±é¿ããŠããã®ãããããŠã©ãããã°ä¿®æ£ã§ããã®ããæããŠãããã·ã¹ãã ãæ§ç¯ãå§ããŠãã ããââå€ãã®å ŽåããŠãŒã¶ãŒãæ°ã¥ãåã«ãããããããæçãããŠãŒã¶ãŒäžå¿ã§ãäžççã«ç«¶äºåã®ãããšã³ãžãã¢ãªã³ã°çµç¹ã®èšŒã§ãã