question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`failed to transpile` `tslib.es6.js` after update to `v0.30.0`

See original GitHub issue

What happens and why it is wrong

failed to transpile '[...]/node_modules/tslib/tslib.es6.js'

rollup-plugin-typescript2 v0.29.0 works fine, v0.30.0 introduces this error.

The setup is a bit complex because it happened as part of Rollpkg. It happens when tsconfig target: es5 (so tslib is needed). I was alerted to it from this issue. Rollpkg v0.5.0 has the bug, v0.5.1 fixes it by downgrading rollup-plugin-typescript2 to v0.29.0.

I’m using TypeScript v4.2.3.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
agilgur5commented, Jun 28, 2022

So, I took a look at this issue and this was a doozy to figure out, but eventually got to the root cause

initial investigation

The setup is a bit complex because it happened as part of Rollpkg. It happens when tsconfig target: es5 (so tslib is needed). I was alerted to it from this issue. Rollpkg v0.5.0 has the bug, v0.5.1 fixes it by downgrading rollup-plugin-typescript2 to v0.29.0.

This took a decent bit more time & effort to investigate as this is not a minimal reproduction – in general, a minimal repro makes it significantly easier to investigate any issue. Given that most maintainers are volunteers with severely limited time, making it as easy possible for them to investigate should be the goal. The permalinks that you gave (and which are still available!) are still helpful that being said.

It so happens that I solo-maintained TSDX for ~1.5 years (that’s how I originally became a contributor here), so reading through rollpkg’s code was measuredly simpler, as they have somewhat similar layouts.

Sidebar: TSDX comparison flaws

(Also your TSDX comparison is flawed, as TSDX actually uses both TypeScript (via rpt2) and Babel (basically: ts -> esnext -> preset-env), and, again, that’s how I found myself here.

Otherwise, the comparison is more or less accurate. See https://github.com/jaredpalmer/tsdx/issues/634 and https://github.com/jaredpalmer/tsdx/issues/635 as the two main RFCs I was pushing to get out of the configuration and compatibility hell. size-limit was (partly) intentional though, given the various trade-offs I analyzed. One was that there’s no reason that stats should be tied to the build or slow it down).

Anyway, there were two things that stood out to me initially:

  1. The error is failing to transpile tslib, which, well, shouldn’t be transpiled in the first place, for a number of reasons
    • For instance, it’s in node_modules and should be an external
  2. This only occurred after updating to 0.30.0
    • As I’ve investigated in a number of different issues, the main change there was a breaking dependency upgrade of @rollup/pluginutils to v4, which included https://github.com/rollup/plugins/pull/517
    • pluginutils is responsible for filtering, i.e. include and exclude in most Rollup plugins’ options.
    • Can read https://github.com/ezolenko/rollup-plugin-typescript2/issues/216#issuecomment-1140024487 and linked comments for more details, but v4 removed the process.cwd() that was added in front of any glob patterns given to it
    • Which means that files outside of the project dir could now be included without changing the default settings. So this change ended up unintentionally solving lots of monorepo issues. And also caused this issue, as it means things like node_modules can also be included by default.
    • This is most plugins’ default too, and is normally not an issue. Especially as unbundled deps get listed out in externals, and because rpt2’s default include only has TS files, which are not often present and not meant to be import’d from node_modules

You can probably see where I’m going from here, but therein lies the problem.

root cause analysis

rollpkg’s tsconfig sets allowJs: true and sets rpt2’s include to also process JS files.

Notably, what’s missing is a changed exclude. rpt2’s docs do point out that you probably want to add node_modules to your exclude if you’re setting allowJs and includeing JS files.

(Your external configuration is also a bit problematic in that it’ll miss submodule deps, similar to https://github.com/stevenbenisek/rollup-plugin-auto-external/issues/16. I personally use rollup-plugin-node-externals, which doesn’t have this issue)

So, with that, the problem becomes a lot more straightforward. HashLink.jsx gets processed by rpt2 (logged on this line) and it returns this code at the top of the file:

import { __rest } from "tslib";
import React from "react";
import PropTypes from "prop-types";
import { Link, NavLink } from "react-router-dom";

Note, of course, the presence of tslib.

So when rpt2 gives this ESM code to Rollup, it parses it and tries to resolve, and if configured to do so, transform, all the imports. Given the lack of tslib in your deps, this means that rollpkg doesn’t add it to your externals list, meaning that tslib ends up getting processed by your Rollup plugins. And, given the lack of exclude, that means rpt2 tries processing tslib.

So the solution therein is to add tslib to your deps. You probably also want to add node_modules to rollpkg’s rpt2’s plugin options exclude. The specific glob that worked for me during testing was exclude: ['**/node_modules/**/*'].

what about the lacking error though?

Surprising that there are no other errors, just failed to transpile. Usually there are typescript errors (semantic or diagnostic) printed before that, which caused typescript language service to not emit output .

I dug a bit more to really understand this though, in particular as the lack of syntactic or semantic errors is still pretty strange. This is where things start to get complicated… especially as we get into the lacking TS Compiler docs 😕

The failed to transpile error message means that rpt2 hit what it currently considers a fatal error somewhere. This results in TS skipping emit of files.

Normally, this is caused either by a compiler option error (i.e. tsconfig configuration issue) or a syntactic or semantic error (i.e. type-checking issue). The fact that neither was printed out in this case is strange, and often indicative of a bug.

I did some logging and that did not make things any less confusing, unfortunately…

emitSkipped and no files, but id clearly exists:

rpt2: transpiling '/rpt2-issue-264/node_modules/tslib/tslib.es6.js'
{
  outputFiles: [],
  emitSkipped: true,
  diagnostics: [],
  exportedModulesFromDeclarationEmit: undefined
}

no semantic or syntactic errors (which is to be expected, given that this is compiled tslib helper code):

[]
[]

snapshot exists and is correct (matches the exact source code of tslib.es6.js):

StringScriptSnapshot {
  text: '/*! *****************************************************************************\r\n' +
    'Copyright (c) Microsoft Corporation.\r\n' +
    '....'
}

So that’s odd. I’ve never seen emitSkipped in a scenario like this (and I don’t think ezolenko has either).

figuring out emitSkipped

So I decided to look into emitSkipped in more detail.

Unfortunately, as usual, the TS Compiler API Docs don’t elaborate in any way on this. It’s just used in 2 examples there, and that’s what most TS Compiler integrations base their implementation on, including rpt2. Based on that example, I didn’t see anything strange about rpt2’s usage (which I’ve already read through dozens of times too).

So I did some more searching about emitSkipped. I stumbled upon this issue in ts-node: https://github.com/TypeStrong/ts-node/issues/693 . That happened to get some explanatory comments on it literally yesterday. Per that comment, it turns out this a rootDir issue.

From the TSConfig Reference on rootDir:

Note that TypeScript will never write an output file to a directory outside of outDir, and will never skip emitting a file. For this reason, rootDir also enforces that all files which need to be emitted are underneath the rootDir path.

So, it turns out (basically through reverse-engineering as the TS Compiler Docs don’t remotely go into this), that a compiled file will have emitSkipped set when that file is outside of the rootDir.

And indeed, rollpkg (similarly to TSDX), sets a default rootDir of ./src. ./node_modules/tslib/tslib.es6.js is clearly outside of ./src and so outside of your rootDir and hence its emit gets skipped.

But normally a rootDir issue will throw a compiler options error (c.f. https://github.com/jaredpalmer/tsdx/issues/638#issue-586338455), such as:

rpt2: options error TS6059: File '/project/test/testUtils.ts' is not under 'rootDir' '/project/src'. 'rootDir' is expected to contain all source files.

But it doesn’t here.

Well that’s because TS doesn’t know what all the files are ahead-of-time. tsc only reads the tsconfig include and bases it off that. But with Rollup and plugins, your files get transformed along the way. In this case, the tslib import was added during compilation (wasn’t there before) and then the lack of external and plugin exclude meant that tslib got passed to rpt2. So the compiler, at run-time, is given a file outside of rootDir that it didn’t know about beforehand. There’s no compiler options error as this is after parsing the compiler opts and not expected based on the tsconfig.json. So the compiler just returns an empty file with emitSkipped … which apparently can indicate that there’s a previously undetected rootDir issue that isn’t documented in the TS Compiler API docs.

Root cause found.

next steps

For @rafgraph , the next steps are fairly straightforward, add tslib to deps in react-router-hash-link, and, ideally, exclude: ['**/node_modules/**/*'] in rollpkg when it configures rpt2’s plugin options. Could also add tslib manually to externals in rollpkg. (maybe modify the TSDX comparison section too 😉 )

For rpt2, the next steps are more opaque. This is the only time this issue has occurred too, so it’s pretty rare.

ts-node addressed this in an intriguing way in https://github.com/TypeStrong/ts-node/pull/1629 which implements https://github.com/TypeStrong/ts-node/issues/1345. Basically, when emitSkipped, ts-node will switch to the simpler transpileModule API, which just does TS -> JS with no type-checking (i.e. similar to Babel and isolatedModules).

I’m not sure if that is ideal behavior for rpt2 though, which does not have as general a use-case as ts-node. rpt2 is only meant to compile projects (not arbitrary code, which is one of ts-node’s capabilities and purposes) and so should respect tsconfig.json as much as possible within the constraints of Rollup semantics.

This does hit a Rollup boundary, but I think in this case, throwing a rootDir compiler options error would be the most accurate behavior and is closest to what tsc would do, which we try to follow to aim for the “principle of least surprise”.

I pasted the text of the rootDir error above, which we could copy+paste, but ideally, we should pull that from the TS API somewhere, which would also make it more resilient to error code / error message changes.

The one caveat is that given that emitSkipped is mostly undocumented, it’s difficult to tell if there are other scenarios where emitSkipped would be hit but there are no syntactic or semantic errors. The only other one I’ve heard of so far (have not confirmed) is when TS skips emit instead of overwriting an existing file, which is usually only hit if allowJs and no outDir. (I also checked the TS source code references to emitSkipped and that did not help my understanding much… there’s only a dozen or so references in the source though (not including tests etc), that being said).

So what we could do is, if emitSkipped and no diagnostics, check the id of the file currently being processed (i.e. its path) against the rootDir, which we have access to. If it’s not within rootDir, we could conclude that it is indeed a rootDir issue, and throw the rootDir error. Basically re-implementing some simple TS logic. Otherwise, we leave it as just failed to transpile, as it would therefore be an unknown error (as in, if it is none of syntactic, semantic, or rootDir error).

Low priority given the rarity of the issue and that this change just improves DX (it’s not a bugfix in that sense, more a feature), but, that being said, it should be fairly simple to implement.

1reaction
ezolenkocommented, Mar 23, 2021

Surprising that there are no other errors, just failed to transpile. Usually there are typescript errors (semantic or diagnostic) printed before that, which caused typescript language service to not emit output .

Read more comments on GitHub >

github_iconTop Results From Across the Web

Developers - Fails to transpile tslib.es6.js - - Bountysource
rollup-plugin-typescript2 v0.29.0 works fine, v0.30.0 introduces this error. The setup is a bit complex because it happened as part of Rollpkg.
Read more >
Project dependencies - D2iQ Help Center
Vendor Name Version License Id github.com/blang/semver v4 v4.0.0 MIT github.com/go-openapi spec v0.19.3 Apache-2.0 github.com/google go-cmp v0.5.4 ...
Read more >
JavaScript Packages - Raspberry Connect
First get an updated package list by entering the following command in to terminal if this has not been done today sudo apt...
Read more >
Open Source Used In Firepower 7.0.0 - Cisco
In your requests please include the following reference number 78EE117C99- ... 1.19 vault-plugin-secrets-azure v0.5.2-0.20190814210135-54b8afbc42ae.
Read more >
rollup-plugin-typescript2 - bytemeta
`failed to transpile` `tslib.es6.js` after update to `v0.30.0`. yaldram ... Syntactically incorrect JS output with `declare const` globals -- due to Rollup ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found