Parcel: Implement TypeScript resolver plugin

Created on 26 Jul 2020  ·  4Comments  ·  Source: parcel-bundler/parcel

TypeScript supports some additional features in its resolver on top of the Node resolution algorithm. These are configured in tsconfig.json.

  • baseUrl - a root directory from which to resolve non-relative paths, in addition to node_modules. See also: #202.
  • paths - additional directories, relative to baseUrl, that should also be searched.
  • rootDirs - virtual directories that relative paths can be resolved from

There's also the legacy module resolution mode that TS supports. Not sure if that's something we should also support, but I guess someone might still use it. 🤷

Implementation

These resolution features should be supported in Parcel for imports declared in .ts or .tsx files. This can be done via a new resolver plugin, included in the default config: @parcel/resolver-typescript. This resolver should look at the sourcePath property of the dependency, and if it has a .ts or .tsx extension, it should resolve using the TS compiler API's resolveModuleName method. It should use a custom ModuleResolutionHost that ensures the Parcel file system is used instead of the Node one. This can be created using the @parcel/ts-utils package, which already includes an FSHost package implementing much of the required interface.

If a module is not resolved, or the source file is not a .ts or .tsx file, then the resolver should return null. This will then fall back to the default Parcel resolver, which will handle Parcel specific features like aliases.

Open questions

  • We'll need to determine whether we can properly track all of the files that the TS resolver reads so we can invalidate the Parcel cache properly. This is a work in progress for the default resolver as well.
  • It's unclear how the TS resolver should interact with Parcel features like aliases and named pipelines (e.g. url:./foo.jpg to import an image as a url). Theoretically we could fall back to the default resolver if TS doesn't find anything, but what if you alias react to preact but react is found by the TS resolver?
Feature RFC TypeScript ✨ Parcel 2

Most helpful comment

Importing images, CSS, etc. from TS-based UI components seems like it‘s fairly common, and should be supported by Parcel. Also other languages that TS doesn’t natively understand like .vue and .svelte. I believe it’s possible to build TS language service extensions to handle these eg https://github.com/mrmckeb/typescript-plugin-css-modules

All 4 comments

In response to the open questions:

  1. From the TS compiler API docs, it's possible to use a custom ModuleResolutionHost that implements fileExists and readFile. With this, it should be possible to track every file read by resolveModuleName.
  2. IDEs will complain about unknown import syntax when using import url from 'url:./foo.jpg', and there is nothing Parcel can do to change that. Therefore, I would think that no Parcel users would use a Parcel-specific import directly from TS. Parcel imports from TS projects will typically either use NodeJS require, or be imported from a JS file that can then be imported by TS (with an accompanying .d.ts). So Parcel should resolve requires from TS and let the TS resolver resolve imports. That is, if it is possible to differentiate require and import.

Importing images, CSS, etc. from TS-based UI components seems like it‘s fairly common, and should be supported by Parcel. Also other languages that TS doesn’t natively understand like .vue and .svelte. I believe it’s possible to build TS language service extensions to handle these eg https://github.com/mrmckeb/typescript-plugin-css-modules

@101arrowz the syntax issue is fairly simple to solve just configure a declaration file with something like this (like Devon already mentioned this is fairly common, I used to do it all the time for svg to react transformers):

declare module 'url:*' {
  const url: string;
  export default url;
}

and it will no longer throw syntax errors, as this is a standard Parcel feature it's probably a good idea to write a config/plugin for people in the docs that really supports everything as this declaration file trick I just mentioned does break the path autocomplete.

I was not aware of the existence of TS language service plugins, which would likely be the best solution for custom Parcel imports. I'd be willing to help with the implementation.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

algebraic-brain picture algebraic-brain  ·  3Comments

dsky1990 picture dsky1990  ·  3Comments

davidnagli picture davidnagli  ·  3Comments

urbanhop picture urbanhop  ·  3Comments

jzimmek picture jzimmek  ·  3Comments