

{"id":13824,"date":"2023-03-18T06:25:33","date_gmt":"2023-03-18T11:25:33","guid":{"rendered":"https:\/\/rud.is\/b\/?p=13824"},"modified":"2023-03-19T16:09:49","modified_gmt":"2023-03-19T21:09:49","slug":"webr-wasm-r-package-load-library-benchmarking-rabbit-hole","status":"publish","type":"post","link":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/","title":{"rendered":"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole"},"content":{"rendered":"<p>I have a post coming on using base and {ggplot2} plots in VanillaJS WebR, but after posting some bits on social media regarding how slow {ggplot2} is to deal with, I had some &#8220;performance&#8221;-related inquiries, which led me down a rabbit hole that I&#8217;m, now, dragging y&#8217;all down into as well.<\/p>\n<p>First, a preview of the aforementioned plot\/graphics:<\/p>\n<ul>\n<li><a href=\"https:\/\/rud.is\/w\/ggwebr\/\">WebR base R plots<\/a><\/li>\n<li><a href=\"https:\/\/rud.is\/w\/ggwebr\/ggindex.html\">WebR {ggplot2} plot<\/a> (this consistently takes +10s to load for me)<\/li>\n<\/ul>\n<p>I encourage you to load both of them before continuuing to see why I was curious about package load times.<\/p>\n<h3>Getting A Package Into WebR: A Look At {ggplot2}<\/h3>\n<p>If we strip away all the cruft, this is the core way to install a package into WebR and make it available to a freshly minted WebR context:<\/p>\n<pre><code class=\"language-js\">import { WebR } from '\/webr\/webr.mjs';\nglobalThis.webR = new WebR({ WEBR_URL: \"\/webr\/\", SW_URL: \"\/w\/bench\/\",});\nawait globalThis.webR.init();\nawait globalThis.webR.installPackages(['PACKAGE'])\nawait globalThis.webR.evalRVoid('library(PACKAGE)')\n<\/code><\/pre>\n<p>Let&#8217;s look at what happens in the browser during the call to <code>installPackages()<\/code> when <code>PACKAGE<\/code> is <code>ggplot2<\/code>:<\/p>\n<div id=\"attachment_13825\" style=\"width: 950px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-13825\" data-attachment-id=\"13825\" data-permalink=\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/ggplot2-downloading\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?fit=940%2C1148&amp;ssl=1\" data-orig-size=\"940,1148\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"ggplot2-downloading\" data-image-description=\"\" data-image-caption=\"&lt;p&gt;Screen capture of DevTools showing ggplot2 dependent packages loading.&lt;\/p&gt;\n\" data-medium-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?fit=246%2C300&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?fit=510%2C623&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=510%2C623&#038;ssl=1\" alt=\"Screen capture of DevTools showing ggplot2 dependent packages loading.\" width=\"510\" height=\"623\" class=\"size-full wp-image-13825\" srcset=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?w=940&amp;ssl=1 940w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=246%2C300&amp;ssl=1 246w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=530%2C647&amp;ssl=1 530w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=123%2C150&amp;ssl=1 123w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=768%2C938&amp;ssl=1 768w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=500%2C611&amp;ssl=1 500w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=150%2C183&amp;ssl=1 150w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=400%2C489&amp;ssl=1 400w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=800%2C977&amp;ssl=1 800w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-downloading.png?resize=200%2C244&amp;ssl=1 200w\" sizes=\"auto, (max-width: 510px) 100vw, 510px\" \/><\/a><p id=\"caption-attachment-13825\" class=\"wp-caption-text\">Screen capture of DevTools showing ggplot2 dependent packages loading.<\/p><\/div>\n<p>Dependent libraries are sequentially loaded until we finally get to ggplot2 (foregoeing {} from now on). There are 28 packages for ggplot2 (including itself) and they have a really skewed package size distribution:<\/p>\n<pre><code class=\"language-plain\">Min.   :   6K\n1st Qu.: 108K\nMedian : 481K\nMean   : 950K\n3rd Qu.: 1.2M\nMax.   : 5.4M\n<\/code><\/pre>\n<p>The good thing is, though, that the browser will cache them (for some period of time) so they aren&#8217;t re-downloaded every time you need them. Because of this, we&#8217;re going to ignore download time from consideration since they&#8217;re all, as we&#8217;ll see, below, yanked form cache in single-digit milliseconds.<\/p>\n<p>When you call <code>library(PACKAGE)<\/code> R code gets executed, and that takes time. On modern desktops with local R installs, you almost never notice the time passage for this. This is not the case for WebR:<\/p>\n<div id=\"attachment_13827\" style=\"width: 1210px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-13827\" data-attachment-id=\"13827\" data-permalink=\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/ggplot2-waterfall\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?fit=1200%2C1218&amp;ssl=1\" data-orig-size=\"1200,1218\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"ggplot2-waterfall\" data-image-description=\"\" data-image-caption=\"&lt;p&gt;Screen capture of the ggplot2 package loading part of a Developer Tools waterfall chart.&lt;\/p&gt;\n\" data-medium-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?fit=296%2C300&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?fit=510%2C518&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=510%2C518&#038;ssl=1\" alt=\"Screen capture of the ggplot2 package loading part of a Developer Tools waterfall chart.\" width=\"510\" height=\"518\" class=\"size-full wp-image-13827\" srcset=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?w=1200&amp;ssl=1 1200w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=296%2C300&amp;ssl=1 296w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=530%2C538&amp;ssl=1 530w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=148%2C150&amp;ssl=1 148w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=768%2C780&amp;ssl=1 768w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=500%2C508&amp;ssl=1 500w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=150%2C152&amp;ssl=1 150w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=400%2C406&amp;ssl=1 400w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=800%2C812&amp;ssl=1 800w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=200%2C203&amp;ssl=1 200w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=57%2C57&amp;ssl=1 57w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=72%2C72&amp;ssl=1 72w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?resize=96%2C96&amp;ssl=1 96w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/ggplot2-waterfall.png?w=1020&amp;ssl=1 1020w\" sizes=\"auto, (max-width: 510px) 100vw, 510px\" \/><\/a><p id=\"caption-attachment-13827\" class=\"wp-caption-text\">Screen capture of the ggplot2 package loading part of a Developer Tools waterfall chart.<\/p><\/div>\n<p>The Matrix, mgcv, and farver packages grind things to a halt. You felt that if you hit up the example at the beginning of the post. Brutal. Painful. Terrible.<\/p>\n<p>This got me curious about all the other packages that are available to WebR (93 as of the date on this post).<\/p>\n<h3>Approaching R Package Load\/library Benchmarking In A Browser<\/h3>\n<p>Much like the skewed package file size distribution of presently available R WASM packages, the per-package dependency distribution is also pretty skewed:<\/p>\n<pre><code class=\"language-plain\">Min.   :  1\n1st Qu.:  1\nMedian :  1\nMean   :  2\n3rd Qu.:  2\nMax.   : 15\n<\/code><\/pre>\n<p>This is good! It means you&#8217;re mostly safe to have fun with WebR and do not have to focus on working around an initial slowdown. Still, this did not deter me from a time sink.<\/p>\n<p>I had to figure out a way to individually test the install\/library of each WASM R packed independently, in a fresh WebR context.<\/p>\n<p>One obvious way is to make 93 HTML files and load them all by hand.<\/p>\n<p>O_O<\/p>\n<p>There <em>had<\/em> to be a better way, and I immediately turned to &#8220;iframes&#8221; as a solution.<\/p>\n<p>While I could have scripted the creation of proper for HTML 93 iframes to be put into a page, that&#8217;s not a great idea for a number of reasons:<\/p>\n<ul>\n<li>that&#8217;ll crash every modern browser: far too many child iframes, all with their own DOM contexts sounds horrible<\/li>\n<li>93 &#8220;simultaneous&#8221; WebR initializations would consume all browser resources and DoS the tab<\/li>\n<li>the &#8220;simultaneous&#8221; loading would skew timing results, even when the package files are cached<\/li>\n<\/ul>\n<p>The solution was to use <em>dynamically created iframes<\/em>. One potential &#8220;gotcha&#8221; for this could have been the modern browser security model. Thanks to some dangerous hardware-level weakness that were discovered and exploited a few years back, Chrome and other browsers shored up the safety contracts between iframes and parent pages. Not doing so could have allowed attackers to have some fun at your expense.<\/p>\n<p>If you&#8217;ve been following along the past week or so, to get the best performance with WebR, you need to make sure certain HTTP headers are in place so the browser can trust what you&#8217;re doing enough to relax some restrictions. Dynamically created iframes have no &#8220;headers&#8221;, per-se, but the clever folks who make browser bits for a living came up <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Security\/IFrame_credentialless\">with a way<\/a> to handle this. We just need to mark the frame as <code>credentialless<\/code> and we&#8217;ll get good performance (please read the link to get more context).<\/p>\n<p>So, we can run a slightly expanded version of the (way) above javascript code to get timer stats, but how do we collect them?<\/p>\n<p>Well, the parent of the iframe can talk to the iframe and vice-versa via <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/postMessage\">postMessage()<\/a>, so all we need to do is have the iframe send data back to the parent when it is done. This is also a signal we can kill the child iframe, freeing up resources, and then move on to the next one.<\/p>\n<h3>An Unexpected Twist<\/h3>\n<p>It turns out that some WASM-ified R packages are busted. Specifically:<\/p>\n<ul>\n<li>fs<\/li>\n<li>Hmisc<\/li>\n<li>latticeExtra<\/li>\n<li>pkgLoad<\/li>\n<\/ul>\n<p>Some functions in each of them are needed by one or more other packages, but \u2014 as you&#8217;ll see if you run the benchmark site \u2014 they fail to <code>library()<\/code> after installation.<\/p>\n<p>This was a &#8220;gotcha&#8221; I just had to wrap a <code>try\/catch<\/code> block around, and also pass back information about.<\/p>\n<h3>Putting It All Together<\/h3>\n<p>You can run your own benchmarks at <a href=\"https:\/\/rud.is\/w\/bench\/\">this playground page<\/a>. View-source on the page to see the code (there&#8217;s just <code>index.html<\/code> and <code>style.css<\/code>). You can also see it at <a href=\"https:\/\/github.com\/hrbrmstr\/webr-experiments\">the WebR Experiments repo<\/a>.<\/p>\n<p>When the page loads, it fetches the last produced copy of <a href=\"https:\/\/rud.is\/data\/webr-packages.json\">https:\/\/rud.is\/data\/webr-packages.json<\/a>. This is a JSON file I&#8217;m generating every night that contains all the packages available in &#8220;WASM notCRAN&#8221;. It just steals <code>PACKAGES.rds<\/code> every day and serializes it to JSON. Feel free to use it (if you get a CORS error lemme know; you shouldn&#8217;t but it&#8217;s an odd year).<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"13829\" data-permalink=\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/controls-table\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?fit=774%2C843&amp;ssl=1\" data-orig-size=\"774,843\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"controls-table\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?fit=275%2C300&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?fit=510%2C555&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=510%2C555&#038;ssl=1\" alt=\"Controls and sample output for the benchmark site.\" width=\"510\" height=\"555\" class=\"aligncenter size-full wp-image-13829\" srcset=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?w=774&amp;ssl=1 774w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=275%2C300&amp;ssl=1 275w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=530%2C577&amp;ssl=1 530w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=138%2C150&amp;ssl=1 138w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=768%2C836&amp;ssl=1 768w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=500%2C545&amp;ssl=1 500w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=150%2C163&amp;ssl=1 150w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=400%2C436&amp;ssl=1 400w, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/controls-table.png?resize=200%2C218&amp;ssl=1 200w\" sizes=\"auto, (max-width: 510px) 100vw, 510px\" \/><\/a><\/p>\n<p>The first thing your eyes will likely be drawn to is: &#8220;\u2705 Context is cross-origin isolated!&#8221;. When I was debugging early on WebR performance issues, George (the Godfather of WebR) noted that we needed certain headers to get those aforementioned safety restrictions loosened up a bit. You can test the global <code>crossOriginIsolated<\/code> variable to see if you&#8217;ve setup the headers correctly and <a href=\"crossOriginIsolated\">read more about it <\/a> when you have time. While it&#8217;s not needed on that page, I left it in so I could write this paragraph.<\/p>\n<p>You&#8217;ll also see a &#8220;download results?&#8221; checkbox that is by default un-checked. If checked, you&#8217;ll get a JSON file with all the results in the table that is dynamically constructed.<\/p>\n<p>After you tap &#8220;Begin Benchmark&#8221;, you can go get a matcha and come back.<\/p>\n<p>You&#8217;ll see the results in a table and a surprise Observable Plot histogram (the post&#8217;s featured image).<\/p>\n<p>I disable the controls after the run since you really should close the tab and start a fresh one (not just a reload) to get a clean context.<\/p>\n<p>If you use the site and download the JSON, you can <a href=\"https:\/\/observablehq.com\/@hrbrmstr\/webr-package-install-library-times\">hit up this Observable notebook<\/a> and put the JSON in a fork of it. I would also not mind it if you could post your JSON to the <a href=\"https:\/\/github.com\/hrbrmstr\/webr-experiments\">WebR Experiments repo<\/a> as an issue and include the browser and system config you were using at the time.<\/p>\n<h3>FIN<\/h3>\n<p>This was a fun distraction, and shows you can use most of the presently available WebR packages without concern.<\/p>\n<p>Make sure to check back for those WebR graphics posts!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have a post coming on using base and {ggplot2} plots in VanillaJS WebR, but after posting some bits on social media regarding how slow {ggplot2} is to deal with, I had some &#8220;performance&#8221;-related inquiries, which led me down a rabbit hole that I&#8217;m, now, dragging y&#8217;all down into as well. First, a preview of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":13830,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[15,91,867],"tags":[],"class_list":["post-13824","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-r","category-webr"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>WebR WASM R Package Load\/Library Benchmarking Rabbit Hole - rud.is<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole - rud.is\" \/>\n<meta property=\"og:description\" content=\"I have a post coming on using base and {ggplot2} plots in VanillaJS WebR, but after posting some bits on social media regarding how slow {ggplot2} is to deal with, I had some &#8220;performance&#8221;-related inquiries, which led me down a rabbit hole that I&#8217;m, now, dragging y&#8217;all down into as well. First, a preview of [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/\" \/>\n<meta property=\"og:site_name\" content=\"rud.is\" \/>\n<meta property=\"article:published_time\" content=\"2023-03-18T11:25:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-03-19T21:09:49+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"1964\" \/>\n\t<meta property=\"og:image:height\" content=\"1422\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"hrbrmstr\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"hrbrmstr\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/\"},\"author\":{\"name\":\"hrbrmstr\",\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"headline\":\"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole\",\"datePublished\":\"2023-03-18T11:25:33+00:00\",\"dateModified\":\"2023-03-19T21:09:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/\"},\"wordCount\":1234,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"image\":{\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1\",\"articleSection\":[\"Javascript\",\"R\",\"webr\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/\",\"url\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/\",\"name\":\"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole - rud.is\",\"isPartOf\":{\"@id\":\"https:\/\/rud.is\/b\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1\",\"datePublished\":\"2023-03-18T11:25:33+00:00\",\"dateModified\":\"2023-03-19T21:09:49+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage\",\"url\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1\",\"width\":1964,\"height\":1422,\"caption\":\"Histogram of WASM R package load times. Most load in well under 1s\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/rud.is\/b\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/rud.is\/b\/#website\",\"url\":\"https:\/\/rud.is\/b\/\",\"name\":\"rud.is\",\"description\":\"&quot;In God we trust. All others must bring data&quot;\",\"publisher\":{\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/rud.is\/b\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\",\"name\":\"hrbrmstr\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"url\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"width\":460,\"height\":460,\"caption\":\"hrbrmstr\"},\"logo\":{\"@id\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\"},\"description\":\"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7\",\"sameAs\":[\"http:\/\/rud.is\"],\"url\":\"https:\/\/rud.is\/b\/author\/hrbrmstr\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole - rud.is","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/","og_locale":"en_US","og_type":"article","og_title":"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole - rud.is","og_description":"I have a post coming on using base and {ggplot2} plots in VanillaJS WebR, but after posting some bits on social media regarding how slow {ggplot2} is to deal with, I had some &#8220;performance&#8221;-related inquiries, which led me down a rabbit hole that I&#8217;m, now, dragging y&#8217;all down into as well. First, a preview of [&hellip;]","og_url":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/","og_site_name":"rud.is","article_published_time":"2023-03-18T11:25:33+00:00","article_modified_time":"2023-03-19T21:09:49+00:00","og_image":[{"width":1964,"height":1422,"url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1","type":"image\/png"}],"author":"hrbrmstr","twitter_card":"summary_large_image","twitter_misc":{"Written by":"hrbrmstr","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#article","isPartOf":{"@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/"},"author":{"name":"hrbrmstr","@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"headline":"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole","datePublished":"2023-03-18T11:25:33+00:00","dateModified":"2023-03-19T21:09:49+00:00","mainEntityOfPage":{"@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/"},"wordCount":1234,"commentCount":1,"publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"image":{"@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1","articleSection":["Javascript","R","webr"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/","url":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/","name":"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole - rud.is","isPartOf":{"@id":"https:\/\/rud.is\/b\/#website"},"primaryImageOfPage":{"@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage"},"image":{"@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1","datePublished":"2023-03-18T11:25:33+00:00","dateModified":"2023-03-19T21:09:49+00:00","breadcrumb":{"@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#primaryimage","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1","width":1964,"height":1422,"caption":"Histogram of WASM R package load times. Most load in well under 1s"},{"@type":"BreadcrumbList","@id":"https:\/\/rud.is\/b\/2023\/03\/18\/webr-wasm-r-package-load-library-benchmarking-rabbit-hole\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/rud.is\/b\/"},{"@type":"ListItem","position":2,"name":"WebR WASM R Package Load\/Library Benchmarking Rabbit Hole"}]},{"@type":"WebSite","@id":"https:\/\/rud.is\/b\/#website","url":"https:\/\/rud.is\/b\/","name":"rud.is","description":"&quot;In God we trust. All others must bring data&quot;","publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/rud.is\/b\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886","name":"hrbrmstr","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","width":460,"height":460,"caption":"hrbrmstr"},"logo":{"@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1"},"description":"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7","sameAs":["http:\/\/rud.is"],"url":"https:\/\/rud.is\/b\/author\/hrbrmstr\/"}]}},"jetpack_featured_media_url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/pkgload.png?fit=1964%2C1422&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p23idr-3AY","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":13834,"url":"https:\/\/rud.is\/b\/2023\/03\/18\/the-road-to-ggplot2-in-webr-part-1-the-road-is-paved-with-good-base-r-plots\/","url_meta":{"origin":13824,"position":0},"title":"The Road To ggplot2 In WebR, Part 1: The Road Is Paved With Good Base R Plots","author":"hrbrmstr","date":"2023-03-18","format":false,"excerpt":"I have graphics working in Vanilla JS WebR, now, and I'll cover the path to that in two parts. The intent was to jump straight into ggplot2-land, but, as you saw in my previous post, WASM'd ggplot2 is a bear. And, I really didn't grok what the WebR site docs\u2026","rel":"","context":"In &quot;ggplot&quot;","block_context":{"text":"ggplot","link":"https:\/\/rud.is\/b\/category\/ggplot\/"},"img":{"alt_text":"WebR plot example with a faceted scatterplot","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-18-at-10.10.23.png?fit=974%2C1200&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-18-at-10.10.23.png?fit=974%2C1200&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-18-at-10.10.23.png?fit=974%2C1200&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-18-at-10.10.23.png?fit=974%2C1200&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":13927,"url":"https:\/\/rud.is\/b\/2023\/04\/10\/introducing-webrider-the-webr-ide-ish-repl-you-didnt-know-you-needed\/","url_meta":{"origin":13824,"position":1},"title":"Introducing WebRIDEr: The WebR &#8220;IDE&#8221;-ish REPL You Didn&#8217;t Know You Needed","author":"hrbrmstr","date":"2023-04-10","format":false,"excerpt":"The official example WebR REPL is definitely cool and useful to get the feel for WebR. But, it is far from an ideal way to deal with it interactively, even as just a REPL. As y'all know, I've been conducing numerous experiments with WebR and various web technologies. I started\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"ide-like view","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/04\/preview.png?fit=1200%2C754&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/04\/preview.png?fit=1200%2C754&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/04\/preview.png?fit=1200%2C754&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/04\/preview.png?fit=1200%2C754&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/04\/preview.png?fit=1200%2C754&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":13885,"url":"https:\/\/rud.is\/b\/2023\/03\/26\/%f0%9f%a7%aa-lit-webr-observable-plot-linking-lits-lightweight-web-components-and-webr-for-vanilla-js-reactivity-js-datavis\/","url_meta":{"origin":13824,"position":2},"title":"? Lit + WebR + Observable Plot: Linking Lit&#8217;s Lightweight Web Components And WebR For Vanilla JS Reactivity &#038; JS DataVis","author":"hrbrmstr","date":"2023-03-26","format":false,"excerpt":"See it live before reading! The previous post brought lit-webr, to introduce Lit and basic reactivity. Today, is more of the same, but we bring the OG Shiny demo plot into the modern age by using Observbable Plot to make the charts. We're still pulling data from R, but we're\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"popup menu + barplot","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/preview.png?fit=1200%2C1174&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/preview.png?fit=1200%2C1174&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/preview.png?fit=1200%2C1174&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/preview.png?fit=1200%2C1174&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/preview.png?fit=1200%2C1174&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":13894,"url":"https:\/\/rud.is\/b\/2023\/03\/29\/using-webr-pyodide-to-fill-in-the-temporary-package-gaps\/","url_meta":{"origin":13824,"position":3},"title":"Using WebR + Pyodide To Fill In The (Temporary) Package Gaps","author":"hrbrmstr","date":"2023-03-29","format":false,"excerpt":"I won't wax long and poetic here since I've already posted the experiment that has all the details. TL;DR: there are still only ~90-ish ? in the WebR WASM \"CRAN\", but more are absolutely on the way, including the capability to build your own CRAN and dev packages via Docker\u2026","rel":"","context":"In &quot;Python&quot;","block_context":{"text":"Python","link":"https:\/\/rud.is\/b\/category\/python-2\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":13845,"url":"https:\/\/rud.is\/b\/2023\/03\/20\/webr-filesystem-and-reefr\/","url_meta":{"origin":13824,"position":4},"title":"WebR Filesystem Machinations &#038; ReefR","author":"hrbrmstr","date":"2023-03-20","format":false,"excerpt":"It's difficult to believe it has only been a couple of weeks since WebR has been around. But that might just be my perception. The spike protein invasion has significantly increased sedentary time, and that has enabled me to focus on this new toy to keep my attention focused on\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":13789,"url":"https:\/\/rud.is\/b\/2023\/03\/12\/almost-bare-bones-webr-starter-app\/","url_meta":{"origin":13824,"position":5},"title":"Almost Bare Bones WebR Starter App","author":"hrbrmstr","date":"2023-03-12","format":false,"excerpt":"Let's walk through how to set up a ~minimal HTML\/JS\/CSS + WebR-powered \"app\" on a server you own. This will be vanilla JS (i.e. no React\/Vue\/npm\/bundler) you can hack on at-will. TL;DR: You can find the source to the app and track changes to it over on GitHub if you\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"screenshot of the example webr app showing a portion of mtcars","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-12-at-10.24.18.png?fit=1200%2C772&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-12-at-10.24.18.png?fit=1200%2C772&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-12-at-10.24.18.png?fit=1200%2C772&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-12-at-10.24.18.png?fit=1200%2C772&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-12-at-10.24.18.png?fit=1200%2C772&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/13824","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/comments?post=13824"}],"version-history":[{"count":0,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/13824\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media\/13830"}],"wp:attachment":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media?parent=13824"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/categories?post=13824"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/tags?post=13824"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}