<p dir="auto">When bundling code that uses the <code class="notranslate">renderToString</code> method, multiple versions of react-dom are included in the bundle.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import { renderToString } from 'react-dom/server';"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">renderToString</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'react-dom/server'</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">This is the visualised breakdown of the code included in a bundle assembled with <a href="https://esbuild.github.io/" rel="nofollow">esbuild</a> with the following options (it is bundled up for use in a server rather than client):</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{
      plugins: [pnpPlugin()],
      bundle: true,
      entryPoints: [`${routesDir}/${config.relativeFilePath}`],
      external: [
        'aws-sdk', // included in Lambda runtime environment
      ],
      minify: true,
      platform: 'node',
      format: 'cjs',
      target: 'node16.0',
      treeShaking: true,
      sourcemap: true,
      outfile: getOutFileForLambda(config),
      metafile: true,
}"><pre class="notranslate"><code class="notranslate">{
      plugins: [pnpPlugin()],
      bundle: true,
      entryPoints: [`${routesDir}/${config.relativeFilePath}`],
      external: [
        'aws-sdk', // included in Lambda runtime environment
      ],
      minify: true,
      platform: 'node',
      format: 'cjs',
      target: 'node16.0',
      treeShaking: true,
      sourcemap: true,
      outfile: getOutFileForLambda(config),
      metafile: true,
}
</code></pre></div>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/1448524/177215014-bc1caa58-2890-4b46-97d7-d3a0e52c57c1.png"><img src="https://user-images.githubusercontent.com/1448524/177215014-bc1caa58-2890-4b46-97d7-d3a0e52c57c1.png" alt="image" style="max-width: 100%;"></a></p>
<p dir="auto">Note here the following files are included:</p>
<ul dir="auto">
<li><code class="notranslate">react-dom-server-legacy.node.production.min.js</code></li>
<li><code class="notranslate">react-dom-server.node.production.min.js</code></li>
<li><code class="notranslate">react-dom-server.node.development.js</code></li>
<li><code class="notranslate">react-dom-server-legacy.node.development.js</code></li>
<li><code class="notranslate">react-dom.production.min.js</code></li>
<li><code class="notranslate">react-dom.development.js</code></li>
</ul>
<p dir="auto">I would assume only two of these should be required (one for <code class="notranslate">react-dom</code> and one for <code class="notranslate">react-dom-server</code>).</p>
<p dir="auto">Note I carefully cleaned the dependency tree of the project to ensure there is only one version of <code class="notranslate">react</code> and <code class="notranslate">react-dom</code> referenced.</p>
<p dir="auto">The workspace this was tested in was created using Yarn 3.</p>
<p dir="auto">React version: 18.2.0</p>
<h2 dir="auto">Steps To Reproduce</h2>
<ol dir="auto">
<li>Create a file <code class="notranslate">render.ts</code> that contains a call to the renderToString method.</li>
</ol>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import type React from 'react';
import { renderToString } from 'react-dom/server';

renderToString(&lt;div&gt;Hi&lt;/div&gt;);"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-k">type</span> <span class="pl-smi">React</span> <span class="pl-k">from</span> <span class="pl-s">'react'</span><span class="pl-kos">;</span>
<span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">renderToString</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'react-dom/server'</span><span class="pl-kos">;</span>

<span class="pl-s1">renderToString</span><span class="pl-kos">(</span><span class="pl-kos">&lt;</span><span class="pl-smi">div</span><span class="pl-kos">&gt;</span><span class="pl-smi">Hi</span><span class="pl-c1">&lt;</span><span class="pl-c1">/</span>div&gt;<span class="pl-kos">)</span>;</pre></div>
<ol start="2" dir="auto">
<li>Provide this file as the <a href="https://esbuild.github.io/api/#entry-points" rel="nofollow"><code class="notranslate">entrypoint</code></a> to bundle it with esbuild</li>
</ol>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="esbuild render.ts --bundle --metafile=meta.json --platform=node"><pre class="notranslate"><code class="notranslate">esbuild render.ts --bundle --metafile=meta.json --platform=node
</code></pre></div>
<ol start="3" dir="auto">
<li>Visualise <code class="notranslate">meta.json</code> with <a href="https://www.npmjs.com/package/esbuild-visualizer" rel="nofollow"><code class="notranslate">esbuild-visualizer</code></a></li>
</ol>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="esbuild-visualizer --metadata ./meta.json"><pre class="notranslate">esbuild-visualizer --metadata ./meta.json</pre></div>
<h2 dir="auto">The current behavior</h2>
<p dir="auto">When using the <code class="notranslate">renderToString</code> method in a file that is bundled, the following files are included in the bundle.</p>
<ul dir="auto">
<li><code class="notranslate">react-dom-server-legacy.node.production.min.js</code></li>
<li><code class="notranslate">react-dom-server.node.production.min.js</code></li>
<li><code class="notranslate">react-dom-server.node.development.js</code></li>
<li><code class="notranslate">react-dom-server-legacy.node.development.js</code></li>
<li><code class="notranslate">react-dom.production.min.js</code></li>
<li><code class="notranslate">react-dom.development.js</code></li>
</ul>
<h2 dir="auto">The expected behavior</h2>
<p dir="auto">Only one instance of <code class="notranslate">react-dom</code> and <code class="notranslate">react-dom-server</code> should be included in the bundle.</p>
<p dir="auto">Note there is some reference to a legacy dom server in <code class="notranslate">react/server.node.js</code> which maybe causing this issue:</p>
<p dir="auto"><a href="https://github.com/facebook/react/blob/main/packages/react-dom/server.node.js#L15">https://github.com/facebook/react/blob/main/packages/react-dom/server.node.js#L15</a></p>
<p dir="auto">Using destructuring assignment on objects falsely triggers <code class="notranslate">use-exhaustive-deps</code>. For example, I would expect the following not to trigger lint rule:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="const object = { hello: 'world', foo: 'bar' }

useEffect(() =&gt; {
  const { hello } = object
  console.log(hello)
}, [object.hello])"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-s1">object</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> <span class="pl-c1">hello</span>: <span class="pl-s">'world'</span><span class="pl-kos">,</span> <span class="pl-c1">foo</span>: <span class="pl-s">'bar'</span> <span class="pl-kos">}</span>

<span class="pl-en">useEffect</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-kos">{</span> hello <span class="pl-kos">}</span> <span class="pl-c1">=</span> <span class="pl-s1">object</span>
  <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s1">hello</span><span class="pl-kos">)</span>
<span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-kos">[</span><span class="pl-s1">object</span><span class="pl-kos">.</span><span class="pl-c1">hello</span><span class="pl-kos">]</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">The linter insists I pass <code class="notranslate">object</code> to the dependency array which is problematic since objects are compared by reference instead of value. I could destructure out of the useEffect block but this can cause naming collisions for bigger components/hooks. I can also assign variables the old fashioned way but that conflicts with our coding style.</p>
<p dir="auto">The linting rule also has trouble with safety operator:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="const object = { hello: 'world', foo: 'bar' }

useEffect(() =&gt; {
  const hello = object?.hello
  console.log(hello)
}, [object.hello])"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-s1">object</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> <span class="pl-c1">hello</span>: <span class="pl-s">'world'</span><span class="pl-kos">,</span> <span class="pl-c1">foo</span>: <span class="pl-s">'bar'</span> <span class="pl-kos">}</span>

<span class="pl-en">useEffect</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-s1">hello</span> <span class="pl-c1">=</span> <span class="pl-s1">object</span><span class="pl-kos">?.</span><span class="pl-c1">hello</span>
  <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s1">hello</span><span class="pl-kos">)</span>
<span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-kos">[</span><span class="pl-s1">object</span><span class="pl-kos">.</span><span class="pl-c1">hello</span><span class="pl-kos">]</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">will cause it to ask for object in the dependency array.</p>