Skip to content

Name colours (e.g. "red", "blue") no longer work in 5.4.0 in browser if global process variable is defined #4995

@krassowski

Description

@krassowski

Details

  • Browser and browser version: all
  • xterm.js version: 5.4.0

Steps to reproduce

  1. Define a terminal with a theme like:
const term = new Terminal({theme: {
  background: 'black',
  foreground: 'blue'
}});
  1. Try to run it in a webpack served application with a process fallback such as:
module.exports = {
  resolve: {
    fallback: {
      process: require.resolve('process/browser')
    }
  }
}

Se no error, and no warning but named colours no longer work.

This was introduced by #4851 which changed heuristic for detecting whether xterm.js is running in a browser or in a Node,js environment. It now simply looks for whether a process variable is defined, which makes isNode incorrectly true in many browser environments. These means that ctx is never defined here:

export namespace css {
let $ctx: CanvasRenderingContext2D | undefined;
let $litmusColor: CanvasGradient | undefined;
if (!isNode) {
// This is guaranteed to run in the first window, so document should be correct
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
const ctx = canvas.getContext('2d', {
willReadFrequently: true
});
if (ctx) {
$ctx = ctx;
$ctx.globalCompositeOperation = 'copy';
$litmusColor = $ctx.createLinearGradient(0, 0, 1, 1);
}

and then toColor short-circiuts due to lack of $ctx here:

// Validate the context is available for canvas-based color parsing
if (!$ctx || !$litmusColor) {
throw new Error('css.toColor: Unsupported css format');
}

Note that presence of process in webpack-served browser apps is a common concern - see the highly up-voted first comment on: https://stackoverflow.com/a/34550964/6646912

I found that many proposed solutions stop working if the code has been webpack'd, because webpack defines all kinds of process, module, require, etc symbols. window usually still works, unless of course you additionally also want to detect being run from a webworker, where there is no window.

Now process/browser shim is actually easy to detect because it has a .browser attribute and it's title is "browser". So, checking for: process.title !== 'browser' && !process.browser would already solve this for me.

However, something to consider is whether rather than checking for isNode in:

if (!isNode) {
// This is guaranteed to run in the first window, so document should be correct
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
const ctx = canvas.getContext('2d', {
willReadFrequently: true
});

would it be better to just try-catch here? It (maybe naively) appears to me that what matters is not the fact of running on Node or not, but the fact of whether canvas context can be obtained or not.

What do you think is the best way forward?

Metadata

Metadata

Assignees

Labels

type/bugSomething is misbehaving

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions