<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bohdan Liashenko</title>
    <description>The latest articles on Forem by Bohdan Liashenko (@bogdanlyashenko).</description>
    <link>https://forem.com/bogdanlyashenko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F118078%2F3be63482-a950-448d-a337-7189dd034065.jpeg</url>
      <title>Forem: Bohdan Liashenko</title>
      <link>https://forem.com/bogdanlyashenko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bogdanlyashenko"/>
    <language>en</language>
    <item>
      <title>Simple mistake to ruin Webpack bundle optimization</title>
      <dc:creator>Bohdan Liashenko</dc:creator>
      <pubDate>Wed, 13 Oct 2021 15:00:47 +0000</pubDate>
      <link>https://forem.com/bogdanlyashenko/simple-mistake-to-ruin-webpack-bundle-optimization-5c7a</link>
      <guid>https://forem.com/bogdanlyashenko/simple-mistake-to-ruin-webpack-bundle-optimization-5c7a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Read &lt;a href="https://codecrumbs.io/library/most-popular-mistake-webpack"&gt;interactive version&lt;/a&gt; of this post on my blog.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Working on big projects brings many difficult challenges, keeping applications bundle size in check is one of them. When project grows, inevitably you will start separating big sections of features into separate modules or sub-applications, delegating development to other teams or, sometimes, even other companies.  Not after long you have huge application, tens teams building hundreds of modules, all to be packed, bundled and shipped towards user.&lt;/p&gt;

&lt;p&gt;Control of bundle size becomes critical at this point, one module, &lt;strong&gt;one bad apple&lt;/strong&gt;, can just ruin everything. Fortunately webpack does a lot of optimisation under the hood, to make sure you ship as minimum code as required. However, and I witnessed this over and over again, there is still one simple mistake you can do that will prevent webpack from working its magic. Let's talk about that.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;We all know at this point, webpack does "tree shaking" to optimise bundle size. Just in case, "tree shaking"  is a term commonly used in the JavaScript context for dead-code elimination, or in simple words - export-ed code that wasn't import-ed and executed will be detected as &lt;em&gt;unused&lt;/em&gt;, so it can be safely removed to decrease bundle size.&lt;/p&gt;

&lt;p&gt;What you might not know, it's not the webpack that cleans up dead code per se. Of course, it does bulk of "preparation" work, but it is &lt;a href="https://github.com/terser/terser"&gt;terser&lt;/a&gt; package that actually will *&lt;em&gt;cut off *&lt;/em&gt; unused code. Terser is JavaScript parser, mangler and compressor toolkit for ES6+.&lt;/p&gt;

&lt;p&gt;Let's lay this out - webpack will take your modules, concatenate them into chunks and feed to terser for minification (all of this, obviously, will happen only if optimization is enabled).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RGNt0bn0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ukxkviis3gfsozfzbo5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RGNt0bn0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ukxkviis3gfsozfzbo5b.png" alt="Swimlane"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to highlight few key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, webpack always will try to concatenate your code from different modules (files) into one scope and create a chunk from it later. E.g. moduleA.js imports few methods from moduleB.js will end up being chunk-[hash].js containing code from both files mentioned before within one scope, like it was written inside one file in the first place (essentially removing "module" concept). When it can't be concatenated though, webpack will register those files as modules, so they can be accessed globally via internal helper &lt;strong&gt;webpack_require&lt;/strong&gt; later. &lt;/li&gt;
&lt;li&gt;By default terser doesn't cut off global references in your code (topLevel flag is false). E.g. you build some library with global scope API, you don't want it to be removed during minification. In essence, only somewhat "obviously" dead (unreachable) code or unused in near scopes code will be removed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You probably saw this coming - terser  &lt;strong&gt;can&lt;/strong&gt; remove your  unused export-s only if webpack scoped them in a way that unused declarations can be easily detected.&lt;/p&gt;

&lt;p&gt;For optimization webpack heavily relies on the static structure of ES2015 module syntax, i.e. import and export key-words, and, as for now, doesn't work for other module types. We can see this ourself from the source.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s5pmpDM4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygcljhkso9im1vtdtbq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s5pmpDM4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygcljhkso9im1vtdtbq8.png" alt="Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ModuleConcatenationPlugin puts code from JavaScript files into "chunks" (basically concatenating code from different files into one scope). It bails though if it can not identify ECMAScript module exports.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Like you can see, messing up module interfaces prevents &lt;a href="https://github.com/webpack/webpack/blob/v4.43.0/lib/optimize/ModuleConcatenationPlugin.js"&gt;ModuleConcatenationPlugin&lt;/a&gt; (plugin for optimization) to do its job.&lt;/p&gt;

&lt;p&gt;We all love and use babel to transpile modern ES syntax in our modules, but in this situation the &lt;a href="https://github.com/babel/babel-preset-env#modules"&gt;babel-preset-env&lt;/a&gt; becomes a bad friend of ours - by default modules are transpiled to "commonjs" standard and that's precisely what we don't want when pulling together multiple packages into one application! We have to make sure to set modules: false in preset config. Webpack can do majority of its optimizations only for Harmony modules!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not  transpile modules with your babel setup!  If you do so, webpack will treat files as a blobs, loosing ability to prepare chunks properly for terser to cut off unused code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, technically it's not that straightforward, of course. Webpack does ton of processing on its side in order to build the concatenated code, it does track of provided and used export-s on its side as well, before even calling terser, so "combined" code with all modules is still valid for terser. But once again - it won't work for anything else but static ES module syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;There is quite a complex process going under the hood, starting from you passing webpack.config.js to compiler and before bundle is generated. We'll touch slightly the parts that are interesting for our discussion.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0y-yD2Ix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtnvmq0r53snkxnh47yq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0y-yD2Ix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtnvmq0r53snkxnh47yq.png" alt="Swimlane"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compilation phase is where all fun happens, below you can see its main steps.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qgReWaI9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0t3h7whqboq0o8my9q3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qgReWaI9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0t3h7whqboq0o8my9q3.png" alt="Swimlane"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ultimately, during compilation webpack builds dependency graph for the entry point specified in your webpack.config.js (or several of them, if configuration specifies multiple entry points).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In essence, the idea is to start from the entry point, go through dependent modules, build them and connect together  - modules are nodes and dependencies are connections of the graph.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dmjZHeEa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1yl1v4qwf3pwvoscwna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dmjZHeEa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1yl1v4qwf3pwvoscwna.png" alt="Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;(0)&lt;/td&gt;
&lt;td&gt;Start for entry module (&lt;a href="https://github.com/webpack/webpack/blob/v4.43.0/lib/Compilation.js#1033"&gt;Compilation.js#1033&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(1)&lt;/td&gt;
&lt;td&gt;Build module (&lt;a href="https://github.com/webpack/webpack/blob/v4.43.0/lib/Compilation.js#1111"&gt;Compilation.js#1111&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(2)&lt;/td&gt;
&lt;td&gt;After build process module dependencies (&lt;a href="https://github.com/webpack/webpack/blob/v4.43.0/lib/Compilation.js#1095"&gt;Compilation.js#1095&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(3)&lt;/td&gt;
&lt;td&gt;Add dependencies to module (&lt;a href="https://github.com/webpack/webpack/blob/v4.43.0/lib/Compilation.js#843"&gt;Compilation.js#843&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To &lt;strong&gt;build module&lt;/strong&gt; means to generate AST while extracting all needed information (export-s, import-s etc.). Webpack relies on acorn.Parser (from &lt;a href="https://github.com/acornjs/acorn"&gt;acorn&lt;/a&gt;) to build and process AST.&lt;/p&gt;

&lt;p&gt;Next comes optimization phase.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6KPla4YT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgey24oc56z3x3xa88w5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6KPla4YT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgey24oc56z3x3xa88w5.png" alt="Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;FlagDependencyUsagePlugin&lt;/code&gt; identifies &lt;code&gt;usedExports&lt;/code&gt; and assign to the &lt;code&gt;module&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;FlagDependencyUsagePlugin hooks into the compilation phase and identifies usedExports.  Basically, the idea is to find what "moduleA" imports from "moduleB", to set its usedExports. This process requires a lot of recursive traversing and "counting references".  &lt;/p&gt;

&lt;p&gt;As you know,  webpack has pipe of plugins working on events, if you want to learn more, check out my other post &lt;a href="https://codecrumbs.io/library/webpack-tapable-core"&gt;Tapable library as a core of webpack architecture&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/webpack/webpack/blob/v4.43.0/lib/FlagDependencyUsagePlugin.js"&gt;FlagDependencyUsagePlugin.js&lt;/a&gt; follows what &lt;a href="https://github.com/webpack/webpack/blob/v4.43.0/lib/dependencies/HarmonyImportDependencyParserPlugin.js"&gt;HarmonyImportDependencyParserPlugin.js&lt;/a&gt; found about dependencies usage. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KEgQ0zRq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iroud0eea719mrjfsieq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KEgQ0zRq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iroud0eea719mrjfsieq.png" alt="Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;(1)&lt;/td&gt;
&lt;td&gt;Once &lt;code&gt;importSpecifier&lt;/code&gt; is detected, variable will be marked as "imported var" for further tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(2)&lt;/td&gt;
&lt;td&gt;Listen to calls (AST element &lt;code&gt;method&lt;/code&gt; call), i.e. webpack is smart, imported method doesn't necessary means it's used, it needs to make sure it's called as well&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(3)&lt;/td&gt;
&lt;td&gt;Called imported method detected and saved as dependency (later going to be inside &lt;code&gt;usedExports&lt;/code&gt; for imported module)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Webpack is smart, imported method doesn't necessary means it's used, we need to make sure it's called as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once again, in order for this to work, import-s/export-s should remain in the package (not transpiled).&lt;/p&gt;

&lt;h2&gt;
  
  
  Interesting finds
&lt;/h2&gt;

&lt;p&gt;There are way too many interesting things I've noticed in the source code of webpack that should be to mentioned. It probably needs a separate post.&lt;/p&gt;

&lt;p&gt;I'll highlight just a few of them.&lt;/p&gt;

&lt;p&gt;Remember that error when you run webpack for the first time, but forgot to install webpack-cli package? They are not peerDependencies, so webpack provides quite useful guidance for users on how to solve it.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vFi_YErw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3hucfymljthg9drhdya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vFi_YErw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3hucfymljthg9drhdya.png" alt="Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Simply try to resolve the package, thrown error means it's not installed!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another rather big surprise, how many independent packages-dependencies webpack has. Literally for everything:&lt;/p&gt;

&lt;p&gt;1) &lt;a href="https://github.com/webpack/tapable"&gt;tapable&lt;/a&gt; package for event-driven architecture &lt;br&gt;
2)  &lt;a href="https://github.com/terser/terser"&gt;terser&lt;/a&gt; for minification&lt;br&gt;
3)  &lt;a href="https://github.com/acornjs/acorn"&gt;acorn&lt;/a&gt; for AST processing&lt;br&gt;
4)  &lt;a href="https://github.com/webpack/watchpack"&gt;watchpack&lt;/a&gt; to watch file changes&lt;/p&gt;

&lt;p&gt;That's obviously very nice, hence all of them can be reused for different purposes in other tools!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read &lt;a href="https://codecrumbs.io/library/most-popular-mistake-webpack"&gt;interactive version&lt;/a&gt; of this post on my blog.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Under the hood webpack: core library behind the event-driven architecture</title>
      <dc:creator>Bohdan Liashenko</dc:creator>
      <pubDate>Wed, 29 Jul 2020 15:31:09 +0000</pubDate>
      <link>https://forem.com/bogdanlyashenko/under-the-hood-webpack-core-library-behind-the-event-driven-architecture-3fhj</link>
      <guid>https://forem.com/bogdanlyashenko/under-the-hood-webpack-core-library-behind-the-event-driven-architecture-3fhj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Read &lt;a href="https://codecrumbs.io/stories/webpack-tapable-core"&gt;full interactive version&lt;/a&gt; of this post on my blog.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Webpack architecture is heavily based on events. Each webpack &lt;strong&gt;plugin&lt;/strong&gt; is basically a &lt;strong&gt;set of listeners&lt;/strong&gt; hooked on different events during compilation phases. Under the hood, webpack uses a library called &lt;code&gt;tapable&lt;/code&gt; to encapsulate "publish-subscribe" implementation.&lt;/p&gt;

&lt;p&gt;Tapable provides different "hooks" classes (&lt;code&gt;SyncBailHook&lt;/code&gt;, &lt;code&gt;AsyncParallelHook&lt;/code&gt;, etc.) to "hook" on events with some extra rich functionality (e.g. interceptions or cross-listeners integration).&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;DefinePugin&lt;/code&gt; (used to define environment variables, e.g. &lt;code&gt;NODE_ENV&lt;/code&gt;) and &lt;code&gt;SizeLimitsPlugin&lt;/code&gt; (reports oversized chunks, e.g. &lt;em&gt;size &amp;gt; 250kb&lt;/em&gt;) tap into compiler instance hooks: the first one listens to compilation event in order to insert extra variables and the latter to afterEmit event - to proceed with assets evaluation once they were emitted.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uxPgeB9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bio4fv5seebwzznhse2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uxPgeB9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bio4fv5seebwzznhse2g.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's have a quick look under the hood of &lt;code&gt;webpack&lt;/code&gt; at &lt;code&gt;SizeLimitsPlugin&lt;/code&gt; integration.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vnq8nZrP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1orqn76u9ivwu0kkx4gd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vnq8nZrP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1orqn76u9ivwu0kkx4gd.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1) &lt;code&gt;SizeLimitsPlugin&lt;/code&gt; is instantiated and assigned to compiler in &lt;code&gt;WebpackOptionsApply&lt;/code&gt; if performance option is enabled from webpack config.&lt;br&gt;
2) Then &lt;code&gt;SizeLimitsPlugin&lt;/code&gt; taps on &lt;code&gt;afterEmit&lt;/code&gt; event and will sit still until most of the compilation flow is done and that particular event is called.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ddb0sR1k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e4dhs7jvixs58cgya7vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ddb0sR1k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e4dhs7jvixs58cgya7vn.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the event is called the plugin will do its job (collecting oversized chunks in our case 2, 3).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Indeed, all plugins are assigned similarly, so then you have a pipeline of plugins performing different operations but staying very loosely coupled.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://codecrumbs.io/stories/webpack-tapable-core"&gt;full interactive version&lt;/a&gt; of this post on my blog.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Codecrumbs - a new way of learning and documenting source code</title>
      <dc:creator>Bohdan Liashenko</dc:creator>
      <pubDate>Mon, 18 Feb 2019 21:40:58 +0000</pubDate>
      <link>https://forem.com/bogdanlyashenko/codecrumbs---a-new-way-of-learning-and-documenting-source-code-53j</link>
      <guid>https://forem.com/bogdanlyashenko/codecrumbs---a-new-way-of-learning-and-documenting-source-code-53j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Hi there. My name is Bohdan and I am studying problems of reading code. I just finished working on the first version of "codecrumbs"- visual tool for learning a codebase by putting breadcrumbs in a source code. Check out &lt;a href="https://github.com/Bogdan-Lyashenko/codecrumbs" rel="noopener noreferrer"&gt;github repo here&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fywbbz34pmkkf35qxj8ba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fywbbz34pmkkf35qxj8ba.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Reasoning
&lt;/h2&gt;

&lt;p&gt;Recently I conducted a survey about main challenges we are facing when start learning a big codebase (if you haven't submitted your answers yet, you can still&lt;br&gt;
 do it &lt;a href="https://goo.gl/forms/n0SjqMQ27DLDfP6I2" rel="noopener noreferrer"&gt;here&lt;/a&gt;). The question about "elephant in the room" is particularly interesting, just have a look:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fia9iyg7k5w7f4db7kipu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fia9iyg7k5w7f4db7kipu.png"&gt;&lt;/a&gt;&lt;br&gt;
The trend is quite clear already (and that was obvious before) - it's way harder to "connect dots" and "get the big picture" than just understand the code of particular function or file (so, that means code editors don't help much here). In the unknown codebase we get lost easily and start jumping between files without a clear understanding of what we are doing. It’s just too much useless noise, too many details which blur our vision and understanding of code. &lt;/p&gt;

&lt;p&gt;So we need some way to &lt;strong&gt;diminish the noise&lt;/strong&gt; of the big codebase and &lt;strong&gt;highlight important spots&lt;/strong&gt; in the codebase. A visual tool is a good way to solve that if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it gives the right perspective (and not just to make it look fancy)&lt;/li&gt;
&lt;li&gt;in fact, reduces useless details (and doesn't add one more, visual)&lt;/li&gt;
&lt;li&gt;it is easy to use with existing codebases without a need to rewrite the code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Codecrumbs for rescue
&lt;/h2&gt;

&lt;p&gt;So I've built &lt;a href="https://github.com/Bogdan-Lyashenko/codecrumbs" rel="noopener noreferrer"&gt;codecrumbs&lt;/a&gt; (the name combines "code" and "breadcrumb"). It's a visual tool which gives you what text-based code editor misses - a bigger view of the entire codebase.&lt;/p&gt;

&lt;p&gt;How does it work? You run codecrumbs command for a codebase, it analyzes source code and builds its visual representation. Write down a codecrumb-comment and codebase state will be reflected by a visual client in browser on the fly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;Trail of breadcrumbs - a sequence of codecrumbs can be used to describe some data flow (e.g. user login, or form submit, etc.).&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AOTbzqtV0UxTq_OLkoMfHMw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AOTbzqtV0UxTq_OLkoMfHMw.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dependencies tree - generate dependencies tree for an entry point. You can select connections and see “what is imported” and “its implementation”&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1400%2F1%2AnW72xtwWP4cKcBoWsoQ7wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1400%2F1%2AnW72xtwWP4cKcBoWsoQ7wg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Flowchart - builds SVG flowchart of selected file code (&lt;a href="https://github.com/Bogdan-Lyashenko/js-code-to-svg-flowchart" rel="noopener noreferrer"&gt;js2flowchart&lt;/a&gt; is used under the hood)&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1400%2F1%2A0AoFj03FeYs6eqKIhl0f0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1400%2F1%2A0AoFj03FeYs6eqKIhl0f0w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multi-codebase integration - helps to study connections between several codebases (sub-modules).&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FBogdan-Lyashenko%2Fcodecrumbs%2Fmaster%2Fdocs%2Fmulti-l-c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FBogdan-Lyashenko%2Fcodecrumbs%2Fmaster%2Fdocs%2Fmulti-l-c.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Share codecrumbs state - you can easily share your findings with others. Simply download the json file of codecrumbs store, send it to the friend, he/she can later upload it to the codecrumbs to see the same picture (even without having project locally).&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FBogdan-Lyashenko%2Fcodecrumbs%2Fmaster%2Fdocs%2Fupload-feature-2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FBogdan-Lyashenko%2Fcodecrumbs%2Fmaster%2Fdocs%2Fupload-feature-2.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multi-language support - current version supports the next programming languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;C++
and others which use // as a comment :)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Future plans
&lt;/h3&gt;

&lt;p&gt;The tool (codecrumbs) allows us to learn, document and explain a codebase much faster. Also, with Download &amp;amp; Upload feature it becomes super easy to collect and share your "investigation results".&lt;/p&gt;

&lt;p&gt;The ultimate goal is to have many case studies hosting at &lt;a href="https://codecrumbs.io" rel="noopener noreferrer"&gt;https://codecrumbs.io&lt;/a&gt;. The library of projects "Explained with codecrumbs", the place for collaborative learning with real-world examples.&lt;/p&gt;

&lt;p&gt;More features coming soon, stay tuned. Please put a "star" and share with friends, appreciate it :) Github-repo here &lt;a href="https://github.com/Bogdan-Lyashenko/codecrumbs" rel="noopener noreferrer"&gt;https://github.com/Bogdan-Lyashenko/codecrumbs&lt;/a&gt;. Thanks!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>learning</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
