๐ bug report
tsconfig.json
:
{
"compilerOptions": {
"outDir": "./dist/",
"baseUrl": "./src",
"sourceMap": true,
"module": "commonjs",
"target": "es5",
"removeComments": true
}
}
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!'
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();
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.
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.
| 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.
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/*"
],
"*": [
"*"
]
},
Can someone make a simple reproduction repo triggering the error?
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 |
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.
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.
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
$
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.
@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
.
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 ๐
@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.
@fathyb Sorry, but since I'm new to parcel, I may need a how to
to get your code to test.
@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
What's wrong here?
install without global
and run by yarn run build
@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.
Is there a solution currently?
@atilkan it's only supported with parcel-plugin-typescript
currently
@fathyb is there any example? Appritiate it.
@atilkan Just install the right version of the plugin (mostly the latest) and it's done.
Hi @fathyb, the example given by @Ty3uK still doesn't work with the latest parcel-plugin-typescript
.
@dlee did you try to remove the .cache
directory or launch parcel
using --no-cache
?
@fathyb This worked. Thank you!
So, what's the conclusion?
Any progress?
Due to baseUrl
, It is not possible to use custom paths
.
__Parcel:__ v1.10.3
app.tsx:3:31: Failed to install @app/store
node_modules/parcel-bundler/src/utils/installPackage.js:46:11)
at process._tickCallback (internal/process/next_tick.js:68:7)
Reference: https://github.com/fathyb/parcel-plugin-typescript/issues/59
my team wants to use parcel, but this is preventing us from switching away from webpack.... We have a bunch of paths in our tsconfig and they can't be resolved:
error An unexpected error occurred: "https://registry.yarnpkg.com/@my-path%2factions: Not found".
The combination that worked for us:
https://gist.github.com/croaky/e3394e78d419475efc79c1e418c243ed
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.
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.
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"
}
}
]
]
}
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 https://github.com/parcel-bundler/parcel/issues/2813
@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.
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"))
@joseluisq It should work with just
"~/*"
, without the "~/assets/*"
, etc. (At least for tsconfig.json; I'm less sure about .babelrc.)
@mbrowne yeah, because I've copied and pasted. It just works for TS and Babel. So comment above updated.
@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.
Most helpful comment
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: