「使用 webpack5从0到1搭建React+TypeScript 项目环境」1. React 与 TypeScript 集成

简介: 「使用 webpack5从0到1搭建React+TypeScript 项目环境」1. React 与 TypeScript 集成

「使用 webpack 5 从0到1搭建React + TypeScript 项目环境」1. React 与 TypeScript 集成

本篇文章会带大家使用 webpack 5集成 ReactTypeScript,同时为了提高我们的代码质量,我们会在构建中添加类型检查和代码规范校验。

创建项目结构

首先我们新建一个项目,结构如下:

b3814a544f111b94986578f4ba3bafa6.png

由于很多配置在「生产环境」「开发环境」中存在不一致的情况,比如开发环境没有必要设置缓存,生产环境还需要设置公共路径等等。所以这里我们分开发环境和生产环境,让打包更灵活。

  • webpack.config.common.js (开发环境和生产环境的共同配置)
  • webpack.config.dev.js(开发环境配置)
  • webpack.config.prod.js (生产环境配置)
  • webpack.config.js (对不同环境下的配置文件进行整合)

初始内容

webpack.config.common.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  // webpack 配置
  // 入口起点
  entry: './src/index.tsx',
  // 输出
  output: {
    // 输出文件名
    filename: 'scripts/[name].[contenthash].js',
    // 输出路径
    path: resolve(__dirname, '../dist'),
    clean: true, // 打包前清理 dist 文件夹
  },
  // loader 配置
  module: {
    rules: [
    ]
  },
  resolve: {
    extensions: [ '.tsx', '.ts', '.jsx', '.js'], 
  },
  // plugins 的配置
  plugins: [
    // 功能:默认会创建一个空的html文件,自动引入打包输出的所有资源(js/css)
    new HtmlWebpackPlugin({
      // 增加一个配置
      // 复制 '../index.html' 文件,并自动引入打包输出的所有资源(js/css)
      template: '../index.html',
      // 压缩html资源
      // minify: {
      //   collapseWhitespace: true, //去空格
      //   removeComments: true // 去注释
      // }
    }),
  ],
}

「【注】」 插件html-webpack-plugin 需要我们通过 yarn add html-webpack-plugin -D 下载,详情请看 html-webpack-plugin

webpack.config.dev.js

const Package = require('../package.json')
const proxy = Package.proxy ?? {} // 获取 package.json 中的 代理配置
module.exports = {
  module: {
    rules: [
    ]
  },
  devtool: 'eval-cheap-module-source-map',
  mode: 'development',
  devServer: {
    static: '../dist', // 将 ../dist 目录下的文件作为 web 服务的根目录。
    compress: true,
    port : 3000, // 设置端口号
    open : true, // 自动打开本地默认浏览器
    hot: true, // 开启热更新
    proxy,
    historyApiFallback: true
  }
}
  • 为了我们开发调式,这里设置了devtool: 'eval-cheap-module-source-map',关于 sourcemap的详情请看:一文了解source-map
  • compress 是否选择开启gzips压缩功能,对应静态资源请求的响应头里的  Content-Encoding: gzip
  • historyApiFallback :如果我们的应用是个 SPA (单页面应用),当路由到/some时(可以直接在地址栏里输入),会发现此时刷新页面后,控制台会报错:GET http://localhost:3000/some 404 (Not Found)。此时打network,刷新并查看,就会发现问题所在———浏览器把这个路由当作了静态资源地址去请求,然而我们并没有打包出/some这样的资源,所以这个访问无疑是404的。如何解决它?这种时候,我们可以通过配置来提供页面代替任何404的静态资源响应。详情请看:DevServer | webpack 中文文档 (docschina.org)
  • proxy 开启代理:
  • 我们打包出的 jsbundle 里有时会含有一些对特定接口的网络请求(ajax/fetch).要注意,此时客户端地址是在 http://localhost:3000/ 下,假设我们的接口来自http://localhost:4001/ ,那么毫无疑问,此时控制台里会报错并提示你跨域。如何解决这个问题?在开发环境下,我们可以使用devServer自带的proxy功能:
proxy: { "/api": "http://localhost:4001" }
  • 详情请看:DevServer | webpack 中文文档 (docschina.org)

webpack.config.prod.js

module.exports = {
  output: {
    filename: 'scripts/[name].[contenthash].js'
  },
  module: {
    rules: [
    ]
  },
  plugins: [
  ],
  mode: 'production',
}

webpack.config.js

const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.config.common')
const productionConfig = require('./webpack.config.prod')
const developmentConfig = require('./webpack.config.dev')
module.exports = (env) => {
  switch(true) {
    case env.development:
      return merge(commonConfig, developmentConfig)
    case env.production:
      return merge(commonConfig, productionConfig)
    defult:
      return new Error('No matching configuration was found')
  }
}
  • 我们使用一个名为 webpack-merge 的工具。详情请看:survivejs/webpack-merge: Merge designed for webpack (github.com)
  • webpack 命令行 环境配置 的 --env 参数,可以允许你传入任意数量的环境变量。而在 webpack.config.js中可以访问到这些环境变量。例如, --env production。对于我们的 webpack配置,有一个必须要修改之处。通常, module.exports指向配置对象。要使用 env 变量,你必须将 module.exports转换成一个函数:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React App</title>
</head>
<body>
  <div id='root'></div>
</body>
</html>

这个 HTML 文件是Webpack 构建过程中的模板文件。目的是告诉 WebpackReact代码注入到 id="root"div 元素中,并在 HTML 中自动引入打包好的 JavaScriptCSS

npm 脚本

每次打包或启动服务时,都需要在命令行里输入一长串的命令。配置 npm 脚本来简化命令行的输入,这时可以省略 npx

// package.json
{
  ...,
  "scripts": {
    "start": "webpack serve -c ./config/webpack.config.js --env development",
    "build": "webpack -c ./config/webpack.config.js --env production"
  },
}

配置 React 和 TypeScript环境

安装 React 及其对应的类型库:

yarn add react react-dom
yarn add @types/react @types/react-dom -D

src/index.tsx 来编写 React 组件,此代码将会被展示到index.html 文件id="root"div 元素下:

import React from "react";
import ReactDOM from "react-dom";
const App = () => <h1>Hello World!</h1>;
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

「添加 Babel」

在项目中,我们需要使用 BabelReactTypeScript 代码转换为 JavaScript。接下来我们安装一些 Babel 工具

yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/plugin-transform-runtime @babel/runtime typescript -D
  • babel-loader通知 BabelReactTypeScript代码转换为 JavaScript
  • @babel/core: Babel 核心库
  • @babel/preset-env:让我们可以在不支持 JavaScript 最新特性的浏览器中使用 ES6+语法
  • @babel/preset-react:将 React代码转换为 JavaScript
  • @babel/preset-typescript:将 TypeScript 代码转换为 JavaScript
  • @babel/plugin-transform-runtime@babel/runtime:支持在低版本浏览器使用 ES6+语法,如 async/await

「Babel 配置」

我们通过.babelrc文件来进行 Babel 配置,在根目录创建此文件并加入以下内容

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react",
    "@babel/preset-typescript"
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "regenerator": true
      }
    ]
  ]
}

上面的配置是告诉 Babel 使用哪些插件

或者也可以直接写在webpack.config.common.jsrules中:

{
  test: /\.(ts|js)x?$/i,
  exclude: /node_modules/,
  use: {
    loader: "babel-loader",
    options: {
      presets: [
        "@babel/preset-env",
        "@babel/preset-react",
        "@babel/preset-typescript",
      ],
      plugins: [
        [
          "@babel/plugin-transform-runtime",
          {
            regenerator: true,
          },
        ],
      ],
    },
  },
}

相应的我们还需要配置 tsconfig.json

我们可以用ts自带的工具来自动化生成它。

npx tsc --init

我们发现生成了一个tsconfig.json,里面注释掉了绝大多数配置。现在,根据我们想要的效果来打开对应的配置。

{
  "compilerOptions": {
    "target": "es2016",                                
    "jsx": "preserve",                                /* Specify what JSX code is generated. */
    "module": "commonjs",                                /* Specify what module code is generated. */
    "rootDir": "./src/",                                  /* Specify the root folder within your source files. */
    "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
    "outDir": "./dist/",                                   /* Specify an output folder for all emitted files. */
    "removeComments": true,                           /* Disable emitting comments. */
    "esModuleInterop": true,                            
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */
    "strict": true,                                      /* Enable all strict type-checking options. */
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  }
}

启动开发环境

「安装 webpack

yarn add webpack webpack-cli webpack-dev-server -D

src/index.tsx 中添加:

import React from "react";
import ReactDOM from "react-dom";
const App = () => <h1>Hello World!</h1>;
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

通过yarn start启动开发环境,,然后我们在浏览器中访问http://localhost:3000,可以看到:

99d8d26c071e5a58ad9659452a273a61.png

在 webpack 构建过程中添加类型检查

当我们把 src/index.tsx 修改如下:

import React from "react";
import ReactDOM from "react-dom";
const App = () => {
  console.log(a);
  return (
    <h1>Hello World!</h1>
  )
}
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

我们发现 webpack 还是能正常构建:

2a71fbe86728768ca4ef90d8e3d4e403.png

但是因为我们输出了一个为声明的变量a,所以浏览器的控制台上会报错:

0ff636fd56baab8cfbf313e042493ebc.png

为了开发的时候方便,我们希望在 webpack 构建过程中就能发现错误,我们可以使用fork-ts-checker-webpack-pluginwebpack 构建过程支持类型检查。这意味着 webpack 会通知我们任何类型相关的错误。

首先我们先安装依赖:

yarn add fork-ts-checker-webpack-plugin -D

webpack.config.dev.js中:

引用第三方库:

const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

在插件配置中使用该插件:

plugins: [
    ...,
    new ForkTsCheckerWebpackPlugin({
     async: false
 }),
],

我们使用 async 标志来告诉 webpack 等待代码的类型检查结束,然后才提交代码进行编译。

接下来我们重新启动:

可以看到控制台报错:

28ef17b9d70f9d9807ea9d4936249073.png

同时,在浏览器中访问http://localhost:3000,可以看到:

f3a28dd3a528f84466053b051cffcb7e.png

如果想了解更多 fork-ts-checker-webpack-plugin 的相关配置,请看TypeStrong/fork-ts-checker-webpack-plugin:在单独的进程上运行typescript类型检查器的Webpack插件。(github.com)

在 webpack 构建过程中添加代码规范校验

webpack构建流程不会执行代码规范校验。我们可以使用ESLintPlugin来使 webpack构建过程能够使用 ESLint 进行代码规范校验。

下面我们来安装相应的依赖:

yarn add eslint-webpack-plugin eslint -D

配置eslint,只需要在根目录下添加一个.eslintrc文件(或者.eslintrc.json, .js等)。当然,我们可以使用eslint工具来自动生成它:

npx eslint --init

f0103ce313b9aaa8d6032403750c6d34.png

并生成了一个配置文件(.eslintrc.json),这样我们就完成了eslint的基本规则配置。

webpack.config.dev.js中:

引用第三方库:

const ESLintPlugin = require('eslint-webpack-plugin');

在插件配置中使用该插件:

plugins: [
    ...,
    new ESLintPlugin({
      extensions: ["js", "jsx", "ts", "tsx"],
    }),
],

src/index.tsx 中,添加一个未使用的变量:

import React from "react";
import ReactDOM from "react-dom";
const App = () => {
  const a = '';
  // console.log(a);
  return (
    <h1>Hello World!</h1>
  )
}
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

输入 yarn start 构建,可以看到警告:

e52432091f0000c037ccc2e14d657a99.png

启动生存环境打包

输入 yarn build 可以进行生产环境打包,我们可以看到输出了一个 dist 文件夹:

52dc6c81ba1d7360cd615fc4f2094088.png

最后

至此我们已经集成了 ReactTypeScript,下一篇文章是 「「使用 webpack 5 从0到1搭建React + TypeScript 项目环境」2. 集成 css、less 与 sass」

相关文章
|
前端开发 JavaScript
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
本文介绍了在React项目中实现路由懒加载的方法,使用React提供的`lazy`和`Suspense`来优化项目首次加载的速度。通过将路由组件改为懒加载的方式,可以显著减少初始包的大小,从而加快首次加载速度。文章还展示了如何使用`Suspense`组件包裹`Switch`来实现懒加载过程中的fallback效果,并提供了使用前后的加载时间对比,说明了懒加载对性能的提升作用。
1091 2
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
|
前端开发 JavaScript Java
SpringBoot项目部署打包好的React、Vue项目刷新报错404
本文讨论了在SpringBoot项目中部署React或Vue打包好的前端项目时,刷新页面导致404错误的问题,并提供了两种解决方案:一是在SpringBoot启动类中配置错误页面重定向到index.html,二是将前端路由改为hash模式以避免刷新问题。
1654 1
|
运维 前端开发 数据可视化
【CodeBuddy】挑战一句话开发一个完整项目之:React表单验证系统
本文分享了一个基于React 19构建的用户注册表单系统,采用模块化CSS和状态驱动视图更新,实现实时校验、错误提示与提交反馈等功能。核心亮点包括验证规则引擎(如密码复杂度校验)、交互反馈体系(输入框警示、按钮禁用)及加载动画优化。通过函数式更新确保状态同步,正则表达式实现多条件验证,CSS伪元素打造流畅体验。代码结构清晰,可扩展性强,适合作为React表单开发模板。文末附CodeBuddy免费下载链接,助力高效开发!
303 1
【CodeBuddy】挑战一句话开发一个完整项目之:React表单验证系统
|
JavaScript 前端开发 安全
使用 TypeScript 加强 React 组件的类型安全
【10月更文挑战第1天】使用 TypeScript 加强 React 组件的类型安全
389 106
|
移动开发 前端开发
react项目配合diff实现文件对比差异功能
在React项目中,可以使用`diff`库实现文件内容对比差异功能。首先安装`diff`库,然后在组件中引入并使用`Diff.diffChars`或`Diff.diffLines`方法比较文本差异。通过循环遍历`diff`结果,可以生成不同样式的HTML元素来高亮显示文本差异。
920 1
react项目配合diff实现文件对比差异功能
|
前端开发 算法 JavaScript
React项目input输入框输入自动失去焦点
本文讨论了在React项目中如何处理input输入框自动失去焦点的问题,特别是在移动端开发中。文章提供了一个使用React Native的TouchableWithoutFeedback组件来监听点击事件,并在事件处理函数中通过调用Keyboard.dismiss()方法使输入框失去焦点的示例代码。这种方法可以确保在用户点击页面其他区域时,键盘能够收起,输入框失去焦点。
631 1
React项目input输入框输入自动失去焦点
|
JavaScript 前端开发 应用服务中间件
本地运行打包好的React、Vue项目
本文讨论了如何本地运行打包好的React和Vue项目,并解决了使用React-Router时Tomcat部署刷新页面导致404的问题,提出了将请求转回index.html的解决方案。
510 1
本地运行打包好的React、Vue项目
|
前端开发 JavaScript
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
|
前端开发 JavaScript 应用服务中间件
linux安装nginx和前端部署vue项目(实际测试react项目也可以)
本文是一篇详细的教程,介绍了如何在Linux系统上安装和配置nginx,以及如何将打包好的前端项目(如Vue或React)上传和部署到服务器上,包括了常见的错误处理方法。
4692 0
linux安装nginx和前端部署vue项目(实际测试react项目也可以)
|
资源调度 JavaScript 前端开发
使用vite+react+ts+Ant Design开发后台管理项目(二)
使用vite+react+ts+Ant Design开发后台管理项目(二)