Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an embeddable next.js (react) component for third-party websites?

I'm attempting to create widgets for our customers to paste (embed) within their own site.

Ideally to be used by a third-party like so:

example.html

<div id="example"></div>
<script src="https://example.com/widgets/example.bundle.js"></script>
<script>
Example.init({
    selector: "#example",
    name: "example"
});
</script>

I just can't figure out how to "bundle" specific entry points down to a single file with next.js.

I'm using Vercel which builds from GitHub, so ideally I want these bundles to be generated on build, without breaking the existing next.js site.

What I've tried:

next.config.js

module.exports = {
    entry: {
        example: './pages/example.js'
    },
    output: {
        path: "./public/widgets",
        filename: '[name].bundle.js'
    }
}

Result:

This achieves nothing, and I don't understand why! :(

Useful Sources:

Github (Next.js Discussions): Adding a Webpack entry to load separately from main.js

Next.js: Custom Webpack Config

Next.js: Setting a custom build directory

Next.js: exportPathMap

Stackoverflow: Writing embeddable Javascript plugin with React & Webpack

Webpack: Configuration Documentation

like image 922
Mattijs Avatar asked Aug 04 '20 13:08

Mattijs


1 Answers

First of all, your desired embedded / initialization format (which is of course typical for embeddable widgets) requires that the loaded script creates the Example global object, on which you can then invoke .init(), which then renders your widget html into the tag specified in selector.

Next creates a full page, not an object that can be called as described above.

To change this you need to override the Next server to bypass the whole app.render() process for specific urls, and instead create the Example object, which does its own call to ReactDOM.render() on .init().

You also need to address the two possible scenarios that the web page where your widget is embedded can be a React-based page or not. So you either need to use already loaded ReactDOM or make the browser load React before you can render your widget.

While all this is doable, it is not easy to make robust, and doing it inside NextJS makes it more cumbersome. My advice would be to structure the code of your NextJS app in such a way that the parts you need in the widget are components that you can use both in the NextJS main app and in a separate embeddable widget using plain CRA.

Some further reading:

https://selleo.com/blog/how-to-create-embedded-react-widget (not the iFrame parts though)

https://meda.io/embed-react-into-an-html-web-page/

like image 91
Jesper We Avatar answered Sep 17 '22 07:09

Jesper We