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.ts
to run themod.ts
code 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/[email protected]/dist/es/rollup.browser.js:11:65715) at ja (https://unpkg.com/[email protected]/dist/es/rollup.browser.js:11:325076) at async Qa.loadEntryModule (https://unpkg.com/[email protected]/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/[email protected]/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
null
and either theimporter
isundefined
, thesource
is 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
importer
isundefined
then 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
.