<?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: Maximilian Fellner</title>
    <description>The latest articles on DEV Community by Maximilian Fellner (@mxfellner).</description>
    <link>https://dev.to/mxfellner</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%2F267948%2F21a49ab2-e491-4d9c-9a29-238d4aac52a5.jpg</url>
      <title>DEV Community: Maximilian Fellner</title>
      <link>https://dev.to/mxfellner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mxfellner"/>
    <language>en</language>
    <item>
      <title>Dynamic import with HTTP URLs in Node.js</title>
      <dc:creator>Maximilian Fellner</dc:creator>
      <pubDate>Tue, 20 Jul 2021 23:17:46 +0000</pubDate>
      <link>https://dev.to/mxfellner/dynamic-import-with-http-urls-in-node-js-7og</link>
      <guid>https://dev.to/mxfellner/dynamic-import-with-http-urls-in-node-js-7og</guid>
      <description>&lt;p&gt;Is it possible to import code in Node.js from HTTP(S) URLs just like in the browser or in &lt;a href="https://deno.land" rel="noopener noreferrer"&gt;Deno&lt;/a&gt;? After all, Node.js has had stable support for &lt;a href="https://nodejs.org/api/esm.html" rel="noopener noreferrer"&gt;ECMAScript modules&lt;/a&gt; since version 14, released in April 2020. So what happens if we just write something like &lt;code&gt;import('https://cdn.skypack.dev/uuid')&lt;/code&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6n64wzxqnrul0hlree8i.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%2Fuploads%2Farticles%2F6n64wzxqnrul0hlree8i.png" alt="import('https://cdn.skypack.dev/uuid') causes ERR_UNSUPPORTED_ESM_URL_SCHEME"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately it's neither possible import code from HTTP URLs statically nor dynamically because the URL scheme is not supported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loaders and VM
&lt;/h2&gt;

&lt;p&gt;An experimental feature of Node.js are custom &lt;a href="https://github.com/nodejs/loaders" rel="noopener noreferrer"&gt;loaders&lt;/a&gt;. A loader is basically a set of "hook" functions to resolve and load source code. There is even an example of an &lt;a href="https://nodejs.org/api/esm.html#esm_https_loader" rel="noopener noreferrer"&gt;HTTP loader&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Such a loader would be passed to Node.js as a command line argument:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

node &lt;span class="nt"&gt;--experimental-loader&lt;/span&gt; ./https-loader.mjs


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

&lt;/div&gt;
&lt;p&gt;A downside to this approach is that a loader's influence is quite limited. For instance, the execution context of the downloaded code cannot be modified. The &lt;a href="https://github.com/nodejs/loaders" rel="noopener noreferrer"&gt;team&lt;/a&gt; working on loaders is still modifying their API, so this could still be subject to change.&lt;/p&gt;

&lt;p&gt;Another Node.js API that offers more low-level control is &lt;a href="https://nodejs.org/api/vm.html" rel="noopener noreferrer"&gt;vm&lt;/a&gt;. It enables the execution of raw JavaScript code within the V8 virtual machine.&lt;/p&gt;

&lt;p&gt;In this blog post, we're going to use it to create our own dynamic import implementation!&lt;/p&gt;
&lt;h2&gt;
  
  
  Downloading code
&lt;/h2&gt;

&lt;p&gt;Let's start with downloading the remotely hosted code. A very simple and naive solution is to just use "node-fetch" or a similar library:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&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;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&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;fetchCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Error fetching &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&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="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;We can use this function to download any ECMAScript module from a remote server. In this example we are going to use the &lt;a href="https://www.skypack.dev/view/lodash-es" rel="noopener noreferrer"&gt;lodash-es&lt;/a&gt; module from Skypack&lt;sup id="fnref1"&gt;1&lt;/sup&gt;, the CDN and package repository of the &lt;a href="https://www.snowpack.dev" rel="noopener noreferrer"&gt;Snowpack&lt;/a&gt; build tool.&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;import cdn.skypack.dev/lodash-es&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;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;Obviously important security and performance aspects have been neglected here. A more fully-featured solution would handle request headers, timeouts, and caching amongst other things.&lt;/p&gt;
&lt;h2&gt;
  
  
  Evaluating code
&lt;/h2&gt;

&lt;p&gt;For the longest time, Node.js has provided the &lt;a href="https://nodejs.org/api/vm.html#vm_class_vm_script" rel="noopener noreferrer"&gt;vm.Script&lt;/a&gt; class to compile and execute raw source code. It's a bit like &lt;code&gt;eval&lt;/code&gt; but more sophisticated. However, this API only works with the classic CommonJS modules.&lt;/p&gt;

&lt;p&gt;For ECMAScript modules, the new &lt;a href="https://nodejs.org/api/vm.html#vm_class_vm_module" rel="noopener noreferrer"&gt;vm.Module&lt;/a&gt; API must be used and it is still experimental. To enable it, Node.js must be run with the &lt;code&gt;--experimental-vm-modules&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;To use &lt;code&gt;vm.Module&lt;/code&gt; we are going to implement the 3 distinct steps creation/parsing, linking, and evaluation:&lt;/p&gt;
&lt;h3&gt;
  
  
  Creation/parsing
&lt;/h3&gt;

&lt;p&gt;First, we need to create an execution context. This is going to be the global context in which the code will be executed. The context can be just an empty object but some code may require certain global variables, like &lt;a href="https://nodejs.org/api/globals.html" rel="noopener noreferrer"&gt;those defined by Node.js itself&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;vm&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;vm&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;Next, we create an instance of &lt;code&gt;vm.SourceTextModule&lt;/code&gt; which is a subclass of &lt;code&gt;vm.Module&lt;/code&gt; specifically for raw source code strings.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SourceTextModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&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="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;identifier&lt;/code&gt; is the name of the module. We set it to the original HTTP URL because we are going to need it for resolving additional imports in the next step.&lt;/p&gt;
&lt;h3&gt;
  
  
  Linking
&lt;/h3&gt;

&lt;p&gt;In order to resolve additional static &lt;code&gt;import&lt;/code&gt; statements in the code, we must implement a custom &lt;code&gt;link&lt;/code&gt; function. This function should return a new &lt;code&gt;vm.SourceTextModule&lt;/code&gt; instance for the two arguments it receives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;specifier&lt;/strong&gt; of the imported dependency. In ECMAScript modules this can either be an absolute or a relative URL to another file, or a "bare specifier" like &lt;code&gt;"lodash-es"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;referencing module&lt;/strong&gt; which is an instance of &lt;code&gt;vm.Module&lt;/code&gt; and the "parent" module of the imported dependency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example we are only going to deal with URL imports for now:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;referencingModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create a new absolute URL from the imported&lt;/span&gt;
  &lt;span class="c1"&gt;// module's URL (specifier) and the parent module's&lt;/span&gt;
  &lt;span class="c1"&gt;// URL (referencingModule.identifier).&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;referencingModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Download the raw source code.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Instantiate a new module and return it.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SourceTextModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;referencingModule&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Perform the "link" step.&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Evaluation
&lt;/h3&gt;

&lt;p&gt;After the &lt;code&gt;link&lt;/code&gt; step, the original module instance is fully initialised and any exports could already be extracted from its namespace. However, if there are any imperative statements in the code that should be executed, this additional step is necessary.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Executes any imperative code.&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Getting the exports
&lt;/h3&gt;

&lt;p&gt;The very last step is to extract whatever the module exports from its namespace.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// The following corresponds to &lt;/span&gt;
&lt;span class="c1"&gt;// import { random } from 'https://cdn.skypack.dev/lodash-es';&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;random&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="nx"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Providing global dependencies
&lt;/h3&gt;

&lt;p&gt;Some modules may require certain global variables in their execution context. For instance, the &lt;a href="https://www.skypack.dev/view/uuid" rel="noopener noreferrer"&gt;uuid&lt;/a&gt; package depends on &lt;code&gt;crypto&lt;/code&gt;, which is the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API" rel="noopener noreferrer"&gt;Web Crypto API&lt;/a&gt;. Node.js provides an &lt;a href="https://nodejs.org/api/webcrypto.html" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; of this API since version 15 and we can inject it into the context as a global variable.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;webcrypto&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;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;vm&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;vm&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;webcrypto&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;By default, no additional global variables are available to the executed code. It's very important to consider the security implications of giving potentially untrusted code access to additional global variables, e.g. &lt;code&gt;process&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bare module specifiers
&lt;/h2&gt;

&lt;p&gt;The ECMAScript module specification allows for a type of import declaration that is sometimes called "bare module specifier". Basically, it's similar to how a &lt;code&gt;require&lt;/code&gt; statement of CommonJS would look like when importing a module from &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;uuid&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;uuid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Where does 'uuid' come from?&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;Because ECMAScript modules were designed for the web, it's not immediately clear how a bare module specifier should be treated. Currently there is a draft proposal by the W3C community for &lt;a href="https://wicg.github.io/import-maps" rel="noopener noreferrer"&gt;"import maps"&lt;/a&gt;. So far, some browsers and other runtimes have already added support for import maps, including &lt;a href="https://deno.land/manual/linking_to_external_code/import_maps" rel="noopener noreferrer"&gt;Deno&lt;/a&gt;. An import map could look like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"imports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.skypack.dev/view/uuid"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;
&lt;p&gt;Using this construct, the &lt;code&gt;link&lt;/code&gt; function that is used by &lt;code&gt;SourceTextModule&lt;/code&gt; to resolve additional imports could be updated to look up entries in the map:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;imports&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;importMap&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;specifier&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;imports&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;referencingModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Importing core node modules
&lt;/h2&gt;

&lt;p&gt;As we have seen, some modules may depend on certain global variables while others may use bare module specifiers. But what if a module wants to import a core node module like &lt;code&gt;fs&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;We can further enhance the &lt;code&gt;link&lt;/code&gt; function to detect wether an import is for a Node.js builtin module. One possibility would be to look up the specifier in the list of &lt;a href="https://nodejs.org/api/module.html#module_module_builtinmodules" rel="noopener noreferrer"&gt;builtin module names&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;builtinModules&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;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Is the specifier, e.g. "fs", for a builtin module?&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;builtinModules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create a vm.Module for a Node.js builtin module&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 


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

&lt;/div&gt;
&lt;p&gt;Another option would be to use the import map and the convention that every builtin module can be imported with the &lt;code&gt;node:&lt;/code&gt; URL protocol. In fact, Node.js ECMAScript modules already support &lt;code&gt;node:&lt;/code&gt;, &lt;code&gt;file:&lt;/code&gt; and &lt;code&gt;data:&lt;/code&gt; &lt;a href="https://nodejs.org/api/esm.html#esm_urls" rel="noopener noreferrer"&gt;protocols&lt;/a&gt; for their import statements (and we just added support for &lt;code&gt;http/s:&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// An import map with an entry for "fs"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;imports&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="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fs&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:fs/promises&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;specifier&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;imports&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specifier&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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https:&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;// Download code and create a vm.SourceTextModule&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&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:&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;// Create a vm.Module for a Node.js builtin module.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Other possible schemes could be file: and data:&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Creating a vm.Module for a Node.js builtin
&lt;/h3&gt;

&lt;p&gt;So how do we create a &lt;code&gt;vm.Module&lt;/code&gt; for a Node.js builtin module? If we used another SourceTextModule with an &lt;code&gt;export&lt;/code&gt; statement for, e.g. &lt;code&gt;fs&lt;/code&gt;, it would lead to an endlessly recursive loop of calling the &lt;code&gt;link&lt;/code&gt; function over and over again. &lt;/p&gt;

&lt;p&gt;On the other hand, if we use a SourceTextModule with the code &lt;code&gt;export default fs&lt;/code&gt;, where &lt;code&gt;fs&lt;/code&gt; is a global variable on the context, the exported module would be wrapped inside an object with the &lt;code&gt;default&lt;/code&gt; property.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// This leads to an endless loop, calling the "link" function.&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SourceTextModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`export * from 'fs';`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// This ends up as an object like { default: {...} }&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SourceTextModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`export default fs;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&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&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;p&gt;However, we can use &lt;a href="https://nodejs.org/api/vm.html#vm_class_vm_syntheticmodule" rel="noopener noreferrer"&gt;vm.SyntheticModule&lt;/a&gt;. This implementation of &lt;code&gt;vm.Module&lt;/code&gt; allows us to programatically construct a module without a source code string.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Actually import the Node.js builtin module&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imported&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;identifier&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;exportNames&lt;/span&gt; &lt;span class="o"&gt;=&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;imported&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Construct a new module from the actual import&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SyntheticModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;exportNames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;function &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;name&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;exportNames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setExport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;imported&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&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="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;referencingModule&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="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The (still experimental) APIs of Node.js allow us to implement a solution for dynamically importing code from HTTP URLs "in user space". While ECMAScript modules and &lt;code&gt;vm.Module&lt;/code&gt; were used in this blog post, &lt;code&gt;vm.Script&lt;/code&gt; could be used to implement a similar solution for CommonJS modules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loaders&lt;/strong&gt; are another way to achieve some of the same goals. They provide a simpler API and enhance the behaviour of the native &lt;code&gt;import&lt;/code&gt; statements. On the other hand, they are less flexible and they're possibly &lt;em&gt;even more experimental&lt;/em&gt; than &lt;code&gt;vm.Module&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are many details and potential pitfalls to safely downloading and caching remotely hosted code that were not covered. Not to even mention the &lt;strong&gt;security implications&lt;/strong&gt; of running arbitrary code. A more "production ready" (and potentially safer) runtime that uses HTTP imports is already available in &lt;strong&gt;Deno&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That said, it's interesting to see what can be achieved with the experimental APIs and there may be certain use cases where the risks to use them are calculable enough.&lt;/p&gt;
&lt;h2&gt;
  
  
  Complete example
&lt;/h2&gt;

&lt;p&gt;Check out a complete working example on Code Sandbox:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-micro-frontendsdynamic-import-uols2?module=/index&amp;amp;view=editor"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Or find the code in this repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mfellner" rel="noopener noreferrer"&gt;
        mfellner
      &lt;/a&gt; / &lt;a href="https://github.com/mfellner/react-micro-frontends" rel="noopener noreferrer"&gt;
        react-micro-frontends
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Examples for React micro frontends
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Skypack is nice because it offers ESM versions of most npm packages. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>node</category>
      <category>deno</category>
    </item>
    <item>
      <title>Node.js compatibility: Using npm packages in Deno </title>
      <dc:creator>Maximilian Fellner</dc:creator>
      <pubDate>Sat, 26 Dec 2020 22:22:22 +0000</pubDate>
      <link>https://dev.to/mxfellner/node-js-compatibility-using-npm-packages-in-deno-52hh</link>
      <guid>https://dev.to/mxfellner/node-js-compatibility-using-npm-packages-in-deno-52hh</guid>
      <description>&lt;p&gt;Ever since &lt;a href="http://deno.land" rel="noopener noreferrer"&gt;Deno&lt;/a&gt; was released, developers have been busy writing hundreds of native TypeScript modules for it. At least to a certain extent, this effort is an attempt to recreate some of the rich diversity that &lt;strong&gt;Node.js&lt;/strong&gt; and the &lt;strong&gt;npm&lt;/strong&gt; ecosystem have to offer.&lt;/p&gt;

&lt;p&gt;That's not only because Deno's philosophy is different from that of Node.js, but the two JavaScript runtimes are also technically incompatible. Although they both support modern JavaScript and can in principle run the same code, their module loading mechanisms and core APIs are different.&lt;/p&gt;

&lt;p&gt;Node.js uses CommonJS modules and looks up installed packages in the &lt;code&gt;node_modules&lt;/code&gt; directory with the "require" function&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. Deno on the other hand uses ES modules and absolute URLs to download code directly from the web, much like a browser. Reading or writing files and handling HTTP requests also work differently, making it virtually impossible to use an npm package in Deno.&lt;/p&gt;

&lt;p&gt;Thankfully the Deno project has begun to address this limitation, opening up exciting possibilities for code reuse!&lt;/p&gt;

&lt;h1&gt;
  
  
  Deno Node compatibility
&lt;/h1&gt;

&lt;p&gt;The standard library module &lt;a href="https://deno.land/std@0.82.0/node" rel="noopener noreferrer"&gt;deno.land/std/node&lt;/a&gt; offers two important features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An implementation of the &lt;strong&gt;"require"&lt;/strong&gt; function to load CommonJS modules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polyfills&lt;/strong&gt; for the Node.js core APIs (still incomplete).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how it works:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRequire&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;https://deno.land/std@0.82.0/node/module.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;const&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRequire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Require a Node.js polyfill.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt; &lt;span class="p"&gt;}&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="s2"&gt;events&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Require an npm module from `node_modules`.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;constantCase&lt;/span&gt; &lt;span class="p"&gt;}&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="s2"&gt;change-case&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Require a local CommonJS module.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFunction&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="s2"&gt;./my-module&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;To use the Node compatibility library, a few flags must be set:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno run &lt;span class="nt"&gt;--unstable&lt;/span&gt; &lt;span class="nt"&gt;--allow-read&lt;/span&gt; &lt;span class="nt"&gt;--allow-env&lt;/span&gt; main.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's it! One downside is that the results of the "require" function are typed as &lt;code&gt;any&lt;/code&gt;. Unfortunately, the only way to get TypeScript types is to add them manually.&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding types
&lt;/h2&gt;

&lt;p&gt;The solution is quite straightforward: import the types and cast the result of the "require" function. Note that we use &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export" rel="noopener noreferrer"&gt;&lt;code&gt;import type&lt;/code&gt;&lt;/a&gt; to prevent any confusion about what we're importing (there is no runtime code for Deno to load here).&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRequire&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;https://deno.land/std@0.82.0/node/module.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ChangeCase&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;./node_modules/camel-case/dist/index.d.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;const&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRequire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;constantCase&lt;/span&gt; &lt;span class="p"&gt;}&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="s2"&gt;change-case&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;ChangeCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is not the whole story, however. The &lt;code&gt;.d.ts&lt;/code&gt; type declaration files of 3rd party modules will typically make use of bare import specifiers, e.g.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Options&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;pascal-case&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;Deno needs an &lt;a href="https://deno.land/manual/linking_to_external_code/import_maps" rel="noopener noreferrer"&gt;import map&lt;/a&gt; to resolve such specifiers. In a file &lt;code&gt;import_map.json&lt;/code&gt; we can simply declare all the imports and their respective type declaration files, for instance:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"imports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"change-case"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./node_modules/camel-case/dist/index.d.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pascal-case"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./node_modules/pascal-case/dist/index.d.ts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It's not actually necessary to do this for all the imports in the type declaration files of a 3rd party library, only the ones that expose types used in your own code. Undeclared bare specifiers will simply be typed as &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When running Deno the import map file must be provided as a flag:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; deno run &lt;span class="nt"&gt;--import-map&lt;/span&gt; import_map.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unstable&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--allow-read&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--allow-env&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  main.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By the way, with the import map in place, we can also shorten the original type import to just &lt;code&gt;import type ChangeCase from "change-case"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can check out a complete example in this repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mfellner" rel="noopener noreferrer"&gt;
        mfellner
      &lt;/a&gt; / &lt;a href="https://github.com/mfellner/deno-node-compatibility-example" rel="noopener noreferrer"&gt;
        deno-node-compatibility-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Using npm packages in Deno
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  The future
&lt;/h2&gt;

&lt;p&gt;So far, only a small subset of Node.js core API polyfills have been implemented in Deno and it is only possible to reuse npm packages with no or very few dependencies on Node.js itself. &lt;/p&gt;

&lt;p&gt;For instance, &lt;code&gt;http&lt;/code&gt; and &lt;code&gt;https&lt;/code&gt; don't exist yet so one could not use Express.js or any of the other popular web frameworks in Deno.&lt;/p&gt;

&lt;p&gt;Given how much effort and polish has gone into many of the most popular Node.js libraries, it is safe to say that it would be a big win for Deno if it was possible to take advantage of this great collection of code.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Node.js &lt;a href="https://nodejs.org/api/esm.html" rel="noopener noreferrer"&gt;can actually load ES modules&lt;/a&gt; since version 13 but they're not widely used yet. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>node</category>
      <category>deno</category>
      <category>npm</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
