vadimdemedes/ink

Bundle ink without `devtools`

fantua opened this issue · 7 comments

fantua commented

I would like to bundle ink with esbuild using the following config:

bundle: true,
define: {
  'process.env.DEV': 'false'
},
platform: 'node',
format: 'esm'

'process.env.DEV': 'false' should do dead code elimination for this part:

ink/src/reconciler.ts

Lines 26 to 44 in fb66872

if (process.env['DEV'] === 'true') {
try {
await import('./devtools.js');
// eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
} catch (error: any) {
if (error.code === 'MODULE_NOT_FOUND') {
console.warn(
`
Debugging with React Devtools requires \`react-devtools-core\` dependency to be installed.
$ npm install --save-dev react-devtools-core
`.trim() + '\n'
);
} else {
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw error;
}
}
}

But devtools import still presents because we’re not using global process reference. Once I remove this line everything works as expected:

import process from 'node:process';

see evanw/esbuild#3015 for more details

What is the benefit of excluding devtools.js from the resulting bundle?

But devtools import still presents because we’re not using global process reference. Once I remove this line everything works as expected:

This sounds like something esbuild should fix. If they support handling the global process, they should handle the imported one. Open an issue on esbuild instead.

fantua commented

First of all devtools is useful for dev mode only, I don't need it in production bundle.

Benefit of excluding devtools.js from the resulting bundle:

  • decrease bundle size
  • remove extra chunk (esbuild will create new chunk for devtools because of dynamic import)
  • fix for the following error (I don't install react-devtools-core as a dependency):
✘ [ERROR] Could not resolve "react-devtools-core"

    ../../node_modules/ink/build/devtools.js:5:21:
      5 │ import devtools from 'react-devtools-core';
        ╵                      ~~~~~~~~~~~~~~~~~~~~~

  You can mark the path "react-devtools-core" as external to exclude it from the bundle, which will
  remove this error.
fantua commented

This sounds like something esbuild should fix. If they support handling the global process, they should handle the imported one. Open an issue on esbuild instead.

Issue description contains a link to esbuild issue alteady. Basically esbuild supports global variables only evanw/esbuild#3015 (comment).

First of all devtools is useful for dev mode only, I don't need it in production bundle.

react-devtools-core isn't included with Ink and it's an optional peer dependency, so it shouldn't be part of your bundle if you didn't install it yourself.

fix for the following error (I don't install react-devtools-core as a dependency):

esbuild is suggesting a fix there to mark react-devtools-core as an external dependency. Try that.

This sounds like something esbuild should fix. If they support handling the global process, they should handle the imported one. Open an issue on esbuild instead.

Agree with @sindresorhus on this one. If Node.js recommends to import process now, it makes sense for bundlers to handle that scenario.

I came across this issue while trying to bundle my scripts with webpack to package into an executable.

I found that replacing

if (process.env['DEV'] === 'true') {

if (process.env['DEV'] === 'true') {

with if (process.env['NODE_ENV'] === 'development') { fixes the issue for me with webpack. webpack correctly checks the node environment and ignores the devtools.js import and related imports in production builds.

The way the dev tools are initialized (as a top-level await behind an if statement and shipped in with the build you're shipping to users) makes this library difficult to bundle and might be hindering adoption. As is, we need to utilize one of the heftier static analysis tools that can support understanding and removing the dead code if we want to use this in CJS code. Normal ESM/CJS problems, so might not be high on the priority list.

But at a glance, the entire library appears to be sync code except for where we're initializing the dev tools behind an if statement... it almost looks like a mistake that somehow made it into the prod builds.

The fix seems easy, though? Don't ship your dev tools to your users. Have a shim that initializes them before you import the rest of your (CJS) code and run that in development?

For what it's worth, though, thanks for the cool library, and hoping I don't have to switch off it!