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

[v2] Typescript plugin not working #5520

Closed
jaredpalmer opened this issue May 22, 2018 · 32 comments
Closed

[v2] Typescript plugin not working #5520

jaredpalmer opened this issue May 22, 2018 · 32 comments
Labels
help wanted Issue with a clear description that the community can help with. type: maintenance An issue or pull request describing a change that isn't a bug, feature or documentation change

Comments

@jaredpalmer
Copy link

Description

I tried to use the typescript plugin with v2 to no avail. I get the following error message.

ERROR in ./src/pages/index.tsx
Module parse failed: Unexpected token (3:7)
You may need an appropriate loader to handle this file type.
| import * as React from 'react';
|
| export interface IndexProps {}
|
| export interface IndexState {}
 @ ./.cache/sync-requires.js 11:51-124
 @ ./.cache/root.js
 @ ./.cache/app.js
 @ multi ./node_modules/react-hot-loader/patch.js (webpack)-hot-middleware/client.js?path=http://localhost:8000/__webpack_hmr&reload=true&overlay=false ./.cache/app
ℹ 「wdm」: Failed to compile.

Environment

  • Gatsby version (npm list gatsby): 2.0.0-alpha.40
  • gatsby-cli version (gatsby --version):
  • Node.js version: 8.9.x
  • Operating System: macOS Sierra

File contents (if changed)

gatsby-config.js:

module.exports = {
  plugins: [`gatsby-plugin-typescript`, `gatsby-plugin-react-helmet`],
};

package.json: N/A
gatsby-node.js: N/A
gatsby-browser.js: N/A
gatsby-ssr.js: N/A

@KyleAMathews
Copy link
Contributor

Hmm not sure — you can check out the source here to see if something looks awry https://github.com/gatsbyjs/gatsby/blob/v2/packages/gatsby-plugin-typescript/src/gatsby-node.js#L14

@jaredpalmer
Copy link
Author

@KyleAMathews
Copy link
Contributor

Not sure — @jquense wrote this so I'll you off to him ;-)

@jaredpalmer
Copy link
Author

hmmm onCreateWebpack config is not even getting fired... i just threw an error in there and nothin happened.
screenshot 2018-05-22 16 32 45

@KyleAMathews
Copy link
Contributor

Hmm are any of the functions being called?

@jaredpalmer
Copy link
Author

confirmed that resolvableExtensions is def getting called

@jaredpalmer
Copy link
Author

confirmed that preprocessSource is too.

@KyleAMathews
Copy link
Contributor

Odd — this is where the API is called — perhaps there's a subtle typo or something?

await apiRunnerNode(`onCreateWebpackConfig`, {

Is there any console errors?

@jaredpalmer
Copy link
Author

jaredpalmer commented May 22, 2018

oh well v2 of typescript plugin is using actions.setWebpackConfig it's not merging and returning.

@jaredpalmer
Copy link
Author

actions is not being passed to the code you just linked to.

@mquandalle
Copy link
Contributor

So #5522 fixes this issue?

@jaredpalmer
Copy link
Author

#5522 and the TypeScript plugin needs a newer version of ts-loader that's compat with Webpack 4

@jquense
Copy link
Contributor

jquense commented May 24, 2018

Why are you adding the js loaders here?

#3369

I've never felt like that was a good choice tho...especially now that babel has a TS parser

@mquandalle
Copy link
Contributor

Indeed NextJS 6 uses babel parser for Typescript which integrates better with the build toolchain (you still get the TS experience in the editor)

@mquandalle
Copy link
Contributor

I'm new to the Gatsby ecosystem and I have a Typescript app in which I would really benefit from webpack 4 tree-shaking. So I'm trying the following configuration in gatsby-node.js with gatsby@next:

exports.resolvableExtensions = () => ['.ts', '.tsx']

exports.onCreateBabelConfig = ({ actions }, options) => {
  actions.setBabelPreset({
    name: '@babel/preset-typescript',
    options,
  })
}

exports.onCreateWebpackConfig = ({ actions, loaders }) => {
  actions.setWebpackConfig({
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          use: [loaders.js()],
        },
      ],
    },
  })
}

Unfortunately this isn't working. Any pointer to what could go wrong here?

@KyleAMathews
Copy link
Contributor

Indeed NextJS 6 uses babel parser for Typescript which integrates better with the build toolchain

Yeah, switching to a native babel parser sounds great (from my limited, haven't used typescript perspective)

@jquense
Copy link
Contributor

jquense commented May 29, 2018

We should pull in someone who is knowlegable about TS tooling, my understanding is that as a compiler babel is incomplete in terms of which features it supports (if any?).

From what i can understand the original problem was that the TS plugin was only compiling to es6, so that Gatsby tools could read out exports and graphql tags for extracting frontmatter and queries. So it was going TS -> es6 -> (via babel) -> es5- With the babel parser we can now run static analysis to extract queries and frontmatter directly against the TS files, and then let the TScompiler compile down to whatever. That may or may not be a good idea tho i barely use TS :P

@vadistic
Copy link

@mquandalle gatsby loads general babel configs which contain preset @babel/preset-flow. This one is incompatible with @babel/preset-typescript and will throw errors together- you would need to remove flow preset and give it a try.

@jquense from what I get from playing with it, @babel/preset-typescript handles build perfectly. And it's faster than TS loader. The issue is, that the only thing it does is stripping TS markup - you still want to fire ts-loader (with noEmit in config (possibly in spawned process)) to get friendly errors and static type analysis. What's the point in using TS without compile time type check?

@jaredpalmer
Copy link
Author

@vadistic on large applications ts-loader becomes a bottleneck typechecking. In addition to all of our apps at TPG, I know that the Outlook team also opts for fork-ts-webpack-checker-plugin https://github.com/Realytics/fork-ts-checker-webpack-plugin which allows you to typecheck with multiple workers and pipe errors into terminal logs. You just keep ts-loader in happyPack / transpileOnly mode. You can get a serious speed boost if you use the also turn on experimentalWatchApi which enables incremental builds

@mquandalle
Copy link
Contributor

@vadistic One possibility is to have type errors being reported in the code editor and not handled by the build toolchain (since Babel is only stripping TS type annotations). That's already the case with Gatsby v1 as your app compiles even if the TS type check fails.

Thanks for the pointer about @babel/preset-flow, I'll try to remove it and test the typescript preset instead.

@dennari
Copy link
Contributor

dennari commented May 30, 2018

In case someone is looking for a temporary fix before gatsby-plugin-typescript is updated for v2, this seems to work:

  1. Add ts-loader as dependency
  2. Use the following gatsby-node.js:
const { transpileModule } = require(`typescript`)

const test = /\.tsx?$/
const compilerDefaults = {
  target: `esnext`,
  experimentalDecorators: true,
  jsx: `react`,
  module: `es6`,
}

exports.resolvableExtensions = () => {
  return [`.ts`, `.tsx`]
}

exports.onCreateWebpackConfig = (
  { actions, loaders },
  { compilerOptions, ...options }
) => {
  const typescriptOptions = {
    transpileOnly: false,
    compilerOptions: {
      ...compilerDefaults,
      ...compilerOptions,
    },
  }
  actions.setWebpackConfig({
    module: {
      rules: [
        {
          test,
          use: [
            loaders.js(),
            {
              loader: require.resolve(`ts-loader`),
              options: typescriptOptions,
            },
          ],
        },
      ],
    },
  })
}

exports.preprocessSource = ({ contents, filename }, { compilerOptions }) => {
  const copts = { ...compilerDefaults, ...compilerOptions }

  // return the transpiled source if it's TypeScript, otherwise null
  return test.test(filename)
    ? transpileModule(contents, { compilerOptions: copts }).outputText
    : null
}

My tsconfig.json is:

{
  "include": ["./src/**/*"],
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "lib": ["dom", "es2017"],
    "jsx": "react",
    "strict": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

@dennari
Copy link
Contributor

dennari commented May 30, 2018

Regarding the future of gatsby-plugin-typescript, I'd also vote for going the Babel route as was done with https://github.com/zeit/next-plugins/tree/master/packages/next-typescript. I'd be interested in contributing to this.

@dannywils
Copy link
Contributor

I'm able to get a v2 project working with ts-loader with the guidance above but no static queries are running in dev or build.

Debugging a bit leads me to believe the issue is related to this function:

https://github.com/gatsbyjs/gatsby/blob/v2/packages/gatsby/src/internal-plugins/query-runner/file-parser.js#L106

The execution never seems to get to line 130.

Anybody else running into this or have any ideas why typescript would affect static query execution?

@dennari
Copy link
Contributor

dennari commented May 30, 2018

@vadistic

gatsby loads general babel configs which contain preset @babel/preset-flow. This one is incompatible with @babel/preset-typescript and will throw errors together- you would need to remove flow preset and give it a try.

Looking at this commit, it seems that the two have been made compatible.

Btw, why is @babel/preset-flow included by default?

@jquense
Copy link
Contributor

jquense commented May 30, 2018

Btw, why is @babel/preset-flow included by default?

My guess is that it was to reduce breakage in the babel7 migration, babel6's react preset included flow. Good question tho as to whether that is still a good idea..

@dennari
Copy link
Contributor

dennari commented Jun 1, 2018

Got preset-typescript working (only tried with babel beta 49) with the following configuration:

const resolvableExtensions = () => {
  return [`.ts`, `.tsx`]
}

const onCreateWebpackConfig = (
  { actions, loaders, stage },
  { compilerOptions, ...options }
) => {
  actions.setWebpackConfig({
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          use: [
            {
              loader: require.resolve(`babel-loader`),
              options: {
                cacheDirectory: true,
                babelrc: false,
                sourceType: "unambiguous",
                presets: [
                  `@babel/preset-env`,
                  `@babel/preset-react`,
                  `@babel/preset-typescript`,
                ].map(require.resolve),
                plugins: [
                  require.resolve(`babel-plugin-remove-graphql-queries`),
                ],
              },
            },
          ],
        },
      ],
    },
  })
}
exports.onCreateWebpackConfig = onCreateWebpackConfig
exports.resolvableExtensions = resolvableExtensions

Here I'm not using setBabelPreset, since that seems to only affect /.jsx?/ files.

This is only a quick fix though, since in a more general setup we should somehow be able to pass all the correct arguments to the presets and plugins. For comparison, here's a simplified version of the default rules for js/jsx parsing:

{
  rules: [
    {
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      use: [
        {
          options: {
            cacheDirectory: true,
            babelrc: false,
            sourceType: "unambiguous",
            presets: [
              [
                "preset-env",
                {
                  loose: true,
                  modules: false,
                  useBuiltIns: "usage",
                  targets: { browsers: [Array] },
                },
              ],
              [
                "preset-react",
                {
                  useBuiltIns: true,
                  pragma: "React.createElement",
                  development: false,
                },
              ],
              ["preset-flow", {}],
            ],
            plugins: [
              "babel-plugin-remove-graphql-queries",
              ["plugin-proposal-class-properties", { loose: true }],
              ["plugin-syntax-dynamic-import", {}],
              [
                "plugin-transform-runtime",
                { helpers: true, regenerator: true, polyfill: false },
              ],
            ],
          },
          loader: "babel-loader",
        },
      ],
    },
  ]
}

@dennari
Copy link
Contributor

dennari commented Jun 1, 2018

@dannywils , can you get the static query execution working with the above?

@dannywils
Copy link
Contributor

It works but I had to force the preset to @babel/preset-typescript 7.0.0-beta.42 because 7.0.0-beta.49 throws the following error:

Module build failed: Error: [BABEL] C:\dev\gatsby-typescript-staticquery\src\pages\index.tsx: .overrides is not allowed in preset options
    at Object.keys.forEach.key (C:\dev\gatsby-typescript-staticquery\node_modules\@babel\core\lib\config\validation\options.js:71:13)

Test repo at https://github.com/dannywils/gatsby-typescript-staticquery/tree/babel

@mquandalle
Copy link
Contributor

mquandalle commented Jun 2, 2018

I used @dennari gatsby-node.js configuration with success. A few remarks:

  • In my case adding @babel/preset-react generates a lot of syntax errors (I didn't realize that at first because I forgot to yarn add it), so I didn't include it
  • I needed to add others babel plugins to fix typescript syntax errors, in my case @babel/plugin-proposal-class-properties and @babel/plugin-proposal-numeric-separator. Since TS code bases use these features, I'm surprised that these transformers aren't included with @babel/preset-typescript and I opened an issue on that in the babel repo: Add other syntax plugins in the typescript preset babel/babel#8098
  • I add another issue with syntax error with interface reported in Syntax error with a TS interface using syntax-typescript babel/babel#8099
  • I had to add react-hot-loader/babel as a plugin to get hot reload working, I'm not sure why.

I also experienced the same issue than @dannywils about the preset-typescript error with beta.49. Is there already a bug open about this issue?

@m-allanson m-allanson added help wanted Issue with a clear description that the community can help with. type: maintenance An issue or pull request describing a change that isn't a bug, feature or documentation change labels Jun 4, 2018
@dennari
Copy link
Contributor

dennari commented Jun 4, 2018

I believe #5709 should solve the mentioned problems.

@mquandalle
Copy link
Contributor

I'm using #5709 since a few days without issues. Also as noted before 7.0.0-beta.49 of @babel/preset-typescript was bugged, but the issue is now fixed in the latest 7.0.0-beta.51 so we don't have to pin to this particular beta version anymore.

@KyleAMathews
Copy link
Contributor

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Issue with a clear description that the community can help with. type: maintenance An issue or pull request describing a change that isn't a bug, feature or documentation change
Projects
None yet
Development

No branches or pull requests

8 participants