Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TypeScript] baseUrl inside tsconfig.json not supporting. #202

Closed
shunia opened this issue Dec 11, 2017 · 45 comments · Fixed by #8807
Closed

[TypeScript] baseUrl inside tsconfig.json not supporting. #202

shunia opened this issue Dec 11, 2017 · 45 comments · Fixed by #8807

Comments

@shunia
Copy link

shunia commented Dec 11, 2017

🐛 bug report

🎛 Configuration (.babelrc, package.json, cli command)

tsconfig.json:

{
    "compilerOptions": {
        "outDir": "./dist/",
        "baseUrl": "./src",
        "sourceMap": true,
        "module": "commonjs",
        "target": "es5", 
        "removeComments": true
    }
}

🤔 Expected Behavior

structure:

- project
   - src
      - component
         Custom.ts
      Main.ts
   index.html
   tsconfig.json

component/Custom.ts:

export default function hello() {
    console.log('Hello!');
};

Main.ts:

import hello from 'component/Custom';

hello();

console should show 'Hello!'

😯 Current Behavior

Running from shell:

$ parcel index.html
/Users/shunia/Documents/parcel-test/src/Main.ts:3:23: Cannot resolve dependency 'components/Custom'
  1 | import hello from "components/Custom";
  2 |
> 3 | hello();

💁 Possible Solution

The compiler should read tsconfig.json file right, and understands that baseUrl has made the from part of import ... from ... no need to be the actual relative path from the current file.

In my case, because of baseUrl set to ./src, the original import hello from '../componet/Custom' can be replaced as import hello from 'component/Custom'`.

This might because of the way typescript compiles the import part just as what is written in the codes:

import hello from "components/Custom";

is just compiled to:

var Custom_1 = require("components/Custom");

And then, parcel-require can not recognize the path and throws error.

🔦 Context

Our actual project are full of relative paths based on baseUrl, which we omitted the ../ parts when using relative import. With webpack and awesome-typescript-loader it works as expected. So when we are trying to get our hands on parcel, this problem really blocks us from going further.

🌍 Your Environment

Software Version(s)
Parcel 1.1.0
Node v8.9.3
npm/Yarn Yarn 1.3.2
Operating System macOS Sierra 10.12.6

Sorry for my poor english.

@emanuel-lundman
Copy link
Contributor

Also, related, paths in tsconfig does not seem be resolving correctly..
Did a quick test run with a current project:
Result index.tsx:15:24: Cannot resolve dependency '@client/store'
tsconfig paths example:

"paths": {
    "@store/*": [
        "src/client/app/store/*"
    ],
    "@shared/*": [
        "src/client/shared/*"
    ],
    "@client/*": [
        "src/client/*"
    ],
    "*": [
        "*"
    ]
},

@fathyb
Copy link
Contributor

fathyb commented Dec 11, 2017

Can someone make a simple reproduction repo triggering the error?

@Ty3uK
Copy link
Contributor

Ty3uK commented Dec 12, 2017

Yep, here we go:
Ty3uK/parcel-tsconfig-issue
Error log:

$ parcel index.html
⏳  Building...
Server running at http://localhost:1234
🚨  /Users/ty3uk/projects/js/parcel-test/src/Main.ts:3:23: Cannot resolve dependency '@components/Custom'
  1 | import hello from '@components/Custom';
  2 | import { bye } from 'components/NewCustom';
> 3 |
    | ^
  4 | hello();
  5 | bye();
  6 |

@itsMapleLeaf
Copy link
Contributor

Note that this shouldn't be considered a bug, but a feature or enhancement, since the baseUrl and paths options in the tsconfig are only meant to affect type checking. Actual path resolution is the job of the bundler/module loader.

With that said, as a possible solution, maybe we could make use of this, by translating the options from the tsconfig into the babel plugin's config accordingly. Unless anyone else has a better idea, I could try making a solution out of that.

@Ty3uK
Copy link
Contributor

Ty3uK commented Dec 12, 2017

since the baseUrl and paths options in the tsconfig are only meant to affect type checking

Not right. If you run tsc without any files, it reads tsconfig.json and builds project, resolving paths according to baseUrl and paths sections.

@Ty3uK
Copy link
Contributor

Ty3uK commented Dec 12, 2017

That's what I'm talking about. If you run tsc or tsc -p tsconfig.json modules are resolved.

$ tsc src/Main.ts
src/Main.ts(1,19): error TS2307: Cannot find module '@components/Custom'.
src/Main.ts(2,21): error TS2307: Cannot find module 'components/NewCustom'.
$ tsc
$

@itsMapleLeaf
Copy link
Contributor

itsMapleLeaf commented Dec 12, 2017

Huh, I must be mistaken then, since it's never outputted the resolved module paths for me in the past unless I configured it separately outside of the tsconfig. I'll look into it some more later.

EDIT: No, I tested to make sure, and I'm not mistaken. What I meant was that typescript itself will not edit the import paths in the compiled output. All baseUrl and paths do is make your code pass the typecheck, and allows TS to find the modules and give them the appropriate typings. It does nothing in compilation. Sorry if I wasn't clear.

@shunia
Copy link
Author

shunia commented Dec 12, 2017

@kingdaro Yes, the typescript compiler will not handle the path. That's why I mentioned webpack and awesome-typescript-loader in my post. So I think it is a problem that parcel could handle, to make everything right when compiling.

I tried to point this out in my post, but maybe not so clear:
parcel should make things right just as webpack+awesome-typescript-loader do, because I take parcel as a replacement of webpack+awesome-typescript-loader.

@itsMapleLeaf
Copy link
Contributor

itsMapleLeaf commented Dec 12, 2017

Yes, and I fully agree! Just wanted to mention that it'd be a feature instead of a bug as an aside, but I suppose that's somewhat pedantic, so ignore that part of my comment I guess 😅

@fathyb
Copy link
Contributor

fathyb commented Dec 12, 2017

@shunia I just finished implementing it on parcel-plugin-typescript#ast/path-mappings using AST transforms (so it's totally transparent to Parcel). It's highly experimental but feel free to try. When stable I will try to merge it here in the core.

@shunia
Copy link
Author

shunia commented Dec 12, 2017

@fathyb Sorry, but since I'm new to parcel, I may need a how to to get your code to test.

@fathyb
Copy link
Contributor

fathyb commented Dec 12, 2017

@shunia yarn add [email protected] or npm install [email protected] should be enough.

Just be sure you are using the latest git version of Parcel (eg. yarn add https://github.com/parcel-bundler/parcel or using yarn link).

Update: I just published it, you can just use the latest version on npm of Parcel and the plugin : yarn add parcel-bundler parcel-plugin-typescript

@shunia
Copy link
Author

shunia commented Dec 13, 2017

image
What's wrong here?

@shunia
Copy link
Author

shunia commented Dec 13, 2017

image
install without global and run by yarn run build

@fathyb
Copy link
Contributor

fathyb commented Dec 13, 2017

@shunia you are using the test version I have built for Angular AOT compilation (I'm not good with npm tags, sorry). Can you use the 0.2.0 version? ("parcel-plugin-typescript": "0.2.0", with no ^ or ~, check the version with npm ls parcel-plugin-typescript).

Also let's keep this issue about Parcel support of this feature and not my plugin bugs, please continue on the plugin issue tracker, or in Slack.

@ghost
Copy link

ghost commented Feb 26, 2018

Is there a solution currently?

@fathyb
Copy link
Contributor

fathyb commented Feb 26, 2018

@atilkan it's only supported with parcel-plugin-typescript currently

@ghost
Copy link

ghost commented Feb 26, 2018

@fathyb is there any example? Appritiate it.

@shunia
Copy link
Author

shunia commented Feb 27, 2018

@atilkan Just install the right version of the plugin (mostly the latest) and it's done.

@dlee
Copy link

dlee commented Mar 11, 2018

Hi @fathyb, the example given by @Ty3uK still doesn't work with the latest parcel-plugin-typescript.

@uglycoyote
Copy link

I opened a separate issue #4014 but later closed it because it was basically a duplicate of this one. I thought I would mention here though that my newer issue included a link to a repro case that I created:

https://github.com/uglycoyote/parcel-import-problem

This might make it easier for Parcel developers to test that the baseUrl in tsconfig is respected once the fix is made.

@ngocvantran
Copy link

We can make use of Typescript's internal module resolve, especially now that Parcel 2 supports customization of resolve.

The following code successfully resolves the target component:

const path = require("path");
const ts = require("typescript");

const root = "/test";
const config = require(path.resolve(root, "tsconfig.json"));
const compilerOptions = config.compilerOptions;

if (compilerOptions.baseUrl) {
    compilerOptions.baseUrl = path.resolve(root, compilerOptions.baseUrl);
}

const host = ts.createCompilerHost(compilerOptions);
const cache = ts.createModuleResolutionCache(root, path => path, compilerOptions);
const resolved = ts.resolveModuleName("component/Custom", "Main", compilerOptions, host, cache);
console.log(JSON.stringify(resolved));

The output is:

{"resolvedModule":{"resolvedFileName":"/test/src/component/Custom.ts","extension":".ts","isExternalLibraryImport":false},"failedLookupLocations":[]}

I think TypeScript's built-in resolver would also handle paths mapping as well.

I'll be happy to take up implementing this as a resolver for parcel 2, but will need someone to help guiding me since I'm not familiar with parcel yet. I'm looking into moving my project from webpack to parcel 2 for performance and missing paths support is a huge obstacle that I hope can help to solve.

@chiefGui
Copy link

chiefGui commented May 1, 2020

Simple solution using babel-plugin-module-resolver:

$ yarn add --dev babel-plugin-module-resolver

Then create (or modify) a .babelrc (for total newcomers: in your root folder, where your package.json is):

{
  "plugins": [
    [
      "module-resolver",
      {
        "root": ["./src"],
        "alias": {
          "@components": "./src/components",
          "@features": "./src/features"
        }
      }
    ]
  ]
}

@mbrowne
Copy link

mbrowne commented May 31, 2020

Note that in Parcel 2 (currently in alpha), ~ will point to the root of the project rather than wherever your index.html file is. So that means you'll have to change your imports to ~/src/.... See #2813

@chiefGui
Copy link

chiefGui commented Jun 3, 2020

@mbrowne Hey, thanks for pointing that out. I'll edit my comment accordingly, but pretty much that was just a personal token choice. We can exchange ~ for something like @ with no problem.

@joseluisq
Copy link

joseluisq commented Jun 10, 2020

The "simple" setup by @chiefGui worked for me:

parcel-bundler: ^1.12.4

.babelrc

{
    "plugins": [
        [
            "module-resolver",
            {
                "root": [
                    "./src"
                ],
                "alias": {
                    "~": "./src"
                }
            }
        ]
    ]
}

tsconfig.json

{
    // .......

    "compilerOptions": {
        // .......

        "baseUrl": "./",
        "paths": {
            "~/*": [
                "src/*"
            ]
        }
    }
}

A React/Typescript component example:

import * as React from "react"
import * as ReactDOM from "react-dom"

import { WorldMap } from "~/core/worldmap"
import "~/assets/main.css"

export class App extends React.Component {
    render () {
        return (
            <div>
                <WorldMap />
            </div>
        )
    }
}

ReactDOM.render(<App />, document.getElementById("root"))

@mbrowne
Copy link

mbrowne commented Jun 10, 2020

@joseluisq It should work with just
"~/*", without the "~/assets/*", etc. (At least for tsconfig.json; I'm less sure about .babelrc.)

@joseluisq
Copy link

@mbrowne yeah, because I've copied and pasted. It just works for TS and Babel. So comment above updated.

@alexeychikk
Copy link

@chiefGui Doesn't your solution add an additional overhead of processing ts files with Babel? I guess by default ts files are only processed with TypeScript compiler.

@EsaNuurtamo
Copy link

I just moved to monorepos with typescript and after spending countless hours with Parcel2 (also downgraded to 1) I just can't get moduel resolution working with all the guides there is. Only thing that works is using relative imports. Worked relatively fine before monorepo. In submodules I need tsconfig options alot. If someone has working example of monorepo with working path resolution I would like to see it. (Feel free to suggest better place for this comment)

Tried fuse-box bundler now that has build in typescript support and based on small testing works like a charm with small monorepo I put up. Also the bundle times were much faster and no caching issues (with parcel I need to destroy my cache many times a day)

@zachbryant
Copy link

zachbryant commented Apr 27, 2021

I see a fair amount of quick solutions here, but I spent a lot of time on my tsconfig and just do not want to switch away. It kind of irked me that there wasn't a good path forward and seems like there won't be, so I created parcel-resolver-tspaths that reads your tsconfig.json for aliases. V2 users can find it on npm. I'd love feedback or to hear if this helps anyone. In the meantime I'll finally continue to use my @components/, @styles/, etc ;)

@MylesWardell
Copy link

MylesWardell commented Jan 21, 2022

Is their any way to have endpoints point to folders without the / in ~/. E.G ~types over ~/types.

This is my current setup so ~/types resolves to ./src/types
what I want to achieve ~types resolves to ./src/types

babelrc

{
  "plugins": [
    [
      "module-resolver",
      {
        "root": ["./src"],
        "alias": {
          "~": "./src"
        }
      }
    ]
  ]
}

tsconfig

{
  "compilerOptions": {
    ...
    "rootDir": ".",
    "baseUrl": ".",
    "paths": {
      "~/*": ["src/*"]
    }
  }
}
import { type } from '~/types'

I have tried removing the / (ie "~/*": ["src/*"] -> "~*": ["src/*"]) in the tsconfig and while that removed typescript errors the parcel did not compile throwing a similar error as this issues error. Any assistance? The reason this is relevant is I am trying to avoid ~60 thousand line changes on my Git Repo

@jacekkopecky
Copy link

@zachbryant are you planning to release 1.0.0 of parcel-resolver-tspaths please? 8-)

@devongovett
Copy link
Member

baseUrl support is added in #8807, along with some other TypeScript resolver features - See #4936 (comment)

This is now released in nightly if anyone wants to try it and report back.

@maxhaton
Copy link

maxhaton commented Apr 3, 2024

baseUrl support is added in #8807, along with some other TypeScript resolver features - See #4936 (comment)

This is now released in nightly if anyone wants to try it and report back.

Should this work in parcel 2.12? I can't seem to get any absolute imports working using any baseUrl-isms so curious if its actually "turned on"?

@mischnic
Copy link
Member

mischnic commented Apr 3, 2024

baseUrl support is added in #8807, along with some other TypeScript resolver features - See #4936 (comment)
This is now released in nightly if anyone wants to try it and report back.

Should this work in parcel 2.12? I can't seem to get any absolute imports working using any baseUrl-isms so curious if its actually "turned on"?

It should work automatically: https://parceljs.org/features/dependency-resolution/#tsconfig

Otherwise, please open a new issue with a reproduction and I can take a look

@maxhaton
Copy link

maxhaton commented Apr 3, 2024

baseUrl support is added in #8807, along with some other TypeScript resolver features - See #4936 (comment)
This is now released in nightly if anyone wants to try it and report back.

Should this work in parcel 2.12? I can't seem to get any absolute imports working using any baseUrl-isms so curious if its actually "turned on"?

It should work automatically: https://parceljs.org/features/dependency-resolution/#tsconfig

Otherwise, please open a new issue with a reproduction and I can take a look

It doesn't seeeem to. I am just redacting an strace to post, you can clearly see it going through the right directory but it doesn't actually look for source files rather than directories.

@maxhaton
Copy link

maxhaton commented Apr 3, 2024

Here trying to resolve `import 'ui'"!

openat(AT_FDCWD, "/REDACTED/web/frontend/src/ui/package.json", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
statx(AT_FDCWD, "/REDACTED/web/frontend/src/ui/", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc3b67b280) = -1 ENOENT (No such file or directory)
statx(AT_FDCWD, "/REDACTED/web/frontend/src/startupreact.ts/node_modules/ui", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc3b67b580) = -1 ENOTDIR (Not a directory)
statx(AT_FDCWD, "/REDACTED/web/frontend/src/node_modules/ui", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc3b67b580) = -1 ENOENT (No such file or directory)
statx(AT_FDCWD, "/REDACTED/web/frontend/node_modules/ui", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc3b67b580) = -1 ENOENT (No such file or directory)
statx(AT_FDCWD, "/REDACTED/web/node_modules/ui", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc3b67b580) = -1 ENOENT (No such file or directory)

@maxhaton
Copy link

maxhaton commented Apr 3, 2024

Is there something to copy in the testsuite?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.