{"id":26,"date":"2016-04-05T22:18:29","date_gmt":"2016-04-05T22:18:29","guid":{"rendered":"https:\/\/andrewperr.in\/blog\/?p=26"},"modified":"2016-12-11T07:06:22","modified_gmt":"2016-12-11T07:06:22","slug":"dry-browserify","status":"publish","type":"post","link":"https:\/\/andrewperr.in\/blog\/2016\/04\/05\/dry-browserify\/","title":{"rendered":"DRY, Browserify"},"content":{"rendered":"<p><a href=\"https:\/\/andrewperr.in\/blog\/2016\/03\/09\/reactjs-what-i-learned-from-my-first-component\/\">In my last post<\/a>, I discussed some of the biggest lessons I learned while building my first component in ReactJS. One of those lessons revolved around <a href=\"http:\/\/browserify.org\/\">Browserify<\/a>, and how it was the best way to leverage component reuse.<\/p>\n<p>As I moved closer to production, I realized there was one particularly nasty side effect to Browserify. Take the following code for example:<\/p>\n<pre class=\"size-big\"><code class=\"language-javascript\">var React = require(\"react\");\r\nvar ReactDOM = require(\"react-dom\");\r\n\r\n\/\/ Custom React Component\r\nvar RecipeTabs = require(\"components\/RecipeTabs.js\");\r\n\r\nfunction initPage()\r\n{\r\n\tReactDOM.render(\r\n\t  React.createElement(RecipeTabs),\r\n\t  document.getElementById('recipeTabs')\r\n\t);\r\n}<\/code><\/pre>\n<p>Browserify lets us use CommonJS <code>require<\/code> syntax even though browsers don&#8217;t natively support it. One way it does this is by inlining the entire contents of your <code>require<\/code>&#8217;d JavaScript into your script. So, in the example above, our 13-line script will suddenly grow to include <em>all<\/em> of React, <em>all<\/em> of ReactDOM and <em>all<\/em> of the code for RecipeTabs.<\/p>\n<p>If we blindly require React in this manner inside every JavaScript file on our site, then we end up with a bunch of duplicate inlined code. Even worse, we are forcing users to download the same code over and over. The browser only sees unique file names and sizes &#8212; it isn&#8217;t smart enough to realize that <em>inside<\/em> those files are large chunks of repeated code. What we really want is one file that contains all of our common code, and reuse that file on every page. That way, the browser only downloads the code once; every other page load uses a cached copy.<\/p>\n<p>Thankfully, Browserify natively provides a solution to this issue.<\/p>\n<p>The trick is to create a single file that contains all JavaScript <code>require<\/code>s used site-wide. This single bundle can then be included on all of your pages.<\/p>\n<p>Browserify gives us an easy way to do this. For example, using gulp:<\/p>\n<pre class=\"size-big\" data-line=\"3\"><code class=\"language-javascript\">gulp.task('browserify-global', function() {\r\n\treturn browserify()\r\n\t\t.require(['react','react-dom'])\r\n\t\t.transform(envify)\r\n\t\t.bundle()\r\n\t\t.pipe(source('exports.js'))\r\n\t\t.pipe(gulp.dest('.\/js'));\r\n});<\/code><\/pre>\n<p>This creates an <code>exports.js<\/code> file which is a bundle of React and ReactDOM. We can now include this on every page of our site &#8212; the browser will download it once and then cache it for every subsequent page.<\/p>\n<p>But we still have a problem. Browserify doesn&#8217;t know about <code>exports.js<\/code> when it processes the rest of the site&#8217;s JavaScript. It will go ahead and inline React and ReactDOM as usual wherever it&#8217;s <code>require<\/code>&#8217;d.<\/p>\n<p>The second piece to make this work is to tell Browserify to not inline certain <code>require<\/code>&#8217;d libraries:<\/p>\n<pre class=\"size-big\" data-line=\"6\"><code class=\"language-javascript\">gulp.task('browserify-custom', function() {\r\n    return glob('.\/src\/**\/*.js', function(err, files) {\r\n        if(!err) {\r\n\t        var tasks = files.map(function(entry) {\r\n\t            return browserify({ entries: [entry] })\r\n\t                .external(['react','react-dom'])\r\n\t                .bundle()\r\n\t                .pipe(source(entry))\r\n\t                .pipe(gulp.dest('.\/js'));\r\n\t        });\r\n\t\t}\r\n\t});\t\r\n});<\/code><\/pre>\n<p>Now, whenever Browserify encounters a <code>require<\/code> for &#8216;react&#8217; or &#8216;react-dom&#8217;, it won&#8217;t inline the script. But, as long as we include the <code>exports.js<\/code> generated in the previous step, the reference will resolve, and it will be able to execute any React or ReactDOM code.<\/p>\n<p>This isn&#8217;t limited to third-party JavaScript libraries either. If you have your own code that is referenced across the entire site, then you can include it:<\/p>\n<pre class=\"size-big\"><code class=\"language-javascript\">.require(['react','react-dom', {file: '.\/src\/pn.js', expose: 'pn'}])<\/code><\/pre>\n<p>The <code>expose<\/code> property specifies the name to use in your <code>require<\/code> statements. In this case, whenever I need to reference code in <code>pn.js<\/code>, I can simply <code>require(&#8216;pn&#8217;)<\/code>.<\/p>\n<p>In the second step, we can now specify <code>pn<\/code> as an external library:<\/p>\n<pre class=\"size-big\"><code class=\"language-javascript\">.external(['react','react-dom','pn'])<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In my last post, I discussed some of the biggest lessons I learned while building my first component in ReactJS. One of those lessons revolved around Browserify, and how it was the best way to leverage component reuse. As I moved closer to production, I realized there was one particularly nasty side effect to Browserify. [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"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":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[2,3],"tags":[5,7,8,9,11],"class_list":["post-26","post","type-post","status-publish","format-standard","hentry","category-computers","category-programming","tag-browserify","tag-front-end","tag-gulp","tag-javascript","tag-react"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p85fRU-q","_links":{"self":[{"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/posts\/26","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/comments?post=26"}],"version-history":[{"count":4,"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/posts\/26\/revisions"}],"predecessor-version":[{"id":33,"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/posts\/26\/revisions\/33"}],"wp:attachment":[{"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/media?parent=26"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/categories?post=26"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andrewperr.in\/blog\/wp-json\/wp\/v2\/tags?post=26"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}