Skip to content

Instantly share code, notes, and snippets.

@pringshia
Last active May 21, 2021 18:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pringshia/8278a23f1ac32fbfff527d6382b1da05 to your computer and use it in GitHub Desktop.
Save pringshia/8278a23f1ac32fbfff527d6382b1da05 to your computer and use it in GitHub Desktop.
Turning a create-react-app project into an embeddable sandboxed component
1. `npx create-react-app embeddable-app`
2. Install a few packages:
```
npm install --save-dev react-frame-component \
@babel/core \
@babel/preset-env \
@babel/preset-react \
babel-loader base64-inline-loader css-loader style-loader \
webpack webpack-cli
```
3. Use a webpack config as such:
```
var webpack = require("webpack");
module.exports = {
entry: "./src/index.js",
output: {
path: __dirname,
filename: "build/bundle.js",
library: "EmbeddableReactApp",
libraryTarget: "umd",
},
target: "web",
externals: {
react: {
commonjs: "react",
commonjs2: "react",
amd: "react",
umd: "react",
root: "React", // indicates global variable
},
"react-dom": {
commonjs: "react-dom",
commonjs2: "react-dom",
amd: "react-dom",
umd: "react-dom",
root: "ReactDOM", // indicates global variable
},
},
node: {
net: "empty",
dns: "empty",
},
plugins: [
new webpack.ProvidePlugin({
_RUNNING_WEBPACK_BUILD_: true,
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: /node_modules/,
options: { presets: ["@babel/env"] },
},
{
test: /\.*css$/,
use: [
{
loader: "style-loader",
options: {
insert: (el) => {
window._EMBED_TEMPLATE_BUILD_STYLES_ =
window._EMBED_TEMPLATE_BUILD_STYLES_ || [];
window._EMBED_TEMPLATE_BUILD_STYLES_.push(el);
},
},
},
{ loader: "css-loader" },
],
},
{
test: /\.(jpe?g|png|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
use: "base64-inline-loader",
},
],
},
};
```
4. Create an <EmbeddableApp /> component
```
import React from "react";
import Frame, {FrameContextConsumer} from "react-frame-component";
export default function EmbeddableApp({
children,
head = null,
style,
skip = false,
frameProps,
}) {
const parentWindow = window;
return skip ? (
children
) : (
<Frame
style={{ border: 0, width: "100%", ...style }}
head={
<>
{(window._EMBED_TEMPLATE_BUILD_STYLES_ || []).map((el, idx) => (
<style key={idx}>{el.outerText}</style>
))}
{head}
</>
}
{...frameProps}
>
<FrameContextConsumer>
{
// Callback is invoked with iframe's window and document instances
({ document, window }) => {
parentWindow._EMBED_FRAME_DOCUMENT_ = document;
parentWindow._EMBED_FRAME_WINDOW_ = window;
return children;
}
}
</FrameContextConsumer>
</Frame>
);
}
```
4. Create a .babelrc file:
```
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}
```
5. You may want to add the following to the "scripts" section of your package.json:
```
"embed": "NODE_ENV=production webpack -p",
"embed:dev": "webpack",
"prepublishOnly": "NODE_ENV=production webpack -p"
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment