UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

103 lines (87 loc) 4.22 kB
import { copyFile, copyFileSync, existsSync, readFileSync, writeFileSync } from 'fs'; import { getOutputDirectory } from './config.js'; const loadInstantGamesStr = `/* needle: injected to initialize facebook instant games */ let __progress = 0; function onNeedleEngineInstantGamesLoadingProgress(_ctx, evt) { FBInstant.setLoadingProgress(evt.detail.totalProgress01 * 100); } document.addEventListener("DOMContentLoaded", function () { FBInstant.initializeAsync().then(function () { FBInstant.startGameAsync() }); }); ` // https://regex101.com/r/4ApFD9/1 function insertCallToOnProgress(html) { const match = /(?<component><needle-engine.*?.*?>)/g.exec(html); if (!match) { log("!!! Could not find needle-engine component in index.html"); return html; } const progressEvtSignature = "progress=\"onNeedleEngineInstantGamesLoadingProgress\""; const component = match.groups.component; if (component.includes("progress")) return html; log("Inserting progress callback event into needle-engine component") const newComponent = component.replace(">", ` ${progressEvtSignature}>`); return html.replace(component, newComponent); } function log(...any) { console.log("[needle facebook instant games] ", ...any); } /** * @param {{facebookInstantGames?:object}} config * @param {import('../types').userSettings} userSettings */ export const needleFacebookInstantGames = (command, config, userSettings) => { if (userSettings.noFacebookInstantGames === true) return; // If the config is not present it means that we don't want to use fb instant games if (!config || !(userSettings.facebookInstantGames || config.facebookInstantGames)) return; /** @type {import('../types').userSettings["facebookInstantGames"]} */ const facebookInstantGamesConfig = { ...config.facebookInstantGames, ...userSettings.facebookInstantGames }; log("Setup Facebook Instant Games", facebookInstantGamesConfig); // https://developers.facebook.com/docs/games/build/instant-games/reference/bundle-config let bundleConfig = {} const bundleConfigPath = process.cwd() + "/fbapp-config.json"; if (existsSync(bundleConfigPath)) { log(`Found facebook bundle config exists at "${bundleConfigPath}" ...`); bundleConfig = JSON.parse(readFileSync(bundleConfigPath, 'utf8')); } else { log(`No facebook bundle config exists at "${bundleConfigPath}" - will generate one now`); } // Make sure the bundle has the required arguments: if (!bundleConfig.instant_games) bundleConfig.instant_games = {} const gamesConfig = bundleConfig.instant_games; if (!gamesConfig.orientation) gamesConfig.orientation = "PORTRAIT"; if (!gamesConfig.override_web_orientation) gamesConfig.override_web_orientation = "LANDSCAPE"; if (!gamesConfig.navigation_menu_version) gamesConfig.navigation_menu_version = "NAV_BAR"; const outputDir = getOutputDirectory(); return { name: 'needle:facebook-instant-games', transformIndexHtml: { order: 'post', handler(html, _ctx) { // post transform so we want to linebreak after the vite logs console.log("\n"); writeFileSync(outputDir + "/fbapp-config.json", JSON.stringify(bundleConfig), 'utf8'); html = insertCallToOnProgress(html); return { html, tags: [ { tag: 'script', attrs: { src: 'https://connect.facebook.net/en_US/fbinstant.6.3.js', async: true, }, injectTo: 'head', }, { tag: 'script', children: loadInstantGamesStr, injectTo: 'body', }, ] } } }, } }