SvelteKit中+layout.svelte内FB.init()初始化不稳定的问题求助
嗨,我太懂你这种崩溃的感觉了——本来在app.html里好好的Facebook SDK初始化,移到+layout.svelte或者拆成组件之后,居然十次里才成功一次,大部分时候连Facebook is init2的日志都打不出来,这排查起来真闹心。
先帮你捋清楚核心问题:为啥在app.html里稳定,到了layout组件里就拉胯了?
在app.html里,你的代码顺序是先定义window.fbAsyncInit函数,再加载Facebook的SDK脚本。SDK脚本加载完成后,会立刻检查全局有没有这个函数,有就直接执行,所以日志顺序是init1先出,然后init2,稳得一批。
但到了+layout.svelte里,你把fbAsyncInit放在了onMount钩子里面——这个钩子是组件挂载到DOM之后才会执行的。问题就出在这:如果浏览器缓存了Facebook的SDK脚本,或者脚本加载速度比组件挂载快,那SDK脚本加载完成时,fbAsyncInit还没被定义呢!SDK只会在加载完成时检查一次这个函数,之后就不会再触发了,自然就看不到init2的日志了。
那该怎么解决?给你几个靠谱的方案:
方案一:合并组件,动态控制脚本加载时机
把FacebookInit.svelte和FacebookScript.svelte合并成一个组件,确保fbAsyncInit先定义,再加载SDK脚本:
<!-- FacebookInit.svelte --> <script> import { onMount } from 'svelte'; onMount(() => { // 先把初始化函数挂到全局 window.fbAsyncInit = function () { // 先判断是否已经初始化过,避免重复操作 if (window.FB) { console.log("Facebook SDK已经初始化过啦"); return; } FB.init({ appId: '你的APP_ID', autoLogAppEvents: true, xfbml: true, version: 'v18.0', }); console.log("Facebook is init2"); }; // 动态创建脚本标签,确保在函数定义后再加载SDK const fbScript = document.createElement('script'); fbScript.src = 'https://connect.facebook.net/en_US/all.js'; fbScript.async = true; fbScript.defer = true; fbScript.crossOrigin = 'anonymous'; document.body.appendChild(fbScript); console.log("Facebook is init1"); }); </script>
然后在+layout.svelte里只引入这个组件就行:
<!-- +layout.svelte --> <script> import '../global.css'; import Footer from '$lib/Footer.svelte'; import FacebookInit from '$lib/FacebookInit.svelte'; </script> <FacebookInit /> <!-- 其他布局内容 --> <Footer />
方案二:用SvelteKit的load函数提前定义(进阶版)
如果想更早地初始化,可以在+layout.js的load函数里定义fbAsyncInit,注意要判断是否在浏览器环境:
// +layout.js export async function load() { if (typeof window !== 'undefined') { window.fbAsyncInit = function () { if (window.FB) return; FB.init({ appId: '你的APP_ID', autoLogAppEvents: true, xfbml: true, version: 'v18.0', }); console.log("Facebook is init2"); }; } }
然后在+layout.svelte里用动态创建脚本的方式加载SDK,保证脚本在函数定义后执行。
关键注意点
- 绝对不要把
fbAsyncInit放在onMount之后才执行的逻辑里,一定要保证它在SDK脚本加载前就存在于全局 - 加个
window.FB的判断,避免重复初始化导致的奇怪问题 - 尽量不要直接在组件里写
<script>标签引入第三方脚本,动态创建脚本标签能更好地控制加载顺序
试试上面的方案,应该能解决你初始化不稳定的问题!
备注:内容来源于stack exchange,提问作者DavidF

