简体   繁体   中英

How can I solve my TypeScript/ESLint/Webpack transpiling problem

I've checked other threads for more than a few days; I've found the same error online a few times, but haven't been able to replicate a posted solution. The fact that there's so many ways of writing babel/webpack configs for each different version hasn't helped much. I'm running Webpack, TS, and ESLint. The 'best case' error I've been able to get is the following. I'd really love some help! :[ Among many things, I've tried turning tsx's into jsx's and using jsx preserve instead of react.

Terminal compiler error:

ERROR in ./src/index.tsx
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: C:\Users\Milo\Desktop\Programacion\zekeapp\src\index.tsx: Unexpected token (12:2)

  10 | 
  11 | ReactDOM.render(
> 12 |   <Provider store={store}>
     |   ^
  13 |     <Router>
  14 |       <Main />
  15 |     </Router>

index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ThemeProvider } from 'styled-components';
import { BrowserRouter as Router, Route } from 'react-router-dom';

import store from './store';
import Main from './containers/Main';
import { lightTheme } from './templates/theme';

ReactDOM.render(
  <Provider store={store}>
    <Router>
      <Main />
    </Router>
  </Provider>,
  document.getElementById('root')
);

webpack.config.tsx

import * as path from 'path';

module.exports = {
  entry: path.join(__dirname, './src/index.tsx'),
  mode: 'production',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist/scripts')
  },

  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
  },

  module: {
    rules: [
      {
        test: /\.(js|jsx|tsx|ts)$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  }
};

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2018" /* Specify ECMAScript target version: "ES3" (default), "ES5", "ES2015", "ES2016", "ES2017", "ES2018", "ES2019" or "ESNEXT". */,
    "module": "commonjs" /* Specify module code generation: "none", "commonjs", "amd", "system", "umd", "es2015", or "ESNext". */,
    "jsx": "preserve" /* Specify JSX code generation: "preserve", "react-native", or "react". */,
    "strict": true /* Enable all strict type-checking options. */,
    "noImplicitAny": false /* Raise error on expressions and declarations with an implied "any" type. */,
    "moduleResolution": "node" /* Specify module resolution strategy: "node" (Node.js) or "classic" (TypeScript pre-1.6). */,
    "baseUrl": "./" /* Base directory to resolve non-absolute module names. */,
    "paths": {
      "#server/*": ["./server/*"],
      "#src/*": ["./src/*"]
    },
    "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
    "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,
    "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
  }
}

I got an example project working by following the official React & Webpack documentation.

Make these changes:

  1. Rename webpack.config.tsx to webpack.config.js (it's run by node not TypeScript)

  2. Install ts-loader to transpile the .ts/.tsx files: npm install --save-dev ts-loader

  3. Edit webpack.config.js and configure ts-loader

This example includes babel-loader as well.

Note the exclude: /node_modules/, and configFile: path.resolve('./tsconfig.json'), lines, they are important and required to work properly (see troubleshooting section below for details)

    // webpack.config.js
    {
        //...
        module: {
            rules: [
                {
                    test: /\.(js|jsx|tsx|ts)$/,
                    exclude: /node_modules/,
                    use: [
                        {
                            loader: 'babel-loader',
                        },
                        {
                            loader: 'ts-loader',
                            options: {
                                configFile: path.resolve('./tsconfig.json'),
                            },
                        },
                    ],
                }
            ]
        }
    }
  1. Edit tsconfig.json and add these settings:
    // tsconfig.json
    {
        "compilerOptions": {
            //...

            // Can use to "react" if you aren't using `babel-loader` and `@babel/preset-react` to handle jsx
            "jsx": "react" /* Specify JSX code generation: "preserve", "react-native", or "react". */,

            // Include these so the `react` imports work nicely:
            "esModuleInterop": true,
            "allowSyntheticDefaultImports": true
        }
    }
  1. You should hopefully be able to build the project at this point: npx webpack
    $ npx webpack
    Hash: 184cde71516bcbc08144
    Version: webpack 4.41.5
    Time: 2558ms
    Built at: 01/13/2020 2:34:08 PM
        Asset     Size  Chunks             Chunk Names
    bundle.js  128 KiB       0  [emitted]  main
    Entrypoint main = bundle.js
    [2] ./src/index.tsx 498 bytes {0} [built]
    [8] ./src/Main.tsx 385 bytes {0} [built]
        + 7 hidden modules

2. Example files

Here are the file contents for my test project:

package.json

{
    "devDependencies": {
        "@babel/core": "^7.8.0",
        "babel-loader": "^8.0.6",
        "ts-loader": "^6.2.1",
        "typescript": "^3.7.4",
        "webpack": "^4.41.5",
        "webpack-cli": "^3.3.10"
    },
    "dependencies": {
        "@types/react": "^16.9.17",
        "@types/react-dom": "^16.9.4",
        "react": "^16.12.0",
        "react-dom": "^16.12.0"
    }
}

tsconfig.json

{
    "compilerOptions": {
        "target": "ES2018" /* Specify ECMAScript target version: "ES3" (default), "ES5", "ES2015", "ES2016", "ES2017", "ES2018", "ES2019" or "ESNEXT". */,
        "module": "commonjs" /* Specify module code generation: "none", "commonjs", "amd", "system", "umd", "es2015", or "ESNext". */,
        "strict": true /* Enable all strict type-checking options. */,
        "noImplicitAny": false /* Raise error on expressions and declarations with an implied "any" type. */,
        "moduleResolution": "node" /* Specify module resolution strategy: "node" (Node.js) or "classic" (TypeScript pre-1.6). */,
        "baseUrl": "./" /* Base directory to resolve non-absolute module names. */,
        "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
        "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,
        "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
        "jsx": "react" /* Specify JSX code generation: "preserve", "react-native", or "react". */,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true
    }
}

webpack.config.json

const path = require('path');

module.exports = {
    entry: path.join(__dirname, './src/index.tsx'),
    mode: 'production',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist/scripts')
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx|tsx|ts)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                    },
                    {
                        loader: 'ts-loader',
                        options: {
                            configFile: path.resolve('./tsconfig.json'),
                        },
                    },
                ],
            }
        ]
    }
};

src/index.tsx

import React from 'react';
import ReactDOM from 'react-dom';

import Main from './Main';

ReactDOM.render( <Main />, document.getElementById('root') );

src/Main.tsx

import React from 'react';
import ReactDOM from 'react-dom';

export default function Main(){
    return (<h1>This is Main</h1>);
}

3. Troubleshooting

I ran into these issues getting this set up - here are the solutions I found.

Error: You get an error like: The 'files' list in config file 'tsconfig.json' is empty.

eg

ERROR in [tsl] ERROR
  TS18002: The 'files' list in config file 'tsconfig.json' is empty.

ERROR in ./src/index.tsx
Module build failed (from ./node_modules/ts-loader/index.js):
Error: error while parsing tsconfig.json

Solution: resolve the full tsconfig.json path

// webpack.config.js
{
    loader: 'ts-loader',
    options: {
        // configFile: './tsconfig.json', // !! WRONG
        configFile: path.resolve('./tsconfig.json'),    // CORRECT
    },
}

Error: You get an error like: Module not found: Error: Can't resolve '...' in 'path-to-project/node_modules/react'

eg

ERROR in ./node_modules/react/index.js
Module not found: Error: Can't resolve './Main' in 'C:\webpack-typescript\node_modules\react'
@ ./node_modules/react/index.js 15:31-48
@ ./src/index.tsx

Solution: Make sure you are excluding node_modules from the ts-loader rule.

// webpack.config.js
{
    module: {
        rules: [
            {
                test: /\.(js|jsx|tsx|ts)$/,
                exclude: /node_modules/, // <--- make sure this is here!
                // ...
            }
        ]
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM