Last active
May 21, 2021 18:47
-
-
Save pringshia/8278a23f1ac32fbfff527d6382b1da05 to your computer and use it in GitHub Desktop.
Turning a create-react-app project into an embeddable sandboxed component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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