快来跟我一起学 React(Day3)
Posted vv_小虫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快来跟我一起学 React(Day3)相关的知识,希望对你有一定的参考价值。
简介
上一节我们介绍了 React
官方提供的脚手架(create-react-app),然后用官方脚手架创建了一个 react-demo1
项目,用脚手架创建出来的项目算是 React
官方认为的最佳项目实践了,但是从上一节使用中我们可以看出,官方脚手架可还是有一些弊端,它只提供一些可改的 webpack
配置,如果你想自己添加一个 loader
、plugin
什么的,你可能就需自定义 webpack
配置了,就不能在依赖脚手架了,既然是重新学习 React
,我们就来挑战一下自己,从 0
开始搭建一个企业级的 React
项目,大家跟紧节奏吧。
知识点
- Webpack (打包编译)
- TypeScript(语法规范)
- React(js 框架)
- html-webpack-plugin(webpack 插件)
- Sass(css 预处理框架)
- PostCss(css 预处理框架)
- mini-css-extract-plugin(提取 css 模块插件)
- Babel( es 语法转化)
- Jsx & Tsx(jsx 语法)
- ESLint(代码质量校验)
- Optimization(项目优化)
ok!要搭建一个企业级的项目需要准备的东西还是有点多的,我们分一下类:
- Js 框架(Vue、TypeScript、Tsx、Jsx)
- Css 样式(Sass)
- 工程化工具(Eslint、Babel、webpack、webpack-chain)
我们开始吧。
项目初始化
我们创建一个 cus-react-demo
目录,然后在 cus-react-demo
目录下执行 npx init -y
命令:
mkdir cus-react-demo && cd cus-react-demo && npm init -y
如上图所示,初始化完毕后会看到一个 package.json
文件。
webpack
接下来我们需要安装 webpack 相关的依赖:
安装 webpack
webpack 核心库。
在工程目录 cus-react-demo
执行以下命令安装 webpack:
npm install -D webpack --registry https://registry.npm.taobao.org
目前 webpack
的版本是 5.26.3
。
安装 webpack-cli
webpack 指令库。
在工程目录 cus-react-demo
执行以下命令:
npm install -D webpack-cli --registry https://registry.npm.taobao.org
安装 webpack-dev-server
webpack 开发者服务框架。
在工程目录 cus-react-demo
执行以下命令:
npm install -D webpack-dev-server --registry https://registry.npm.taobao.org
安装 webpack-chain
webpack 配置工具。
在工程目录 cus-react-demo
执行以下命令:
npm install -D webpack-chain --registry https://registry.npm.taobao.org
创建 webpack 配置
在工程目录 cus-react-demo
下创建一个 webpack.config.js
文件:
touch webpack.config.js
然后对 webpack.config.js
进行配置,用 webpack-chain
导入一个 webpack 配置:
const config = new (require('webpack-chain'))();
module.exports = config.toConfig();
安装 cross-env
定义 node
中的 process.env
中的变量。
在工程目录 cus-react-demo
执行以下命令:
npm install -D cross-env --registry https://registry.npm.taobao.org
为了开发方便,我们在 package.json
中声明两个脚本 build
跟 dev
:
"name": "cus-react-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts":
"test": "echo \\"Error: no test specified\\" && exit 1",
"build": "rimraf dist && cross-env NODE_ENV=production webpack --mode=production",
"start": "cross-env NODE_ENV=development webpack serve --mode=development --progress"
,
"author": "",
"license": "ISC",
"devDependencies":
"cross-env": "^7.0.3",
"webpack": "^5.26.3",
"webpack-chain": "^6.5.1",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^3.11.2"
我们可以试着运行一下 build
跟 start
脚本命令:
npm start
现在运行肯定是报错的,因为我们还没有对项目进行任何配置。
入口与出口
我们首先在工程目录 cus-react-demo
下创建一个 src
目录,然后在 src
目录下创建一个 main.tsx
文件:
mkdir src && cd src && touch main.tsx && cd ..
然后我们找到 webpack.config.js
文件,对 webpack 的入口和出口进行配置:
const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判断是否是开发环境
config
.context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
.entry('app') // 入口文件名称为 app
.add('./src/main.tsx') // 入口文件为 ./src/main.tsx
.end()
.output
.path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
.filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出来的 bundle 名称为 "[name].[contenthash:8].js"
.publicPath('/') // publicpath 配置为 "/"
.end();
module.exports = config.toConfig();
可以看到,我们配置了一个 app
入口 ./src/main.ts
,然后给所有的输出文件名称改成了 [name].[hash:8].js
。
我们再次执行 build
命令:
npm run build
可以看到,这次没有报错了。
但是当我们给 src/main.tsx
添加点内容试试:
let a: string = 'hello';
我们再次运行 npm run build
命令:
可以看到,又报错了,这次是因为 webpack 没法去解析 main.tsx
中的 ts
语法,所以接下来我们就需要配置一下 webpack
的 loader
了,让我们的项目能够支持 jsx
、ts
、tsx
语法。
Babel & TypeScript
因为我们项目是需要支持 ts 语法的,所以我们需要安装一下 TypeScript 相关依赖:
babel-preset-react-app
很幸运哈,React
官方已经提供了一套 babel
插件集合,它会自动的帮我们添加 babel
相关的配置,让我们能够轻松的使用 jsx
、ts
、tsx
语法,而且不需要考虑 es
语法的兼容性问题,会根据我们的浏览器配置自动做语法兼容等操作。
在工程目录 cus-react-demo
执行以下命令:
npm install -D babel-preset-react-app --registry https://registry.npm.taobao.org
babel-loader
webpack 加载器。
在工程目录 cus-react-demo
下执行以下命令安装:
npm install -D babel-loader --registry https://registry.npm.taobao.org
ok!安装完 Babel 的一些依赖后,我们开始配置 webpack。
找到 webpack.config.js
文件,然后添加 babel-loader
配置:
const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判断是否是开发环境
config
.context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
.entry('app') // 入口文件名称为 app
.add('./src/main.tsx') // 入口文件为 ./src/main.tsx
.end()
.output
.path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
.filename('[name].[contenthash:8].js') // 打包出来的 bundle 名称为 "[name].[contenthash:8].js"
.publicPath('/') // publicpath 配置为 "/"
.end()
.resolve
.extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后缀自动解析
.end()
.module
.rule('ts') // 配置 typescript
.test(/\\.(js|mjs|jsx|ts|tsx)$/)
.exclude
.add(filepath =>
// Don't transpile node_modules
return /node_modules/.test(filepath)
)
.end()
.use('babel-loader')
.loader('babel-loader')
.end()
.end()
module.exports = config.toConfig();
然后我们需要在工程目录 cus-react-demo
下创建一个文件 babel.config.js
:
touch babel.config.js
然后写入以下代码到 babel.config.js
文件:
module.exports =
presets: [
[
"babel-preset-react-app", // 添加 react-app 插件集合
],
]
TypeScript 配置
因为我们需要进行 ts 语法的我们还需要在工程目录 cus-react-demo
下创建一个 ts
配置文件 tsconfig.json
:
touch tsconfig.json
然后写入以下代码到 tsconfig.json
文件:
"compilerOptions":
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"suppressImplicitAnyIndexErrors": true,
"resolveJsonModule": true,
"sourceMap": true,
"baseUrl": ".",
"types": ["webpack-env"],
"paths":
"@/*": ["src/*"]
,
"lib": ["esnext", "dom", "dom.iterable"]
,
"include": ["src/**/*.ts", "src/**/*.tsx",],
"exclude": ["node_modules"]
ok!我们再次运行 npm run build
命令:
可以看到,这一次 webpack 正常完成了编译打包。
React 配置
我们首先安装一下 React
所需要的依赖:
安装 react & react-dom
React 核心 API。
在工程目录 cus-react-demo
执行以下命令:
npm install react react-dom @types/react @types/react-dom --registry https://registry.npm.taobao.org
然后我们修改一下 src/main.tsx
文件来测试一下:
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<div>hello react</div>,
document.getElementById('root')
);
很简单,就是利用 tsx
语法在页面中输出了一句 “hello react” 字符串。
如果需要开启 webpack-dev-server
的话,我们还需要配置一下 devServer
。
我们找到 webpack.config.js
配置文件,然后添加 devServer
配置:
const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判断是否是开发环境
config
.context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
.entry('app') // 入口文件名称为 app
.add('./src/main.tsx') // 入口文件为 ./src/main.tsx
.end()
.output
.path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
.filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出来的 bundle 名称为 "[name].[contenthash:8].js"
.publicPath('/') // publicpath 配置为 "/"
.end()
.resolve
.extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后缀自动解析
.end()
.module
.rule('ts') // 配置 typescript
.test(/\\.(js|mjs|jsx|ts|tsx)$/)
.exclude
.add(filepath =>
// Don't transpile node_modules
return /node_modules/.test(filepath)
)
.end()
.use('babel-loader')
.loader('babel-loader')
.end()
.end()
.end()
.devServer
.host('0.0.0.0') // 服务器外部可访问
.disableHostCheck(true) // 关闭白名单校验
.contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
.historyApiFallback(
disableDotRule: true, // 禁止在链接中使用 "." 符号
rewrites: [
from: /^\\/$/, to: '/index.html' , // 将所有的 404 响应重定向到 index.html 页面
],
)
.port(8080) // 当前端口号
.hot(true) // 打开页面热载功能
.sockPort('location'); // 设置成平台自己的端口
module.exports = config.toConfig();
ok!然后我们在工程目录 cus-react-demo
下执行 npm start
开启 webpack-dev-server
:
npm start
执行完毕后,我们可以直接用浏览器访问一下打包过后的目录(http://127.0.0.1:8080/webpack-dev-server):
可以看到,webpack-dev-server
列出了 webpack 打包出来的所有 js 资源文件。
接下来我们在工程目录 cus-react-demo
底下创建一个 public
目录,然后在 public
目录下创建一个 index.html
文件作为我们 app 的入口页面:
mkdir public && touch public/index.html
然后写入以下代码到 public/index.html
文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<noscript>your browser should support javascript!</noscript>
<!-- 挂载点 -->
<div id="root"></div>
<!-- 引入入口文件 -->
<!-- 注意!这里的 64a558f4 每个人是不一样的 -->
<script src="/app.64a558f4.js"></script>
</body>
</html>
(**注意!**这里的 64a558f4
每个人是不一样的)创建完毕后,我们重启服务:
npm start
然后我们可以直接用浏览器访问 http://127.0.0.1:8080/ 项目入口了:
可以看到,页面渲染了我们在 src/index.js
入口文件中定义的 “hello react” 字符串。
html-webpack-plugin
虽然浏览器中正常显示了我们的结果,但是我们现在还是手动去引入 app.xxx.js
文件的,而 xxx
是经常变化的,所以我们不可能每次都去改 public/index.html
文件,能不能自动去引入 js 资源文件到入口 index.html
呢?
安装 html-webpack-plugin
在工程目录 cus-react-demo
执行以下命令:
npm install -D html-webpack-plugin --registry https://registry.npm.taobao.org
然后修改一下 webpack.config.js
配置文件,引入 html-webpack-plugin
插件:
const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判断是否是开发环境
config
.target('web')
.context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
.entry('app') // 入口文件名称为 app
.add('./src/main.tsx') // 入口文件为 ./src/main.tsx
.end()
.output
.path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
.filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出来的 bundle 名称为 "[name].[contenthash:8].js"
.publicPath('/') // publicpath 配置为 "/"
.end()
.resolve
.extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后缀自动解析
.end()
.module
.rule('ts') // 配置 typescript
.test(/\\.(js|mjs|jsx|ts|tsx)$/)
.exclude
.add(filepath =>
// Don't transpile node_modules
return /node_modules/.test(filepath)
)
.end()
.use('babel-loader')
.loader('babel-loader')
.end()
.end()
.end()
.plugin('html') // 添加 html-webpack-plugin 插件
.use(require('html-webpack-plugin'), [
template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
chunks: ['app'], // 指定需要加载的 chunk
inject: 'body', // 指定 script 脚本注入的位置为 body
,
])
.end()
.devServer
.host('0.0.0.0') // 服务器外部可访问
.disableHostCheck(true) // 关闭白名单校验
.contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
.historyApiFallback(
disableDotRule: true, // 禁止在链接中使用 "." 符号
rewrites: [
from: /^\\/$/, to: '/index.html' , // 将所有的 404 响应重定向到 index.html 页面
],
)
.port(8080) // 当前端口号
.hot(true) // 打开页面热载功能
.sockPort(以上是关于快来跟我一起学 React(Day3)的主要内容,如果未能解决你的问题,请参考以下文章