<?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: Zhe Li</title>
    <description>The latest articles on DEV Community by Zhe Li (@sneezry).</description>
    <link>https://dev.to/sneezry</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%2F156537%2F0d95ef1e-0711-4b1d-9b85-53b77607f2b8.png</url>
      <title>DEV Community: Zhe Li</title>
      <link>https://dev.to/sneezry</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sneezry"/>
    <language>en</language>
    <item>
      <title>Test for uploading images to Imgur in VS Code</title>
      <dc:creator>Zhe Li</dc:creator>
      <pubDate>Mon, 07 Oct 2019 17:24:20 +0000</pubDate>
      <link>https://dev.to/sneezry/test-for-uploading-images-to-imgur-in-vs-code-41p2</link>
      <guid>https://dev.to/sneezry/test-for-uploading-images-to-imgur-in-vs-code-41p2</guid>
      <description>&lt;p&gt;You can upload images to Imgur using DEV Community extension for Visual Studio Code now!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YnR-Ozc6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/aGazSgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YnR-Ozc6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/aGazSgs.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Write Posts in DEV Community using Visual Studio Code</title>
      <dc:creator>Zhe Li</dc:creator>
      <pubDate>Thu, 03 Oct 2019 11:00:34 +0000</pubDate>
      <link>https://dev.to/sneezry/write-posts-in-dev-community-using-visual-studio-code-2l4o</link>
      <guid>https://dev.to/sneezry/write-posts-in-dev-community-using-visual-studio-code-2l4o</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to"&gt;DEV Community&lt;/a&gt; is one of the most famous platform for developers to share great ideas. Thanks to &lt;a href="https://docs.dev.to/api/"&gt;DEV API&lt;/a&gt;, I made an extension to make it possible to write posts using Visual Studio Code.&lt;/p&gt;

&lt;p&gt;In this article, you will learn how to use &lt;a href="https://marketplace.visualstudio.com/items?itemName=sneezry.vscode-devto" rel="noopener noreferrer"&gt;DEV Community extension for Visual Studio Code&lt;/a&gt; to write posts in DEV Community using Visual Studio Code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;To get started, you need install &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;. For better user experience, you can also install one or more &lt;a href="https://marketplace.visualstudio.com/search?term=markdown&amp;amp;target=VSCode&amp;amp;category=All%20categories&amp;amp;sortBy=Relevance" rel="noopener noreferrer"&gt;markdown extensions&lt;/a&gt; for Visual Studio Code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Install the DEV Community extension
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In Visual Studio Code, open &lt;strong&gt;Extensions&lt;/strong&gt; and search for &lt;strong&gt;dev.to&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Install&lt;/strong&gt; to install the extension.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Restart Visual Studio Code and select &lt;strong&gt;DEV&lt;/strong&gt; icon on the activity bar.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fstart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fstart.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Sign In DEV Community Account
&lt;/h1&gt;

&lt;p&gt;To write posts you need to sign in your DEV Community account first.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Create API key&lt;/strong&gt; in &lt;strong&gt;DEV COMMUNITY: POSTS&lt;/strong&gt; view to open DEV Community account dashboard in browser. Input &lt;strong&gt;vscode&lt;/strong&gt; in description inputbox then click &lt;strong&gt;Generate API key&lt;/strong&gt; button:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fgenerate-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fgenerate-key.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the generated API key:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fget-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fget-key.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Back to Visual Studio Code, and click &lt;strong&gt;Sign in&lt;/strong&gt;, paste API key:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fset-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fset-key.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can see all your posts after signed in:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fsigned-in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fsigned-in.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Edit or Write A New Post
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;To edit a post, click its title in post list to open in Visual Studio Code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fedit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fedit.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Press &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;S&lt;/code&gt; to save your changes.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fsaving.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fsaving.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click the &lt;strong&gt;Plus&lt;/strong&gt; icon to create a new post:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fcreate-new.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fcreate-new.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Updated on 2019/10/23&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker" rel="noopener noreferrer"&gt;Code Spell Checker&lt;/a&gt; for spell check. To make Code Spell Checker work with DEV Community extension, you need add &lt;code&gt;devto&lt;/code&gt; to Code Spell Checker allowed schemas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;File&lt;/strong&gt; - &lt;strong&gt;Preferences&lt;/strong&gt; - &lt;strong&gt;Settings&lt;/strong&gt; to open Visual Studio Code settings page.&lt;/li&gt;
&lt;li&gt;Search &lt;strong&gt;Allowed Schemas&lt;/strong&gt;, click &lt;strong&gt;Add Item&lt;/strong&gt; button to add &lt;code&gt;devto&lt;/code&gt; into the list:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGOZzyS6.png"&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Preview and View Online
&lt;/h1&gt;

&lt;p&gt;Visual Studio Code has built-in support for markdown preview, you can press &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;K&lt;/code&gt; then press &lt;code&gt;V&lt;/code&gt; (&lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;K&lt;/code&gt; &lt;code&gt;V&lt;/code&gt;) to preview locally.&lt;/p&gt;

&lt;p&gt;To published post, you can also right click its title in the post list to select &lt;strong&gt;View online&lt;/strong&gt; to view the post in browser:&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%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fview-online.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fview-online.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Publish A Post
&lt;/h1&gt;

&lt;p&gt;To publish a post you can do one of the followings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Change &lt;code&gt;publish&lt;/code&gt; value to &lt;code&gt;true&lt;/code&gt; in post yaml properties at top of the content, and save the post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Right click the post in post list and select &lt;strong&gt;Publish post&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fpublish.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fpublish.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Insert Images
&lt;/h1&gt;

&lt;p&gt;Like any markdown, you can insert online images like following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;![description](image-url)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Updated on 2019/10/8&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From &lt;strong&gt;v0.0.11&lt;/strong&gt;, the extension uploads images to Imgur by default. If you would like to upload to GitHub instead, press &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;P&lt;/code&gt; and execute &lt;strong&gt;DEV Community: Update GitHub personal access token&lt;/strong&gt; to configure GitHub token, and the extension will upload images to your GitHub repository then.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The DEV Community extension can help you to quickly upload images to GitHub and insert the code to your current post.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open browser and go to &lt;a href="https://github.com/settings/tokens/new" rel="noopener noreferrer"&gt;https://github.com/settings/tokens/new&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Input &lt;strong&gt;vscode&lt;/strong&gt; in note inputbox, check &lt;strong&gt;repo&lt;/strong&gt; scope and click &lt;strong&gt;Generate token&lt;/strong&gt; button:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fgenerate-token.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fgenerate-token.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the generated token.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Upload images&lt;/strong&gt; at bottom left corner of Visual Studio Code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fset-token.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fset-token.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From &lt;strong&gt;v0.0.11&lt;/strong&gt;, you need set GitHub token by executing &lt;strong&gt;DEV Community: Update GitHub personal access token&lt;/strong&gt; command. Or the image will be uploaded to Imgur. See step 7.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the image you would like to upload, and the extension starts to upload the image to GitHub:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fuploading-image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fuploading-image.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After upload complete, the code will insert to your current post automatically:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fauto-insert-image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fauto-insert-image.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To change or remove GitHub token, press &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;P&lt;/code&gt;, and execute &lt;strong&gt;DEV Community: Update GitHub personal access token&lt;/strong&gt; and &lt;strong&gt;DEV Community: Remove GitHub personal access token&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fremove-token.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSneezry%2F_dev_community_post_images_%2Fmaster%2Fremove-token.png"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Feedback and Contribute
&lt;/h1&gt;

&lt;p&gt;DEV Community extension for Visual Studio Code is published under MIT license. You can find its source code from &lt;a href="https://github.com/Sneezry/vscode-devto" rel="noopener noreferrer"&gt;https://github.com/Sneezry/vscode-devto&lt;/a&gt;. This extension is still in preview, and its functionality may be limited. If you have any feedback, welcome to open a ticket at &lt;a href="https://github.com/Sneezry/vscode-devto/issues" rel="noopener noreferrer"&gt;https://github.com/Sneezry/vscode-devto/issues&lt;/a&gt; (GitHub account required).&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Hello World</title>
      <dc:creator>Zhe Li</dc:creator>
      <pubDate>Thu, 03 Oct 2019 08:54:20 +0000</pubDate>
      <link>https://dev.to/sneezry/hello-world-3ge5</link>
      <guid>https://dev.to/sneezry/hello-world-3ge5</guid>
      <description>&lt;p&gt;Hello from VS Code!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sjdZGY1T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/Sneezry/_dev_community_post_images_/master/unicorn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sjdZGY1T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/Sneezry/_dev_community_post_images_/master/unicorn.png" alt="" width="400" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;test&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build Desktop Apps with Node and Web Tech on VS Code Platform</title>
      <dc:creator>Zhe Li</dc:creator>
      <pubDate>Mon, 27 May 2019 08:13:26 +0000</pubDate>
      <link>https://dev.to/sneezry/build-desktop-apps-with-node-and-web-tech-on-vs-code-platform-5216</link>
      <guid>https://dev.to/sneezry/build-desktop-apps-with-node-and-web-tech-on-vs-code-platform-5216</guid>
      <description>&lt;p&gt;Build desktop apps with Node and web is very cool, however, Electron is a bit heavy. VS Code, one of the most popular editors, is the program I use every day. It is built with Electron. Can I run apps written with Node and web on its platform without install the runtime again? After some attempts, yes! I did it!&lt;/p&gt;

&lt;p&gt;I made a VS Code extension that provides a gallery to show and launch such an app. You can install it from &lt;a href="https://marketplace.visualstudio.com/items?itemName=sneezry.vscode-toolkit" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=sneezry.vscode-toolkit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The extension is at its very early stage, and it's just for to verify my idea.&lt;/p&gt;

&lt;p&gt;After install the extension, you can find a green beaker at bottom left corner of VS Code window, click it to open the app gallery.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yzkfjjuz6frp47tltyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yzkfjjuz6frp47tltyt.png" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the gallery, you can see an app called Installer has already been installed. Click it and select any .tka (Toolkit App) to install.&lt;/p&gt;

&lt;p&gt;Here's a sample Toolkit App you can download and have a try: &lt;a href="https://github.com/Sneezry/cpu.tka/releases" rel="noopener noreferrer"&gt;https://github.com/Sneezry/cpu.tka/releases&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzm4rhz54mo0qqv1rnjhs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzm4rhz54mo0qqv1rnjhs.png" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sample app with show CPU usage on your machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo209nfsa7eyl45gberqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo209nfsa7eyl45gberqf.png" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How to write your own app? It's very simple!&lt;/p&gt;

&lt;p&gt;The first thing is to create package.json, in the file to define &lt;code&gt;displayName&lt;/code&gt;, &lt;code&gt;icon&lt;/code&gt;, &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;view&lt;/code&gt;. &lt;code&gt;displayName&lt;/code&gt; is the text shows in the gallery, and &lt;code&gt;icon&lt;/code&gt; is the relative path of the app icon. &lt;code&gt;main&lt;/code&gt; is the entry file of the app, &lt;code&gt;index.js&lt;/code&gt; for example. You need always declare a &lt;code&gt;main&lt;/code&gt; function and export it in the entry file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; function will be called when launch the app. &lt;code&gt;webview&lt;/code&gt; is the context of the web interface. You can call &lt;code&gt;webview.send(data)&lt;/code&gt; to send data to web.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;view&lt;/code&gt; is the root path of web. &lt;code&gt;index.html&lt;/code&gt; in the web root path will be open when the app launches.&lt;/p&gt;

&lt;p&gt;On the web side, you can call any export Node function with a built-in &lt;code&gt;NodeJS&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;For example, in the entry file, we have exported a function called &lt;code&gt;foo&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&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;p&gt;And you can call it in web like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NodeJS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All NodeJS functions are async in the web, no matter how you declare it on Node side.&lt;/p&gt;

&lt;p&gt;If you want to receive data sent from Node on web side, declare a function call &lt;code&gt;messager&lt;/code&gt;, and data sent by &lt;code&gt;webview.send&lt;/code&gt; will pass to this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;messager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the data flow between Node and web:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------+                     +--------------------+
| Node         |                     | Web                |
|              |                     |                    |
| webview.send ----------------------&amp;gt; messager(data)     |
|              |                     |                    |
| exports.foo  &amp;lt;---------------------- await NodeJS.foo() |
|              |                     |                    |
+--------------+                     +--------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, you can install any node module in your app.&lt;/p&gt;

&lt;p&gt;After all, zip your app and rename it to &lt;code&gt;.tka&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Still have trouble to make it? See the sample app code: &lt;a href="https://github.com/Sneezry/cpu.tka" rel="noopener noreferrer"&gt;https://github.com/Sneezry/cpu.tka&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>vscode</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Speed Up Your VS Code Extension - Not Only Webpack</title>
      <dc:creator>Zhe Li</dc:creator>
      <pubDate>Thu, 02 May 2019 20:40:59 +0000</pubDate>
      <link>https://dev.to/sneezry/how-to-speed-up-your-vs-code-extension-not-only-webpack-48b5</link>
      <guid>https://dev.to/sneezry/how-to-speed-up-your-vs-code-extension-not-only-webpack-48b5</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Extensions let users add language, debuggers, and tools to VS Code to support their development workflow. VS Code has rich extensibility model which lets extension access to UI and contribute functionality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Generally, more than one extension would be installed in VS Code, so as an extension developer, we should always care about performance of the extension to avoid slowing down other extensions or even the main process of VS Code.&lt;/p&gt;

&lt;p&gt;Some rules we should follow when develop an extension:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Avoid using &lt;code&gt;sync&lt;/code&gt; methods. &lt;code&gt;sync&lt;/code&gt; methods would block the entire Node process till they return. Instead, you should use &lt;code&gt;async/await&lt;/code&gt; as much as possible. If you find it hard to replace &lt;code&gt;sync&lt;/code&gt; methods with &lt;code&gt;async&lt;/code&gt;, consider to make a refactoring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only require what you need. Some dependencies may be very large, &lt;code&gt;lodash&lt;/code&gt; for an example. Usually, we do not need all methods of &lt;code&gt;lodash&lt;/code&gt;, and require the entire &lt;code&gt;lodash&lt;/code&gt; library doesn't make sense. Every method of &lt;code&gt;lodash&lt;/code&gt; has a standalone module, and you can require the part only you need.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regard activating rule seriously. In most case, your extension may have no need to activate. Do not use &lt;code&gt;*&lt;/code&gt; as activating rule. If your extension really needs always to activate to listen some events, consider to execute the main code within a &lt;code&gt;setTimeout&lt;/code&gt; to act as a low priority job.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Load modules on demand. Using &lt;code&gt;import ... from ...&lt;/code&gt; is a common way to require modules, however, it may be not a good way sometimes. For example, a module called &lt;code&gt;request-promise&lt;/code&gt; may cost too much time to load (1 to 2 seconds on my side), but only when some conditions are met we may need to fetch remote resources, such as local cache is expired.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first three rules mentioned above are followed by many developers. In this article, we will discuss about a way to load modules on demand, which should meet the habits we write TS or JS to import modules, and require as little cost to change existing code as possible.&lt;/p&gt;

&lt;h1&gt;
  
  
  Load Modules on Demand
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Meet the habits
&lt;/h2&gt;

&lt;p&gt;Commonly, we use &lt;code&gt;import&lt;/code&gt; statement to load modules on top of the script as code shows below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;os&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;os&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;Node loads the specific module synchronously as soon as we import it, and blocks rest code behind.&lt;/p&gt;

&lt;p&gt;What we need is a new method, called &lt;code&gt;impor&lt;/code&gt; for example, to import module without loading it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;osModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;impor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// osModule is unaccessible as os module is not loaded yet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To reach this target, we need to use &lt;code&gt;Proxy&lt;/code&gt;. The &lt;code&gt;Proxy&lt;/code&gt; object is used to define custom behavior for fundamental operations.&lt;/p&gt;

&lt;p&gt;We can customize &lt;code&gt;get&lt;/code&gt; method to load the module only when it is called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reciver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reciver&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;p&gt;With use of &lt;code&gt;Proxy&lt;/code&gt;, &lt;code&gt;osModule&lt;/code&gt; would be a &lt;code&gt;Proxy&lt;/code&gt; instance, and &lt;code&gt;os&lt;/code&gt; module will be loaded only when we call one of its methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;osModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;impor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// os module is not loaded&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;osModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// os module loads here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;import {...} for ...&lt;/code&gt; is widely used when we only want to use part of the module. However, it may make Node have to access to the module to check its properties. Thus, getter will be executed and the module is loaded at that time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load modules with background job
&lt;/h2&gt;

&lt;p&gt;Load on demand still is not enough. We can move forward a single step&lt;br&gt;
 to improve the user experience. Between the extension startup and the module requirement when user executes a command, we have enough time to load the module in advance.&lt;/p&gt;

&lt;p&gt;It's an obvious idea to make a job in the background to load modules in a queue.&lt;/p&gt;
&lt;h2&gt;
  
  
  Timings
&lt;/h2&gt;

&lt;p&gt;We built an extension called &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt;, which makes it easy to code, build, deploy and debug IoT project with multiple Azure services and popular IoT development boards.&lt;/p&gt;

&lt;p&gt;Because of the big scope of &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt; touches, the extension is very heavy to activate. Also, it needs always to activate to listen USB event to take actions when IoT devices connect to the computer.&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%2Fsneezry.com%2Flazy-load-blog%2Factivate-time.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%2Fsneezry.com%2Flazy-load-blog%2Factivate-time.png" alt="Activate Time"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Figure 1&lt;/strong&gt; Activation timing of Azure IoT Device Workbench with lazy load and normal load&lt;/p&gt;

&lt;p&gt;We have compared with lazy load and normal load for &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt; in different cases. From top to bottom in Figure 1, the charts are for launch without workspace open, non IoT project workspace open, and IoT project workspace open. The left charts are for cold boot, and the right for warm boot. Cold boot only happens when the extension is installed at the first time. After VS Code makes some caches, the extension always launches with warm boot. X-aixs is for time of millisecond, and Y-aixs is for loaded module number.&lt;/p&gt;

&lt;p&gt;With normal load, the extension is activated at end of the chart. We find the extension is activated very advanced with lazy load with both cold boot and warm boot, especially when VS Code launches without workspace open.&lt;/p&gt;

&lt;p&gt;For cold boot without workspace open, lazy load has ~30x speed to start up, and ~20x speed for warm boot. With non IoT project open, lazy load is ~10x faster then normal load for cold boot, and ~20x faster for warm boot. When VS Code opens an IoT project, &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt; needs require amount of modules to load the project, however, we still have ~2x speed with cold boot, and ~3x speed with warm boot.&lt;/p&gt;

&lt;p&gt;Here're the complete timing charts for lazy load:&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%2Fsneezry.com%2Flazy-load-blog%2Flazy-load.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%2Fsneezry.com%2Flazy-load-blog%2Flazy-load.png" alt="Lazy Load"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Figure 2&lt;/strong&gt; Complete timing of Azure IoT Device Workbench with lazy load&lt;/p&gt;

&lt;p&gt;Same as Figure 1, the charts in Figure 2 are for both cold and warm boot with no workspace open, non IoT project workspace open, and IoT project workspace open.&lt;/p&gt;

&lt;p&gt;Load timing stage of modules loaded by background job after activated shows in the charts very clearly. The user can hardly notice this small action, and the extension launches quite smoothly.&lt;/p&gt;

&lt;p&gt;To make this performance improvement available to all VS Code extension developers, we have published a Node module called &lt;a href="https://www.npmjs.com/package/impor" rel="noopener noreferrer"&gt;&lt;code&gt;impor&lt;/code&gt;&lt;/a&gt; and have used it in &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt;. You can apply it in your project with very little code change.&lt;/p&gt;
&lt;h1&gt;
  
  
  Module Bundle
&lt;/h1&gt;

&lt;p&gt;Almost all of the VS Code extensions have Node module dependencies. Because of the way Node module works, the depth of dependency level may be very deep. Other, structure of the module may be complex. And that is what Node module black hole talks about.&lt;/p&gt;

&lt;p&gt;To clean up Node modules, we need an awesome tool, webpack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Webpack is a static module bundler for modern JavaScript applications, such as VS Code extension. When webpack processes the application, it internally builds a dependency graph which maps every module the project needs and generates one or more bundles.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Tree shaking
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. It relies on the static structure of ES2015 module syntax, i.e. import and export. The name and concept have been popularized by the ES2015 module bundler rollup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is very easy to make a tree shaking with webpack. The only thing we need is to specific an entry file and its output name, webpack will handle the rest things.&lt;/p&gt;

&lt;p&gt;With tree shaking, untouched files, including JavaScript code, markdown files, and etc, will be removed. Then webpack will merge all code into a single bundled file.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code splitting
&lt;/h2&gt;

&lt;p&gt;Merging all code into one file is not a good idea. To work with load on demand, we should split the code into different parts, and only load the part we need.&lt;/p&gt;

&lt;p&gt;Now, to find a way to split code is another problem we need to solve. A feasible solution is to split every Node module into a single file. It is unacceptable to write every Node module path in webpack configuration file. Fortunately, we can use &lt;a href="https://docs.npmjs.com/cli/ls.html" rel="noopener noreferrer"&gt;&lt;code&gt;npm-ls&lt;/code&gt;&lt;/a&gt; to get all Node modules used in production mode. Then, in output section of webpack configuration, we use &lt;code&gt;[name].js&lt;/code&gt; as output to compile every module.&lt;/p&gt;
&lt;h2&gt;
  
  
  Apply bundled modules
&lt;/h2&gt;

&lt;p&gt;When we ask to load a module, &lt;code&gt;happy-broccoli&lt;/code&gt; for example, Node will try to find &lt;code&gt;happy-broccoli.js&lt;/code&gt; in &lt;code&gt;node_modules&lt;/code&gt; folder. If the file doesn't exist, Node will try to find &lt;code&gt;index.js&lt;/code&gt; under &lt;code&gt;happy-broccoli&lt;/code&gt; folder in &lt;code&gt;node_modules&lt;/code&gt;. If still fail, Node looks for &lt;code&gt;main&lt;/code&gt; section in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To apply the bundled modules, we can put them into &lt;code&gt;node_modules&lt;/code&gt; folder in &lt;code&gt;tsc&lt;/code&gt; output directory.&lt;/p&gt;

&lt;p&gt;If a module is incompatible with webpack bundle, it can be just copied to the output directory &lt;code&gt;node_modules&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Here's an example of extension project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|- src
|  |- extension.ts
|
|- out
|  |- node_modules
|  |  |- happy-broccoli.js
|  |  |- incompatible-with-bundle-module
|  |     |- package.json
|  |
|  |- extension.js
|
|- node_modules
|  |- happy-broccoli
|     |- package.json
|
|  |- incompatible-with-bundle-module
|     |- package.json
|
|- package.json
|- webpack.config.js
|- tsconfig.json

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without bundling Node modules, there are 4368 files in &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt;, and only 343 files are left after applying bundled modules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webpack config example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs-plus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getEntry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;npmListRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm list -only prod -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="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;npmListRes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unbundledModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;impor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;unbundledModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copySync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;out/node_modules/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDependeciesFromNpm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moduleList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="nx"&gt;unbundledModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/^@types&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;moduleList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./node_modules/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDependeciesFromNpm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&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;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getDependeciesFromNpm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**@type {import('webpack').Configuration}*/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getEntry&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;out/node_modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[name].js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;libraryTarget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;commonjs2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;devtoolModuleFilenameTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../[resource-path]&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="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.js&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compare with webpack classic solution
&lt;/h2&gt;

&lt;p&gt;Instead of bundling the entire extension, only bundling modules respectively can make a big benefit of packing. It is very possible that the extension throws dozens of errors after webpacked'. Splitting every module into a single file makes it easier to debug. Also, loading specific bundled module on demand will minimize the impact on performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment Results
&lt;/h2&gt;

&lt;p&gt;Module bundle is applied to &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt; with lazy load to compare with normal load.&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%2Fsneezry.com%2Flazy-load-blog%2Fbundle-activate.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%2Fsneezry.com%2Flazy-load-blog%2Fbundle-activate.png" alt="module bundle"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Figure 3&lt;/strong&gt; Activation timing of Azure IoT Device Workbench with lazy load with bundled modules and normal load&lt;/p&gt;

&lt;p&gt;Module bundle has decreased activation time sharply. For cold boot, lazy load even costs less time than normal load to load all modules completely in some cases.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Normal Load&lt;/th&gt;
&lt;th&gt;Webpack Classic Solution*&lt;/th&gt;
&lt;th&gt;Lazy Load&lt;/th&gt;
&lt;th&gt;Lazy Load with Bundled Modules**&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No workspace, cold boot&lt;/td&gt;
&lt;td&gt;19474 ms&lt;/td&gt;
&lt;td&gt;1116 ms&lt;/td&gt;
&lt;td&gt;599 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;196 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No workspace, warm boot&lt;/td&gt;
&lt;td&gt;2713 ms&lt;/td&gt;
&lt;td&gt;504 ms&lt;/td&gt;
&lt;td&gt;118 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;38 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non IoT workspace, cold boot&lt;/td&gt;
&lt;td&gt;11188 ms&lt;/td&gt;
&lt;td&gt;1050 ms&lt;/td&gt;
&lt;td&gt;858 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;218 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non IoT workspace, warm boot&lt;/td&gt;
&lt;td&gt;4825 ms&lt;/td&gt;
&lt;td&gt;530 ms&lt;/td&gt;
&lt;td&gt;272 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;102 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IoT workspace, cold boot&lt;/td&gt;
&lt;td&gt;15625 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1178 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7629 ms&lt;/td&gt;
&lt;td&gt;2001 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IoT workspace, warm boot&lt;/td&gt;
&lt;td&gt;5186 ms&lt;/td&gt;
&lt;td&gt;588 ms&lt;/td&gt;
&lt;td&gt;1513 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;517 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;*,** Some modules required by &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt; are incompatible with webpack, and are not bundled.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Table 1&lt;/strong&gt; Activation time of Azure IoT Device Workbench in different statuses&lt;/p&gt;

&lt;p&gt;Activation time shows in Table 1 is between very beginning of the entry to the extension and the end of &lt;code&gt;activate&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// start of timing&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;vscode&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;vscode&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExtensionContext&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="c1"&gt;// end of timing&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;p&gt;Usually, time before activated is longer then startup time shows in VS Code Running Extensions page. For example, when open IoT workspace with warm boot, the activation time is 517 ms in the table, but the startup time is ~200 ms in VS Code Running Extensions page.&lt;/p&gt;

&lt;p&gt;Activation time of classic webpack solution only has relationship to boot mode, because all modules are always loaded in the same way. When applying lazy load on &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt;, it starts up further faster without workspace open than with IoT workspace open, no matter whether with or without bundled modules. When we open an IoT workspace, most modules are required, and the benefit taken from lazy load is not obvious, so lazy load with bundled modules has similar activation time with classic webpack solution.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this article, a load bundled modules on demand method is proposed. A heavy extension called &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.vscode-iot-workbench" rel="noopener noreferrer"&gt;Azure IoT Device Workbench&lt;/a&gt; is tested for the method of multiple cases, and its startup speed has been increased to dozens of times. In some cases, this method also shows better performance than classic webpack solution.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
