React项目构建详解(不含ESLint和Prettier)
React项目构建详解(不含ESLint和Prettier)
一、初始化项目
yarn init
二、Webpack 打包三件套
1.webpack webpack核心
2.webpack-cli 命令行中运行 webpack 的工具
3.webpack-merge 分离的配置进行合并
yarn add webpack webpack-cli webpack-dev-server webpack-merge -D
webpack 相关的东西人家官网写的还是很好,要学会看文档。
三、安装React 和 React-Dom
1.React React核心提供React API
2.ReactDom 渲染器,渲染DOM树
yarn add react react-dom
四、解析器
首先根据考虑需要哪些解析器,比如 html ts js jsx css less sass png jpg ttf 等
举例:
文件或功能 | 解析器或插件 | 备注 |
---|---|---|
html | html-webpack-plugin | html解析和打包插件 |
css | css-loader | css解析器 |
less | less-loader | less解析器 |
sass | sass-loader | sass解析器 |
file | file-loader | 文件解析器 |
thread | thread-loader | 多线程打包 |
mini-css-extract-plugin | mini-css-extract-plugin | css文件提取插件 |
postcss | postcss | css浏览器兼容处理 |
babel-loader | babel-loader | webpack使用babel |
五、babel(代码转化器)
1、作用
高版本ES转换语法到低版本ES语法。
2、安装
yarn add @babel/core core-js @babel/preset-env babel-loader @babel/preset-react @babel/preset-typescript babel-plugin-dynamic-import-node @babel/plugin-transform-runtime @babel/plugin-transform-runtime @babel/plugin-proposal-decorators -D
3、说明
文件或功能 | 解析器或插件 | 备注 |
---|---|---|
@babel/core | @babel/core | babel核心 |
babel-loader | babel-loader | webpack使用babel |
core-js | core-js | JavaScript的模块化标准库 |
@babel/preset-env | @babel/preset-env | 转码插件 |
@babel/preset-react | @babel/preset-react | react转码插件,包含3个插件,有兴趣点击链接了解 |
@babel/preset-typescript | @babel/preset-typescript | typescript转码插件 |
babel-plugin-dynamic-import-node | babel-plugin-dynamic-import-node | import()转require(),使用有些许不一样,可以看下文或者点击查看 |
@babel/plugin-transform-runtime | @babel/plugin-transform-runtime | JavaScript标准库注入 |
@babel/plugin-proposal-decorators | @babel/plugin-proposal-decorators | ES7修饰器转码器 |
其实需要什么功能去搜索就可以了,用法我是直接去npm搜索插件看,再不行点击上面的git地址去看,实在不清楚建议阅读源码,宗旨就是这么一个学习过程,没有捷径,不要什么都喂到嘴里,又不是所有人是你双亲,授人以鱼不如授人以渔。
4、配置
/*babel.config.json*/
{
"comments": false, //注释状态
"presets": [
[
"@babel/preset-env", //语法转化
{
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
},
"useBuiltIns": "usage",
"corejs": 3,
"loose": true
}
],
"@babel/preset-react", //解析React语法,JSX
"@babel/preset-typescript" //解析TS
],
"plugins": [
"dynamic-import-node", //将import() 转为 require()
"@babel/plugin-transform-runtime", //注入兼容性方法
[
"@babel/plugin-proposal-decorators", //ES7修饰器转化
{
"legacy": true
}
]
]
}
六、Typescript(TS配置)
1、作用
为项目能使用Typescript
2、安装
yarn add typescript -D
3、说明
文件或功能 | 解析器或插件 | 备注 |
---|---|---|
typescript | typescript | typescript核心 |
ts-node | ts-node | 直接运行TS代码,看个人需求 |
ts-loader | ts-loader | webpack解析ts代码,推荐使用babel就不用loader了,看个人需求 |
4、配置
(1)初始化
tsc --init
执行命令会生成一个tsconfig.json文件,文件里面有详细的配置说明,更详细的点击配置说明
{
"compilerOptions": {
"module": "commonjs", //设置程序的模块系统。
"target": "es5", //编译目标
"jsx": "react", //控制 JSX 在 JavaScript 文件中的输出方式。
"sourceMap": true, //调试显示原始的 TypeScript 代码。
"removeComments": true, //移除注释
/**
* TypeScript 开启严格模式 ,开启 "noImplicitAny": true,"strictNullChecks": true, "strictFunctionTypes": true,
* "strictBindCallApply": true,"strictPropertyInitialization": true,"noImplicitThis": true,"alwaysStrict": true
*/
"strict": true,
"noImplicitAny": true, //ypeScript无法推断变量的类型时,TypeScript将返回到变量的any。
"strictNullChecks": true, //null和undefined有各自不同的类型
"moduleResolution": "node", //指定模块解析策略
"baseUrl": "./", //基准目录
"typeRoots": ["node_modules/@types"], //类型根路径
"allowSyntheticDefaultImports": true, //允许合成默认导入
"esModuleInterop": true, //ES 模块互操作性
"experimentalDecorators": true //ES7类修饰器允许
},
"exclude": ["node_modules", "config/*"], //忽略文件
"include": ["src/**/*"] //包含文件
}
七、组装
1、html文件书写
新建index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-store, must-revalidate" />
<meta http-equiv="expires" content="Wed, 26 Feb 1997 08:21:57 GMT" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
/>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app_root"></div>
</body>
</html>
2、新建源码文件夹和入口
(1)根目录下新建文件夹src (2)src下新建index.tsx (3)src下新建APP.tsx
//index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
createRoot(document.querySelector('#app_root') as Element).render(<App />);
//APP.tsx
import React, { FC } from 'react';
const App: FC<any> = (props) => {
return <>app</>;
};
export default App;
3、新建webpack配置文件夹和配置文件
(1)在根目录下创建Webpack文件及 (2)在Webpack文件夹下创建webpack.base.js、webpack.dev.js、webpack.prod.js (3)编写webpack配置文件 首先梳理一下 公共部分 入口,ts,js,图片,其他文件,less,html相同 dev模式 less 略微不同,devServer相关配置,代理,resove路径,优化模式 product模式 出口,优化模式, 公共部分配置
//webpack.base.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
const devMode = process.env.NODE_ENV !== 'production';
const resolve = (dir) => path.resolve(__dirname, dir);
module.exports = {
target: 'web',
entry: resolve('../src/index.tsx'), //入口
plugins: [
/**
* html文件处理
*/
new HtmlWebpackPlugin({
title: 'Wizard-RUI',
filename: 'index.html',
template: resolve('../index.html'),
hash: true,
cache: false,
inject: true,
minify: {
removeComments: true,
removeAttributeQuotes: true,
collapseWhitespace: true,
minifyJS: true, // 在脚本元素和事件属性中缩小JavaScript(使用UglifyJS)
minifyCSS: true // 缩小CSS样式元素和样式属性
},
nodeModules: resolve('../node_modules')
}),
/**
* MiniCss插件,在生产环境使用
*/
!devMode
? new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: 'css/[id].[contenthash].css',
ignoreOrder: true
})
: function(){}
],
module: {
rules: [
/**
* 处理less,css 为dev模式下使用style-loader 为pod模式下使用MIniCss
*/
{
test: /\.(le|c)ss$/i,
use: [devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
},
/**
* ts,tsx,js,jsx解析
*/
{
test: /\.(ts|tsx)$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
]
},
/**
* 图片处理
*/
{
test: /\.(png|svg|jpg|gif)$/, // 图片
use: [
{
loader: 'file-loader',
options: {
name: 'assets/images/[name].[ext]' // 存放的位置: dist/assets/images/文件
}
}
]
},
/**
* 字体文件处理
*/
{
test: /\.(woff|woff2|eot|ttf|otf)$/, // 字体
use: [
{
loader: 'file-loader',
options: {
name: 'assets/fonts/[name].[ext]' // 存放的位置: dist/assets/fonts/文件
}
}
]
}
]
}
};
开发环境配置
//webpack.dev.js
const base = require('./webpack.base'); //取出公共部分
const { merge } = require('webpack-merge');
const path = require('path');
const resolve = (dir) => path.resolve(__dirname, dir);
module.exports = merge(base, {
mode: 'development', //开发环境webpack内置优化
devtool: 'inline-source-map', //控制台调试代码
devServer: {
client: {
progress: true //在浏览器中以百分比显示编译进度。
},
compress: false, //gzip压缩
hot: true, //热更新
open: {
app: {
name: 'goole-chrome', //走动打开chrome
arguments: ['--incognito', '--new-window'] //无痕,新的窗口
}
},
port: 8081, //监听端口
proxy: {} //代理配置
},
optimization: {
//优化模式
minimize: false
},
/**
* 路径别名
*/
resolve: {
alias: {
// "@": ["../src"],
'@': resolve('../src/'),
src: resolve('../src/'),
components: resolve('../src/components'),
config: resolve('../src/config'),
hook: resolve('../src/hook'),
apis: resolve('../src/apis'),
router: resolve('../src/router'),
store: resolve('../src/store'),
theme: resolve('../src/theme'),
util: resolve('../src/util'),
i18n: resolve('../src/i18n'),
assets: resolve('../src/assets'),
views: resolve('../src/views')
},
extensions: ['.tsx', '.ts', '.wasm', '.mjs', '.js', '.json']
}
});
生产环境配置
//webpack.prod.js
const base = require('./webpack.base'); //取出公共部分
const { merge } = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
const path = require('path');
const resolve = (dir) => path.resolve(__dirname, dir);
module.exports = merge(base, {
mode: 'production', // 环境 development 和 production 环境 链接: https://www.webpackjs.com/concepts/mode/#mode-development
output: {
filename: 'index.js', // 文件名
path: resolve('../dist'), // 文件输出地址
library: {
/**
* 发布运行环境
* umd——兼容浏览器
* commonjs,commonjs2,module——node
* amd——require.js
* cmd——sea.js
*/
type: 'umd'
},
clean: true
},
optimization: {
//优化模式
minimize: false
},
/**若通过CDN引入React和ReactDOM可以使用 */
// externals: {
// react: 'React',
// 'react-dom': 'ReactDOM'
// },
plugins: [new CleanWebpackPlugin()],
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
}
});
(4)配置运行命令 package.json 的script加入
{
"dev": "webpack-dev-server --config ./webpack/webpack.dev.js",
"build": "webpack --config ./webpack/webpack.prod.js",
"test": "echo \"Error: no test specified\" && exit 1"
}
(5)yarn build,yarn dev 看看成功与否
附件: package.json
{
"name": "wizard-rui",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --config ./webpack/webpack.dev.js",
"build": "webpack --config ./webpack/webpack.prod.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.19.3",
"@babel/core": "^7.20.2",
"@babel/plugin-proposal-decorators": "^7.20.2",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"@typescript-eslint/eslint-plugin": "^5.42.1",
"@typescript-eslint/parser": "^5.42.1",
"babel-loader": "^9.1.0",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-transform-runtime": "^6.23.0",
"clean-webpack-plugin": "^4.0.0",
"core-js": "^3.26.1",
"css-loader": "^6.7.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.6.1",
"prettier": "^2.7.1",
"style-loader": "^3.3.1",
"typescript": "^4.8.4",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
最后还是那就话,授人以鱼不如授人以渔,少抄袭,多学习少年!
转载自:https://juejin.cn/post/7166211968289177636