This instructions are for reproducing in Deno. Please note that the same code snippet will also reproduce the issue in any modern browser which supports ESM, namely via <script type="module">.
-
Install Deno following the installation instructions for your platform;
-
Execute
deno run https://gist.githubusercontent.com/cmorten/fdffbd9ce521b6436f5fcbce429e752d/raw/d20036022c30ea8011def64a741aa82155c2afff/mod.tsto run themod.tscode in this gist. -
Observe that the rollup browser distribution throws the error:
error: Uncaught TypeError: Cannot read property 'split' of undefined at Et (https://unpkg.com/rollup@2.38.0/dist/es/rollup.browser.js:11:65715) at ja (https://unpkg.com/rollup@2.38.0/dist/es/rollup.browser.js:11:325076) at async Qa.loadEntryModule (https://unpkg.com/rollup@2.38.0/dist/es/rollup.browser.js:11:334442) at async Promise.all (index 0)
-
The error is thrown in https://github.com/rollup/rollup/blob/master/browser/path.ts#L61 where there is an attempt to call
.split()on the output ofpaths.shift(). -
The above code has made use of the non-null assertion operator to insist that the output of
paths.shift()is non-null and non-undefined, noting that it is a possibility given[].shift() === undefined. -
We can find the transpiled version of this
resolve()function code in https://unpkg.com/rollup@2.38.0/dist/es/rollup.browser.js on line 11 column 65715 which is prettified below for ease:function Et(...e) { let t = e.shift().split(/[/\\]/); return ( e.forEach((e) => { if (dt(e)) t = e.split(/[/\\]/); else { const s = e.split(/[/\\]/); for (; "." === s[0] || ".." === s[0]; ) { ".." === s.shift() && t.pop(); } t.push.apply(t, s); } }), t.join("/") ); }
We can see that the result of
let resolvedParts = paths.shift()!.split(/[/\\]/);islet t = e.shift().split(/[/\\]/);with no protection against the output ofpaths.shift()(equiv.e.shift()) beingundefined. -
In https://github.com/rollup/rollup/blob/master/src/utils/resolveId.ts#L31 we observe Rollup's logic for handling the resolution of module ids. Specifically, if plugins return
nulland either theimporterisundefined, thesourceis an absolute path or the source starts with.(relative path) then Rollup uses someresolve()logic to derive a module id. -
In this logic, if the
importerisundefinedthen the code callsresolve()without any arguments. In NodeJS this is valid and is the equivalent of callingresolve("./")effectively returning the current working directory. -
However, in the browser implementation of Rollup we have seen above that the arguments passed to
resolve()are used inpaths.shift()!.split(/[/\\]/). If no arguments are provided thenpaths === []and thereforepaths.shift() === undefined, resulting in the error we have seen above as.split()cannot be called on the value ofundefined. -
This will occur for the browser distribution for entry modules and potentially a few other use-cases for external modules.
-
The expected behaviour should be a deliberate and descriptive Rollup thrown error (e.g. entry module does not exist), not an
Uncaught TypeError.