gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.27k stars 10.31k forks source link

Support for TypeScripts 'paths' option #4357

Closed ChristoRibeiro closed 6 years ago

ChristoRibeiro commented 6 years ago

Description

I'm trying to implement alias for importing Typescript modules from root of my project. According to typescripts docs it can be done by adding following configuration to 'tsconfig.json' file

    "baseUrl": "./src",
    "paths": {
      "@components": ["/components"]

Then from anywhere ts/tsx file: import { MyComponent } from '@components/MyComponent'.

Environment

Gatsby version: 1.1.40 Node.js version: v8.9.4 Operating System: macOS 10.13.3

Actual result

Module @components/MyComponent not found. The Same behavior has been fixed with create-react-app: issue 203.

Expected behavior

Typescript should find my module.

Steps to reproduce

1. gatsby new website-gatsby-clean https://github.com/haysclark/gatsby-starter-typescript

2. add Typescript paths config to tsconfig.json

"compilerOptions": {
    ...
    "baseUrl": "./src",
    "paths": {
        "@components": ["/components"]
    }
}

3. create src/components/MyComponent.tsx

const MyComponent = () => <h1>Hello</h1>
export default MyComponent

4. import MyComponent into src/pages/index.tsx

...
import MyComponent from '@components/MyComponent'
...
public render() {
    return <MyComponent />
}
...
m-allanson commented 6 years ago

It looks like you'd need to use the tsconfig-paths-webpack-plugin to enable this setup? I think you could do this using Gatsby's webpack hooks - see the docs page on custom webpack configs.

Note that Gatsby v1 uses webpack version one. Gatsby v2 will upgrade to a newer release of webpack.

ChristoRibeiro commented 6 years ago

@m-allanson thanks. Not sure how to make it work. I've tried that:

yarn add --dev tsconfig-paths-webpack-plugin

then

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

function TsconfigPathsContructor() {
  return new TsconfigPathsPlugin();
}

exports.modifyWebpackConfig = ({ config, stage }) => {
  if (stage == "develop" || stage == "build-javascript") {
    const opts = [{
      configFile: "./tsconfig.json"
    }];

    config.plugin("ts-config-paths-plugin", TsconfigPathsContructor, opts);
  }

  return config;
};
tsriram commented 6 years ago

Not a complete solution, but I got rid of the TS error (in VS Code) with this in tsconfig.json:

"compilerOptions": {
    ...
    "baseUrl": "./src",
    "paths": {
        "@components/*": ["/components/*"]
    }
}

Though gatsby/webpack still throws an error that the dependency is not found when I import a module using path defined in tsconfig.json. Not sure how to get this working!

ChristoRibeiro commented 6 years ago

@m-allanson any idea how to make it work?

t49tran commented 6 years ago

I resolved the problem after having a look here #484. Basically, what I do is add an alias option to webpack.resolve in gatsby-node.js:

exports.modifyWebpackConfig = function({ config, env }) {
  config.merge({
    resolve: {
      alias: {
        `[ALIAS]`: [PATH_TO_ALIAS]
      }
    }
  });
  return config;
};
m-allanson commented 6 years ago

Thanks @t49tran. It'd be nice for gatsby-plugin-typescript to support this automatically. It could read tsconfig.json and automatically apply the aliases to webpack.

t49tran commented 6 years ago

I think it makes complete sense @m-allanson, I will have a look into gatsby-plugin-typescript and see if I can do something.

KyleAMathews commented 6 years ago

Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!

0x80 commented 5 years ago

I was struggling to make this work, not realizing the example by @t49tran was using the v1 gatsby config API. For the record, if anyone arrives here looking for a solution using v2, here's the summary:

You don't need the tsconfig-paths-webpack-plugin, and I'm not sure how it relates to be honest.

In tsconfig I have this:

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

So in code you can write things like import { widths } from '@src/styles/variables'

Then to make the build succeed, add to gatsby-node.js:

exports.onCreateWebpackConfig = function({ actions }) {
  actions.setWebpackConfig({
    resolve: {
      alias: {
        '@src': path.resolve(__dirname, 'src')
      }
    }
  })
}

I personally like the @ prefix, because it makes it very clear that you're not importing from node_modules.

jbmusso commented 5 years ago

I personally like the @ prefix, because it makes it very clear that you're not importing from node_modules.

This could also indicate a @scoped package located in ./node_modules/, although I didn't check if @src scope is available there. In this context, maybe using # instead of @ could help better distinguish between scoped-packages and internal/local packages resolved via paths.

Thanks for the exports.onCreateWebpackConfig info :-).

0x80 commented 5 years ago

@jbmusso You're right, a different character would probably be better. I realized that shortly after :) But I haven't ran into any problems yet. The prefixes I'm using are so generic they are not very likely to clash with a library namespace (src, components, modules, utils, config, ...)

martinmckenna commented 5 years ago

@0x80 Forgetting this line at the top of the gatsby-node.js file

var path = require('path');

Here's a quick starter project for anyone interested:

https://github.com/martinmckenna/gatsby-typescript-starter

thetrevorharmon commented 5 years ago

Has anybody been successful at getting this working while also using TSLint? I have followed what @0x08's recommendedation but I keep running into a "not found" error:

Cannot find module '@src/UI-Kit'.

I'll also run in to other lint errors (like no-submodule-imports) but those are easily fixed by explicitly allowing @src in my tslint.json.

kirbycool commented 5 years ago

If anyone's still struggling with this issue, I was able to get it working pretty easily using tsconfig-paths-webpack-plugin.

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@components/*": ["components/*"]
    }
  }
}

gatsby-node.js

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')

exports.onCreateWebpackConfig = ({ actions }) => {
  actions.setWebpackConfig({
    resolve: {
      plugins: [new TsconfigPathsPlugin()],
    },
  })
}

And then you can import like this

import Foo from '@components/foo'
anxious-coder-lhs commented 5 years ago

If anyone's still struggling with this issue, I was able to get it working pretty easily using tsconfig-paths-webpack-plugin.

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@components/*": ["components/*"]
    }
  }
}

gatsby-node.js

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')

exports.onCreateWebpackConfig = ({ actions }) => {
  actions.setWebpackConfig({
    resolve: {
      plugins: [new TsconfigPathsPlugin()],
    },
  })
}

And then you can import like this

import Foo from '@components/foo'

This certainly works for Gatsby v2.

kaluabentes commented 4 years ago

How to remove the warning from VSCode? Did anyone found a solution to this?

d0t15t commented 3 years ago

I'm also struggling with this in Gatsby v3. i've tried variations of with/without tsconfig-paths-webpack-plugin, and onCreateWebpackConfig as suggested here, but no luck. Does anyone have a definitive solution for this in Gatsby v3?

aaronadamsCA commented 3 years ago

Deleted my prior comment.

This Gatsby plugin is working for me: https://www.gatsbyjs.com/plugins/gatsby-plugin-tsconfig-paths/

Its key limitation is that it doesn't work for require statements in gatsby-config.js. Once I worked around that, it's all good.