<?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>DEV Community: Todd Anglin</title>
    <description>The latest articles on DEV Community by Todd Anglin (@toddanglin).</description>
    <link>https://dev.to/toddanglin</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%2F172840%2Ff1d8601c-0236-4d1f-85d6-7653eddaa1bb.png</url>
      <title>DEV Community: Todd Anglin</title>
      <link>https://dev.to/toddanglin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/toddanglin"/>
    <language>en</language>
    <item>
      <title>Using Graph Explorer to Get Sample Data via REST</title>
      <dc:creator>Todd Anglin</dc:creator>
      <pubDate>Mon, 27 Jul 2020 22:33:24 +0000</pubDate>
      <link>https://dev.to/toddanglin/using-graph-explorer-to-get-sample-data-via-rest-2hah</link>
      <guid>https://dev.to/toddanglin/using-graph-explorer-to-get-sample-data-via-rest-2hah</guid>
      <description>&lt;p&gt;&lt;strong&gt;Here's the scenario:&lt;/strong&gt; you've got an idea for an app that includes data from Microsoft's Graph API. You want to mock up the concept using dummy data from Graph API, and you don't want to jump through hoops writing "real code" around authentication.&lt;/p&gt;

&lt;p&gt;What do you do?&lt;/p&gt;

&lt;h1&gt;
  
  
  Graph Explorer to the rescue
&lt;/h1&gt;

&lt;p&gt;For the unfamiliar, &lt;a href="https://developer.microsoft.com/graph/graph-explorer?WT.mc_id=devto-blog-toanglin" rel="noopener noreferrer"&gt;Graph Explorer&lt;/a&gt; is a browser-based tool that makes it easy to...well, explore the &lt;a href="https://docs.microsoft.com/graph/?WT.mc_id=devto-blog-toanglin" rel="noopener noreferrer"&gt;vast capabilities of the Graph API&lt;/a&gt;. You can sign in to Graph Explorer to see your own data as you explore, or you can browse anonymously and get sample dummy data.&lt;/p&gt;

&lt;p&gt;And really, if you work at a company that uses M365 (and most of us do) and you have not yet explored Graph API, do yourself a favor and &lt;a href="https://docs.microsoft.com/graph/?WT.mc_id=devto-blog-toanglin" rel="noopener noreferrer"&gt;check it out today&lt;/a&gt;. Much like social graphs do for consumer applications, Graph API puts tons of valuable information about your organization right at your developer finger tips. You are one REST call away from listing the members of your team or displaying a contact card in your app powered by the M365 directory. But I digress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Graph Explorer. Dummy data. Your app concept.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Graph Explorer provides sample data when making anonymous requests to Graph API endpoints. For example, if we call this endpoint in Graph Explorer anonymously: &lt;code&gt;https://graph.microsoft.com/v1.0/me/photo/$value&lt;/code&gt;. We get this image:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ocai9um7hcnu90wlbnk.jpeg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ocai9um7hcnu90wlbnk.jpeg" alt="Image of a woman's face"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Easy peasy.&lt;/p&gt;

&lt;p&gt;But if we take that same REST endpoint and try to access the sample data outside of Graph Explorer, we'll be met with a &lt;code&gt;401: Unauthorized&lt;/code&gt; error.&lt;/p&gt;

&lt;h1&gt;
  
  
  Accessing Graph Explorer sample data via REST
&lt;/h1&gt;

&lt;p&gt;The solution to our problem lies in the API proxy that Graph Explorer uses in the browser. Inspecting network traffic for a Graph Explorer request reveals all calls go through a sandbox proxy:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://proxy.apisandbox.msdn.microsoft.com/svc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Graph API endpoint is passed as a URL encoded query string value. In the case of the profile photo endpoint:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;?url=https:%2F%2Fgraph.microsoft.com%2Fv1.0%2Fme%2Fphoto%2F$value&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The request will still fail, however, until you add the following HTTP header to your request (exactly as-is...no need to change the token value):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Authorization: Bearer {token:https://graph.microsoft.com/}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And, whala!✨ Graph Explorer sample data via REST!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jsbin.com/lahololuno/edit?html,js,output" rel="noopener noreferrer"&gt;Try it out with this interactive sample on JSBin&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Get your own sample data
&lt;/h1&gt;

&lt;p&gt;Using Graph Explorer's sample data is a convenient, quick-and-dirty solution for a design mockup or simple demo, but eventually you'll likely want more control over your sample data...and a place where you can test your app with Graph integration before deploying. And for that, you you'll want your own M365 sandbox!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a M365 developer sandbox is free and easy:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit the &lt;a href="https://developer.microsoft.com/microsoft-365/dev-program?WT.mc_id=devto-blog-toanglin" rel="noopener noreferrer"&gt;M365 Developer Program&lt;/a&gt; page&lt;/li&gt;
&lt;li&gt;Sign-up for free&lt;/li&gt;
&lt;li&gt;Create your personal M365 sandbox&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives you a sandbox URL, sandbox domain, and sandbox admin user account you can use to configure and play with M365 (and Graph) to your heart's content. Microsoft even provides &lt;a href="https://docs.microsoft.com/office/developer-program/install-sample-packs?WT.mc_id=devto-blog-toanglin" rel="noopener noreferrer"&gt;sample data packs&lt;/a&gt; that add useful demo data to your environment with a single click (like additional sample users and profiles).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F11dl02lgmeckcjxv09pf.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F11dl02lgmeckcjxv09pf.png" alt="M365 sample data packs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, when you authenticate using your sandbox account, you will see your personal sandbox data in Graph Explorer (or anywhere you access the Graph API). This is useful for any M365 demo where you don't want to expose the "real" data from your organization.&lt;/p&gt;

&lt;p&gt;There you have it. A quick and easy way to grab Graph Explorer sample data, and a more robust path for creating a M365 developer sandbox.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>m365</category>
    </item>
    <item>
      <title>PublishTo.Dev: Scheduling article publishing on dev.to</title>
      <dc:creator>Todd Anglin</dc:creator>
      <pubDate>Tue, 30 Jul 2019 14:35:33 +0000</pubDate>
      <link>https://dev.to/toddanglin/publishto-dev-scheduling-article-publishing-on-dev-to-3m0o</link>
      <guid>https://dev.to/toddanglin/publishto-dev-scheduling-article-publishing-on-dev-to-3m0o</guid>
      <description>&lt;p&gt;It's 11 PM.&lt;/p&gt;

&lt;p&gt;You've finally put the finishing touches on your next masterpiece article on dev.to. You can't wait to share it with the world and start collecting those ❤️ and 🦄.&lt;/p&gt;

&lt;p&gt;You move your cursor to that 'Publish' button, but then pause...&lt;/p&gt;

&lt;p&gt;Should you publish the article now and risk getting buried in the morning's headlines? Should you set an alarm and try to remember to return to your draft and click 'Publish' at the &lt;a href="https://www.blogtyrant.com/best-time-to-publish-blog-articles/" rel="noopener noreferrer"&gt;right moment&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;It's a conundrum and it's too late to think this hard.&lt;/p&gt;

&lt;p&gt;I have a solution: &lt;a href="https://www.publishto.dev" rel="noopener noreferrer"&gt;PublishTo.Dev&lt;/a&gt;. A simple tool for dev.to authors that lets you choose the exact date and time you want your draft article to go live. Just choose a time, schedule your article, and go to bed knowing your content will land at the perfect time.&lt;/p&gt;

&lt;p&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%2Fs0esj4txnzc71dgxx8hj.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs0esj4txnzc71dgxx8hj.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is PublishTo.Dev?
&lt;/h2&gt;

&lt;p&gt;At its core, &lt;a href="https://www.publishto.dev" rel="noopener noreferrer"&gt;PublishTo.Dev&lt;/a&gt; is a scheduling service for dev.to authors. It uses the recently introduced &lt;a href="https://dev.to/api"&gt;dev.to API&lt;/a&gt; to publish draft articles on a specific date and time. Well, I'll let this video explain.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8y9piBXwXts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;There are 3 primary components of this service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;a href="https://chrome.google.com/webstore/detail/publishtodev-extension/bohbnpnialpdpgnibbddaaoaklmnjoaa" rel="noopener noreferrer"&gt;browser extension&lt;/a&gt; used for scheduling articles&lt;/li&gt;
&lt;li&gt;An Azure serverless backend that handles the scheduling&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://www.publishto.dev" rel="noopener noreferrer"&gt;static site&lt;/a&gt; to review/cancel scheduled postings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The browser extension works with both Google Chrome and Microsoft Edge Insider. The extension can be installed directly from the &lt;a href="https://chrome.google.com/webstore/detail/publishtodev-extension/bohbnpnialpdpgnibbddaaoaklmnjoaa" rel="noopener noreferrer"&gt;Chrome Web Store&lt;/a&gt; (and eventually Microsoft Edge Extension store), OR loaded "unpacked" from the &lt;a href="https://github.com/toddanglin/PublishToDev" rel="noopener noreferrer"&gt;GitHub source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PublishTo.Dev does &lt;strong&gt;not&lt;/strong&gt; attempt to change the article authoring experience. It works on saved, unpublished drafts that have already been authored using existing tools. PublishTo.Dev is focused exclusively on scheduling articles. &lt;/p&gt;

&lt;h3&gt;
  
  
  The scheduling process
&lt;/h3&gt;

&lt;p&gt;Let's take a look at how you schedule a draft article using PublishTo.Dev.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup
&lt;/h4&gt;

&lt;p&gt;First, you need to install the browser extension. Follow the instructions in the GitHub repo or (if you're using Chrome) just &lt;a href="https://chrome.google.com/webstore/detail/publishtodev-extension/bohbnpnialpdpgnibbddaaoaklmnjoaa" rel="noopener noreferrer"&gt;install from the Store&lt;/a&gt;.&lt;/p&gt;

&lt;p&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%2Fspggoi0cjnxgbbm2n3pj.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%2Fspggoi0cjnxgbbm2n3pj.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the extension installed, there is a one-time configuration step to add your unique dev.to API access token. This is how PublishTo.Dev publishes on your behalf. Right-click on the extension icon in the browser and choose 'Options'. Alternatively, you can navigate to &lt;code&gt;chrome://extensions&lt;/code&gt; or &lt;code&gt;edge://extensions&lt;/code&gt; to get to the options page, too.&lt;/p&gt;

&lt;p&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%2Fu3mn3djjajicdfinehea.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%2Fu3mn3djjajicdfinehea.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, you are asked for your API access token.&lt;/p&gt;

&lt;p&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%2Fqj9gara9y9akaowj3z7d.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%2Fqj9gara9y9akaowj3z7d.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get that, navigate to the &lt;a href="https://dev.to/settings/account"&gt;settings account page&lt;/a&gt; on dev.to and generate a new token for PublishTo.Dev. Copy the token value and it to the extension options.&lt;/p&gt;

&lt;p&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%2F3lo57iaxvt0g221uoh6m.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%2F3lo57iaxvt0g221uoh6m.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Scheduling
&lt;/h4&gt;

&lt;p&gt;Now that you're all set up, let's schedule an article.&lt;/p&gt;

&lt;p&gt;Navigate to a saved draft. You know you're on the right page when you see the big, red "Unpublished" banner at the top of your article. From here, click the browser extension icon and choose the date and time you want the article to go live.&lt;/p&gt;

&lt;p&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%2Fk6vhy8fv4np3lfxe5xcl.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%2Fk6vhy8fv4np3lfxe5xcl.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The selected publishing time must be in the future (obviously), up to 30 days from now. That is an arbitrary limit that may be removed in the future, but for now, articles can be scheduled up to a month in advance. When choosing a time, specific hours or minutes can be directly input in the calendar text boxes.&lt;/p&gt;

&lt;p&gt;With your date and time selected, click "Schedule Post."&lt;/p&gt;

&lt;p&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%2Fpr5e68hfqpndhuclm4bq.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%2Fpr5e68hfqpndhuclm4bq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If all goes well, you'll see a confirmation message in the extension pop-up.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rescheduling
&lt;/h4&gt;

&lt;p&gt;Oops! You just remembered that &lt;em&gt;Wednesdays&lt;/em&gt; are better for your content than &lt;em&gt;Mondays&lt;/em&gt;. How do you change your publishing schedule?&lt;/p&gt;

&lt;p&gt;Simple. Just revisit the unpublished draft that needs to be rescheduled, and follow the original process. As long as the article has not yet been published, the new scheduled time will override the previous schedule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing and Cancelling Schedules
&lt;/h3&gt;

&lt;p&gt;While the browser extension is used for all article scheduling, a &lt;a href="https://www.publishto.dev" rel="noopener noreferrer"&gt;separate website is available&lt;/a&gt; for reviewing the status of scheduled articles.&lt;/p&gt;

&lt;p&gt;To use the website, simply enter the same dev.to API access token configured with your browser extension and click "Get Scheduled Posts."&lt;/p&gt;

&lt;p&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%2F2vvta3zprv9hgv6wetwh.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%2F2vvta3zprv9hgv6wetwh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have scheduled articles, they will be displayed along with one of the following status indicators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Published:&lt;/strong&gt; Successfully published scheduled article&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pending:&lt;/strong&gt; Article waiting to publish at scheduled time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failed:&lt;/strong&gt; Something went wrong and the article did not publish at scheduled time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancelled:&lt;/strong&gt; Scheduled publishing was cancelled by the author (you)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any article in the &lt;strong&gt;Pending&lt;/strong&gt; state can be cancelled if you no longer want it to be published automatically. Just click the "Cancel" button on the row for that post.&lt;/p&gt;

&lt;p&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%2Fafnco9pcuco8ai59ztjf.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%2Fafnco9pcuco8ai59ztjf.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you decide to reschedule a &lt;strong&gt;Cancelled&lt;/strong&gt; post in the future, just follow the original scheduling process and the article will be rescheduled. The only state that is "final" is &lt;strong&gt;Published.&lt;/strong&gt; A published post cannot be republished or unpublished using PublishTo.Dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this work?
&lt;/h2&gt;

&lt;p&gt;Behind the scenes, the heavy lifting for PublishTo.Dev is made possible by &lt;a href="https://cda.ms/10S" rel="noopener noreferrer"&gt;Azure Durable Functions&lt;/a&gt;. Durable Functions are perfectly suited for dealing with long-running, async tasks, only actively running (and billing) when something needs to be done between periods of waiting. The wait could be seconds, minutes, hours, days...or longer*.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(*Durable function timers &lt;a href="https://cda.ms/111" rel="noopener noreferrer"&gt;cannot last longer than 7 days today&lt;/a&gt;, BUT...that is a limit that's being removed AND there are workarounds today for setting longer timers. I'll get in to that in another post.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the case of PublishTo.Dev, a serverless function runs when an article is initially scheduled, and then using a &lt;a href="https://cda.ms/10T" rel="noopener noreferrer"&gt;durable function timer&lt;/a&gt;, "hibernates" until it's time to publish the post. This eliminates the need to do any kind of interval polling to know when a post needs to be published.&lt;/p&gt;

&lt;p&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%2F6f94d9iqctknc858p66q.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%2F6f94d9iqctknc858p66q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the scheduled publish time arrives, the durable function automatically wakes up and tries to publish the post using the dev.to API.&lt;/p&gt;

&lt;p&gt;Durable functions are good for many different kinds of long-running, async scenarios. In fact, the &lt;a href="https://cda.ms/10W" rel="noopener noreferrer"&gt;docs highlight six common scenarios&lt;/a&gt;, like chaining async functions or even &lt;a href="https://cda.ms/10X" rel="noopener noreferrer"&gt;waiting on human input&lt;/a&gt;, where durable functions make your life much easier.&lt;/p&gt;

&lt;p&gt;In future articles, I will expand on the technical implementation of PublishTo.Dev. Stay tuned for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;From the outset, the goal was to provide an easy way to schedule post publishing, and PublishTo.Dev accomplishes that. Or, it does for me.&lt;/p&gt;

&lt;p&gt;Let me know what you think. How does it work for you? How can it be a more useful utility?&lt;/p&gt;

&lt;p&gt;One day, I fully expect dev.to will support native post scheduling and eliminate the need for this tool, but until then, I hope it helps you improve your publishing workflow.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Testing the Dev.To API for Publishing</title>
      <dc:creator>Todd Anglin</dc:creator>
      <pubDate>Mon, 29 Jul 2019 05:15:26 +0000</pubDate>
      <link>https://dev.to/toddanglin/testing-the-dev-to-api-for-publishing-4bde</link>
      <guid>https://dev.to/toddanglin/testing-the-dev-to-api-for-publishing-4bde</guid>
      <description>&lt;p&gt;There's really no other way to say it: this post is a test.&lt;/p&gt;

&lt;p&gt;For the last week, I've been working on a new tool that leverages the &lt;a href="https://dev.to/api"&gt;DevTo API&lt;/a&gt; to help authors schedule publishing time for new posts. I only recently started publishing to this platform, and was surprised to discover scheduled publishing not available. Fortunately, there &lt;em&gt;is&lt;/em&gt; an API, so I set out to close the gap.&lt;/p&gt;

&lt;p&gt;There is no sandbox for the API, though, and I clearly did not want to publish a bunch of spam during development and testing. So, until now, all testing has simply changed the title of a draft post at the scheduled "publishing" time. My assumption is that if everything else works, it &lt;em&gt;should&lt;/em&gt; be a simple matter of changing the behavior to update the publish status instead of updating the title when development is done.&lt;/p&gt;

&lt;p&gt;Well, let's see.&lt;/p&gt;

&lt;p&gt;This post should go live automatically at 12:15 AM CDT. Hey. It's a test. If it's going to fail, let's fail when no one's watching.&lt;/p&gt;

&lt;p&gt;But if you're reading this at 12:15 AM...it worked! 🎉&lt;/p&gt;

&lt;p&gt;And that means I've got a lot more to share this week about how it was built, how it works, and how you can use it, too. Stay tuned.&lt;/p&gt;

</description>
      <category>showdev</category>
    </item>
    <item>
      <title>Upgrading Older NativeScript Apps to Use Webpack</title>
      <dc:creator>Todd Anglin</dc:creator>
      <pubDate>Thu, 18 Jul 2019 14:30:43 +0000</pubDate>
      <link>https://dev.to/toddanglin/upgrading-older-nativescript-apps-to-use-webpack-3e15</link>
      <guid>https://dev.to/toddanglin/upgrading-older-nativescript-apps-to-use-webpack-3e15</guid>
      <description>&lt;p&gt;"Older" app sounds so negative.&lt;/p&gt;

&lt;p&gt;And I'm not a fan of "legacy," "heritage," or "aging."&lt;/p&gt;

&lt;p&gt;Let's go with "well loved" NativeScript apps.👍 No matter what you call them, they started before NativeScript fully embraced webpack, and now they need to join the webpack party to keep getting the latest NativeScript updates.&lt;/p&gt;

&lt;p&gt;With NativeScript 5.4, the default build mode for NativeScript apps changed to use &lt;a href="https://webpack.js.org/"&gt;Webpack&lt;/a&gt;. And with &lt;a href="https://www.nativescript.org/blog/announcing-nativescript-6.0---webpack-all-the-way-seamless-app-updates-new-core-theme-and-a-lot-more"&gt;this week's NativeScript 6.0 release&lt;/a&gt; 🎉, Webpack is the ONLY supported build mode. Webpack builds do offer big benefits, like reducing app package size and improving app performance (less JavaScript to load), but with that power comes a more complicated build configuration...especially for &lt;del&gt;an older&lt;/del&gt; a well loved app that did not start with the Angular or Vue templates (that work with webpack out of the gate).&lt;/p&gt;

&lt;p&gt;I recently updated my smart home controller app from NativeScript 5.1 to 5.4 and made the big switch to webpack. My app started in 2015, so it doesn't use Angular or Vue, but it does use TypeScript. My upgrade was anything but smooth, but hopefully my pain will be your gain. Here are some tips that will hopefully help make your NativeScript upgrade to webpack easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start the upgrade
&lt;/h2&gt;

&lt;p&gt;Clearly, the first thing we need to do is upgrade our environment and project to the latest version of NativeScript. As of this week, that's {N} 6.0. Upgrade the CLI with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; nativescript
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;NOTE: When I went through this process, I updated to {N} 5.4, but much of the advice should still apply for {N} projects adopting webpack for the first time with {N} 6.0.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then, in your project, update the &lt;code&gt;package.json&lt;/code&gt; to use the latest versions of &lt;code&gt;tns-ios&lt;/code&gt;, &lt;code&gt;tns-android&lt;/code&gt; and &lt;code&gt;tns-core-modules&lt;/code&gt;. It's generally a good idea to consider upgrading other dependencies and plugins at this time, too. In fact, with {N} 6.0, there is a new CLI command that will auto update some of these NativeScript dependencies for you!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;tns migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When doing framework upgrades, I always delete the generated &lt;code&gt;platforms&lt;/code&gt;, &lt;code&gt;hooks&lt;/code&gt; and &lt;code&gt;node_modules&lt;/code&gt; folders to minimize problems caused by cached assets. Once those folders are deleted, they can be regenerated with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;tns &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If your project is adding webpack for the first time, the install process will ask if you want to switch to webpack builds and will generate the required &lt;code&gt;webpack.config.js&lt;/code&gt; and update the dev dependencies in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete old generated JavaScript files
&lt;/h2&gt;

&lt;p&gt;When you use TypeScript with NativeScript &lt;em&gt;pre-webpack&lt;/em&gt;, the build process automatically compiles the &lt;code&gt;.ts&lt;/code&gt; to &lt;code&gt;.js&lt;/code&gt; in your working directory and then syncs the &lt;code&gt;.js&lt;/code&gt; to the device or simulator. With webpack builds, &lt;code&gt;.js&lt;/code&gt; files don't get generated in the working directory. That's great! But...if you forget to clean-out the old generated &lt;code&gt;.js&lt;/code&gt; files, it can create some real debugging head aches. (Ask me how I know...)&lt;/p&gt;

&lt;p&gt;So, first things first. Good hygiene. Clean out generated files from your working directory. If you are using git, this can be done quickly with a command like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clean &lt;span class="nt"&gt;-fX&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This command will remove all ignored files from the working directory.&lt;/p&gt;

&lt;p&gt;If you switch to webpack builds, and it seems like the changes you are making in your TypeScript are not working on the device, this is a likely cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rename files to register as modules
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is the big one.&lt;/strong&gt; If you are upgrading a non-Angular/Vue NativeScript project, there is a good chance that you have your own convention for naming files and views in your project. &lt;strong&gt;With the default NativeScript webpack configuration, module file names must include &lt;code&gt;page&lt;/code&gt; or &lt;code&gt;root&lt;/code&gt;.&lt;/strong&gt; If one of these two words is not in the file name, it will not be registered as a module.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;EDIT: With the final release of {N} 6.0, the default webpack configuration was changed to include all modules in your project. This improves backward compatibility and it means you don't have to rename files.👍 If you are adopting webpack with an upgrade to {N} 5.4, all of this still applies. And, if you still DO decide you want to adopt the standard {N} file naming convention, the tips that follow should help you do that more easily.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are two solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Modify the webpack configuration (in &lt;code&gt;webpack.config.js&lt;/code&gt;) to work with existing file names&lt;/li&gt;
&lt;li&gt;Rename all view file names so they will be registered as modules&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While renaming a BUNCH of files is daunting (and has some cascading impacts), I ultimately opted to go down this route. It's a one time tax and it will make future NativeScript upgrades easier.&lt;/p&gt;

&lt;p&gt;Where my project previously had files like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;settings.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings.ts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To work with webpack, those files are now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;settings-page.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings-page.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings-page.ts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My project also has a lot of "partial" views that are dynamically composed at runtime. Using &lt;code&gt;page&lt;/code&gt; or &lt;code&gt;root&lt;/code&gt; in these file names felt wrong, so I slightly modified the &lt;code&gt;webpack.config.js&lt;/code&gt; to accommodate a "&lt;code&gt;widget&lt;/code&gt;" option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;registerModules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="nx"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;scss&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This change is made in &lt;code&gt;webpack.config.js&lt;/code&gt; &amp;gt; &lt;code&gt;config&lt;/code&gt; &amp;gt; &lt;code&gt;module&lt;/code&gt; &amp;gt; &lt;code&gt;rules&lt;/code&gt; &amp;gt; loader options.&lt;/p&gt;

&lt;p&gt;Meanwhile, TypeScript files that are not associated with a view &lt;strong&gt;do not&lt;/strong&gt; need to be renamed. They will get picked-up by the separate &lt;code&gt;ts-loader&lt;/code&gt; webpack configuration and work properly. Said to say, you don't need to rename &lt;em&gt;every&lt;/em&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean-up the rename mess
&lt;/h3&gt;

&lt;p&gt;You've just renamed ALL of the files associated with views in your app. There's a good chance you broke some code if you use any of the following APIs that expect file names and paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.navigate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.showModal&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;builder.load&lt;/code&gt; or &lt;code&gt;builder.parse&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Search your code base for any occurrences of these API calls and update the file names to match the new webpack-friendly names. This will catch a lot of the common problems that file renaming can have on your code. If you are &lt;code&gt;import&lt;/code&gt;ing (or &lt;code&gt;require()&lt;/code&gt;ing) any views programmatically, those paths must be updated, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relative path changes
&lt;/h2&gt;

&lt;p&gt;With webpack, relative path resolution &lt;em&gt;can&lt;/em&gt; work differently than pre-webpack builds. This applies mostly to the way relative paths are resolved in &lt;code&gt;.xml&lt;/code&gt; views. Fortunately, the "&lt;code&gt;~/&lt;/code&gt;" relative to root syntax works very well everywhere with webpack, so any place you are using relative path navigation can be converted to ues the &lt;code&gt;~/&lt;/code&gt; syntax.&lt;/p&gt;

&lt;p&gt;For example, my app had several views importing a local custom component like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Page&lt;/span&gt; &lt;span class="na"&gt;xmlns:ui=&lt;/span&gt;&lt;span class="s"&gt;"../../shared/ui/loadingSpinner"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To make that work with webpack, it now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Page&lt;/span&gt; &lt;span class="na"&gt;xmlns:ui=&lt;/span&gt;&lt;span class="s"&gt;"~/shared/ui/loadingSpinner-widget"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(Don't forget the file renaming.)&lt;/p&gt;

&lt;p&gt;This works in TypeScript files for &lt;code&gt;import&lt;/code&gt; statements, too. It's probably a good idea to use &lt;code&gt;~/&lt;/code&gt; everywhere, but webpack won't break relative paths in code.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Frame&lt;/code&gt; element is now required
&lt;/h2&gt;

&lt;p&gt;This should be a quick and easy fix, but critical nonetheless. Around the time of {N} 5.0, support for multiple &lt;code&gt;frame&lt;/code&gt; elements was added so that more complex views could be achieved with NativeScript (think: independent navigation in a split view). Until now, if you did not manually add a &lt;code&gt;frame&lt;/code&gt; element to your &lt;code&gt;.xml&lt;/code&gt; view, NativeScript could create it implicitly. With webpack, a missing &lt;code&gt;frame&lt;/code&gt; element will cause a runtime error.&lt;/p&gt;

&lt;p&gt;For most apps, only one &lt;code&gt;frame&lt;/code&gt; is needed in the "root" view. This is the view in which all other "page" views will load. If your app does not have a "root" view:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new top level view with "root" in the name (ex: &lt;code&gt;myapp-root.xml&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;In the new root view, add the following XML (with a reference to whatever your default "page" should be)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Frame&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"my-app-root"&lt;/span&gt; &lt;span class="na"&gt;defaultPage=&lt;/span&gt;&lt;span class="s"&gt;"views/myApp-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/Frame&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update your &lt;code&gt;app.ts&lt;/code&gt; to load the &lt;code&gt;root&lt;/code&gt; module when your app starts
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;views/myapp-root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can gather, NativeScript with webpack builds is like running NativeScript in "strict" mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Builder &lt;code&gt;parse&lt;/code&gt; vs &lt;code&gt;load&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If you dynamically load modules at runtime using the &lt;code&gt;builder&lt;/code&gt; API, you will likely need to update your code to use &lt;code&gt;builder.parse&lt;/code&gt; instead of &lt;code&gt;builder.load&lt;/code&gt;. Webpack pre-registers and loads JavaScript and XML at runtime, and this can create trouble for the &lt;code&gt;builder&lt;/code&gt;. In short, the &lt;code&gt;builder&lt;/code&gt; attempts to load something that has already been loaded (by webpack) at runtime. (There is more discussion on GitHub &lt;a href="https://github.com/NativeScript/nativescript-dev-webpack/issues/620"&gt;in this issue&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;To fix this problem in my code, I changed this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newViewJs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;views/dynamicView.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;views/dynamicView.xml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newViewJs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newViewJs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;~/views/dynamicView.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;~/views/dynamicView-widget.xml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;newViewJs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We are now looking for these TypeScript and XML paths (as registered with webpack) and loading the resources from webpack's compiled, minified runtime resources.&lt;/p&gt;

&lt;p&gt;Frankly, this feels hacky. There could be a better way. And it appears the project is &lt;a href="https://github.com/NativeScript/NativeScript/pull/7386"&gt;actively refactoring&lt;/a&gt; around these APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging the errors
&lt;/h2&gt;

&lt;p&gt;Even with the most thorough upgrade, you are likely to hit some new webpack related runtime errors when you first fire-up your app. Here are two common errors I hit and how I worked through them:&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing &lt;code&gt;Module not found&lt;/code&gt; errors
&lt;/h3&gt;

&lt;p&gt;I hit this error &lt;em&gt;a lot&lt;/em&gt; when I first started trying to run my webpack built NativeScript project. In short, this error indicates that some path configured in your app (like the &lt;code&gt;moduleName&lt;/code&gt; used by your &lt;code&gt;app.ts&lt;/code&gt; on startup or a navigation path) can't be found in the registered webpack modules. Steps to resolve:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make sure the module is actually registered.&lt;/strong&gt; I didn't realize I had to change my file names to properly register the modules when I first upgraded, so that knowledge should already save you some time. Using the webpack "build reports" also helped me troubleshoot. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ tns build ios --env.report&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This creates a folder called &lt;code&gt;report&lt;/code&gt; with a HTML and JSON doc that can be analyzed with tools &lt;a href="http://webpack.github.io/analyse/"&gt;like this&lt;/a&gt;. For relative webpack n00bs (like me), this report helps understand what webpack is doing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make sure the file name in code is correct.&lt;/strong&gt; Assuming you took the path I did and renamed files, make sure the code is looking for the new file name with &lt;code&gt;page&lt;/code&gt;, &lt;code&gt;root&lt;/code&gt; or whatever additional tokens you've added to your &lt;code&gt;webpack.config.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make sure JSON imports include a file extension.&lt;/strong&gt; There were a few places in my app where I was directly &lt;code&gt;require&lt;/code&gt;-ing a JSON file (usually to load some static configuration values). Pre-webpack, these imports did not require an explicit file extension, so this worked:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let config = require("../shared/config");&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That doesn't match a registered path with webpack, so to work now, the file extension must be added:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let config = require("../shared/config.json");&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As an aside, if you are loading static JSON resources in your project using local HTTP (and not explicitly &lt;code&gt;require()&lt;/code&gt;ing), you will need to further update the &lt;code&gt;webpack.config.js&lt;/code&gt; to load these static resources when your app is built.&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CopyWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assets/*.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;- Add this&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fonts/**&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/*.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/*.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Fixing &lt;code&gt;Module parse failed&lt;/code&gt; errors
&lt;/h3&gt;

&lt;p&gt;Another common error I ran in to was this &lt;code&gt;Module parse failed&lt;/code&gt; error, usually along with &lt;code&gt;Unexpected token&lt;/code&gt; or &lt;code&gt;Unexpected character&lt;/code&gt; log messages.&lt;/p&gt;

&lt;p&gt;In my case, all of these errors were caused by accidentally registering files as modules that did not need to be. It's likely an edge case when doing a NativeScript upgrade like this, but if you find yourself head scratching with this error, double check that you're not inadvertently loading files as modules.&lt;/p&gt;

&lt;p&gt;For reference, the wonky file in my project that caused these inadvertent errors was trying to dynamically &lt;code&gt;require&lt;/code&gt; files like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dynamicPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Don't do that with webpack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Double-check for circular references in barrel files
&lt;/h3&gt;

&lt;p&gt;There's NO WAY I added a circular reference to my app.&lt;/p&gt;

&lt;p&gt;I know better. I wouldn't do that.&lt;/p&gt;

&lt;p&gt;Leave it to webpack to serve me some humble pie. Circular references that &lt;em&gt;somebody&lt;/em&gt; added (checks contributor count: 1 😬) did not have any negative affect on the app before webpack, but once Mr. Strict joined the party, they triggered app crashes on startup.&lt;/p&gt;

&lt;p&gt;These circular references crept in to my code via &lt;a href="http://tattoocoder.com/angular2-barrels/"&gt;"barrel" files&lt;/a&gt;. Basically, convenience modules that re-export lots of related modules to simplify imports later. It's a concept borrowed from Angular. For example, here is a barrel file from my app:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app-factories.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./BaseController.factory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./SceneProvider.factory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./CameraProvider.factory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./ThermostatProvider.factory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using this barrel file simplifies an import like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BaseController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SceneProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CameraProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;~/providers/app-factories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;My mistake was accidentally using a barrel file short cut in a file that was exported by that barrel file. Webpack made me aware of my error, but the error messages were cryptic and the problem was not immediately obvious. &lt;strong&gt;Lesson learned: webpack may expose errors in your code that didn't stop your app from running previously.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Phew. It took some heavy lifting, but with a little debugging my app is now running on NativeScript 5.4 and working with webpack builds. It's also ready for NativeScript 6.0, which should now be a quick and easy upgrade. 🤞&lt;/p&gt;

&lt;p&gt;There are a few more potential "gotchas" when upgrading to {N} 6.0 that the NativeScript team &lt;a href="https://www.nativescript.org/blog/nativescript-6.0-application-migration"&gt;highlighted in a new blog post this week&lt;/a&gt;, so be sure to check that out for additional tips.&lt;/p&gt;

&lt;p&gt;With the foundation of my app updated, my next step is to address the app backend and start connecting with Azure. Now the real fun can begin! 'Til then, I hope these lessons learned through pain will make your big webpack upgrades for &lt;em&gt;well loved&lt;/em&gt; NativeScript apps easier.&lt;/p&gt;

</description>
      <category>nativescript</category>
      <category>webpack</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Removing Short Imports in NativeScript, the Easy Way (with VS Code)</title>
      <dc:creator>Todd Anglin</dc:creator>
      <pubDate>Wed, 17 Jul 2019 03:42:58 +0000</pubDate>
      <link>https://dev.to/toddanglin/removing-short-imports-in-nativescript-the-easy-way-with-vs-code-660</link>
      <guid>https://dev.to/toddanglin/removing-short-imports-in-nativescript-the-easy-way-with-vs-code-660</guid>
      <description>&lt;p&gt;As NativeScript continues to evolve, some of the features that made sense in 2015 are creating more trouble than they're worth in 2019. One such feature is the so called "short import."&lt;/p&gt;

&lt;p&gt;Short imports were intended to improve the developer experience by saving a few key strokes. Instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tns-core-modules/platform&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A developer could simply use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;platform&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's convenient, but it has created unintended side effects. And with great tooling like VS Code that can automatically add imports, the value of this feature low.&lt;/p&gt;

&lt;p&gt;So, now it's deprecated (as of {N} 5.2). &lt;a href="https://www.nativescript.org/blog/say-goodbye-to-short-imports-in-nativescript"&gt;Read all about it on the NativeScript blogs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now what?
&lt;/h2&gt;

&lt;p&gt;While short imports still work, they will become a real problem with NativeScript 6.0, when webpack becomes the default and only available {N} build system. Webpack expects the full import path, so short imports quickly cause webpack problems.&lt;/p&gt;

&lt;p&gt;But if you are maintaining an app that has been around for a while, removing short imports could be quite a chore. In my case, the app I was updating had more than 275 short imports to fix!&lt;/p&gt;

&lt;p&gt;I started to fix the imports manually and &lt;em&gt;quickly&lt;/em&gt; realized that was a mistake.&lt;/p&gt;

&lt;p&gt;If only there was a way to automatically fix all these imports...&lt;/p&gt;

&lt;h2&gt;
  
  
  VS Code (and RegEx) to the rescue
&lt;/h2&gt;

&lt;p&gt;Everyone knows that &lt;a href="https://code.visualstudio.com/docs/editor/codebasics?WT.mc_id=devto-blog-toanglin#_search-across-files"&gt;VS Code has great search and replace tools&lt;/a&gt;, but what may not be as obvious is that you can use regular expressions in the search &lt;em&gt;and&lt;/em&gt; replace. Simply toggle "Use Regular Expressions" on and use standard JavaScript regex in the Search, and use &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, etc to include matching groups in the Replace.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE: To run really advanced regex searches with backreferences and lookaround (like we'll do today) does require a setting change in VS Code. Go to Settings &amp;gt; Features &amp;gt; Search &amp;gt; Use PCRE2 and check the box to enable these extra capabilities. &lt;a href="https://code.visualstudio.com/docs/editor/codebasics?WT.mc_id=devto-blog-toanglin#_search-across-files"&gt;See the VS Code docs for more context&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And I know, I know. If you have a problem and use RegEx to solve it, now you have two problems. But it beats the tedious alternative.&lt;/p&gt;

&lt;h3&gt;
  
  
  RegEx to find short imports
&lt;/h3&gt;

&lt;p&gt;The trick to building the right regular expression for this task is trying find short imports for things that &lt;em&gt;should&lt;/em&gt; have the &lt;code&gt;tns-core-modules&lt;/code&gt; prefix while &lt;em&gt;avoiding&lt;/em&gt; imports for "non-core" modules AND imports that already have the correct long format.&lt;/p&gt;

&lt;p&gt;Fortunately, most NativeScript modules follow a similar convention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core modules use "plain" names with no prefix (like &lt;code&gt;application&lt;/code&gt; or &lt;code&gt;ui/layout&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Non-core modules usually prefix the module name with &lt;code&gt;nativescript-&lt;/code&gt; or &lt;code&gt;ns-&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Local modules referenced by path usually start with &lt;code&gt;./&lt;/code&gt; or &lt;code&gt;../&lt;/code&gt; or &lt;code&gt;~/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By example, we want to FIND imports that look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import * as imageSource from "image-source";&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import * as util from "utils/utils";&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import { Image } from "ui/image";&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While AVOIDING imports that look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import { Settings } from "../models/app-models";&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import * as firebase from "nativescript-plugin-firebase";&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import { Color } from "tns-core-modules/color/color";&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AND THEN, when we have a match, we want to insert "&lt;code&gt;tns-core-modules/&lt;/code&gt;" in front of the import path while keeping the rest of the line the same.&lt;/p&gt;

&lt;p&gt;Put it all together, and we get this search regex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)(?!nativescript)(?!ns)(?!tns-core-modules)((?:[&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;w&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/])+)(&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since regex always looks like a cat walked across your keyboard, let's explain in english:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start finding imports by searching for &lt;code&gt;from "&lt;/code&gt; (including the quote) (and store in matching group 1)...&lt;/li&gt;
&lt;li&gt;Followed by any number of word characters OR &lt;code&gt;-&lt;/code&gt; (dashes) OR &lt;code&gt;/&lt;/code&gt; (whacks)(and store in matching group 2)...&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BUT ignore if the matching group contains the words &lt;code&gt;nativescript&lt;/code&gt; or &lt;code&gt;ns&lt;/code&gt; or &lt;code&gt;tns-core-modules&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;These are likely non-core modules OR imports that already have the correct long format&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And finally, match the trailing &lt;code&gt;"&lt;/code&gt; (quote)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combo does a remarkably accurate job of finding the imports we want while ignoring everything else. You can &lt;a href="https://regexr.com/4hj93"&gt;play with a working version of this regex using Regexr in your browser&lt;/a&gt; to experiment with what it matches and misses.&lt;/p&gt;

&lt;p&gt;When running the search in VS Code, to avoid false positives, you obviously also want to exclude files and folders that are not part of your code, like &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;platforms&lt;/code&gt;, &lt;code&gt;*.js&lt;/code&gt; (assuming you're using TypeScript), &lt;code&gt;.git&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replace syntax
&lt;/h3&gt;

&lt;p&gt;When the search finds a match to this pattern, it will create three matching groups with these values:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;from "&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[name of matched module]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, when the following line is matched:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui/image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The matching groups will contain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;from "&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ui/image&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We want to insert &lt;code&gt;tns-core-modules/&lt;/code&gt; between group 1 and group 2. Using VS Code, our replace syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$1tns&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;$2$3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Boom! Job done. Almost...&lt;/p&gt;

&lt;h2&gt;
  
  
  Another search and replace pass
&lt;/h2&gt;

&lt;p&gt;If you're using the plain JavaScript &lt;code&gt;require()&lt;/code&gt; syntax to import modules, you clearly need a different search pattern. Even in my TypeScript-based app, I had a handful of imports done with &lt;code&gt;require()&lt;/code&gt; for reasons specific to module implementation.&lt;/p&gt;

&lt;p&gt;Conceptually, the search regex we need is similar to above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)(globals)+(&lt;/span&gt;&lt;span class="se"&gt;\"\&lt;/span&gt;&lt;span class="s2"&gt;))
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This pattern matches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;require("&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;globals&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;")&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You could modify the "globals" pattern if you need a wider search. In my case, this was the only &lt;code&gt;require()&lt;/code&gt; in my app that needed the &lt;code&gt;tns-core-modules&lt;/code&gt; prefix.&lt;/p&gt;

&lt;p&gt;The replace pattern is the same as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$1tns&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;$2$3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;Hopefully you've learned two things in this post:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Eliminating short imports in your NativeScript app doesn't have to be tedious manual process&lt;/li&gt;
&lt;li&gt;VS Code search and replace is REALLY powerful when combined with regex and matching groups&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>nativescript</category>
      <category>vscode</category>
      <category>regex</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
