教你从0到1搭建一个React开发框架(webpack5+typescript+eslint+prettier)
前言
对于刚开始接触并使用create-react-app
脚手架创建一个react前端工程,我们肯定好奇这个工程里面都集成了哪些功能?各个工具之间是怎么协作运用的?每一个工具的主要作用是什么?而像typescript、eslint、babel、prettier这些工具又都提供了相关的插件(plugin),这些plugin又有什么用途?假如要我们自己从0搭建一个react开发框架,又该如何开始?接下来这篇文章,将一步一步基于webpack5,带领大家一起看是如何将这些工具集成在一起使用。
初始化工程
-
创建工程目录:mkdir webpack5-react
-
初始化项目:npm init
webpack基本配置
在上面我们已经初始化了一个空的项目,这里我们首先安装配置webpack。
-
首先安装webpack相关包:
yarn add webpack webpack-cli webpack-dev-server webpack-merge --dev
说明下几个包的功能:
- webpack: webpack的核心包
- webpack-cli: 从webpack4之前的版本中,webpack-cli和webpack都在一个包里,从webpack4开始被单独作为一个包,用来在命令行中运行webpack的工具。
- webpack-dev-server: 在开发环境帮我们开启一个本地开发服务。
- webpack-merge: 合并webpack的配置,帮助区分开发环境和生产环境不同的配置。
-
根目录添加文件
- 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><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
- index.js: 入口文件
function add(num1, num2){
return num1 + num2
}
- webpack.config.js: webpack公共配置文件
const path = require('path');
console.log(path.resolve(__dirname, 'dist'));
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
optimization: {
// 单纯添加新文件或者依赖,不对别的bundle的contenthash产生影响。
moduleIds: 'deterministic',
// 将 runtime 代码拆分为一个单独的 chunk,dist目录将会多出一个runtime文件
runtimeChunk: 'single',
// tree shaking
usedExports: true,
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
module: {
rules: []
},
plugins: []
};
- webpack.dev.js: 开发环境配置
const {merge} = require('webpack-merge');
const commonConfig = require('./webpack.config.js');
module.exports = merge(commonConfig, {
// 模式
mode: 'development',
// 启用sourcemap
devtool: 'inline-source-map',
// dev-server
devServer: {
static: './dist',
// HMR
hot: true
},
})
- webpack.prod.js:生产环境配置
const {merge} = require('webpack-merge');
const commonConfig = require('./webpack.config.js');
module.exports = merge(commonConfig, {
mode: 'production',
})
-
添加webpack插件html-webpack-plugin
在上面我们已经在根目录添加了index.html,我们安装html-webpack-plugin,在执行webpack大包的过程中就可以依据index.html为模版,输出html模版文件并自动引入大包过程中输出的资源文件如script、link等。
yarn add html-webpack-plugin --dev
然后在webpack.config.js文件添加配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({
title: 'webpack for react',
template: './index.html'
})
]
-
图片、字体等资源文件处理
webpack5内置了Asset Modules,我们只需要添加对应配置
在webpack.config.js的module的rules添加如下配置:
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
include: path.resolve(__dirname, 'src'),
type: 'asset/resource'
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
include: path.resolve(__dirname, 'src'),
type: 'asset/resource'
}
]
-
css、less、scss、sass支持
webpack默认只支持对js文件的处理,所以我们对于不同的文件需要对应的loader支持处理
安装:
yarn add style-loader css-loader less less-loader sass sass-loader --dev
各个包的作用说明:
- style-loader:通过js脚本创建一个style标签将样式添加到html之中。
- css-loader: 支持webpack处理css文件。
- less:less的解析核心包。
- less-loader: 支持webapck处理less文件
- sass: sass的解析核心包,之前需要安装node-sass,现在默认安装dart-sass。
- sass-loader: 支持webpack处理scss\sass文件
然后在webpack.config.js添加对应配置:
rules: [
{
test: /\.css$/i,
include: path.resolve(__dirname, 'src'),
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/i,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', 'sass-loader']
},
]
-
添加babel支持es6+语法,jsx支持
babel的主要作用可以概括为三个:
- 编译es6语法
- 实现旧版本浏览器不支持的api
- 支持jsx
安装:
yarn add babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime
包说明:
- @babel/core: babel 核心包
- @babel/preset-env: 官方提供的一个智能预设,它允许开发者使用
最新
的 javascript,儿无需管理目标环境需要哪些语法转换。 - babel-loader: 允许 webpack 使用 babel 转移 javascript 文件
- @babel/plugin-transform-runtime:
这个包需要理解下,在使用@babel/preset-env 做语法转换时候,babel 在转换后的代码里面注入辅助函数
,以便语法转换时候使用。@babel/runtime 这个包提供了 babel 所有的语法转换的辅助函数包。而@babel/plugin-transform-runtime 其中之一功能就是自动引入需要用到的辅助函数包。
- 自动移除语法转换后内联的辅助函数
- 当代码里使用了 core-js 的 API,自动引入@babel/runtime-corejs3/core-js-stable/,以此来替代全局引入的 core-js/stable;
- 当代码里使用了 Generator/async 函数,自动引入@babel/runtime/regenerator,以此来替代全局引入的 regenerator-runtime/runtime;
这里再重点说明下@babel/preset-env这个包,对于这个包的理解,可以分为两个部分:
- preset,预设,babel 编译了 es6+的语法和 api,是通过一个个插件 plugin 去实现的。然而每年都会有新的提案、新的语法、新的 api,但是我们不可能一个一个插件去配置,所以就有了 preset-env 这个包;我们可以把它理解为一个
语法插件集合包
,这样我们只需要安装这一个包,就不需要一个一个插件配置,方便的使用和编译最新的语法了。 - env,指的是环境,我们可以通过它配置我们代码运行的目标环境,它来控制哪些语法需要 polyfill。它只提供编译 es6+语法,并不包含新的 es6+API.
webpack添加bebel配置:
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
根目录创建babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.30.2"
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime"
]
]
}
-
react配置
在有了前面的基础配置,我们可以安装react来完成对react的支持。
yarn add react react-dom @babel/preset-react
包说明:
- react,react-dom:react官方核心包
- @babel/preset-react:babel的react预设,使babel能够支持处理react的jsx语法
然后我们还需要在babel.config.json文件添加react预设
[
"@babel/preset-react",
{
// 新版的jsx转换,不需要强制引入react
"runtime": "automatic"
}
],
添加typescript支持
这里需要提前说明,现在我们添加typescript需要影响到的有:
- webpack: 使得webpack能够支持ts,tsx文件
- babel: 使得babel能够解析ts语法
安装:
yarn add typescript ts-loader --dev
yarn add @types/react @types/react-dom @babel/preset-typescript
包说明:
-
typescript: typescript核心包
-
ts-loader: webpack的loader,能够处理ts文件
-
@types/react@types/react-dom:react和react-dom的类型文件包
-
@babel/preset-typescript:使得babel能够解析ts tsx
-
根目录创建tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
"rootDir": "./",
"module": "es6",
"target": "es5",
"strict": true,
"alwaysStrict": true,
"importHelpers": true,
"moduleResolution": "node",
"esModuleInterop": true,
"declaration": true,
"jsx": "react-jsx",
"allowJs": false,
"checkJs": false,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
},
"allowUnreachableCode": true,
"noImplicitAny": true,
"noImplicitThis": false,
"noUnusedLocals": true,
"noImplicitReturns": false,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
-
webpack添加对应loader配置
{
test: /\.(jsx?)|(tsx?)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
},
-
babel.config.json添加配置
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.30.2"
}
],
[
"@babel/preset-react",
{
"runtime": "automatic"
}
],
// typescript
["@babel/preset-typescript"]
],
"plugins": [
[
"@babel/plugin-transform-runtime"
]
]
}
添加editorconfig
为什么要添加editorconfig?
在一个团队开发项目中,不能保证团队中成员全部采用相同编辑器,这就会造成项目代码格式无法统一问题。不同的编辑器之间的格式可能不同、缩进可能不同。那么如何保证团队成员的代码多人开发风格统一呢?
editorconfig 官方:EditorConfig 帮助开发人员在不同的编辑器和 IDE 之间定义和维护一致的编码样式。
项目根目录创建文件:.editorconfig文件
root = true
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.{js,css,html,vue,tsx,less,scss}]
charset = utf-8
indent_style = space
indent_size = 2
注意
:vscode 默认不支持 editorconfig,需要自行安装插件
添加prettier
prettier是一个统一代码风格的格式化工具。
安装:
yarn add prettier --dev
根目录新建文件:.prettierrc.js
module.exports = {
// 行尾需要有分号
semi: true,
// 末尾不需要逗号
trailingComma: 'none',
// 使用单引号
singleQuote: true,
// 一行最多 160 字符
printWidth: 160,
// 不使用缩进符,而使用空格
useTabs: false,
// 使用 2 个空格缩进
tabWidth: 2,
// 大括号内的首尾需要空格
bracketSpacing: true,
// 箭头函数,只有一个参数的时候,不需要括号
arrowParens: 'always', // always
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'ignore',
// 换行符使用 lf crlf auto
endOfLine: 'lf'
};
现在有了prettier,我们希望可以在保存的时候自动格式化我们的代码。以vscode为例,我们可以在项目根目录添加.vscode目录,并新建settings.json
{
// 保存自动格式化
"editor.formatOnSave": true
}
添加eslint
eslint是一个插件化的javascript的代码检查工具。可以帮助开发者避免和修复代码中潜在的问题。
安装:
yarn add eslint eslint-webpack-plugin @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier eslint-plugin-react --dev
包说明:
- eslint: eslint 核心包
- eslint-webpack-plugin: webpack5 已经弃用 eslint-loader,而是采用插件 eslint-webpack-pplugin,可以在构建过程中执行eslint
- @typescript-eslint/parser:一个 eslint 解析器,使 eslint 可以解析 typescript,eslint 默认解析器只能解析 js
- @typescript-eslint/eslint-plugin: typescript 语法的默认推荐
- eslint-config-prettier: 处理 eslint 的一些检查与 prettier 冲突,采用 prettier。
- eslint-plugin-react: 让eslint检查react语法。
项目根目录添加文件:.eslintrc.js和.eslintignore文件
module.exports = {
root: true,
env: {
browser: true,
es6: true
},
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: __dirname,
ecmaVersion: 12,
ecmaFeatures: {
jsx: true
}
},
// 扩展
// eslint:recommended 官方推荐扩展,
// eslint开头的是官方扩展。
// plugin开头的是插件类型
// 还有一种形式来自npm包的形式,官方规定npm包的扩展必须以esling-config-开头,使用时可以省略开头,如eslint-config-react-app,直接写成react-app
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'prettier'],
// 插件
plugins: ['@typescript-eslint'],
//
rules: {}
};
/node_modules
/dist
/*.js
总结
本篇文章介绍了从0到1如何搭建一个react的前端开发框架并集成typescript、eslint、prettier等的综合配置,简单介绍了在配置每个功能过程中需要安装用到依赖包以及包的作用。typescript、eslint、prettier在这篇文章并没有进行详细的说明,后续可能会给每一个单独写到一篇文章中去详细的讲解。如果有问题,欢迎评论区交流。
转载自:https://juejin.cn/post/7241813423461351483