{"data":{"allMarkdownRemark":{"edges":[{"node":{"id":"7cae20df-634c-53fc-9b57-d14a4a98b03e","frontmatter":{"category":"Social","title":"Embeddable Lightweight React Widgets","date":"2018-12-11","summary":"This article will introduce two approaches to integrate lightweight react apps (we will call them widgets) that can be embedded in any project","thumbnail":{"relativePath":"pages/embeddable-leightweight-react-widgets/thumbnail.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAACDElEQVQ4y6WSa0tUURSG92+q6GL3soIypA+FRQbWkLcZtbxEQmpoF7MUoYxKbIgmJYmSoiDDz/2EOmdGZ+aM5khfDwNJ+2nts3Ps4uSBPjyss9c+e6137XerVCpFMpnExP9hpYYKfcgcCIEylUPhuqFQ6XSa9ZgzZL1QKM/zKEk2S8bL8TWX4Xu8l+XhFpbvtq1BaxHlisxSmBE+J1Pkk5+gsxIim6BhO9RuhfObLbVboH4b1FnUeka4s3MszTpw9RS6aQ/6Qjn60lF01wnL5Up0y37JHwhQKdehJI6DK0WXjMKeKnRsN0R3wmAjTA5b7rVZ1dKI5n3icu4LReYNixZZp3ILOAt58tm0LVhfBt1V8OQaTCfgwzgk+qH3NJhmolQVJoYojA9i4x0KT29RSAys5hK3+TYzKYeq0UaJjIgYxNs4vIvbgp3HoGmvLRhcqOlcJxfdLMmhKPRV24s2Bc5tgJF29PUaaJRxo7usorFuoQf6I5LfsTqyvngQ3XoILQvddwY98xz9bADdcYRgLyZGjF5B36hBS7HAFLPXUYFuPywGVfw0pTxABSoMRmVMut88C13HrULTObIR7neIyyftt8mtPJMgymQNZUWU/+Yx/mshiGP4rx7iTz2ya8PUKP7H9/jTE/gvRuz+n7x8YJFv5YqbvyEOB/yay3i43vzf+TX49zss4hLuP4cfa1IV+zKNxLYAAAAASUVORK5CYII=","width":402,"height":325,"src":"/static/dd3ba552f348daf0d9beb74158081069/b3029/thumbnail.png","srcSet":"/static/dd3ba552f348daf0d9beb74158081069/b3029/thumbnail.png 1x,\n/static/dd3ba552f348daf0d9beb74158081069/8d141/thumbnail.png 1.5x,\n/static/dd3ba552f348daf0d9beb74158081069/ee72c/thumbnail.png 2x,\n/static/dd3ba552f348daf0d9beb74158081069/5dfa8/thumbnail.png 3x"}}},"authorName":"Kareem Elbahrawy","authorDescription":"Kareem is Senior Frontend Engineer at AUTO1 Group","authorAvatar":{"relativePath":"pages/embeddable-leightweight-react-widgets/avatar.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAAFRUlEQVQ4yyWUa1BUZRjHz8e+9MEP1SiWgrvsLrDAooBAYHIzHanwMpmZt3FMI8NMRSdzwEuYiAgusAu4BMsuuyzLXpDLAuH97piXvKIoCKiJWVYz9enXA334z3vOM+f83v/z/M97lJHBuwwN3Gbo0W2GB+7Q33d9/Pr50L1x/TooetzH6FAfL4b7+O3JA1G/6CEvRvoZHX7A6IjURu7zx9OHKAMPbvBs7MXHd3km6rt5iVtXz/P7037+fD7Av6+e8UQ2ePLwJk9l45dSH7p/nd8F+vfoY17JMy8F/lyMjW2o/HL1LCOPbomTu/LiLW5fPcfxrlbuXrvA0L3r+Jrq8DqPcPlUgJuXTnDj4ikunezmyukefhPXf78YFPAgf4n+eTmMcuPKaU71tjPcf2t89zvXL+Ky19PpaWbDmhW88fpraN6ZSKI+lB05qzgd8HHj0hm6fU0M3PmZZ2JiVDp8+ugmg/euoXS0NeNvsXOs08fJnlbavE5qzCZKiw+QFhvNR4mxLEpO4IM4A+kGHaX5ebjtNmpNldgsZurNRkyHSqg2llB16AcUU9l+qkr2UrF/F8Z9+VQW78ViLCYvdz3ZSXHs/HQh3y75kMK1y1gyK4Fl6Ql46spw1JRQX7EPl+UglQd3U7AjD2PRPpTCb3M5lP81Zbs2iTZTWrCJw3s3UZC7nIXJ8axMS+KbxfNZm5XGuqwMNn6cSYNxK+WFX2Dcu57yPespK5C1cBvmsp0oFpNR7B6ktlJU8b8ctZWYC3eS80EGOfNS2Zg9h1XpSXy3fDGm3BVYindTuGMzu/I2cKBgK3vyvmJzzjq25K5E8bmdHPU4ZXYOumSevZ0eLp/9iYC7QdpdwPcrl1C4aikHPl9G9ebVdFYXc+HsCY73tNMb8NPb7uZYhxdLZRkF2/NQGhstOB0WXM5aPG4rbT473R3NnJGA8pcvYuuCuez4JJtt2al4Du/m3IkAPRJgV0cL7f4mGo4Y6TraRG+Xl8BR1xiwFocAm1x1tHgaaPXZxKmL86e6KN6SI6A55I8FsyiDs946qffQJoB2kd/nwO+10d7qEEmXfieKzVYz7tApDt3uegLtzZwTWK2plKVpyXy3eK7McTar56ZRXr4fe3cLAXHj8drx+hplteGTrnxy7fM7UKwN5nGYSxwelWJFaRGLsubyfmoK2ZLylx9msnBOJu+npRMVE01mzmcYPRY5KYHx51sF1ioO/f5GWloaUH60lGOtM2G3mvFLEPPSZvPWhAmERYSTEh9HltzPiIlBowklIiyMMJ2W9xJm0GY1crLbTXvL/2PyiTweK0ptdRn1MthGq0AtFcTNiCE4VI1WFGaIRquPIDRchyZMh0EfSaRKjXryZPSTgsjYsobS0166PAJsscqJE6BVHNrrKmhqqKL6cBGRiTMJmTpVzu8UVHodoVGRaCIi0Ov1xEdGEz5NRXhIMOqgybxp0JNeV4S30yU/kR/xyOiUsdjra0ppqjdRU1mMPikBVdDb6KYINCpCFIVWgLHRMSREGdCrBBg8Fa1azdSQaQTNTyfPZaZDMnDZq6RlgVhrynAK0FpbQcKsJFQTJxGj1ZIYF0+YAPWi5Nh4kgzTiRJQuHQQqpqGSqfjLa2GlO3rcTlq8DRWozis1TilZbfNhE3CSU1NRT0xiDhpMTMpmZTYmURrw5muCyMx2oBBoxGHIWhkxqFSmxyiwvBxFs2eOvyNNShF+37AXGnGYaunylxOSmIyEcFqkmNiyUh6l9nxM8eD0MpMx0D6aSFEhISMh6bW6pgiQJV8p4eOlNAmM/wPrWQIzBh2TMkAAAAASUVORK5CYII=","width":50,"height":50,"src":"/static/ea2656d13f68652e7e988d1a80c98c8b/45876/avatar.png","srcSet":"/static/ea2656d13f68652e7e988d1a80c98c8b/45876/avatar.png 1x,\n/static/ea2656d13f68652e7e988d1a80c98c8b/eb85b/avatar.png 1.5x,\n/static/ea2656d13f68652e7e988d1a80c98c8b/4f71c/avatar.png 2x,\n/static/ea2656d13f68652e7e988d1a80c98c8b/9ec3e/avatar.png 3x"}}},"headerImage":{"relativePath":"pages/embeddable-leightweight-react-widgets/header.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsSAAALEgHS3X78AAAA50lEQVQY032OsUvDQBTG+0e6OhYXFzcXXXQRxUEQpODgJIg4OImubiKiUoRCPC6X0FqSixbbhOQuP5ujOtRrP/h4D973/XgtZqrr2rlRWZbkee5cFIV3Npn5XqOWD6i1RgiBUoo4jpFSosKQKIoY9Pu8BwFJkiwHzh8n4zF6WsrS1DnJMvTXaDo/+Z7kXpj3w9/AIM14E5KeVM6i+4J4fSJ4fmQYhd7Ogg+t20fdBz7uLhne36BvL2BrBU63YXcVznZwCGsXf/gHtMbt9rqD2WtjTjYx+2tUh+tU5wdURxuYq+NZ/j/wB5xHx6fGez75AAAAAElFTkSuQmCC","width":1280,"height":420,"src":"/static/4786c8105880f38270b7cd8b2ee3faaf/26421/header.png","srcSet":"/static/4786c8105880f38270b7cd8b2ee3faaf/26421/header.png 1x,\n/static/4786c8105880f38270b7cd8b2ee3faaf/34a7a/header.png 1.5x,\n/static/4786c8105880f38270b7cd8b2ee3faaf/77cb2/header.png 2x"}}}},"html":"<p><em>\"We need to re-write EVERYTHING!\"</em>... It's understandable that a huge technical debt is created during the first period of building a company app, a lot of business needs, a lot of deadlines and smaller teams. And for webapps where a proper frontend solution was not considered, most of this technical debt falls on frontend and by time it becomes harder and harder to refactor till it reaches a point where the right way to refactor it is to re-write it. But that's not an option sometimes, isn't it?</p>\n<p>As an alternative, This article will introduce two approaches to integrate lightweight react apps (we will call them widgets) that can be embedded in any project.</p>\n<ul>\n<li>Traditional Approach</li>\n<li>Standalone Approach</li>\n</ul>\n<h2>React Widgets: Traditional Approach</h2>\n<p>React widgets implemented directly in your codebase.</p>\n<p>Create a similar folder structure to this:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">.\n├── server\n    └── ....\n├── frontend\n    ├── widgets\n        ├── login.js\n        └── subscribe.js\n    └── components\n        ├── Login.js\n        ├── Subscribe.js\n        └── ....\n├── dist #ignored\n    ├── widget_login_bundle.js\n    └── widget_subscribe_bundle.js\n├── webpack.config.js\n└── package.json</code></pre></div>\n<p><code class=\"language-text\">/frontend/widgets</code> directory will contain entry points for all the widgets, each file inside should render a react app in a corresponding DOM element id</p>\n<p>For example <code class=\"language-text\">/frontend/widgets/login.js</code></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> Login <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Login'</span><span class=\"token punctuation\">;</span>\n\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Login <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">,</span>\n    document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'widget:login'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// &lt;-- NOTE the element id</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p><code class=\"language-text\">webpack.config.js</code> will look like this</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    entry<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token string\">'./frontend/widgets/login.js'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string\">'./frontend/widgets/subscribe.js'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    output<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        filename<span class=\"token operator\">:</span> <span class=\"token string\">'widget_[name]_bundle.js'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Now running <code class=\"language-text\">webpack</code> from the project folder will create two bundle files <code class=\"language-text\">widget_login_bundle.js</code> and <code class=\"language-text\">widget_subscribe_bundle.js</code> in the <code class=\"language-text\">dist</code> folder.</p>\n<p>Now you can use a widget in one of your views like this</p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"language-html\"><code class=\"language-html\">...\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>widget:login<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">defer</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/dist/widget_login_bundle.js<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n...</code></pre></div>\n<h3>Pros</h3>\n<ul>\n<li>Easy to implement and straightforward.</li>\n<li>Doesn't need any further backend integration to make it work (except for SSR).</li>\n</ul>\n<h3>Cons</h3>\n<ul>\n<li>Depending on your backend, it might not be an easy task to server side render (SSR) widgets with this approach.</li>\n<li>You will need to configure your deployment process to run webpack.</li>\n<li>The frontend development and deployment processes are tightly coupled to the backend.</li>\n</ul>\n<hr>\n<h2>React Widgets: Standalone Approach</h2>\n<p>In this approach we will keep all frontend in a separate repository and have an npm script to generate an html and bundle js file for each widget and upload them to a CMS.</p>\n<p>But first, A new database model need to be introduced that will hold the widget data (name and html) and there should be a way to upload assets to a content server.</p>\n<p>For example you may expose two web service APIs similar to this:</p>\n<ul>\n<li>POST <code class=\"language-text\">example.com/api/widget/save-or-update</code> (Save or upload a widget entry in the database)</li>\n<li>POST <code class=\"language-text\">example.com/api/content-server/upload</code> (Upload an asset file to content server)</li>\n</ul>\n<p>The folder structure will be similar to the previous approach but this time in a separate repository:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">.\n├── frontend # Same as before\n├── dist # Same as before\n└── scripts\n    ├── deployWidget.js\n    └── ....\n├── webpack.config.js\n└── package.json</code></pre></div>\n<p><code class=\"language-text\">/scripts/deployWidget.js</code> is a nodejs script that expects a <code class=\"language-text\">--widget</code> argument and will do the following:</p>\n<ul>\n<li>Upload this widget bundle file to a content server</li>\n<li>Create or update the widget entry html value in the database.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> path <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> argv <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'yargs'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>argv<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> uploadAssetToContentServer <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./uploadAssetToContentServer'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> createOrUpdateWidgetEntry <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./createOrUpdateWidgetEntry'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">deployWidget</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> widget <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> bundleFile <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span>\n        process<span class=\"token punctuation\">.</span><span class=\"token function\">cwd</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'dist'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">widget_</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>widget<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">_bundle.js</span><span class=\"token template-punctuation string\">`</span></span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> uploadedUrl <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">uploadAssetToContentServer</span><span class=\"token punctuation\">(</span>bundleFile<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> html <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n        &lt;div id=\"widget:</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>widget<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\">&lt;/div>\n        &lt;script defer src=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>uploadedUrl<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\">&lt;/script>\n    </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">await</span> <span class=\"token function\">createOrUpdateWidgetEntry</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        name<span class=\"token operator\">:</span> widget<span class=\"token punctuation\">,</span>\n        html<span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">widget </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>widget<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> deployed successfully</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token function\">deployWidget</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    widget<span class=\"token operator\">:</span> argv<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span>console<span class=\"token punctuation\">.</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p><strong>NOTE:</strong> I encapsulated the logic to upload the bundle file and save widget entry in <code class=\"language-text\">uploadAssetToContentServer.js</code> and <code class=\"language-text\">createOrUpdateWidgetEntry.js</code> respectively, which you will need to implement.</p>\n<p>In <code class=\"language-text\">package.json</code></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token operator\">...</span>\n<span class=\"token string\">\"scripts\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">...</span><span class=\"token punctuation\">.</span>\n    <span class=\"token string\">\"deploy-widget\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"webpack &amp;&amp; ./scripts/deployWidget\"</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>And now to deploy the login widget:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm run deploy-widget -- --widget login</code></pre></div>\n<p>Going back to the backend repository, You can render a specific widget using the html value saved in DB, for example</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">...\n{{ getWidgetHtmlFromDB('login') | raw }}\n...</code></pre></div>\n<h3>Pros</h3>\n<ul>\n<li>You have full control over what to put in the widget html so it's quite easy to enable SSR, critical css, ...etc.</li>\n<li>The development and deployment processes for frontend is totally separated from backend (happier developers).</li>\n<li>Deployment process is much faster which will make daily AB tests more realistic.</li>\n<li>More suited for larger teams where separation between frontend and backend is more clear.</li>\n</ul>\n<h3>Cons</h3>\n<ul>\n<li>Remember the saying \"with great flexibility comes great responsibility\"? The widget deployment process is merely updating an entry in DB, if you didn't build proper versioning around this feature or you allowed developers to push directly to production DB then disasters might happen.</li>\n<li>SSR is quite hacky with dynamic data... doable but hacky.</li>\n<li>Needs a lot of work on the backend side to integrate and maintain this feature properly in the CMS.</li>\n</ul>\n<hr>\n<h2>What's next</h2>\n<ul>\n<li>Having one vendor file that's shared between all widgets. @see <a href=\"https://webpack.js.org/plugins/dll-plugin/\">webpack DllPlugin</a></li>\n<li>\n<p>For <code class=\"language-text\">Standalone Approach</code></p>\n<ul>\n<li>Add Server Side Rendering and critical css in <code class=\"language-text\">deployWidget.js</code> script.</li>\n<li>Add versioning for the widget entry in CMS i.e. each widget deployment should be associated with a version number that you can rollback in CMS.</li>\n<li>Only allow the script <code class=\"language-text\">deployWidget.js</code> to deploy widgets to QA env. and create the scary-red \"Move to production\" button in QA CMS to just copy the entry from QA DB to Production DB.</li>\n</ul>\n</li>\n</ul>","fields":{"slug":"/embeddable-leightweight-react-widgets/","tags":["auto1","engineering","react","widgets","refactoring","modularity"]}}}]}},"pageContext":{"slug":"/tags/refactoring","tag":"refactoring","categories":["Architecture","Coding","DevOps","Engineering","ProjectManagement","QA","Social","TechRadar"]}}