{"data":{"article":{"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"]}},"categoryArticles":{"edges":[{"node":{"id":"a34b3781-aea3-55c9-b730-6e611a223ff2","frontmatter":{"category":"Social","title":"Back to Social Life at AUTO1 Tech","date":"2023-08-25","summary":"A hybrid social life has begun in the spring of 2023 after the pandemic. We have experts at AUTO1 Tech that have been invited to different public speeches.","thumbnail":null,"authorName":"Yi-Wen Fang","authorDescription":"Executive Assistant Tech","authorAvatar":null,"headerImage":null},"html":"<p>A hybrid social life has begun in the spring of 2023 after the pandemic. We have experts at AUTO1 Tech that have been invited to different public speeches.</p>\n<h3>QA Session on TEST AUTOMATION DAYS 2023 in Rotterdam</h3>\n<p>On May 25th 2023, our Director of Software Quality Assurance, Alexander Gyulai, gave a session on the topic of MODULAR AUTOMATION at TEST AUTOMATION DAYS 2023, where networking with software testing professionals and learning from the world’s leading test automation experts.</p>\n<p>He focused on topics of scaling, architecture and collaboration in automation testing. And the details covered in</p>\n<ul>\n<li>\n<p>How and why to move common components into modules and how to re-use it across the company.</p>\n</li>\n<li>\n<p>How did we scale testing of our platform with 700+ services and hundreds of releases per month.</p>\n</li>\n<li>\n<p>Setup release and distribution process of the automation modules</p>\n</li>\n<li>\n<p>Integrate platform modules into automation components</p>\n</li>\n</ul>\n<p>Besides technical advantages, he also shared how this approach improved collaboration and communication between developers and quality assurance engineers.</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/54a23b1dab0aaa9a98cf2a670be05257/c1266/test_automation_days_1.jpeg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 60.74999999999999%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAACAP/aAAwDAQACEAMQAAABSuPZqTsBX//EABkQAQADAQEAAAAAAAAAAAAAAAIAAQMRIv/aAAgBAQABBQJtiW2a9qPRaQHrIoV//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8BR//EABURAQEAAAAAAAAAAAAAAAAAAAAS/9oACAECAQE/AVP/xAAcEAADAAEFAAAAAAAAAAAAAAAAARECISIyUWH/2gAIAQEABj8C1xnQquRcTcJekR//xAAbEAEAAgIDAAAAAAAAAAAAAAABABEhMUFRcf/aAAgBAQABPyGg4uDpiLUDCsKdh6xAVdagMXTSBSwdz//aAAwDAQACAAMAAAAQfw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/EB//xAAXEQADAQAAAAAAAAAAAAAAAAABEBEh/9oACAECAQE/EKZqf//EAB0QAQEAAgIDAQAAAAAAAAAAAAERAEEhMVFxgZH/2gAIAQEAAT8Qt+awN2tj2YUq4U6PHM39xAmvdCP5zlq5QSBcSNdm6z305XP/2Q=='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"test_automation_days_1\"\n        title=\"Test Automation Days 2023\"\n        src=\"/static/54a23b1dab0aaa9a98cf2a670be05257/f8fb9/test_automation_days_1.jpeg\"\n        srcset=\"/static/54a23b1dab0aaa9a98cf2a670be05257/e8976/test_automation_days_1.jpeg 148w,\n/static/54a23b1dab0aaa9a98cf2a670be05257/63df2/test_automation_days_1.jpeg 295w,\n/static/54a23b1dab0aaa9a98cf2a670be05257/f8fb9/test_automation_days_1.jpeg 590w,\n/static/54a23b1dab0aaa9a98cf2a670be05257/85e3d/test_automation_days_1.jpeg 885w,\n/static/54a23b1dab0aaa9a98cf2a670be05257/d1924/test_automation_days_1.jpeg 1180w,\n/static/54a23b1dab0aaa9a98cf2a670be05257/c1266/test_automation_days_1.jpeg 1200w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/c1266/test_automation_days_2.jpeg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 69.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQD/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAdMITNKUP//EABoQAAMAAwEAAAAAAAAAAAAAAAECAwAREiH/2gAIAQEAAQUCT2bMRS1CtCxGBjurHv8A/8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8Bh//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAQEBAQEAAAAAAAAAAAAAAAEAEQIx/9oACAEBAAY/AjpgD2TnMi2dv//EABoQAQACAwEAAAAAAAAAAAAAAAEAESFBUTH/2gAIAQEAAT8ht7R4Q8WGyAgtLggLMdlxa0yXKECzk//aAAwDAQACAAMAAAAQJz//xAAVEQEBAAAAAAAAAAAAAAAAAAAREP/aAAgBAwEBPxBKz//EABcRAQEBAQAAAAAAAAAAAAAAAAERAFH/2gAIAQIBAT8QpJMBzf/EABwQAQADAAMBAQAAAAAAAAAAAAEAESExQWFxkf/aAAgBAQABPxDbKdodcypsBcl1OnyCFusNp+xuUbtOqfOoYapk+Q6hC/Ckpu8v2f/Z'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"test_automation_days_2\"\n        title=\"Test Automation Days 2023\"\n        src=\"/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/f8fb9/test_automation_days_2.jpeg\"\n        srcset=\"/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/e8976/test_automation_days_2.jpeg 148w,\n/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/63df2/test_automation_days_2.jpeg 295w,\n/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/f8fb9/test_automation_days_2.jpeg 590w,\n/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/85e3d/test_automation_days_2.jpeg 885w,\n/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/d1924/test_automation_days_2.jpeg 1180w,\n/static/5b7a8bcc0e5bdeacf4fe1aa17782de70/c1266/test_automation_days_2.jpeg 1200w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<h3></h3>\n<hr>\n<h3>Podcast on Data Observability &#x26; Beyond</h3>\n<p>Fabian Schomm-von Auenmüller, Head of Data Platform, was interviewed in July by the Data For Good Podcast, which is hosted by Zuma, a recruitment agency focusing on data technology professionals in Berlin.</p>\n<p>In this interview, Fabian focused on the monitoring and assurance of data quality within data pipelines. He explained that data observability encompasses processes from logging to monitoring, alerting, and ensuring data quality throughout its lifecycle. Fabian emphasized that catching data issues early is crucial for maintaining trust and preventing downstream problems. He recommended initiating data observability practices as early as possible and discussed tools like Elementary that integrate well with DBT (Data Build Tool). He highlighted the benefits of having explicit tests to validate assumptions and being prepared for failures. Fabian anticipates that future trends in data observability might involve leveraging AI and machine learning for pattern recognition and anomaly detection, ultimately enhancing the quality and reliability of data pipelines.</p>\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/8V102SVHkz4\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen></iframe>\n<p>We are proud of Alexander and Fabian and their works that provided an insight to the everyday projects and challenges the Technology team at the AUTO1 Group manages. We hope you find these as interesting as we do. We all grow along with the company, as does our data and infrastructure. Let’s work SMARTER instead of harder!</p>","fields":{"slug":"/back-to-social-life-at-auto1-tech/","tags":["auto1","engineering","social","qa","dataengineer"]}}},{"node":{"id":"43c570a3-c0cd-5599-ad87-bb0667eab8b0","frontmatter":{"category":"Social","title":"Product meets QA - Tech Talk by Antonella Zagaria & Alexander Gyulai","date":"2020-06-22","summary":"The second AUTO1 Group Tech Talk is now available in video format, featuring Antonella Zagaria, Senior Product Manager and Alexander Gyulai, Director of Quality Assurance.","thumbnail":null,"authorName":"Alex Stoicescu","authorDescription":"Alex is Tech Community Manager at AUTO1 Group.","authorAvatar":{"relativePath":"pages/QA-meets-Product-Tech-Talk/avatar.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAACyElEQVQ4y4VUO2gUURR9mZmN8YcItoKVjeXuzsxu9jOzm92NkBBTqDEmjZAEgtqIpSgI1gp+uhS6kEI7wc7GQsFCLERiISGCaGHhF02yu+M5s/cujyC4cJY379573r3n3XdNvV51xsYiJ4rKbqlUyBj8wjAYyWazp4BVYB3YAraBDeAhMBcE/l76lkrFTLVachuNyCGXEbJMrVbx6ADnaWAtn88nvu8nWBMdQcJ9Auv3wCxjWq2aC9IMSF3DzCyyG1YAs9pSYkL2melmLpfT71tKGkUlz2iZJAuCgA5dEjGAwPoV0AbuAy+tfR7YkZjb5CiXR1OutEw5jWQdCfgCnEiSxNg/7LWAj+KTSiHSzBvrAtascrriPCmnDkP4AYQ0Em3TGPHf8P38ARpP/4PsHQ7aU69Hqdi4OJeI47JXLg9IX1tVbUuWCzSsygcJO+L0goGNRpySoB1colarerhEvcCn4tuxCB/TsC5ZdS3Ct2Ho75uZmRoigWbIbgCxt7Q0O8TLsgg17o2R2+JHzzJcV/1IoBlybel42SLsCcc3I6UqoaZ+lUHFYjjCzJSQa+4J4UVLKiX8ScOGVXJXDN+xd7SfZXFYS65U+n2Wz+cOw+ezHadSkfCRdVJiZdlmMG9ZtHMpgWR3Z0eMSvWExjmrbXoCbZ951dIim7Yk6u1IYtlwavChW51Pp01tXOwf01eC9RHs/Rbbnx2Hf4IUh/Q5zdol8H3KG22Pj9edOK54LF1876pd37TELhqdZ+J4MwxDHUvXgDOFQrB7YqLpjI4WdhG8GLYNbCeBK/1+TWNWRG+Pfy5Hj5Dek3IXzX9+8DkL/AIeLC/PDU1NHXdSQk5altNsDkjPAT+ArzKyFnK5bB2IxbYik4hanmfM5GTL6Q/Y2DUc25y0HLToubR8TI39cL4APJOxr/35AXgOXEJnHKQvepP6eiQj119kDrZjqLo8HAAAAABJRU5ErkJggg==","width":50,"height":50,"src":"/static/26a7a327ccc4b335712e5a7086f2b26d/45876/avatar.png","srcSet":"/static/26a7a327ccc4b335712e5a7086f2b26d/45876/avatar.png 1x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/eb85b/avatar.png 1.5x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/4f71c/avatar.png 2x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/9ec3e/avatar.png 3x"}}},"headerImage":null},"html":"<p>Hello, colleagues, friends, readers and all of you <strong>excellent</strong> people out there!</p>\n<p><em>It's been a while, right?</em> Let's pick up where we left off...</p>\n<p>Our <strong>second Tech Talk</strong> took place in February at Maze, an event space fashioned after the Berliner spirit. Antonella and Alexander attracted almost 100 people with their promise of delivering amazing content, while having two different tracks allowed for the exposure of the participants to other vital parts of a tech start-up/<a href=\"https://www.youtube.com/watch?v=mBt2Gjv7cdY\">unicorn</a>.</p>\n<p>This event, the second in a series of events meant to promote local growth and accelerated learning, is now available for everyone to enjoy, on Youtube, along with the slides from the presentations.</p>\n<p><strong>Antonella Zagaria - Localisation in an ever-growing startup</strong>\n\n        <div class=\"embedVideo-container\">\n            <iframe\n              width=\"800\"\n              height=\"400\"\n              src=\"https://www.youtube-nocookie.com/embed/jnBZaDxAogw?rel=0\"\n              class=\"embedVideo-iframe\"\n              style=\"border:0\"\n              allowfullscreen\n            ></iframe>\n        </div></p>\n<p><strong>Alexander Gyulai - SHIFT your testing gear</strong>\n\n        <div class=\"embedVideo-container\">\n            <iframe\n              width=\"800\"\n              height=\"400\"\n              src=\"https://www.youtube-nocookie.com/embed/BPid8IicnN8?rel=0\"\n              class=\"embedVideo-iframe\"\n              style=\"border:0\"\n              allowfullscreen\n            ></iframe>\n        </div></p>\n<p>As always, sign up on our community page on <a href=\"https://www.meetup.com/AUTO1-Group-Tech-Talks/\">Meetup.com</a> to stay up to date and be amongst the first to find out when our next event is going to be. And it might be sooner than you think ;)</p>","fields":{"slug":"/QA-meets-Product-Tech-Talk/","tags":["auto1","engineering","social","tech talks","product"]}}},{"node":{"id":"2bf7354b-946c-5b99-826e-3c9ebed6b92c","frontmatter":{"category":"Social","title":"How to build a data-driven unicorn - Niv Liran","date":"2020-01-23","summary":"Watch the full video of the first AUTO1 Group Tech Talk, featuring CPO Niv Liran.","thumbnail":null,"authorName":"Alex Stoicescu","authorDescription":"Alex is Tech Community Manager at AUTO1 Group.","authorAvatar":{"relativePath":"pages/how-to-build-a-data-driven-unicorn-with-niv-liran/avatar.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAACyElEQVQ4y4VUO2gUURR9mZmN8YcItoKVjeXuzsxu9jOzm92NkBBTqDEmjZAEgtqIpSgI1gp+uhS6kEI7wc7GQsFCLERiISGCaGHhF02yu+M5s/cujyC4cJY379573r3n3XdNvV51xsYiJ4rKbqlUyBj8wjAYyWazp4BVYB3YAraBDeAhMBcE/l76lkrFTLVachuNyCGXEbJMrVbx6ADnaWAtn88nvu8nWBMdQcJ9Auv3wCxjWq2aC9IMSF3DzCyyG1YAs9pSYkL2melmLpfT71tKGkUlz2iZJAuCgA5dEjGAwPoV0AbuAy+tfR7YkZjb5CiXR1OutEw5jWQdCfgCnEiSxNg/7LWAj+KTSiHSzBvrAtascrriPCmnDkP4AYQ0Em3TGPHf8P38ARpP/4PsHQ7aU69Hqdi4OJeI47JXLg9IX1tVbUuWCzSsygcJO+L0goGNRpySoB1colarerhEvcCn4tuxCB/TsC5ZdS3Ct2Ho75uZmRoigWbIbgCxt7Q0O8TLsgg17o2R2+JHzzJcV/1IoBlybel42SLsCcc3I6UqoaZ+lUHFYjjCzJSQa+4J4UVLKiX8ScOGVXJXDN+xd7SfZXFYS65U+n2Wz+cOw+ezHadSkfCRdVJiZdlmMG9ZtHMpgWR3Z0eMSvWExjmrbXoCbZ951dIim7Yk6u1IYtlwavChW51Pp01tXOwf01eC9RHs/Rbbnx2Hf4IUh/Q5zdol8H3KG22Pj9edOK54LF1876pd37TELhqdZ+J4MwxDHUvXgDOFQrB7YqLpjI4WdhG8GLYNbCeBK/1+TWNWRG+Pfy5Hj5Dek3IXzX9+8DkL/AIeLC/PDU1NHXdSQk5altNsDkjPAT+ArzKyFnK5bB2IxbYik4hanmfM5GTL6Q/Y2DUc25y0HLToubR8TI39cL4APJOxr/35AXgOXEJnHKQvepP6eiQj119kDrZjqLo8HAAAAABJRU5ErkJggg==","width":50,"height":50,"src":"/static/26a7a327ccc4b335712e5a7086f2b26d/45876/avatar.png","srcSet":"/static/26a7a327ccc4b335712e5a7086f2b26d/45876/avatar.png 1x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/eb85b/avatar.png 1.5x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/4f71c/avatar.png 2x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/9ec3e/avatar.png 3x"}}},"headerImage":null},"html":"<p>Back in November 2019, we had the pleasure of hearing from our Chief Product Officer, Niv Liran, about the makings of a data-driven unicorn. This event, the first in a series of events meant to promote local growth and accelerated learning, is now available as a video, along with the slides from the presentation.</p>\n<p>\n        <div class=\"embedVideo-container\">\n            <iframe\n              width=\"800\"\n              height=\"400\"\n              src=\"https://www.youtube-nocookie.com/embed/mBt2Gjv7cdY?rel=0\"\n              class=\"embedVideo-iframe\"\n              style=\"border:0\"\n              allowfullscreen\n            ></iframe>\n        </div></p>\n<p>As always, sign up on our community page on <a href=\"https://www.meetup.com/AUTO1-Group-Tech-Talks/\">Meetup.com</a> to stay up to date and be amongst the first to find out when our next event is going to be.</p>","fields":{"slug":"/how-to-build-a-data-driven-unicorn-with-niv-liran/","tags":["auto1","engineering","social","tech talks","product"]}}}]},"authorArticles":null},"pageContext":{"slug":"/embeddable-leightweight-react-widgets/","tags":["auto1","engineering","react","widgets","refactoring","modularity"],"category":"Social","author":"Kareem Elbahrawy","date":"2018-12-11"}}