랜딩페이지에 채널톡을 달게 되었다.
채널톡은 위와 같이 웹 빌더를 통해 설치하는 게 아니라면 웹에 다는 방법이 스크립트를 추가하는 것말고는 방법이 없다.
가이드를 확인해보면 SPA를 위한 방식도 있기는 하다.
하지만 Next.js는 SSR(Server Side Rendering)이라서 window객체에 직접 접근이 어렵고 useEffect 내부에서 사용하는 방법이 있는데 채널톡에서 제공되는 방식은 class를 사용하는 거라서 그것 역시 어렵게 되었다(내 수준에서는). 그래서 이틀을 삽질하고 이것저것 해보다가 생각해보니 Next.js에 다른 사람들은 외부 모듈을 어떻게 추가해주나 봐야겠다는 생각이 들어 찾아봤고 GA(Google Analytics)를 Next.js에 추가한 예시를 봤는데 dangerouslySetInnerHTML을 사용해서 붙인다는 것을 확인했다.
dangerouslySetInnerHTML은 브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체 방법입니다. 일반적으로 코드에서 HTML을 설정하는 것은 사이트 간 스크립팅 공격에 쉽게 노출될 수 있기 때문에 위험합니다. 따라서 React에서 직접 HTML을 설정할 수는 있지만, 위험하다는 것을 상기시키기 위해 dangerouslySetInnerHTML을 작성하고 __html 키로 객체를 전달해야 합니다. 아래는 예시입니다.
<script>
(function() {
var w = window;
if (w.ChannelIO) {
return (window.console.error || window.console.log || function(){})('ChannelIO script included twice.');
}
var ch = function() {
ch.c(arguments);
};
ch.q = [];
ch.c = function(args) {
ch.q.push(args);
};
w.ChannelIO = ch;
function l() {
if (w.ChannelIOInitialized) {
return;
}
w.ChannelIOInitialized = true;
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'https://cdn.channel.io/plugin/ch-plugin-web.js';
s.charset = 'UTF-8';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
}
if (document.readyState === 'complete') {
l();
} else if (window.attachEvent) {
window.attachEvent('onload', l);
} else {
window.addEventListener('DOMContentLoaded', l, false);
window.addEventListener('load', l, false);
}
})();
ChannelIO('boot', {
"pluginKey": "YOUR_PLUGIN_KEY", //please fill with your plugin key
"memberId": "YOUR_USER_ID", //fill with user id
"profile": {
"name": "YOUR_USER_NAME", //fill with user name
"mobileNumber": "YOUR_USER_MOBILE_NUMBER", //fill with user phone number
"CUSTOM_VALUE_1": "VALUE_1", //any other custom meta data
"CUSTOM_VALUE_2": "VALUE_2"
}
});
</script>
붙이는 방법은 매우 간단하다! 삽질만 안 했다면 5초만에 했을 듯. 물론 개발의 절반은 삽질하며 보내는 시간이기는 하다.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
<script
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: `여기에 채널톡 코드 복붙!`
}}
/>
<script
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: `(function() {
var w = window;
if (w.ChannelIO) {
return (window.console.error || window.console.log || function(){})('ChannelIO script included twice.');
}
var ch = function() {
ch.c(arguments);
};
ch.q = [];
ch.c = function(args) {
ch.q.push(args);
};
w.ChannelIO = ch;
function l() {
if (w.ChannelIOInitialized) {
return;
}
w.ChannelIOInitialized = true;
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'https://cdn.channel.io/plugin/ch-plugin-web.js';
s.charset = 'UTF-8';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
}
if (document.readyState === 'complete') {
l();
} else if (window.attachEvent) {
window.attachEvent('onload', l);
} else {
window.addEventListener('DOMContentLoaded', l, false);
window.addEventListener('load', l, false);
}
})();
ChannelIO('boot', {
"pluginKey": "본인의 채널톡 플러그인 키(사람마다 달라요)"
});
`}}
/>
이렇게 써주면 끝이다.
이틀간 삽질했던 채널톡 안녕!
웬만 하면 dangerouslySetInnerHTML 너무나 무서운 이름이라서 다른 방식으로 교체할 수 있다면 추후에 교체하고자 한다.