[DevTools] iPhone ์์ดํฐ ์ฌํ๋ฆฌ์์ ๋๋ฒ๊น / ์ฝ์ ์ฌ์ฉํ๊ธฐ
Safari ๊ฐ๋ฐ์ ๋๊ตฌ
๐ก ์์ดํฐ ํ๋ฉด์ด ์ ๊ฒจ์์ ๋ ์ฝ์์ ์ฌ์ฉํ ์ ์๋ค.
โถ ๋งฅ๋ถ โ ์์ดํฐ USB ์ฐ๊ฒฐ
โท ์์ดํฐ ์ค์ → Safari → ๊ณ ๊ธ → <์น ์์ฑ> ์ฒดํฌ
โธ macOS ์ฌํ๋ฆฌ ์ค์ → ๊ณ ๊ธ → <๋ฉ๋ด ๋ง๋์์ ๊ฐ๋ฐ์์ฉ ๋ฉ๋ด ๋ณด๊ธฐ> ์ฒดํฌ
โน macOS ์ฌํ๋ฆฌ ์๋จ ๋ฉ๋ด → ๊ฐ๋ฐ์์ฉ → ์์ดํฐ ๊ธฐ๊ธฐ ์ด๋ฆ → ์์ดํฐ ์ฌํ๋ฆฌ์ ์ด๋ ค์๋ ์น์ฌ์ดํธ ์ ํ
โบ macOS ์ฌํ๋ฆฌ ์ฝ์ ์ฐฝ์์ ํ์ฌ ์ฐ๋์ค์ธ ์น์ฌ์ดํธ์ ์์ฑ ํ์ธ
iOS Simulator
๐ก Status bar(๋ ธ์น ์์ญ), Nav bar, Tab bar(์ฃผ์์ฐฝ ์์ญ), Home indicator ๊ฐ์ ์์ดํฐ UI๋ฅผ ๊ทธ๋๋ก ํํํ๋ฏ๋ก ์ค๋ฌผ ๊ธฐ๊ธฐ๋ฅผ ์ด์ฉํ ๋ ์ด๋ป๊ฒ ๋ณด์ผ์ง ํ์ธํ ์ ์๋ค. ์ค์ ์ ์๋ฃํ ํ Xcode ์คํ ์์ด ์คํฌํธ๋ผ์ดํธ์์ Simulator๋ฅผ ๊ฒ์ํ ํ ๋ฐ๋ก ์คํํ ์ ์๋ค.
โถ ์ฑ์คํ ์ด์์ Xcode ์ค์น
โท โ
,
๋จ์ถํค๋ก ์ค์ ์ฐฝ ์ง์
→ Platforms → ์ํ๋ ๋ฒ์ ์ iOS Simulator ์ค์น
โธ Xcode ์๋จ ๋ฉ๋ด → Window → Devices and Simulators → ์ํ๋ iOS ๋ฒ์ /๊ธฐ๊ธฐ Simulator ์ถ๊ฐ
โน Xcode ์๋จ ๋ฉ๋ด → Xcode → Open Developer Tool → Simulator ํด๋ฆญ
โบ Simulator ์๋จ ๋ฉ๋ด → File → Open Simulator → ๊ธฐ๊ธฐ ์ ํ
โป macOS ์ฌํ๋ฆฌ ์ค์ → ๊ณ ๊ธ → <๋ฉ๋ด ๋ง๋์์ ๊ฐ๋ฐ์์ฉ ๋ฉ๋ด ๋ณด๊ธฐ> ์ฒดํฌ
โผ macOS ์ฌํ๋ฆฌ ์๋จ ๋ฉ๋ด → ๊ฐ๋ฐ์์ฉ → ์๋ฎฌ๋ ์ดํฐ → ์น์ฌ์ดํธ ์ ํ (์ ํํ๋ฉด ์ฝ์์ฐฝ์ด ๋ฌ๋ค)
๋ชจ๋ฐ์ผ ์ฝ์ — Eruda
Eruda๋ ๋ชจ๋ฐ์ผ ๋ธ๋ผ์ฐ์ ์์(์์ดํฐ ์ฌํ๋ฆฌ ๋ฑ) ์ฝ์์ ์ฌ์ฉํ ์ ์๋๋ก ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค. ์์, ๋คํธ์ํฌ, ๋ฆฌ์์ค ๋ฑ ํฌ๋กฌ ์ฝ์๊ณผ ๋น์ทํ ์ธํฐํ์ด์ค / ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. npm ํจํค์ง ํน์ ์คํฌ๋ฆฝํธ๋ฅผ ์ง์ ์ถ๊ฐํ๋ ๋ฐฉ์์ผ๋ก ์ค์นํ ์ ์๋ค. ๋ธ๋ผ์ฐ์ ์ฆ๊ฒจ์ฐพ๊ธฐ์ Eruda ์คํฌ๋ฆฝํธ๋ฅผ ๋ฑ๋กํด๋๋ฉด ๋ณ๋ค๋ฅธ ์ค์น ์์ด ์ฌ์ฉํ ์๋ ์๋ค.
- Console: Display JavaScript logs.
- Elements: Check dom state.
- Network: Show requests status.
- Resource: Show localStorage, cookie information.
- Info: Show url, user agent info.
- Snippets: Include snippets used most often.
- Sources: HTML, JS, CSS source viewer.
์ฌ์ฉ ๋ฐฉ๋ฒ — ์คํฌ๋ฆฝํธ ๋ฐฉ์
๐ก </body>
์ ์ ์คํฌ๋ฆฝํธ ํ๊ทธ๋ฅผ ์ฝ์
ํ๋ฉด DOM ํ์ฑ์ ์๋ฃํ ํ ์คํฌ๋ฆฝํธ๋ฅผ ๋ก๋/์คํํ๋ค. defer
์์ฑ์ ๋ช
์ํ์ง ์์ ์คํฌ๋ฆฝํธ๋ฅผ </head>
์ ์ ์ฝ์
ํ๋ฉด <script>
์ฝ๋๋ฅผ ๋ง๋๋ ์๊ฐ DOM ํ์ฑ์ ์ผ์ ์ค์งํ๊ณ ์คํฌ๋ฆฝํธ๋ฅผ ๋ก๋/์คํํ๋ค(์คํฌ๋ฆฝํธ ์คํ ์๋ฃ ํ DOM ํ์ฑ ์ฌ๊ฐ).
React
๋ชจ๋ ํ์ด์ง์์ ์คํํ ๋ ์์ ์ฝ๋. </head>
ํ๊ทธ ์ ์ ๋ฃ๊ณ ์ถ๋ค๋ฉด ์คํฌ๋ฆฝํธ ํ๊ทธ์ defer
์์ฑ์ ์ถ๊ฐํด์ DOM ํ์ฑ์ ๋ฐฉํดํ์ง ์๋๋ก ํ๋ค. ๊ทธ๋ผ DOM ํ์ฑ์ด ์ด๋ค์ง ๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํฌ๋ฆฝํธ๋ฅผ ๋ค์ด๋ก๋ํ๊ณ , DOM ํ์ฑ์ ์๋ฃํ ์์ ์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ค.
<!-- public/index.html — </body> ์ ์ ์ฝ์
ํ ๋ -->
<body>
<!-- ์๋ต -->
<script src="//cdn.jsdelivr.net/npm/eruda" onload="eruda.init()"></script>
</body>
<!-- public/index.html — </head> ์ ์ ์ฝ์
ํ ๋ -->
<head>
<!-- ์๋ต -->
<script
defer
src="//cdn.jsdelivr.net/npm/eruda"
onload="eruda.init()"
></script>
</head>
์ฃผ์์ฐฝ ์ฟผ๋ฆฌ์คํธ๋ง key/value๊ฐ ?eruda=true
์ผ ๋๋ง ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋๋ก ํ ์๋ ์๋ค.
<!-- public/index.html -->
<body>
<!-- ... -->
<script>
(function () {
const isErudaActive = /eruda=true/.test(window.location) || localStorage.getItem('active-eruda') === 'true';
if (!isErudaActive) return;
const script = document.createElement('script');
script.src = '//cdn.jsdelivr.net/npm/eruda';
script.onload = () => eruda.init();
document.body.append(script);
})();
</script>
</body>
Next.js
์ ์ฒด ํ์ด์ง์์ ์คํํ๋ ค๋ฉด _app.tsx
ํ์ผ์, ํน์ ํ์ด์ง์์๋ง ์คํํ๋ ค๋ฉด ํด๋น ํ์ด์ง ํ์ผ์ ์ถ๊ฐํ๋ค.
// _app.tsx
import Script from 'next/script';
export default function App() {
// ...
return (
<>
{/* ... */}
<Script
src="//cdn.jsdelivr.net/npm/eruda"
onLoad={() => window.eruda?.init()}
/>
</>
);
}
ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ญ ๊ฐ์ฒด์์ eruda๋ฅผ ์ฐพ์ ์ ์๋ค๋ ์๋ฌ๊ฐ ๋์ค๋ฏ๋ก, ์ ์ญ ๊ฐ์ฒด ํ์
์ eruda๋ฅผ ์ถ๊ฐํด์ค๋ค. init
๋ฉ์๋ ์ธ์์ ์ต์
์ ๋ฃ๋๋ค๋ฉด InitOptions
์ต์
ํ์
๋ ์ ์ํด์ผ ํ๋ค(์ ์ฒด ํ์
์ ์).
// global.d.ts
declare global {
interface Window {
eruda?: { init: () => void }; // ์ ์ญ ๊ฐ์ฒด์ eruda ํ์
์ถ๊ฐ
}
}
export {};
ErudaScript ์ปดํฌ๋ํธ๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์ ๋ชจ๋ฐ์ผ / ๊ฐ๋ฐ ํ๊ฒฝ ๋ฑ์ ์คํ ์กฐ๊ฑด์ ์ถ๊ฐ ํ ์๋ ์๋ค.
// ErudaScript.tsx
const ErudaScript = () => {
if (
typeof window === 'undefined' ||
process.env.NODE_ENV === 'production' ||
!isMobile // "react-device-detect" ํจํค์ง
)
return null;
return (
<Script
src="//cdn.jsdelivr.net/npm/eruda"
onLoad={() => window.eruda?.init()}
/>
);
};
์ฐธ๊ณ ๋ก Next.js Script ์ปดํฌ๋ํธ์ strategy
์์ฑ์ ๋ช
์ํ์ง ์์ผ๋ฉด afterInteractive
์ค์ ์ด ๊ธฐ๋ณธ ์ ์ฉ๋๋ค. ์ฐจ์ด์ ์ ์๋์ ๊ฐ๋ค. ๋ ์์ธํ ๋ด์ฉ์ ๊ณต์๋ฌธ์ ์ฐธ๊ณ .
afterInteractive
(๊ธฐ๋ณธ๊ฐ)- ์ฝ์
์์น :
</body>
์ด์ (ํด๋ผ์ด์ธํธ์์ ์ฝ์ ) - ์คํ ์์ : ํ์ด๋๋ ์ด์ ์ดํ
- ์ฉ๋ : ํ๊ทธ ๋งค๋์ , ์ ๋๋ฆฌํฑ์ค ๋ฑ
- ์ฝ์
์์น :
beforeInteractive
- ์ฝ์
์์น :
</head>
์ด์ (์๋ฒ์์ ๋ฏธ๋ฆฌ ์ฝ์ ) - ์คํ ์์ : ํ์ด๋๋ ์ด์ ์ด์ (์๋ฒ์์ ์ด๊ธฐ HTML์ ์ฃผ์ ๋ ํ Next.js ๋ชจ๋๋ณด๋ค ๋จผ์ ๋ค์ด๋ก๋)
- ์ฉ๋ : ์ฟ ํค ๋์ ์๋ฆผ, ๋ด ํ์ง๊ธฐ ๋ฑ
- ์ฝ์
์์น :
์ฌ์ฉ ๋ฐฉ๋ฒ — npm ํจํค์ง ๋ฐฉ์
๐ก ์ฐธ๊ณ ๋ด์ฉ
- ๋ชจ๋ ํ์ด์ง์์ ์คํ : ์ต์์ ์ปดํฌ๋ํธ์์ ํธ์ถ e.g.
App.tsx
(React),_app.tsx
(Next.js) - ํน์ ํ์ด์ง์์ ์คํ : ํด๋น ํ์ด์ง ์ปดํฌ๋ํธ์์ ํธ์ถ
React
useEruda
์ปค์คํ
ํ
์ผ๋ก ๋ง๋ค์ด์ ์ฌ์ฉํ ์์ โผ
// useEruda.ts
import eruda from 'eruda';
const useEruda = () => {
useEffect(() => {
eruda.init();
return () => eruda.destroy(); // ์ธ๋ง์ดํธ์ eruda ์ธ์คํด์ค ์ ๊ฑฐ
}, []);
};
// App.tsx
// ๋ชจ๋ ํ์ด์ง์์ ์คํ
function App() {
useEruda();
// ...
}
Next.js
๐ก import(module)
๊ตฌ๋ฌธ์ ๋ชจ๋์ด ๋ด๋ณด๋ธ ๊ฐ์ฒด๋ฅผ ๋ด์ ์ดํ๋ ํ๋ก๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค.
Next.js์์ eruda ๋ชจ๋์ ๋ถ๋ฌ์์ ์ฌ์ฉํ๋ฉด self is not defined
๋ ํผ๋ฐ์ค ์๋ฌ๋ฅผ ๋ฟ๋๋ค. ์ด ๋ฌธ์ ๋ ๋ค์ด๋๋ฏน import ๋ฐฉ์์ ํ์ฉํด์ ref
๊ฐ์ฒด์ ๋ด์๋๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์๋ค.
// useEruda.ts
import { Eruda } from 'eruda';
const useEruda = () => {
const instance = useRef<Eruda | null>(null);
useEffect(() => {
if (!instance.current) {
import('eruda').then((module) => {
// default export ๋ชจ๋์ default ํ๋กํผํฐ๋ก ์ฝ๋๋ค
instance.current = module.default;
instance.current.init();
});
}
}, []);
useEffect(() => {
return () => instance.current?.destroy();
}, []);
};
// _app.tsx
// ๋ชจ๋ ํ์ด์ง์์ ์คํ
function App({ Component, pageProps }: AppProps) {
useEruda();
// ...
return <Component {...pageProps} />;
}
์ฌ์ฉ ๋ฐฉ๋ฒ — ๋ถ๋งํฌ ๋ฐฉ์ โญ๏ธ
์๋ ์ฃผ์๋ก ์ฌํ๋ฆฌ๋ ํฌ๋กฌ ์ฆ๊ฒจ์ฐพ๊ธฐ์ ์ถ๊ฐํด๋๋ฉด ์ด๋ค ์ฌ์ดํธ / ํ์ด์ง์์๋ ๋ชจ๋ฐ์ผ ์ฝ์์ ์ฌ์ฉํ ์ ์๋ค. ํ๋ก์ ํธ์ ๋ฐ๋ก ์ค์นํ ํ์ ์์ผ๋ฏ๋ก ๊ฐ์ฅ ํธ๋ฆฌํ ๋ฐฉ์(์ถ์ฒ).
javascript: (function () {
const script = document.createElement('script');
script.src = '//cdn.jsdelivr.net/npm/eruda';
document.body.appendChild(script);
script.onload = () => eruda.init();
})();
์ต์
์ฝ์ ํจ๋์ด ๋ถ์ ์ปจํ
์ด๋๋ฅผ ์ง์ ํ๊ฑฐ๋, ์ฝ์ ์ฐฝ์ ์ด๋ค ํญ(Tool)์ ํฌํจํ ์ง ์ง์ ์ค์ ํ ์ ์๋ค. ์ด ์ธ์๋ ํฌ๋ช
๋ / ์ฌ์ด์ฆ / ํ
๋ง๋ฅผ ๋ณ๊ฒฝํ ์ ์๊ณ , show()
, hide()
๋ฉ์๋๋ก ์ฝ์ ํจ๋ ํ์๋ฅผ ์ ์ดํ ์๋ ์๋ค. ๋ ์์ธํ ๋ด์ฉ์ ๊ณต์ ๋ฌธ์ ์ฐธ๊ณ .
์ด๋ฆ | ํ์ | ์ค๋ช |
container | element | ์ปจํ ์ด๋ ์์. ์ค์ ํ์ง ์์ผ๋ฉด HTML ๋ฃจํธ ์์ ์๋์ ์ถ๊ฐ๋จ |
tool | string, array | ๊ธฐ๋ณธ ๋๊ตฌ ์ ํ. ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๋๊ตฌ๊ฐ ์ถ๊ฐ๋จ |
autoScale=true | boolean | ๋ค์ํ ๋ทฐํฌํธ ์ค์ ์ ๋ง์ถฐ eruda๋ฅผ ์๋์ผ๋ก ์ค์ผ์ผ๋งํ ์ง ์ฌ๋ถ |
useShadowDom=true | boolean | CSS ์บก์ํ๋ฅผ ์ํด Shadow DOM ์ฌ์ฉ ์ฌ๋ถ |
defaults | object | ๊ธฐ๋ณธ ์ค์ |
defaults.transparency | number | 0~1 ์ฌ์ด ํฌ๋ช ๋ |
defaults.displaySize | number | 0~100 ์ฌ์ด ํ์ ํฌ๊ธฐ |
defaults.theme | string | ํ ๋ง ์ค์ . ๊ธฐ๋ณธ๊ฐ์ ๋ผ์ดํธ ํน์ ๋คํฌ ๋ชจ๋์์ ๋คํฌ |
// eruda.init() ์ต์
์์ via ๊ณต์ ๋ฌธ์
const el = document.createElement('div');
document.body.appendChild(el);
eruda.init({
container: el, // eruda ํจ๋์ el ์๋ฆฌ๋จผํธ์ append
tool: ['console', 'elements'], // console, elements ํญ๋ง ํ์
useShadowDom: true, // #Shadow Dom ์ฌ์ฉ
autoScale: true, // ์๋ ์ค์ผ์ผ
defaults: {
displaySize: 50, // ๋์ด 50%
transparency: 0.9, // ํฌ๋ช
๋
theme: 'Atom One Dark', // ํ
๋ง
},
});
๋ ํผ๋ฐ์ค
- next/script | Next.js
- Next.js์์ Script Component ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ
- Debugging iOS Safari (when all you have is a Mac)
- https://github.com/liriliri/eruda
๊ธ ์์ ์ฌํญ์ ๋ ธ์ ํ์ด์ง์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ฉ๋๋ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์
'๐ช Programming' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[React/JS] Promise ํ๋ก๋ฏธ์ค๋ฅผ ํ์ฉํ UX ๊ฐ์ — ํด ๋ฏธ๋ฃจ๊ธฐ
[React/JS] Promise ํ๋ก๋ฏธ์ค๋ฅผ ํ์ฉํ UX ๊ฐ์ — ํด ๋ฏธ๋ฃจ๊ธฐ
2024.05.16 -
[React] ๋ฆฌ์กํธ Profiler ํ๋กํ์ผ๋ฌ์ Hook ์์
[React] ๋ฆฌ์กํธ Profiler ํ๋กํ์ผ๋ฌ์ Hook ์์
2024.05.16 -
[JS/React] input ํ๋์ ์ซ์๋ง ์ ๋ ฅ ํ์ฉํ๊ธฐ (ํ๊ธ ์ ๋ ฅ ๋ฐฉ์ง)
[JS/React] input ํ๋์ ์ซ์๋ง ์ ๋ ฅ ํ์ฉํ๊ธฐ (ํ๊ธ ์ ๋ ฅ ๋ฐฉ์ง)
2024.05.16 -
[JS] Promise ํ๋ก๋ฏธ์ค ๋ณ๋ ฌ์ฒ๋ฆฌ ๋ฉ์๋ ํบ์๋ณด๊ธฐ
[JS] Promise ํ๋ก๋ฏธ์ค ๋ณ๋ ฌ์ฒ๋ฆฌ ๋ฉ์๋ ํบ์๋ณด๊ธฐ
2024.05.14