{"id":21787,"date":"2016-06-29T09:49:19","date_gmt":"2016-06-29T16:49:19","guid":{"rendered":"https:\/\/www.jamasoftware.com\/?p=21787"},"modified":"2023-01-12T16:55:05","modified_gmt":"2023-01-13T00:55:05","slug":"upgrade-node-module-right-way","status":"publish","type":"post","link":"https:\/\/www.jamasoftware.com\/legacy\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/","title":{"rendered":"How to Upgrade a Node Module The Right Way"},"content":{"rendered":"<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-21861\" src=\"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/06\/blog-featured-image-IN-BLOG.jpg\" alt=\"Node\" \/><\/p>\n<p>Now that all of that left-pad nonsense is behind us, we can get back to focusing on the business of utilizing node modules, or more specifically, how to upgrade our node packages in a safe, verifiable, refactory way (as refactory as Javascript lets us get, anyway).<\/p>\n<h3>The Problem<\/h3>\n<p>Recently, I was tasked with bringing our <a href=\"https:\/\/github.com\/reactjs\/react-router\">react-router <\/a>dependency up to date, which was woefully out-of-date: we were running version 0.13.3, and I believe the most current version as of this writing is 2.4.2.<\/p>\n<p>In our application, our routing code is probably among the most difficult to reason about and hairiest code our frontend employs. It relies a great deal on a home-spun web history module, it accommodates legacy routes and redirects them to their proper current route location, and employs some \u201csmart routing\u201d to determine an object\u2019s route depending on its ID and its context. There are also many places throughout the app where we were exposing the Router object in order to programmatically route to locations (something that isn\u2019t available as an option in later versions of react-router).<\/p>\n<h3>The approach<\/h3>\n<p>We had recently brought in two refactoring experts to give instruction on proper refactoring of legacy code, closely following Martin Fowler\u2019s<a href=\"https:\/\/www.amazon.com\/Refactoring-Improving-Design-Existing-Code\/dp\/0201485672\"> pivotal book on the subject<\/a>. Unfortunately, our instructors didn\u2019t dive as deeply into refactoring frontend code as the frontend engineers would\u2019ve liked, but we still had some valuable takeaways from the instruction that we could apply to our work. I would be utilizing the tools we gained from this instruction to bring this module up to date.<\/p>\n<h3>First things first<\/h3>\n<p>React-router, mercifully, has a lot of documentation around their <a href=\"https:\/\/github.com\/ReactTraining\/react-router\/blob\/master\/packages\/react-router\/docs\/guides\/migrating.md\" target=\"_blank\" rel=\"noopener\">major version<\/a> upgrades. We dug into the documents to gain some understanding of the biggest changes we would have to make.<\/p>\n<p>I won\u2019t get into the specifics of the upgrades unless it\u2019s suitable to explain the process of migrating to the new modules.<\/p>\n<h3>Feature flags<\/h3>\n<p>Javascript is unsafe. Profoundly so. Just about anything you do in the code can introduce some kind of side effect, even something as mundane as importing a module (this, in fact, happened during this process as I found a certain module modified the global state and by importing it after the new module had imported, would break the new module).<\/p>\n<p>The best way to safely make changes to your code is to introduce feature flags or environmental variables or some other environment factor that provides control over the introduction of new code. In our Java application, we use a plugin called Togglz to store the values in a database and inject them into the frontend.<\/p>\n<p>We also use Webpack; we could forego the Java implementation and in our Webpack configuration, we could provide the configuration we wanted. This can be done through an aliased module:<\/p>\n<pre class=\"lang:default decode:true \">\/\/ In the webpack config\r\n...\r\nresolve: {\r\n    alias: {\r\n        featureFlags: {\r\n            'react_013_to_1': true\r\n        }\r\n    }\r\n}\r\n...\r\n\r\n\/\/ In a file that needs the feature flag\r\nvar featureFlags = require('featureFlags');\r\n\r\nif (featureFlags.react_013_to_1) {\r\n    \/\/ do something\r\n}<\/pre>\n<p>There are many ways to do this &#8212; figure out the one that works best for your environment and build setup.<\/p>\n<h3>Two module versions at a time?<\/h3>\n<p>Now that we have somewhere we can turn on and off the feature in question, we have to figure out a way to import and safely use two different versions of a module at the same time. It turns out this is pretty trivial if we break some rules.<\/p>\n<p>We were running 0.13.3 of react-router, but we wanted our first step to be to 1.0.3, or the highest version of version 1.x.x available. The reason is we want to end up as close to the 2.x.x version as we can possibly get so that transition is made much easier.<\/p>\n<p>Since react-router is a direct dependency of our frontend entry point, there\u2019s no real way around the fact that you can only run one version of that dependency at the same time &#8212; <em>at least not through npm<\/em>. What we <em>can<\/em> do is clone react-router from github locally, build it, and then add its libs to our application, checked into our codebase.<\/p>\n<p>At this point, you might be crying foul: Under no circumstance should we be including a library as a checked in member of our code. Indeed,\u00a0<span style=\"color: #35332e; font-family: Courier New;\">node_modules<\/span> should be part of your .gitignore config. But the intention of that rule is to make your build process transferrable, and avoid overhead that comes with having a ton of dependency code checked in. In this case, we want to do something temporary and build-agnostic.<\/p>\n<p>The plan is this:<\/p>\n<ol>\n<li>We clone the react-router repo<\/li>\n<li>We go into the cloned repo and <code>git checkout<\/code>\u00a0version 1.0.3 of the module.<\/li>\n<li>We <span style=\"color: #35332e; font-family: Courier New;\">npm install<\/span><span class=\"Apple-converted-space\">\u00a0<\/span>to get the module\u2019s dependencies<\/li>\n<li>We <span style=\"color: #35332e; font-family: Courier New;\">npm run build<\/span> to create the 1.0.3 build dist of the module<\/li>\n<li>We create a folder in our frontend code called <span style=\"color: #35332e; font-family: Courier New;\">module-upgrades<\/span>, and inside of that, a folder called\u00a0<span style=\"color: #35332e; font-family: Courier New;\">react-router-1<\/span><\/li>\n<li>We copy the <span style=\"color: #35332e; font-family: Courier New;\">lib<\/span> folder generated by the react-router module into the <span style=\"color: #35332e; font-family: Courier New;\">react-router-1<\/span> folder<\/li>\n<\/ol>\n<p>We can now import and use two versions of react-router with the flip of a feature flag switch. The end game of this approach is that once we\u2019ve tested the updates thoroughly, we will upgrade our app\u2019s package.json file to now point at version \u201c^1.0.0\u201d of react-router, refactor references to the temporary react-router (\u201creact-router-1\u201d) we have checked into our app to point to the actual node module (defined in <span style=\"color: #35332e; font-family: Courier New;\">package.json<\/span>), and continue on our merry way.<\/p>\n<h3>Migrating Components<\/h3>\n<p>In the case of the router, we wanted to be able to convert one route at a time and then test it. First, we came up with a plan to test it:<\/p>\n<ol>\n<li>Navigate to route directly<\/li>\n<li>Navigate to route through forward button<\/li>\n<li>Navigate to route through back button<\/li>\n<li>Navigate to route through legacy route (if applicable)<\/li>\n<li>Navigate to route through programmatic interface<\/li>\n<\/ol>\n<p>This plan will vary, or even if you decide to implement a plan. Our unit tests around this area of code were so spotty that we decided it\u2019d be best to at least do a smoke test around the route once we converted it.<\/p>\n<p>Next, we create a place to switch between routes. All of our routes were represented in a file called <span style=\"color: #35332e; font-family: Courier New;\">Routes.jsx<\/span> that merely concatenated the routes into an array and exported them for consumption. It looked something like this<\/p>\n<pre class=\"lang:default decode:true\">var Route = require('react-router').Route;\r\n\r\nvar routes = [\r\n ,\r\n ,\r\n ...\r\n ];\r\n\r\nmodule.export = routes;\r\n<\/pre>\n<p>Since this file was being used by the old router, we thought it best to simply create a temporary new file called <span style=\"color: #35332e; font-family: Courier New;\">New<\/span><span style=\"color: #35332e; font-family: Courier New;\">Routes.jsx<\/span> that would be a carbon copy of the old <span style=\"color: #35332e; font-family: Courier New;\">Routes.jsx<\/span>, and migrate the components over piecemeal. Once we were ready to remove the feature flags, it would simply be a matter of removing the old <span style=\"color: #35332e; font-family: Courier New;\">Routes.jsx<\/span> file and renaming <span style=\"color: #35332e; font-family: Courier New;\">New<\/span><span style=\"color: #35332e; font-family: Courier New;\">Routes.jsx<\/span>, both of which are very easy to do as refactors, even in Javascript.<\/p>\n<p><span style=\"color: #35332e; font-family: Courier New;\">New<\/span><span style=\"color: #35332e; font-family: Courier New;\">Routes.jsx<\/span> looked like this:<\/p>\n<pre class=\"lang:default decode:true\">var Route = require('react-router').Route,\r\n NewRoute = require('module-upgrades\/react-router');\r\n\r\nvar routes = [\r\n , \/\/ migrated\r\n , \/\/ to be migrated\r\n ...\r\n ];\r\n\r\nmodule.export = routes;\r\n<\/pre>\n<p>During the process of migrating each route, we would load both routers, but once all routes were migrated over, we could remove the reference to the old router, and this NewRouter.jsx file would only handle new routes.<\/p>\n<h3>Abstracting away differences<\/h3>\n<p>Now that we\u2019ve secured a path toward being able to safely test changes and refactor our dependencies, we can start the work of migrating our code.<\/p>\n<p>Since the specifics of this depend heavily on your particular migration, there\u2019s no point in delving into the specific transforms we had to do with react-router &#8212; only that we wanted to <em>create<\/em> a set of transforms that could be applied across our codebase.<\/p>\n<p>In our app, we had essentially two different types of programmatic routing:<\/p>\n<ol>\n<li>We would point to a location by \u201cname\u201d (a relic of react-router 0.13)<\/li>\n<li>We would point to a location by name, but also provide data<\/li>\n<\/ol>\n<p>Since scenario 2 is merely an extension of scenario 1, we could just extend the solution of 1 to work with 2.<\/p>\n<p>Here\u2019s an example of our old programmatic routing mechanism:<\/p>\n<pre class=\"lang:default decode:true \">...\r\nvar RouterContainer = require('.\/..\/..\/routes\/RouterContainer'),\r\n...\r\nRouterContainer.get().transitionTo(DocumentTypeToPathMap[documentType], { id: this.props.id }, { projectId: this.getProjectId() });\r\n...<\/pre>\n<p>We obtained a reference to a \u201cRouterContainer\u201d, which held a reference to the router singleton (retrieved with the static \u201cget\u201d method). Then we called the method \u201ctransitionTo\u201d on it, passing the name of the route, parameters (in this case, just an id), and query or search values (<span style=\"color: #35332e; font-family: Courier New;\">p<\/span><span style=\"color: #35332e; font-family: Courier New;\">rojectId<\/span>)<\/p>\n<p>Since the history handling of the new version of react-router was delegated out to the new <span style=\"color: #35332e; font-family: Courier New;\">history<\/span> dependency, there was no longer a built-in way of passing params to a route, so we had to create a new method that could take a route and an id and concatenate them into a properly formed route. The new history dependency did, however, allow us to pass in a search string.<\/p>\n<p>Now we have a transform for all cases of programmatic routing:<\/p>\n<p>The above example, to work in the new world, must turn into this:<\/p>\n<pre class=\"lang:default decode:true \">...\r\nvar NewJamaLocation = require('jama\/routes\/NewJamaLocation'),\r\n ...\r\nNewJamaLocation.push({ pathname: NewDocumentTypeToPathMap.documentTypeToPath(documentType, this.props.id), search: '?projectId='+this.getProjectId() });<\/pre>\n<p><span style=\"color: #35332e; font-family: Courier New;\">NewJamaLocation<\/span> represents the new <span style=\"color: #35332e; font-family: Courier New;\">history<\/span> dependency singleton. It has a <span style=\"color: #35332e; font-family: Courier New;\">push<\/span> method that is analogous to <span style=\"color: #35332e; font-family: Courier New;\">transitionTo.push<\/span> accepts a <span style=\"color: #35332e; font-family: Courier New;\">location<\/span> object that contains a <span style=\"color: #35332e; font-family: Courier New;\">pathname<\/span> and <span style=\"color: #35332e; font-family: Courier New;\">search<\/span>\u00a0value. We\u2019ve abstracted out the formulation of the path to <span style=\"color: #35332e; font-family: Courier New;\">NewDocumentTypetoPathMap <\/span>which has a static method that will take a <span style=\"color: #35332e; font-family: Courier New;\">documentType<\/span> and an <span style=\"color: #35332e; font-family: Courier New;\">id<\/span> and create a viable path from it.<\/p>\n<p>However, we want to be able to safely implement this, so we\u2019re going to do so with the conditional logic. Remember, even importing has side effects, so our end result will look like this:<\/p>\n<pre class=\"lang:default decode:true\">var NewJamaLocation,\r\n    RouterContainer,\r\n    featureFlags = require('featureFlags');\r\n...\r\n\r\nif (featureFlags.react_013_to_1) {\r\n    NewJamaLocation = require('jama\/routes\/NewJamaLocation');\r\n} else {\r\n    RouterContainer = require('.\/..\/..\/routes\/RouterContainer');\r\n}\r\n\r\n...\r\n\r\nif (featureFlags.react_013_to_1) {\r\n    NewJamaLocation.push({ pathname: NewDocumentTypeToPathMap.documentTypeToPath(documentType, this.props.id), search: '?projectId='+this.getProjectId() });\r\n} else {\r\n    RouterContainer.get().transitionTo(DocumentTypeToPathMap[documentType], { id: this.props.id }, { projectId: this.getProjectId() });\r\n}\r\n\r\n...<\/pre>\n<p>Another way to do this would be to write the conditional switch into the RouterContainer, and create a shim function \u201ctransitionTo\u201d that would handle the transition from the old router to the new history object. I avoided this path because I wanted us to get away undocumented methods of implementing libraries. Many libraries have very good documentation and examples. The closer we come to implementing our code the way it is documented at the source, the easier it is for newcomers to jump in our code and learn it, and the less bespoke documentation and domain knowledge we have to write or know for our code.<\/p>\n<h3>Copy\/Paste<\/h3>\n<p>Now that we have a mechanical transform of a programmatic route, we can apply it everywhere we do programmatic routing. Literally keep a copy\/pasted implementation that you can drop in (to avoid fat-fingered errors).<\/p>\n<p>I suggest doing this as well when it comes to conditionals. During the migration work, I had a scratch pad open with the following sets of \u201cmacros\u201d:<\/p>\n<pre class=\"lang:default decode:true \">var NewJamaLocation,\r\n    RouterContainer,\r\n    featureFlags = require('featureFlags');\r\n...\r\n\r\nif (featureFlags.react_013_to_1) {\r\n    NewJamaLocation = require('jama\/routes\/NewJamaLocation');\r\n} else {\r\n    RouterContainer = require('.\/..\/..\/routes\/RouterContainer');\r\n}\r\n\r\nif (featureFlags.react_013_to_1) {\r\n\r\n} else {\r\n\r\n}<\/pre>\n<p>Again, the fewer times you have to explicitly type things, the fewer errors you\u2019ll be prone to.<\/p>\n<h3>A note on committing<\/h3>\n<p>Throughout this process, you should employ a micro-commit philosophy &#8212; that is, you\u2019ll want to commit after just about every meaningful code transformation, and especially after any \u201cdangerous\u201d changes. When I say \u201cdangerous\u201d, I mean any code changes that contain a change that isn\u2019t a provable or safe transformation.<\/p>\n<h3>Finishing<\/h3>\n<p>Once we\u2019ve had our code out in the wild for some time and feel it has been thoroughly tested, we can start our path toward removing the old, obsolete code. At this point, it should be as easy as removing the feature flag conditionals to always run the new code.<\/p>\n<p>I recommend using IntelliJ or another well-mannered IDE that understands refactoring to do filename transforms and dependency renamings. It will catch paths you may have perhaps missed a bit better than a simple grep, since it understands import statements and such.<\/p>\n<p>You can then delete your checked in module, have your module imports point to the resident node module (in this case, <span class=\"Apple-converted-space\">\u00a0<\/span><code>react-router<\/code>), and update your package.json file to point to appropriate version (in this case, <span style=\"font-family: Courier New;\">^1.0.3<\/span>), do an npm install, and if you\u2019ve done everything correctly, there should be no difference whatsoever between having the feature flag on and having removed it and pointed to the newer version of the module.<\/p>\n<h3>Caveats<\/h3>\n<p>Another module upgrade we attempted to perform as safely as possible was upgrading react from 0.14.x to 15.x.x. This upgrade, however, proved impossible in our system. Due to our feature flagging mechanism, which is reliant upon a separate backend generating frontend global objects, we had no way to be able to switch between the versions. React also doesn\u2019t allow two versions of itself to be run at the same time.<\/p>\n<p>There is a possible path to a safe React upgrade if your application has a Node backend, but your server will still require a restart in order to configure the modules to pull from the different versions, so there doesn\u2019t appear to be a way to \u201chot swap\u201d between React versions.<\/p>\n<p>That said, React goes out of its way to inform of deprecations and create tools for migration, so upgrading isn\u2019t typically painful once you\u2019ve gotten past a certain threshold.<\/p>\n<input class=\"fooboxshare_post_id\" type=\"hidden\" value=\"21787\"\/>","protected":false},"excerpt":{"rendered":"<p>Now that all of that left-pad nonsense is behind us, we can get back to focusing on the business of utilizing node modules, or more specifically, how to upgrade our node packages in a safe, verifiable, refactory way (as refactory as Javascript lets us get, anyway). The Problem Recently, I was tasked with bringing our [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[855],"tags":[226,227,228,229,230,231],"industry":[],"class_list":["post-21787","post","type-post","status-publish","format-standard","hentry","category-software-development","tag-code","tag-node","tag-node-modules","tag-node-packages","tag-react-router","tag-smart-routing"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.1 (Yoast SEO v28.1) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Upgrade a Node Module The Right Way - Jama Software<\/title>\n<meta name=\"description\" content=\"How to upgrade Node dependencies without breaking absolutely everything, in a safe, verifiable, refactory way (or as refactory as Javascript lets us).\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Upgrade a Node Module The Right Way\" \/>\n<meta property=\"og:description\" content=\"How to upgrade Node dependencies without breaking absolutely everything, in a safe, verifiable, refactory way (or as refactory as Javascript lets us).\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/\" \/>\n<meta property=\"og:site_name\" content=\"Jama Software\" \/>\n<meta property=\"article:published_time\" content=\"2016-06-29T16:49:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-13T00:55:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/06\/blog-featured-image-IN-BLOG.jpg\" \/>\n<meta name=\"author\" content=\"Jama Software\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jama Software\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/\"},\"author\":{\"name\":\"Jama Software\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#\\\/schema\\\/person\\\/59a942565a528aa5f56b240c9342fc7f\"},\"headline\":\"How to Upgrade a Node Module The Right Way\",\"datePublished\":\"2016-06-29T16:49:19+00:00\",\"dateModified\":\"2023-01-13T00:55:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/\"},\"wordCount\":2101,\"image\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/06\\\/blog-featured-image-IN-BLOG.jpg\",\"keywords\":[\"code\",\"node\",\"node modules\",\"node packages\",\"react-router\",\"smart routing\"],\"articleSection\":[\"Software Development\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/\",\"url\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/\",\"name\":\"How to Upgrade a Node Module The Right Way - Jama Software\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/06\\\/blog-featured-image-IN-BLOG.jpg\",\"datePublished\":\"2016-06-29T16:49:19+00:00\",\"dateModified\":\"2023-01-13T00:55:05+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#\\\/schema\\\/person\\\/59a942565a528aa5f56b240c9342fc7f\"},\"description\":\"How to upgrade Node dependencies without breaking absolutely everything, in a safe, verifiable, refactory way (or as refactory as Javascript lets us).\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/#primaryimage\",\"url\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/06\\\/blog-featured-image-IN-BLOG.jpg\",\"contentUrl\":\"https:\\\/\\\/static.jamasoftware.com\\\/www\\\/imports\\\/2016\\\/06\\\/blog-featured-image-IN-BLOG.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/2016\\\/06\\\/29\\\/upgrade-node-module-right-way\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.jamasoftware.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Upgrade a Node Module The Right Way\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#website\",\"url\":\"https:\\\/\\\/www.jamasoftware.com\\\/\",\"name\":\"Jama Software\",\"description\":\"Jama Connect\u00ae #1 in Requirements Management\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.jamasoftware.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.jamasoftware.com\\\/#\\\/schema\\\/person\\\/59a942565a528aa5f56b240c9342fc7f\",\"name\":\"Jama Software\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g\",\"caption\":\"Jama Software\"},\"description\":\"Subject matter experts from Jama Software provide guidance and best practices on requirements management, test management, compliance and regulation, risk management, and complex product and software development.\",\"url\":\"https:\\\/\\\/www.jamasoftware.com\\\/blog\\\/author\\\/jama-software\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Upgrade a Node Module The Right Way - Jama Software","description":"How to upgrade Node dependencies without breaking absolutely everything, in a safe, verifiable, refactory way (or as refactory as Javascript lets us).","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:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/","og_locale":"en_US","og_type":"article","og_title":"How to Upgrade a Node Module The Right Way","og_description":"How to upgrade Node dependencies without breaking absolutely everything, in a safe, verifiable, refactory way (or as refactory as Javascript lets us).","og_url":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/","og_site_name":"Jama Software","article_published_time":"2016-06-29T16:49:19+00:00","article_modified_time":"2023-01-13T00:55:05+00:00","og_image":[{"url":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/06\/blog-featured-image-IN-BLOG.jpg","type":"","width":"","height":""}],"author":"Jama Software","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jama Software","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/#article","isPartOf":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/"},"author":{"name":"Jama Software","@id":"https:\/\/www.jamasoftware.com\/#\/schema\/person\/59a942565a528aa5f56b240c9342fc7f"},"headline":"How to Upgrade a Node Module The Right Way","datePublished":"2016-06-29T16:49:19+00:00","dateModified":"2023-01-13T00:55:05+00:00","mainEntityOfPage":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/"},"wordCount":2101,"image":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/#primaryimage"},"thumbnailUrl":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/06\/blog-featured-image-IN-BLOG.jpg","keywords":["code","node","node modules","node packages","react-router","smart routing"],"articleSection":["Software Development"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/","url":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/","name":"How to Upgrade a Node Module The Right Way - Jama Software","isPartOf":{"@id":"https:\/\/www.jamasoftware.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/#primaryimage"},"image":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/#primaryimage"},"thumbnailUrl":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/06\/blog-featured-image-IN-BLOG.jpg","datePublished":"2016-06-29T16:49:19+00:00","dateModified":"2023-01-13T00:55:05+00:00","author":{"@id":"https:\/\/www.jamasoftware.com\/#\/schema\/person\/59a942565a528aa5f56b240c9342fc7f"},"description":"How to upgrade Node dependencies without breaking absolutely everything, in a safe, verifiable, refactory way (or as refactory as Javascript lets us).","breadcrumb":{"@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/#primaryimage","url":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/06\/blog-featured-image-IN-BLOG.jpg","contentUrl":"https:\/\/static.jamasoftware.com\/www\/imports\/2016\/06\/blog-featured-image-IN-BLOG.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/www.jamasoftware.com\/blog\/2016\/06\/29\/upgrade-node-module-right-way\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.jamasoftware.com\/"},{"@type":"ListItem","position":2,"name":"How to Upgrade a Node Module The Right Way"}]},{"@type":"WebSite","@id":"https:\/\/www.jamasoftware.com\/#website","url":"https:\/\/www.jamasoftware.com\/","name":"Jama Software","description":"Jama Connect\u00ae #1 in Requirements Management","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.jamasoftware.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.jamasoftware.com\/#\/schema\/person\/59a942565a528aa5f56b240c9342fc7f","name":"Jama Software","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6e1172c5d380b2a20a9e5b5a4c0fb4e38bc497dc27ce100567da29abe37001af?s=96&d=mm&r=g","caption":"Jama Software"},"description":"Subject matter experts from Jama Software provide guidance and best practices on requirements management, test management, compliance and regulation, risk management, and complex product and software development.","url":"https:\/\/www.jamasoftware.com\/blog\/author\/jama-software\/"}]}},"_links":{"self":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/posts\/21787","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/comments?post=21787"}],"version-history":[{"count":0,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/posts\/21787\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/media?parent=21787"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/categories?post=21787"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/tags?post=21787"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/www.jamasoftware.com\/legacy\/wp-json\/wp\/v2\/industry?post=21787"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}