{"id":104,"date":"2017-05-02T22:53:46","date_gmt":"2017-05-02T19:53:46","guid":{"rendered":"http:\/\/iamakulov.com\/notes2\/?p=104"},"modified":"2017-08-19T16:55:29","modified_gmt":"2017-08-19T13:55:29","slug":"webpack-contextreplacementplugin","status":"publish","type":"post","link":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/","title":{"rendered":"How webpack\u2019s ContextReplacementPlugin works"},"content":{"rendered":"<p>It took me quite a long time of using ContextReplacementPlugin to finally realize what it really does. I hope this post will save you from that.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png\" alt=\"\" width=\"1253\" height=\"662\" class=\"alignnone size-full wp-image-105\" srcset=\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png 1253w, https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21-300x158.png 300w, https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21-768x406.png 768w, https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21-1024x541.png 1024w, https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21-1200x634.png 1200w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/p>\n<p>Once in a while, you need to write a dynamic import. A dynamic import is when an imported file is only known at runtime:<\/p>\n<pre><code class=\"javascript\">require('.\/inputs\/' + inputType + '\/index.js');\r\n<\/code><\/pre>\n<p>When you\u2019re bundling this with webpack, webpack can\u2019t know what exact file you\u2019ll need. To make the application work, webpack will find and import all <em>index.js<\/em> files in all subdirectories of the inputs directory, recursively. This can significantly increase your bundle size.<\/p>\n<p>ContextReplacementPlugin lets you change how webpack deals with dynamic imports. In this case, you can use it to narrow the search scope and thus cut the bundle size.<\/p>\n<p>Here\u2019s an example:<\/p>\n<div class=\"example-block\">\nContextReplacementPlugin is often used with moment.js, a library for working with dates. The thing with moment.js is that it has a bunch of locales, and it imports them dynamically on runtime:<\/p>\n<pre><code class=\"javascript\">\/\/ moment.js\r\nrequire('.\/locale\/' + name + '.js');\r\n<\/code><\/pre>\n<p>To make this work, webpack imports all the locales it can find \u2013 which adds 330 kB of non-minified code.<\/p>\n<p>In most cases, you only need to support a few locales and don\u2019t need all the other ones. ContextReplacementPlugin lets you specify the specific locales that webpack should import:<\/p>\n<pre><code class=\"javascript\">\/\/ webpack.config.js\r\nconst webpack = require('webpack');\r\n\r\nmodule.exports = {\r\n  plugins: [\r\n    new webpack.ContextReplacementPlugin(\r\n      \/moment[\/\\]locale\/,\r\n      \/\/ Regular expression to match the files\r\n      \/\/ that should be imported\r\n      \/(en-gb|ru).js\/\r\n    )\r\n  ]\r\n};\r\n<\/code><\/pre>\n<\/div>\n<p>That works, that\u2019s copy-pasteable, but that\u2019s cryptic. Let\u2019s see what all these parameters really mean.<\/p>\n<h1 id=\"context-and-how-to-replace-it\">Context and how to replace it<a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#context-and-how-to-replace-it\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>Each time you compile a dynamic import like this:<\/p>\n<pre><code class=\"javascript\">require('.\/locale\/' + name + '.js');\r\n<\/code><\/pre>\n<p>webpack collects three pieces of information:<\/p>\n<ul>\n<li>in what directory the files are located (in this case, it\u2019s <em>.\/locale<\/em>),<\/li>\n<li>what regular expression should a file match to be imported (in this case, it\u2019s <em>\/^.*.js$\/<\/em>),<\/li>\n<li>and if webpack should look for the files in the subdirectories (<em>recursive flag;<\/em> always <em>true<\/em> by default).<\/li>\n<\/ul>\n<p>These three pieces of information are called <em>context<\/em>.<\/p>\n<p>Then, webpack searches the appropriate files using the context. That means it looks into the directory specified in the context, looks into its subdirectories if the flag from the context is true, and uses the regular expression from the context to match and import the files.<\/p>\n<p>Now, the key point. <mark>ContextReplacementPlugin lets you replace the context that webpack uses for search<\/mark> \u2013 e.g. override the directory in which webpack should look for the files or the regular expression that webpack should use to match the files.<\/p>\n<p class=\"example-block\">\nFor example, with the <em>moment.js<\/em> example from above, ContextReplacementPlugin replaces the original regular expression <em>\/^.*.js$\/<\/em> with another expression we pass \u2013 <em>\/(en-gb|ru).js\/<\/em>. This way, we import only the necessary locales.\n<\/p>\n<p>To replace the context, you pass the parts you want to replace as the last parameters of ContextReplacementPlugin: <\/p>\n<pre><code class=\"javascript\">new webpack.ContextReplacementPlugin(\r\n  \/\/ The criterion to search; we\u2019ll get to it in a moment\r\n  searchCritetion: RegExp,\r\n  \/\/ The new directory to look for the files\r\n  [newDirectory]: String,\r\n  \/\/ The new recursive flag. True by default.\r\n  \/\/ Pass false to disable recursive lookup\r\n  [newRecursiveFlag]: Boolean,\r\n  \/\/ The new regular expression to match\r\n  \/\/ and import the files\r\n  [newFilesRegExp]: RegExp\r\n)\r\n<\/code><\/pre>\n<div class=\"snippet\">\n<h2 id=\"examples\">Examples<a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#examples\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h2>\n<p>If you don\u2019t fully understand how webpack generates context, here\u2019re examples:<\/p>\n<ul>\n<li><a href=\"https:\/\/gist.github.com\/iamakulov\/9731c2ff61af03f31a4fc019d8e0da4b\">of imports and contexts they create<\/a>,<\/li>\n<li><a href=\"https:\/\/gist.github.com\/iamakulov\/59d88d00404259abb83daaf51b70cb07\">of ContextReplacementPlugin calls<\/a>.<\/li>\n<\/ul>\n<\/div>\n<h1 id=\"finding-the-original-context-to-replace\">Finding the original context to replace<a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#finding-the-original-context-to-replace\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>So, you\u2019ve got a case when you have a dynamic import, and you need to replace its context with another one. How do you find this import and pass it to the plugin? You search by the context that the import generates.<\/p>\n<p>ContextReplacementPlugin allows you to search by the context\u2019s directory. This means that if you want to find an import, you should calculate what context it creates, and then pass a regular expression matching that directory to the context. That sounds complex, so let\u2019s just see how it works:<\/p>\n<div class=\"example-block\">\nYou have an import like this:<\/p>\n<pre><code class=\"javascript\">require('.\/locale\/' + name + '.js')\r\n<\/code><\/pre>\n<p>and you want to apply ContextReplacementPlugin to it to limit the number of the included files.<\/p>\n<p><b>Step 1. Calculate the context that will be created by the import<\/b> <br \/> With this import, the context has three parts:<\/p>\n<ul>\n<li>directory, which is <em>.\/locale<\/em>,\n<li>the regular expression to match the files, which is <em>\/^.*.js$\/<\/em>.\n<li>and the recursive flag (always <em>true<\/em>).\n<\/ul>\n<p><b>Step 2. Extract the directory from the context<\/b> <br \/> Here, the directory from the original context is \/\/.\/locale\/\/.<\/p>\n<p><b>Step 3. Find the full absolute path of the directory<\/b> <br \/> On your machine, the full path of the directory could be something like <em>&apos;\/usr\/\u2026\/my-project\/node_modules\/moment\/locale&apos;<\/em>.<\/p>\n<p><b>Step 4. Create a regular expression that matches the path<\/b> <br \/> This could be as simple as <em>\/locale\/<\/em>. Or this could be something more specific, like <em>\/moment[\/\\]locale\/<\/em> (cross-platform version of <em>\/moment\/locale\/<\/em>).<\/p>\n<p>I recommend to be as specific as possible: a simple regular expression, like <em>\/locale\/<\/em>, can unexpectedly match other imports, like <em>require(&apos;.\/images\/flags\/locale\/&apos; + localeName)<\/em>.<\/p>\n<p><b>Step 5. Pass the regular expression as the first parameter of ContextReplacementPlugin<\/b> <br \/> Like this:<\/p>\n<pre><code class=\"javascript\">new webpack.ContextReplacementPlugin(\r\n  \/moment[\/\\]locale\/,\r\n  \u2026\r\n)\r\n<\/code><\/pre>\n<\/div>\n<div class=\"snippet\">\n<h2 id=\"normalmodulereplacementplugin\">NormalModuleReplacementPlugin<a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#normalmodulereplacementplugin\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h2>\n<p>Note: ContextReplacementPlugin works only with dynamic imports. If you ever want to configure a redirect for a normal, non-dynamic import, use <a href=\"https:\/\/webpack.github.io\/docs\/list-of-plugins.html#normalmodulereplacementplugin\">NormalModuleReplacementPlugin<\/a>. It works with static imports (only with them), and it\u2019s way simpler to understand.\n<\/div>\n<h1 id=\"bonus-point-webpack-2\">Bonus point: webpack 2<a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#bonus-point-webpack-2\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>The traditional usage of ContextReplacementPlugin is to replace one context with another context. However, webpack 2 brought a new API that you can use to granularly redirect imports:<\/p>\n<pre><code class=\"javascript\">new ContextReplacementPlugin(\r\n  \/moment[\/\\]locale\/,\r\n  path.resolve(__dirname, 'src'),\r\n  {\r\n    '.\/en.js': '.\/dir1\/en.js',\r\n    '.\/ru.js': '.\/dir2\/ru.js',\r\n  }\r\n)\r\n<\/code><\/pre>\n<p>The code above:<\/p>\n<ul>\n<li>will add two files, <em>.\/src\/dir1\/en.js<\/em> and <em>.\/src\/dir2\/ru.js<\/em>, to the bundle,<\/li>\n<li>will redirect all runtime requests from <em>node_modules\/moment\/locale\/en.js<\/em> to <em>dir1\/en.js<\/em>,<\/li>\n<li>will redirect all runtime requests from <em>node_modules\/moment\/locale\/ru.js<\/em> to <em>dir2\/ru.js<\/em>.<\/li>\n<\/ul>\n<p>This is something that can\u2019t be achieved with traditional ContextReplacementPlugin. Unfortunately, this API is only briefly mentioned <a href=\"https:\/\/github.com\/webpack\/webpack\/issues\/2783#issuecomment-233752248\">in a GitHub issue<\/a>.<\/p>\n<p>When is this helpful? I can only think of some cases when a large existing project is being migrated to webpack \u2013 but I haven\u2019t seen any practical example. If you know any, share them in the comments!<\/p>\n<p>Here\u2019s how you write your own redirection:<\/p>\n<pre><code class=\"javascript\">new ContextReplacementPlugin(\r\n  \/\/ Specify the criterion for search\r\n  \/moment[\/\\]locale\/,\r\n  \r\n  \/\/ Specify any directory that\u2019s common\r\n  \/\/ for all the redirection targets.\r\n  \/\/ It can\u2019t be __dirname: for some reason,\r\n  \/\/ that doesn\u2019t work\r\n  path.resolve(__dirname, 'src'),\r\n  \r\n  \/\/ Specify the mapping in form of\r\n  \/\/ { runtime request : compile-time request }\r\n  \/\/ IMPORTANT: runtime request should exactly match\r\n  \/\/ the text that is passed into `require()`\r\n  \/\/ IMPORTANT: compile-time request should be relative\r\n  \/\/ to the directory from the previous parameter\r\n  {\r\n    '.\/en.js': '.\/dir1\/en.js',\r\n    '.\/ru.js': '.\/dir2\/ru.js',\r\n  }\r\n)\r\n<\/code><\/pre>\n<h1 id=\"%cf%83\">\u03a3<a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#%cf%83\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>The key points:<\/p>\n<ul>\n<li>Each time you do a dynamic import, webpack creates a context. Context is an object containing the directory to look into, the recursive flag and the regular expression for matching files.<\/p>\n<\/li>\n<li>\n<p>Use ContextReplacementPlugin to change how webpack handles dynamic imports. This can be helpful when you need to decrease the bundle size or migrate some complex code to webpack.<\/p>\n<\/li>\n<li>\n<p>You can granularly redirect compile-time requests to the different files with webpack 2.<\/p>\n<\/li>\n<\/ul>\n<h1 id=\"further-reading\">Further reading<a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#further-reading\" class=\"heading-link\" aria-label=\"Link to this section\" title=\"Link to this section\">#<\/a><\/h1>\n<p>Here\u2019re some related links:<\/p>\n<ul>\n<li><a href=\"https:\/\/webpack.github.io\/docs\/context.html\">Webpack docs about context<\/a><\/li>\n<li><a href=\"https:\/\/webpack.github.io\/docs\/list-of-plugins.html#contextreplacementplugin\">Webpack docs about ContextReplacementPlugin<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/webpack\/webpack\/issues\/2783\">GitHub issue with a large discussion around the plugin<\/a><\/li>\n<\/ul>\n<hr \/>\n<p id=\"subscribe\">This is an article in my series of articles about webpack. The next one, \u201cSpeeding up build and improving the development workflow\u201d, is coming in July. Leave your email to know when it\u2019s out:<br \/>\n<small>(you\u2019ll receive an email about this post + a couple of more webpack-related posts if I write them; no spam)<\/small><\/p>\n<div>\n        <link href=\"\/\/cdn-images.mailchimp.com\/embedcode\/horizontal-slim-10_7.css\" rel=\"stylesheet\" type=\"text\/css\">\n<style type=\"text\/css\"> #mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; margin: 0 -16px 28px; padding: 19px 15px; background: rgba(255, 219, 1, 0.25); border: 1px solid #ffdb01; border-radius: 4px; } #mc_embed_signup p:empty { display: none }<\/style>\n<div class=\"signup-form\" id=\"mc_embed_signup\">\n<form action=\"\/\/iamakulov.us15.list-manage.com\/subscribe\/post?u=d7d2af05c405078e8f6a48956&amp;id=d24b88eefe\" method=\"post\" id=\"mc-embedded-subscribe-form\" name=\"mc-embedded-subscribe-form\" class=\"validate\" target=\"_blank\" novalidate>\n<div id=\"mc_embed_signup_scroll\"><input type=\"email\" value=\"\" name=\"EMAIL\" class=\"email\" id=\"mce-EMAIL\" placeholder=\"email address\" required> <\/p>\n<div style=\"position: absolute; left: -5000px;\" aria-hidden=\"true\"><input type=\"text\" name=\"b_d7d2af05c405078e8f6a48956_d24b88eefe\" tabindex=\"-1\" value=\"\"><\/div>\n<div class=\"clear\"><input type=\"submit\" value=\"Subscribe\" name=\"subscribe\" id=\"mc-embedded-subscribe\" class=\"button\"><\/div>\n<\/div>\n<\/form>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>It took me quite a long time of using ContextReplacementPlugin to finally realize what it really does. I hope this post will save you from that. Once in a while, you need to write a dynamic import. A dynamic import is when an imported file is only known at runtime: When you\u2019re bundling this with &hellip; <a href=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;How webpack\u2019s ContextReplacementPlugin works&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[12],"class_list":["post-104","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-webpack"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v23.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How webpack\u2019s ContextReplacementPlugin works - Ivan Akulov\u2019s blog<\/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:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How webpack\u2019s ContextReplacementPlugin works - Ivan Akulov\u2019s blog\" \/>\n<meta property=\"og:description\" content=\"It took me quite a long time of using ContextReplacementPlugin to finally realize what it really does. I hope this post will save you from that. Once in a while, you need to write a dynamic import. A dynamic import is when an imported file is only known at runtime: When you\u2019re bundling this with &hellip; Continue reading &quot;How webpack\u2019s ContextReplacementPlugin works&quot;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/\" \/>\n<meta property=\"og:site_name\" content=\"Ivan Akulov\u2019s blog\" \/>\n<meta property=\"article:publisher\" content=\"http:\/\/facebook.com\/iamakulov.page\" \/>\n<meta property=\"article:published_time\" content=\"2017-05-02T19:53:46+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-08-19T13:55:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1253\" \/>\n\t<meta property=\"og:image:height\" content=\"662\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ivan Akulov\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@iamakulov\" \/>\n<meta name=\"twitter:site\" content=\"@iamakulov\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ivan Akulov\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/\",\"url\":\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/\",\"name\":\"How webpack\u2019s ContextReplacementPlugin works - Ivan Akulov\u2019s blog\",\"isPartOf\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png\",\"datePublished\":\"2017-05-02T19:53:46+00:00\",\"dateModified\":\"2017-08-19T13:55:29+00:00\",\"author\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81\"},\"breadcrumb\":{\"@id\":\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#primaryimage\",\"url\":\"http:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png\",\"contentUrl\":\"http:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/iamakulov.com\/notes\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How webpack\u2019s ContextReplacementPlugin works\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/iamakulov.com\/notes\/#website\",\"url\":\"https:\/\/iamakulov.com\/notes\/\",\"name\":\"Ivan Akulov\u2019s blog\",\"description\":\"Ivan Akulov writes about his front-end experience, React, webpack, and performance optimizations.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/iamakulov.com\/notes\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81\",\"name\":\"Ivan Akulov\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/aec4e9e944911b58f2c3d14b7f9e5412a217e5738359c3f52e824b4de2b2263c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/aec4e9e944911b58f2c3d14b7f9e5412a217e5738359c3f52e824b4de2b2263c?s=96&d=mm&r=g\",\"caption\":\"Ivan Akulov\"},\"description\":\"I'm a software engineer specializing in web performance, JavaScript, and React. I\u2019m also a Google Developer Expert. I work at Framer.\",\"sameAs\":[\"http:\/\/iamakulov.com\",\"https:\/\/x.com\/iamakulov\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How webpack\u2019s ContextReplacementPlugin works - Ivan Akulov\u2019s blog","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:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/","og_locale":"en_US","og_type":"article","og_title":"How webpack\u2019s ContextReplacementPlugin works - Ivan Akulov\u2019s blog","og_description":"It took me quite a long time of using ContextReplacementPlugin to finally realize what it really does. I hope this post will save you from that. Once in a while, you need to write a dynamic import. A dynamic import is when an imported file is only known at runtime: When you\u2019re bundling this with &hellip; Continue reading \"How webpack\u2019s ContextReplacementPlugin works\"","og_url":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/","og_site_name":"Ivan Akulov\u2019s blog","article_publisher":"http:\/\/facebook.com\/iamakulov.page","article_published_time":"2017-05-02T19:53:46+00:00","article_modified_time":"2017-08-19T13:55:29+00:00","og_image":[{"width":1253,"height":662,"url":"https:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png","type":"image\/png"}],"author":"Ivan Akulov","twitter_card":"summary_large_image","twitter_creator":"@iamakulov","twitter_site":"@iamakulov","twitter_misc":{"Written by":"Ivan Akulov","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/","url":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/","name":"How webpack\u2019s ContextReplacementPlugin works - Ivan Akulov\u2019s blog","isPartOf":{"@id":"https:\/\/iamakulov.com\/notes\/#website"},"primaryImageOfPage":{"@id":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#primaryimage"},"image":{"@id":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#primaryimage"},"thumbnailUrl":"http:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png","datePublished":"2017-05-02T19:53:46+00:00","dateModified":"2017-08-19T13:55:29+00:00","author":{"@id":"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81"},"breadcrumb":{"@id":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#primaryimage","url":"http:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png","contentUrl":"http:\/\/iamakulov.com\/notes2\/wp-content\/uploads\/2017\/05\/WINWORD_2017-05-02_22-45-43-21.png"},{"@type":"BreadcrumbList","@id":"https:\/\/iamakulov.com\/notes\/webpack-contextreplacementplugin\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/iamakulov.com\/notes\/"},{"@type":"ListItem","position":2,"name":"How webpack\u2019s ContextReplacementPlugin works"}]},{"@type":"WebSite","@id":"https:\/\/iamakulov.com\/notes\/#website","url":"https:\/\/iamakulov.com\/notes\/","name":"Ivan Akulov\u2019s blog","description":"Ivan Akulov writes about his front-end experience, React, webpack, and performance optimizations.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/iamakulov.com\/notes\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/ebf7b61bf573e7be5fe438f50ebd9b81","name":"Ivan Akulov","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/iamakulov.com\/notes\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/aec4e9e944911b58f2c3d14b7f9e5412a217e5738359c3f52e824b4de2b2263c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/aec4e9e944911b58f2c3d14b7f9e5412a217e5738359c3f52e824b4de2b2263c?s=96&d=mm&r=g","caption":"Ivan Akulov"},"description":"I'm a software engineer specializing in web performance, JavaScript, and React. I\u2019m also a Google Developer Expert. I work at Framer.","sameAs":["http:\/\/iamakulov.com","https:\/\/x.com\/iamakulov"]}]}},"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts\/104","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/comments?post=104"}],"version-history":[{"count":22,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts\/104\/revisions"}],"predecessor-version":[{"id":505,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/posts\/104\/revisions\/505"}],"wp:attachment":[{"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/media?parent=104"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/categories?post=104"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/iamakulov.com\/notes\/wp-json\/wp\/v2\/tags?post=104"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}