Reputation: 1
Have built a chat widget using Next.js and webpack, it works, locally and when deployed on Vercel. Sharing the github repo for reference - https://github.com/SuprSend-NotificationAPI/bifrost
Also sharing the native vercel deployment where you can see it working --https://bifrost-dun.vercel.app/test-widget
The issue is I'm unable to get this created in a script to be embeddable in external HTML websites.
This is the script code I'm trying to use:
<script src="https://bifrost-dun.vercel.app/_next/static/chunks/widget-bundle.js"></script> <script> console.log('Script loaded, BifrostChatWidget:', initializeBifrostChatWidget); if (typeof initializeBifrostChatWidget !== 'undefined' && typeof initializeBifrostChatWidget.attachToWindow === 'function') { initializeBifrostChatWidget.attachToWindow(); } window.onload = function() { console.log('Window loaded, checking for initializeBifrostChatWidget'); if (typeof window.initializeBifrostChatWidget === 'function') { window.initializeBifrostChatWidget(); } else { console.error('Bifrost Chat Widget initialization function not found'); } }; </script>
What am I doing wrong?
What should be the approach or any reference material?
Also attaching two relevant code blocks from this project.
widget-entry.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import ChatWidget from './components/ChatWidget';
console.log('Widget entry file loaded');
function initializeBifrostChatWidget() {
console.log('Initializing Bifrost Chat Widget');
const container = document.createElement('div');
container.id = 'bifrost-chat-widget';
document.body.appendChild(container);
const root = createRoot(container);
root.render(React.createElement(ChatWidget));
console.log('Bifrost Chat Widget initialized');
}
if (typeof window !== 'undefined') {
(window as any).initializeBifrostChatWidget = initializeBifrostChatWidget;
console.log('initializeBifrostChatWidget function attached to window:', (window as any).initializeBifrostChatWidget);
}
// For tree-shaking prevention, export the function
export { initializeBifrostChatWidget };
console.log('Widget entry file execution completed');
and next.config.js
const path = require('path');
/** @type {import('next').NextConfig} */
const nextConfig = (phase, { defaultConfig }) => {
const BUILD_ID = Date.now();
return {
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'cdn-b.saashub.com',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'randomuser.me',
pathname: '/**',
},
],
},
webpack: (config, { isServer, webpack }) => {
// Use different devtool configurations for development and production
config.devtool = isServer
? false
: phase === 'phase-production-build'
? 'source-map'
: 'eval-source-map';
if (!isServer) {
// Minification/Optimization - Disable certain optimizations for debugging
config.optimization.minimize = true; // Disable minification for debugging
config.optimization.concatenateModules = true; // Disable module concatenation
config.optimization.splitChunks = false; // Disable code splitting
// Ensure the widget entry point is included
const originalEntry = config.entry;
config.entry = async () => {
const entries = await originalEntry();
if (!entries['widget-bundle']) {
entries['widget-bundle'] = {
import: path.resolve(__dirname, 'widget-entry.tsx'),
dependOn: undefined,
};
}
return entries;
};
// Output Configuration - Expose the widget as a global library
config.output.library = {
name: 'BifrostChatWidget',
type: 'umd', // or 'umd' for broader compatibility
};
// Ensure the split chunks configuration is set up (only if you re-enable splitChunks)
if (config.optimization.splitChunks !== false) {
config.optimization.splitChunks.cacheGroups = {
...config.optimization.splitChunks.cacheGroups,
widgetBundle: {
name: 'widget-bundle',
test: /widget-entry\.tsx$/,
chunks: 'all',
enforce: true,
},
};
}
// Filename/Path - Ensure correct file naming for cache busting
config.output.filename = (pathData) => {
return pathData.chunk.name === 'widget-bundle'
? `static/chunks/[name].js?v=${BUILD_ID}`
: `static/chunks/[name].[contenthash].js`;
};
config.output.chunkFilename = (pathData) => {
return pathData.chunk.name === 'widget-bundle'
? `static/chunks/[name].js?v=${BUILD_ID}`
: `static/chunks/[name].[contenthash].js`;
};
}
return config;
},
};
};
module.exports = nextConfig;
Thanks
TUsed script tag to load the widget as shown in code.
Created a standalone script that initializes the widget and provides a public API, didn't work still.
Upvotes: 0
Views: 35