第一章、React + TypeScript + Webpack项目构建

React + TypeScript + Webpack项目构建(简版)

一、项目初始化

1. 创建项目文件夹

bash 复制代码
mkdir react-webpack-demo
cd react-webpack-demo

2. 初始化 package.json

npm init -y

二、安装基础依赖

① React 相关依赖

复制代码
npm install react react-dom

② Webpack 相关依赖

vbscript 复制代码
npm install -D webpack webpack-cli webpack-dev-server

③ Babel(转译 JSX 和现代 JS)

bash 复制代码
npm install -D @babel/core @babel/preset-env @babel/preset-react babel-loader

④ HTML 模板插件

css 复制代码
npm install -D html-webpack-plugin

⑤ CSS 支持

复制代码
npm install -D style-loader css-loader

⑥ 安装 TypeScript 相关依赖

bash 复制代码
npm install -D typescript @babel/preset-typescript ts-loader
npm install -D @types/react @types/react-dom

三、目录结构

pgsql 复制代码
react-demo/
├── package.json
└── /webpack
    ├── webpack.common.js
    ├── webpack.dev.js
    └── webpack.prod.js
├── tsconfig.json
├── .babelrc
├── /public
│   └── index.html
└── /src
    ├── index.tsx
    ├── App.tsx
    └── style.css

四、Babel 配置(支持 ts / tsx)

修改 .babelrc

perl 复制代码
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react",
    "@babel/preset-typescript"
  ]
}

这样 Babel 就可以转译 .ts.tsx 文件了。

五、添加 tsconfig.json

在根目录创建 tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}

六、配置 Webpack

我们可以把 webpack 配置拆分为三份

  1. 公共配置(common) :入口、输出、模块解析、Babel、HTML 插件等通用设置
  2. 开发配置(development) :css、devServer、sourceMap、热更新等
  3. 生产配置(production) :压缩、代码分割、提取 CSS、环境变量等

然后用 webpack-merge 来组合。

1️⃣ 安装依赖

sql 复制代码
npm install -D webpack-merge cross-env mini-css-extract-plugin css-minimizer-webpack-plugin terser-webpack-plugin

2️⃣ 目录结构示意

复制代码
webpack/
├── webpack.common.js
├── webpack.dev.js
├── webpack.prod.js

3️⃣ 公共配置(webpack.common.js)

js 复制代码
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./src/index.tsx",
  output: {
    path: path.resolve(__dirname, "../dist"),//`__dirname` 表示当前 webpack 配置文件所在的目录。`../dist` 回到项目根目录再生成
    filename: "js/[name].js",
    assetModuleFilename: "assets/[hash][ext][query]",
    clean: true,
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".jsx"],
    alias: {
      "@": path.resolve(__dirname, "src"),
    },
  },
  module: {
    rules: [
      // JS/TS 文件由 babel-loader 处理
      {
        test: /\.[jt]sx?$/,
        exclude: /node_modules/,
        use: "babel-loader",
      },
      // 图片等资源
      {
        test: /\.(png|jpg|jpeg|svg|gif)$/i,
        type: "asset/resource",
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],
};

4️⃣ 开发环境配置(webpack.dev.js)

js 复制代码
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");

module.exports = merge(common, {
  mode: "development",
  devtool: "eval-cheap-module-source-map",
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          "style-loader", // 将 CSS 注入 <head>
          "css-loader",   // 解析 CSS
        ],
      },
    ],
  },
  devServer: {
    static: "./public",
    port: 3000,
    open: true,
    hot: true,
    historyApiFallback: true,
  },
});

5️⃣ 生产环境配置(webpack.prod.js)

js 复制代码
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const { DefinePlugin } = require("webpack");

module.exports = merge(common, {
  mode: "production",
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader, // 提取 CSS 到单独文件
          "css-loader",
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name].[contenthash:8].css",
    }),
    new DefinePlugin({
      "process.env.NODE_ENV": JSON.stringify("production"),
    }),
  ],
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendors",
          chunks: "all",
        },
      },
    },
  },
});

七、HTML 模板

js 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>React + Webpack</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

八、React 入口文件

src/index.tsx

javascript 复制代码
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import "./style.css";

const container = document.getElementById("root");
const root = createRoot(container!);
root.render(<App />);

src/App.tsx

javascript 复制代码
import React from "react";

const App: React.FC = () => {
  return (
    <div>
      <h1>React + TypeScript + Webpack ⚙️</h1>
      <p>现在支持 TS / JSX 转译!</p>
    </div>
  );
};

export default App;

九、添加启动命令

修改 package.json

js 复制代码
{
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack serve",
    "build": "cross-env NODE_ENV=production webpack"
  },
  "devDependencies": {
    "cross-env": "^7.0.3"
  }
}

安装 cross-env

sql 复制代码
npm install -D cross-env

十、启动项目

开发模式

sql 复制代码
npm start

访问 http://localhost:3000

生产构建

arduino 复制代码
npm run build

输出到 /dist 文件夹,包含压缩后的 JS/CSS。

十一、 其他说明

相关推荐
大杯咖啡5 小时前
localStorage与sessionStorage的区别
前端·javascript
RaidenLiu5 小时前
告别陷阱:精通Flutter Signals的生命周期、高级API与调试之道
前端·flutter·前端框架
非凡ghost5 小时前
HWiNFO(专业系统信息检测工具)
前端·javascript·后端
非凡ghost5 小时前
FireAlpaca(免费数字绘图软件)
前端·javascript·后端
非凡ghost5 小时前
Sucrose Wallpaper Engine(动态壁纸管理工具)
前端·javascript·后端
拉不动的猪5 小时前
为什么不建议项目里用延时器作为规定时间内的业务操作
前端·javascript·vue.js
该用户已不存在5 小时前
Gemini CLI 扩展,把Nano Banana 搬到终端
前端·后端·ai编程
地方地方5 小时前
前端踩坑记:解决图片与 Div 换行间隙的隐藏元凶
前端·javascript
炒米23335 小时前
【Array】数组的方法
javascript