LeDDGroup / typescript-transform-paths

Transforms module resolution paths using TypeScript path mapping and/or custom paths
MIT License
465 stars 22 forks source link

[Feature] Transform paths of svg files #144

Open axedre opened 2 years ago

axedre commented 2 years ago

Hi, and thanks for your typescript-transform-paths plugin, it's really helpful in a monorepo context to resolve imports specified as import Something from '@namespace/some/path/Something' while compiling. However, it would be even more helpful if it could resolve default imports of svg files, and I'll elaborate. Currently in my source code I can import svgs like so:

// in `/home/axedre/repo/projects/sdk/src/Component/index.tsx`, for instance:
import Warning from '@namespace/some/path/icons/alert/warning.svg';
import SomeOtherComponent from '@namespace/some/other/path/SomeOtherComponent';
// ...

Now, while the second import gets correctly compiled to require('<relative_path_to>/SomeOtherComponent'), the former remains untouched (i.e. require('@namespace/...')) and if I publish the library to npm for use in a third-party application outside of the monorepo context it was developed in, it will of course complain that it cannot resolve '@namespace/...'. Regarding my setup I have this in my tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@namespace/some/path/*": ["./actual/path/*"]
    },
    "plugins": [
      { "transform": "typescript-transform-paths" },
      { "transform": "typescript-transform-paths", "afterDeclarations": true }
    ]
  }
}

And this is the ouput of ttsc --traceResolution:

======== Resolving module '@namespace/some/path/icons/alert/warning.svg' from '/home/axedre/repo/projects/sdk/src/Component/index.tsx'. ========
Module resolution kind is not specified, using 'NodeJs'.
'baseUrl' option is set to '/home/axedre/repo/projects/sdk/src', using this value to resolve non-relative module name '@namespace/some/path/icons/alert/warning.svg'.
'paths' option is specified, looking for a pattern to match module name '@namespace/some/path/icons/alert/warning.svg'.
Module name '@namespace/some/path/icons/alert/warning.svg', matched pattern '@namespace/some/path/*'.
Trying substitution './actual/path/*', candidate module location: './actual/path/icons/alert/warning.svg'.
Loading module as file / folder, candidate module location '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg', target file type 'TypeScript'.

:point_up: THAT is actually the correct path, so if the resolution stopped there and actually transformed '@namespace/some/path/icons/alert/warning.svg' to '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg' (aside from the fact it mistakenly says target file type 'TypeScript') I would be a very happy developer. But alas it thinks warning.svg is a typescript file or a folder name, so it proceeds on trying :point_down:

File '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg.ts' does not exist.
File '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg.tsx' does not exist.
File '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg.d.ts' does not exist.
Directory '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg' does not exist, skipping all lookups in it.
Loading module '@namespace/some/path/icons/alert/warning.svg' from 'node_modules' folder, target file type 'TypeScript'.
Directory '/home/axedre/repo/projects/sdk/src/Component/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Directory '/home/axedre/repo/projects/sdk/src/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Directory '/home/axedre/repo/projects/sdk/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Directory '/home/axedre/repo/projects/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Found 'package.json' at '/home/axedre/repo/node_modules/@namespace/some/path/package.json'.
'package.json' does not have a 'typesVersions' field.
File '/home/axedre/repo/node_modules/@namespace/some/path/icons/alert/warning.svg.ts' does not exist.
File '/home/axedre/repo/node_modules/@namespace/some/path/icons/alert/warning.svg.tsx' does not exist.
File '/home/axedre/repo/node_modules/@namespace/some/path/icons/alert/warning.svg.d.ts' does not exist.
'package.json' does not have a 'typings' field.
'package.json' does not have a 'types' field.
'package.json' does not have a 'main' field.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Directory '/home/axedre/projects/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Directory '/home/axedre/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
Directory '/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'actual/path/icons/alert/warning.svg'
'baseUrl' option is set to '/home/axedre/repo/projects/sdk/src', using this value to resolve non-relative module name '@namespace/some/path/icons/alert/warning.svg'.
'paths' option is specified, looking for a pattern to match module name '@namespace/some/path/icons/alert/warning.svg'.
Module name '@namespace/some/path/icons/alert/warning.svg', matched pattern '@namespace/some/path/*'.
Trying substitution './actual/path/*', candidate module location: './actual/path/icons/alert/warning.svg'.
Loading module as file / folder, candidate module location '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg', target file type 'JavaScript'.
File '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg.js' does not exist.
File '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg.jsx' does not exist.
Directory '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg' does not exist, skipping all lookups in it.
Loading module '@namespace/some/path/icons/alert/warning.svg' from 'node_modules' folder, target file type 'JavaScript'.
Directory '/home/axedre/repo/projects/sdk/src/Component/node_modules' does not exist, skipping all lookups in it.
Directory '/home/axedre/repo/projects/sdk/src/node_modules' does not exist, skipping all lookups in it.
Directory '/home/axedre/repo/projects/node_modules' does not exist, skipping all lookups in it.
File '/home/axedre/repo/node_modules/@namespace/some/path/package.json' exists according to earlier cached lookups.
File '/home/axedre/repo/node_modules/@namespace/some/path/icons/alert/warning.svg.js' does not exist.
File '/home/axedre/repo/node_modules/@namespace/some/path/icons/alert/warning.svg.jsx' does not exist.
'package.json' does not have a 'main' field.
Directory '/home/axedre/projects/node_modules' does not exist, skipping all lookups in it.
Directory '/home/axedre/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
'baseUrl' option is set to '/home/axedre/repo/projects/sdk/src', using this value to resolve non-relative module name '@namespace/some/path/icons/alert/warning.svg'.
'paths' option is specified, looking for a pattern to match module name '@namespace/some/path/icons/alert/warning.svg'.
Module name '@namespace/some/path/icons/alert/warning.svg', matched pattern '@namespace/some/path/*'.
Trying substitution './actual/path/*', candidate module location: './actual/path/icons/alert/warning.svg'.
Loading module as file / folder, candidate module location '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg', target file type 'Json'.
Directory '/home/axedre/repo/projects/sdk/src/actual/path/icons/alert/warning.svg' does not exist, skipping all lookups in it.
Loading module '@namespace/some/path/icons/alert/warning.svg' from 'node_modules' folder, target file type 'Json'.
Directory '/home/axedre/repo/projects/sdk/src/Component/node_modules' does not exist, skipping all lookups in it.
Directory '/home/axedre/repo/projects/sdk/src/node_modules' does not exist, skipping all lookups in it.
Directory '/home/axedre/repo/projects/node_modules' does not exist, skipping all lookups in it.
File '/home/axedre/repo/node_modules/@namespace/some/path/package.json' exists according to earlier cached lookups.
'package.json' does not have a 'main' field.
Directory '/home/axedre/projects/node_modules' does not exist, skipping all lookups in it.
Directory '/home/axedre/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name '@namespace/some/path/icons/alert/warning.svg' was not resolved. ========

:disappointed:

Before you ask, I've already tried all the widely-suggested approach of creating a custom.d.ts file with roughly this content:

declare module '*.svg' {
  const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
  export default content;
}

and include it both in tsconfig.json's "include" (also in "compilerOptions.typeRoots") and in package.json's types/typings field, but to no avail. I think this might call for a specific typescript-transform-svg-paths plugin, but open to any suggestion. Cheers!

nonara commented 2 years ago

This is an interesting one. Thank you for the thorough explanation and resolution log detail. I've re-engineered quite a bit for the upcoming major release. We still rely on the compiler's resolution API, however, we're also getting a lot more information via other means, to support the new middleware custom resolver option.

Part of that is to get the full range of path match possibilities, which means we might be able to do a post-resolution fail check for files with non-resolvable extensions.

I'll look into this!

In the mean time, you can use a @transform-path comment above those lines to explicitly transform until the feature is added.