「使用 webpack 5 从0到1搭建React TypeScript 项目环境」1. React 与 TypeScript 集成
本篇文章会带大家使用 webpack 5
集成 React
与TypeScript
,同时为了提高我们的代码质量,我们会在构建中添加类型检查和代码规范校验。
创建项目结构
首先我们新建一个项目,结构如下:
在这里插入图片描述
由于很多配置在「生产环境」和「开发环境」中存在不一致的情况,比如开发环境没有必要设置缓存,生产环境还需要设置公共路径等等。所以这里我们分开发环境和生产环境,让打包更灵活。
webpack.config.common.js
(开发环境和生产环境的共同配置)webpack.config.dev.js
(开发环境配置)webpack.config.prod.js
(生产环境配置)webpack.config.js
(对不同环境下的配置文件进行整合)
初始内容
webpack.config.common.js
代码语言:javascript复制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
代码语言:javascript复制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
开启代理:
- 我们打包出的
js
bundle
里有时会含有一些对特定接口的网络请求(ajax
/fetch
).要注意,此时客户端地址是在 http://localhost:3000/ 下,假设我们的接口来自http://localhost:4001/ ,那么毫无疑问,此时控制台里会报错并提示你跨域。如何解决这个问题?在开发环境下,我们可以使用devServer
自带的proxy
功能:proxy: { "/api": "http://localhost:4001" }
详情请看:DevServer | webpack 中文文档 (docschina.org)
webpack.config.prod.js
代码语言:javascript复制module.exports = {
output: {
filename: 'scripts/[name].[contenthash].js'
},
module: {
rules: [
]
},
plugins: [
],
mode: 'production',
}
webpack.config.js
代码语言:javascript复制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
代码语言:javascript复制<!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
构建过程中的模板文件。目的是告诉 Webpack
将 React
代码注入到 id="root"
的 div
元素中,并在 HTML
中自动引入打包好的 JavaScript
和 CSS
。
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」
在项目中,我们需要使用 Babel
将 React
和 TypeScript
代码转换为 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
通知Babel
将React
和TypeScript
代码转换为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.js
的rules
中:
{
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
,可以看到:
在这里插入图片描述
在 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
还是能正常构建:
在这里插入图片描述
但是因为我们输出了一个为声明的变量a
,所以浏览器的控制台上会报错:
在这里插入图片描述
为了开发的时候方便,我们希望在 webpack
构建过程中就能发现错误,我们可以使用fork-ts-checker-webpack-plugin
让 webpack
构建过程支持类型检查。这意味着 webpack
会通知我们任何类型相关的错误。
首先我们先安装依赖:
代码语言:javascript复制yarn add fork-ts-checker-webpack-plugin -D
在 webpack.config.dev.js
中:
引用第三方库:
代码语言:javascript复制const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
在插件配置中使用该插件:
代码语言:javascript复制plugins: [
...,
new ForkTsCheckerWebpackPlugin({
async: false
}),
],
我们使用 async
标志来告诉 webpack
等待代码的类型检查结束,然后才提交代码进行编译。
接下来我们重新启动:
可以看到控制台报错:
在这里插入图片描述
同时,在浏览器中访问http://localhost:3000
,可以看到:
在这里插入图片描述
如果想了解更多 fork-ts-checker-webpack-plugin
的相关配置,请看TypeStrong/fork-ts-checker-webpack-plugin:在单独的进程上运行typescript类型检查器的Webpack插件。(github.com)
在 webpack 构建过程中添加代码规范校验
webpack
构建流程不会执行代码规范校验。我们可以使用ESLintPlugin
来使 webpack
构建过程能够使用 ESLint
进行代码规范校验。
下面我们来安装相应的依赖:
代码语言:javascript复制yarn add eslint-webpack-plugin eslint -D
配置eslint
,只需要在根目录下添加一个.eslintrc
文件(或者.eslintrc.json, .js
等)。当然,我们可以使用eslint
工具来自动生成它:
npx eslint --init
在这里插入图片描述
并生成了一个配置文件(.eslintrc.json
),这样我们就完成了eslint
的基本规则配置。
在 webpack.config.dev.js
中:
引用第三方库:
代码语言:javascript复制const ESLintPlugin = require('eslint-webpack-plugin');
在插件配置中使用该插件:
代码语言:javascript复制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
构建,可以看到警告:
在这里插入图片描述
启动生存环境打包
输入 yarn build
可以进行生产环境打包,我们可以看到输出了一个 dist
文件夹:
在这里插入图片描述
最后
至此我们已经集成了 React
与TypeScript
,下一篇文章是 「「使用 webpack 5 从0到1搭建React TypeScript 项目环境」2. 集成 css、less 与 sass」