@dark_king_13

Как собрать шаблон под React + Typescript?

Пока код в .tsx файле не имеет ничего от ts, всё работает
import React from 'react'

const App = () => {
  return (
    <div>
      <h1>Hello TS</h1>
    </div>
  )
}

export default App

Но как только дописываю тип для App, получаю ошибку:
Скрин ошибки

5e8dd356edc5e729960911.png

package.json
{
  "name": "unique-starter",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "cross-env NODE_ENV=development nodemon ./src/server/index.ts",
    "build": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.prod.conf.js",
    "server": "cross-env NODE_ENV=production ts-node ./src/server",
    "start": "yarn build && yarn server"
  },
  "devDependencies": {
    "@babel/core": "^7.9.0",
    "@babel/preset-env": "^7.9.0",
    "@babel/preset-react": "^7.9.4",
    "@types/express": "^4.17.4",
    "@types/node": "^13.11.0",
    "@types/react": "^16.9.32",
    "@types/react-dom": "^16.9.6",
    "@types/socket.io": "^2.1.4",
    "autoprefixer": "^9.7.6",
    "babel-loader": "^8.1.0",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^5.1.1",
    "css-loader": "^3.5.1",
    "css-mqpacker": "^7.0.0",
    "cssnano": "^4.1.10",
    "dotenv": "^8.2.0",
    "dotenv-webpack": "^1.7.0",
    "file-loader": "^6.0.0",
    "html-loader": "^1.1.0",
    "html-webpack-plugin": "^4.0.4",
    "image-webpack-loader": "^6.0.0",
    "mini-css-extract-plugin": "^0.9.0",
    "node-sass": "^4.13.1",
    "nodemon": "^2.0.2",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^8.0.2",
    "style-loader": "^1.1.3",
    "ts-node": "^8.8.2",
    "typescript": "^3.8.3",
    "webpack": "^4.42.1",
    "webpack-cli": "^3.3.11",
    "webpack-dev-middleware": "^3.7.2",
    "webpack-hot-middleware": "^2.25.0",
    "webpack-merge": "^4.2.2",
    "webpackbar": "^4.0.0"
  },
  "dependencies": {
    "body-parser": "^1.19.0",
    "consola": "^2.11.3",
    "cross-env": "^7.0.2",
    "express": "^4.17.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "socket.io": "^2.3.0"
  }
}

webpack.base.conf.js
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const Dotenv = require('dotenv-webpack')
const WebpackBar = require('webpackbar')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const PATHS = {
  src: path.join(__dirname, '../src/client'),
  dist: path.join(__dirname, '../dist'),
  assets: 'assets/'
}

const baseWebpackConfig = {
  externals: {
    paths: PATHS
  },
  output: {
    path: PATHS.dist,
    publicPath: '/'
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          name: 'vendors',
          test: /node_modules/,
          chunks: 'all',
          enforce: true
        }
      }
    }
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.jsx']
  },
  module: {
    rules: [
      {
        test: /\.html$/,
        use: ['html-loader']
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: '/node_modules/',
      },
      {
        test: /\.ts$/,
        loader: 'babel-loader',
        exclude: '/node_modules/',
      },
      {
        test: /\.tsx$/,
        loader: 'babel-loader',
        exclude: '/node_modules/',
      },
      {
        test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]',
          outputPath: `${PATHS.assets}fonts`,
        }
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: { sourceMap: true }
          }, {
            loader: 'postcss-loader',
            options: { sourceMap: true, config: { path: `./postcss.config.js` } }
          }
        ]
      }
    ]
  },
  plugins: [
    new WebpackBar({
      name: 'client',
      color: 'green',
    }),
    new Dotenv(),
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin([
      { from: `${PATHS.src}/public`, to: '' },
    ]),
    new HtmlWebpackPlugin({
      template: `${PATHS.src}/public/index.html`,
      filename: `./index.html`
    })
  ]
}

module.exports = baseWebpackConfig

webpack.dev.conf.js
const webpack =  require('webpack')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const devWebpackConfig = merge(baseWebpackConfig, {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  // watch: true,
  stats: 'errors-warnings',
  entry: {
    app: [
      'webpack-hot-middleware/client?path=/__webpack_hmr&reload=true',
      `${baseWebpackConfig.externals.paths.src}/index.tsx`,
    ],
  },
  output: {
    filename: `${baseWebpackConfig.externals.paths.assets}js/[name].[hash].bundle.js`,
  },
  module: {
    rules: [
      {
        test: /\.(png|jp(e)?g|gif|svg)$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: `${baseWebpackConfig.externals.paths.assets}img`,
            useRelativePath: true
          }
        },
      }, 
    ]
  },
  plugins: [
    new webpack.SourceMapDevToolPlugin({
      filename: '[file].map'
    }),
    new MiniCssExtractPlugin({
      filename: `${baseWebpackConfig.externals.paths.assets}css/[name].[hash].css`,
    }),
    new webpack.HotModuleReplacementPlugin(),
  ]
})

module.exports = devWebpackConfig

Из-за чего может быть эта ошибка и как избавиться?
  • Вопрос задан
  • 70 просмотров
Решения вопроса 1
@ned4ded
Верстка, Фронтенд
У вас не установлен лоадер для typescript.

Есть 2 варианта, 1ый - ts-loader, 2ой - babel-loader c typescript пресетом.

Я предпочитаю второй, но в таком случае напрямую бабель не будет производить проверку типов и нужно использовать плагин fork-ts-checker. Проверка типов будет происходить параллельно с процессом компиляции вебпака.

Вот пример для бабель-лоадера.

// webpack.config 

module.exports = {
    module: {
        rules: [
            {
                oneOf: [
                    {
                        test: /\.(js|jsx|ts|tsx)$/,
                        exclude: /(node_modules|bower_components)/,
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true,
                        },
                    },

                    {
                        use: 'file-loader',
                        exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
                    },

                    // ** STOP ** Are you adding a new loader?
                    // Make sure to add the new loader(s) before the "file" loader.
                ],
            },
        ],
    },

    plugins: [
        new ForkTsCheckerWebpackPlugin({
            async: true,
            useTypescriptIncrementalApi: true,
            checkSyntacticErrors: true,
            eslint: true,
        }),
    ],
};

// babelrc

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-typescript"
    ],
}


Не забудьте установить пресеты, лоадеры и плагин.

PS, можете подсмотреть конфиг для create-react-app, там можно выудить много интересного.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы