<?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: Plasmo</title>
    <description>The latest articles on DEV Community by Plasmo (@plasmo).</description>
    <link>https://dev.to/plasmo</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%2Forganization%2Fprofile_image%2F5675%2F730d7c50-dc22-4966-9cca-bdf3eadcaa11.png</url>
      <title>DEV Community: Plasmo</title>
      <link>https://dev.to/plasmo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/plasmo"/>
    <language>en</language>
    <item>
      <title>HOWTO: Injecting UI into Website with Browser Extension</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Fri, 22 Jul 2022 16:17:00 +0000</pubDate>
      <link>https://dev.to/plasmo/injecting-ui-into-website-with-browser-extension-quickly-and-safely-2o85</link>
      <guid>https://dev.to/plasmo/injecting-ui-into-website-with-browser-extension-quickly-and-safely-2o85</guid>
      <description>&lt;h2&gt;
  
  
  TL,DR:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create plasmo inject-ui
&lt;span class="nb"&gt;cd &lt;/span&gt;inject-ui
&lt;span class="nb"&gt;touch &lt;/span&gt;content.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;content.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Overlay&lt;/span&gt; &lt;span class="o"&gt;=&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;(&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;HELLO WORLD&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Overlay&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load the extension in Chrome, refresh and you should see &lt;code&gt;HELLO WORLD&lt;/code&gt; injected into the top of the webpage.&lt;/p&gt;




&lt;h2&gt;
  
  
  Explanations
&lt;/h2&gt;

&lt;p&gt;Browser extensions can inject DOM elements into a website using a content script. However, the injected element might inherit the website's style without proper encapsulation. This is often undesirable for any site-agnostic browser extension.&lt;/p&gt;

&lt;p&gt;There are 3 solutions to the problem above:&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Render the element with a style tag that does &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/unset"&gt;css unset&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;A&lt;/code&gt; is often seen employed by ad. It works well for self-contained, simple components that render images. However, it is very hard to leverage a design system that has inherited styling, since the unset cascades down. Unless you have a dedicated style injection scheme, it is very difficult to use and the extra style tag makes the code not very clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  B. Render the element inside &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe"&gt;an iframe&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;B&lt;/code&gt; isolates the element well and is the go-to technique of many old browser extensions. However, the iframe container can be hard to work with when trying to blend the injected component seamlessly into the website. Iframe's elements are nested inside an inner document within its frame, with its own head and body. This makes it tricky to style and control elements inside the iframe, as well as align them with the elements of the website.&lt;/p&gt;

&lt;h3&gt;
  
  
  C. Render the element inside a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM"&gt;Shadow DOM&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;C&lt;/code&gt; is the best technique for web extension. Introduced as the key part of the web component API, the idea is that the shadow DOM is a separate DOM attached to the underlying main DOM. Nothing inside it can affect the main world. The Plasmo framework uses this technique behind the scene to enable seamless injection of React component into any webpage. We call this feature "content script UI."&lt;/p&gt;

</description>
      <category>extension</category>
      <category>chrome</category>
      <category>typescript</category>
      <category>plasmo</category>
    </item>
    <item>
      <title>Building a Modern React Chrome Extension with a New Framework</title>
      <dc:creator>stefàn</dc:creator>
      <pubDate>Tue, 31 May 2022 13:59:14 +0000</pubDate>
      <link>https://dev.to/plasmo/building-a-modern-react-chrome-extension-with-a-new-framework-4ho1</link>
      <guid>https://dev.to/plasmo/building-a-modern-react-chrome-extension-with-a-new-framework-4ho1</guid>
      <description>&lt;p&gt;When I first started building Chrome extensions, I was so annoyed with the boilerplate. &lt;/p&gt;

&lt;p&gt;It was frustrating to configure the &lt;code&gt;manifest.json&lt;/code&gt;, pointing it to the correct files. You had to read at least 4 blog posts to figure out how to do it correctly. The annoyance compounded if you tried to use modern JavaScript frameworks like React. Now you needed to deal with Webpack, and figure out how that played into the &lt;code&gt;manifest.json&lt;/code&gt; story. &lt;/p&gt;

&lt;p&gt;We decided to tackle this problem by building a framework for browser extension development called &lt;a href="https://docs.plasmo.com" rel="noopener noreferrer"&gt;Plasmo&lt;/a&gt;. It's a different way of thinking about browser extensions, and if you're used to building extensions, some things might look a bit weird.&lt;/p&gt;

&lt;p&gt;If you want to follow along, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dlx plasmo init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the directory &lt;code&gt;plasmo init&lt;/code&gt; generated, you might notice there is no &lt;code&gt;manifest.json&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%2Fqg3xl8kil86s15xqkzch.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%2Fqg3xl8kil86s15xqkzch.png" alt="Plasmo directory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is one of the key features of the Plasmo Framework -- we auto-generate the &lt;code&gt;manifest.json&lt;/code&gt; so you can focus on building cool stuff rather than caring about where to point &lt;code&gt;content_scripts&lt;/code&gt; to, and what the schema format should look like.&lt;/p&gt;

&lt;p&gt;The idea is simple: you add a file called &lt;code&gt;popup.tsx&lt;/code&gt; exporting a React component, and Plasmo will understand it's a popup page. It'll register it in the manifest and write the code to automatically mount the component into your popup view.&lt;/p&gt;

&lt;p&gt;The same is true for &lt;code&gt;content.ts&lt;/code&gt;, &lt;code&gt;background.ts&lt;/code&gt;, and &lt;code&gt;options.tsx&lt;/code&gt;. The framework understands what these files are, and automatically builds the manifest with them in mind. &lt;/p&gt;

&lt;p&gt;If you have multiple scripts, you can use &lt;code&gt;contents/&lt;/code&gt;, &lt;code&gt;options/&lt;/code&gt;, and &lt;code&gt;popups/&lt;/code&gt; directories to get the same effect. &lt;/p&gt;

&lt;h2&gt;
  
  
  Key Principles:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  No manifest.json file
&lt;/h3&gt;

&lt;p&gt;We strongly believe the manifest.json file is a &lt;a href="https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/" rel="noopener noreferrer"&gt;leaky abstraction&lt;/a&gt;. That's why we built the framework to generate as much of the manifest as possible. &lt;/p&gt;

&lt;p&gt;We've still got a bit of a way to go, but we've automated a large chunk of it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  It's good to have opinions
&lt;/h3&gt;

&lt;p&gt;This framework is not for everybody, and that's completely okay. Our goal is not to make a framework that caters to everyone's needs. Instead, we're focusing on people who want to build production-grade extenisons using React quickly. &lt;/p&gt;

&lt;p&gt;If someone wanted to build a minimalist extension that used vanilla Javascript, this framework would not be for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  MV3 Only
&lt;/h3&gt;

&lt;p&gt;Manifest version 3 is the future. Let's embrace it and build good tooling around it to enable people to build amazing products. &lt;/p&gt;

&lt;h2&gt;
  
  
  Docs
&lt;/h2&gt;

&lt;p&gt;Check out our &lt;a href="https://docs.plasmo.com" rel="noopener noreferrer"&gt;docs&lt;/a&gt; to see other cool features we have. We're constantly iterating and improving, so if you have feedback, would love to hear it! &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>HOWTO: Consuming CJS in a Typescript module</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Wed, 26 Jan 2022 12:36:00 +0000</pubDate>
      <link>https://dev.to/plasmo/consuming-cjs-in-a-typescript-module-5402</link>
      <guid>https://dev.to/plasmo/consuming-cjs-in-a-typescript-module-5402</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.plasmo.com/"&gt;Plasmo&lt;/a&gt; we leverage Typescript for our web projects.&lt;br&gt;
CJS project like &lt;a href="https://github.com/ralyodio/humanparser"&gt;humanparser&lt;/a&gt; would have example 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;human&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;humanparser&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;fullName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mr. William R. Hearst, III&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;attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;human&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parseName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrs&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;require&lt;/code&gt; statement is how we import the &lt;code&gt;humanparser&lt;/code&gt; module into a CJS codebase. This statement can be translated into TypeScript/ESM 2 ways:&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;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR&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="nx"&gt;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Which is it?
&lt;/h2&gt;

&lt;p&gt;The answer lies in the source code of the &lt;code&gt;humanparser&lt;/code&gt; module itself. This is an artifact from the evolution of ES, from ES3-&amp;gt; ES5 -&amp;gt; ES6 and beyond (now ESM). There were a couple of ways a module could be exported. &lt;/p&gt;

&lt;p&gt;The first, commonly used during the transition between ES3 -&amp;gt; ES5 (early nodejs days), was to assign an entry function or object into &lt;code&gt;module.exports&lt;/code&gt; global:&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;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;stuff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;module.exports&lt;/code&gt; global was used to bridge into the &lt;code&gt;require&lt;/code&gt; statement. Because &lt;code&gt;module.exports&lt;/code&gt;  represent "everything" that was exported from this module, we must use the import all statement:&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;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;*&lt;/code&gt; represents the &lt;code&gt;module.exports&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Another way, which occurred during the transition between ES5-&amp;gt;ES6, is to export a &lt;code&gt;default&lt;/code&gt; property as the entry for your module:&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;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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stuff&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This assigned &lt;code&gt;stuff&lt;/code&gt; into the &lt;code&gt;defaults&lt;/code&gt; property exported by the module. The reason why this was done is because in ES6, when doing:&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="nx"&gt;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is actually importing the &lt;code&gt;default&lt;/code&gt; props exported by a module. (The export statement in ES6 would be: &lt;code&gt;export default stuff&lt;/code&gt;). The import statement above is doing something like this in equivalent CJS code:&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;humanParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, back to &lt;code&gt;humanparser&lt;/code&gt;'s source code, their export statement looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const parser = module.exports = {};
parser.parseName = function(){}
parser.getFullestName = (str) =&amp;gt; {}
parser.parseAddress = (str) =&amp;gt; {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because there's no &lt;code&gt;default&lt;/code&gt; prop being exported, we can import the parser two ways, either importing the whole object:&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;parser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR, importing the props that was exported separately:&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;parseName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseAddress&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Personally, I like to import the named export, it helps with code intelligent, and I don't have to deal with the import all module namespace issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Back Story
&lt;/h2&gt;

&lt;p&gt;Back in the olden day, pre-2015 to be exact, where angular.js were still trendy, react was still the new kid in the block, and people were comparing Corodva phonegap to react native, there was a transition from ES3/ES5 (commonJS or CJS) to ES6 (ES2015, or ESM, or MJS - modulejs). I suspect whoever named the extension was a huge fan of the late pop king.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cautions
&lt;/h2&gt;

&lt;p&gt;If you are looking at new projects, be cautious of pure ESM module. They will only allow you to import them with:&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="nx"&gt;mod&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;module-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tricky part is that, your project must also be a module - i.e, it cannot be compiled into common js (which converted all &lt;code&gt;import&lt;/code&gt; statement into cjs &lt;code&gt;require&lt;/code&gt; call). It must be an MJS/ecmascript module file (with the .mjs extension) OR that your &lt;code&gt;package.json&lt;/code&gt; have specified the module property. Otherwise, it would simply fail to compile, and you won't be able to import it using require because ESM code looks like this:&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;stuff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of 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="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;stuff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the CJS example, &lt;code&gt;module.exports&lt;/code&gt; are bridged into the &lt;code&gt;require&lt;/code&gt; statement for importing in other modules. Meanwhile, in the ESM example, the &lt;code&gt;stuff&lt;/code&gt; is being exported by the &lt;code&gt;export&lt;/code&gt; statement , and thus can only be imported via the import statement.&lt;/p&gt;

&lt;p&gt;The dilemma here is that if you're using TypeScript and was hoping that it would play well with ESM only module, you are in for some sour candy - it does not. Typescript compiler doesn't yet care if a module it imported is ESM or not -  it converts all to CJS import unless you configured it properly. You would also need to tell nodejs to use an experimental flag when running your compiled code: &lt;a href="https://nodejs.org/api/esm.html#customizing-esm-specifier-resolution-algorithm"&gt;https://nodejs.org/api/esm.html#customizing-esm-specifier-resolution-algorithm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;P.s: this post is a brain-dump. If it's useful, you're welcome. If not, here's the MIT license for this otherwise unreadable post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Copyright 2022 L❤☮🤚

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
