返回

0 到 1 搭建 React+TypeScript+webpack 项目

前端

搭建项目结构

我们的项目将采用如下结构:

.
├── assets
│   ├── css
│   │   ├── main.css
│   │   └── normalize.css
│   └── images
│       ├── logo.png
│       └── favicon.ico
├── components
│   ├── Button
│   │   ├── Button.tsx
│   │   └── Button.scss
│   ├── Card
│   │   ├── Card.tsx
│   │   └── Card.scss
│   ├── Footer
│   │   ├── Footer.tsx
│   │   └── Footer.scss
│   ├── Header
│   │   ├── Header.tsx
│   │   └── Header.scss
│   ├── Layout
│   │   ├── Layout.tsx
│   │   └── Layout.scss
│   ├── Page
│   │   ├── Page.tsx
│   │   └── Page.scss
└── src
    ├── index.tsx
    ├── main.tsx
    ├── App.tsx
    ├── store.ts
    ├── reducers
    │   ├── counterReducer.ts
    │   └── todoReducer.ts
    └── actions
        ├── counterActions.ts
        └── todoActions.ts

安装依赖库

我们使用 npm 安装所需的依赖库:

npm install react react-dom typescript webpack webpack-cli webpack-dev-server @types/react @types/react-dom @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript babel-loader ts-loader css-loader style-loader sass-loader postcss-loader autoprefixer

配置项目

1. webpack.config.js

在项目根目录创建 webpack 配置文件 webpack.config.js

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.tsx',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'sass-loader',
        ],
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[ext]',
              outputPath: 'assets/images',
            },
          },
        ],
      },
    ],
  },
  devServer: {
    contentBase: './dist',
    port: 3000,
  },
};

2. tsconfig.json

在项目根目录创建 TypeScript 配置文件 tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ],
  "exclude": [
    "node_modules"
  ]
}

3. .babelrc

在项目根目录创建 Babel 配置文件 .babelrc

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

开发项目

现在,我们可以使用以下命令启动开发服务器:

npm start

编写组件

为了编写组件,我们将在 components 目录中创建单独的文件,每个组件一个文件。例如,创建一个名为 Button 的组件,并在 Button.tsx 文件中编写代码:

import React from 'react';
import styles from './Button.scss';

interface ButtonProps {
  label: string;
  onClick: () => void;
}

const Button: React.FC<ButtonProps> = ({ label, onClick }: ButtonProps) => {
  return (
    <button className={styles.button} onClick={onClick}>
      {label}
    </button>
  );
};

export default Button;

编写样式

组件的样式放在与其同名的 .scss 文件中,例如 Button.scss

.button {
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background-color: #fff;
  color: #333;
  font-size: 16px;
  cursor: pointer;

  &:hover {
    background-color: #eee;
  }

  &:active {
    background-color: #ddd;
  }
}

编写页面

页面放在 src 目录中,例如创建一个名为 Home 的页面,在 Home.tsx 文件中编写代码:

import React from 'react';
import Button from '../components/Button';

const Home: React.FC = () => {
  return (
    <div>
      <h1>Home</h1>
      <Button label="Click Me" onClick={() => { alert('Hello World!'); }} />
    </div>
  );
};

export default Home;

编写路由

src 目录中创建 index.tsx 文件,作为应用程序的入口:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from './pages/Home';

const App: React.FC = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
      </Routes>
    </BrowserRouter>
  );
};

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

优化项目

1. 代码分割

我们可以使用代码分割来优化项目的加载速度,在 webpack.config.js 中添加如下配置:

optimization: {
  splitChunks: {
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        chunks: 'all',
      },
    },
  },
}

2. 图片压缩

我们可以使用 image-webpack-loader 来压缩图片,在 webpack.config.js 中添加如下配置:

module: {
  rules: [
    // ...其他规则
    {
      test: /\.(png|jpg|gif|svg)$/,
      use: [
        {
          loader: 'image-webpack-loader',
          options: {
            mozjpeg: {
              quality: 80,
            },
            pngquant: {
              quality: [0.65, 0.90],
              speed: 4,
            },
            gifsicle: {
              optimizationLevel: 7,
            },
            svgo: {
              plugins: [
                {
                  removeViewBox: false,
                },
              ],
            },
          },
        },
        {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: 'assets/images',
          },
        },
      ],
    },
  ],
}

3. CSS 提取

我们可以使用 `mini