# react_webpack **Repository Path**: lin1134/react_webpack ## Basic Information - **Project Name**: react_webpack - **Description**: 从零搭建 react + webpack + typescript + mobx + antd + sass + Editorconfig + Prettier + Eslint + 开发环境 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-02-27 - **Last Updated**: 2025-03-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 从零搭建 react + webpack + typescript + mobx + antd + sass + Editorconfig + Prettier + Eslint + 开发环境(上) ## 先睹为快 本次学习完这篇文章,你将会配置以下内容 - 从零初始化 react 代码仓库 - 配置使用 typescript 开发 - 配置 vscode 编辑器功能 - 配置 editorconfig 编码规范 - 配置 prettier 格式化代码 - 配置 eslint 代码检查 - 支持 sacc/scss/less 预编译 - 配置 webpack 打包工具 - Mock.js使用 - 解决开发环境本地跨域反向代理 - react-router 的创建与使用 - store 的创建与使用 ## 一、配置编码环境 ### 1.配置vscode编码环境 ```json // .vscode/settings.json { "search.exclude": { "/node_modules": true, "dist": true, "pnpm-lock.yaml": true }, "editor.formatOnSave": true, "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], "files.associations": { "*.js": "javascript", "*.jsx": "javascriptreact", "*.ts": "typescript", "*.tsx": "typescriptreact" }, "editor.codeActionsOnSave": { "source.fixAll": "explicit", "source.fixAll.stylelint": "explicit" }, "editor.tabSize": 2, "insertSpaces": true, "autoCloseTag": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[less]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[scss]": { "editor.defaultFormatter": "esbenp.prettier-vscode" } } ``` --- ### 2.配置Editorconfig,用于不同编辑器识别让其拥有相同的代码风格 在根目录下新建 `.editorconfig` 文件,文件内容如下 ``` root = true # 控制配置文件 .editorconfig 是否生效的字段 ​ [**] # 匹配全部文件 indent_style = space # 缩进风格,可选space|tab indent_size = 2 # 缩进的空格数 charset = utf-8 # 设置字符集 trim_trailing_whitespace = true # 删除一行中的前后空格 insert_final_newline = true # 设为true表示使文件以一个空白行结尾 end_of_line = lf ​ [**.md] # 匹配md文件 trim_trailing_whitespace = false ``` --- ### 3.配置Perttier,用于保存时自动格式化代码文件` 先安装 `vscode` 的 `Prettier - Code formatter` 插件,然后在在根目录下创建`.prettierrc.js`文件,配置如下 ```javacript module.exports = { printWidth: 100, // 一行的字符数,如果超过会进行换行 tabWidth: 2, // 一个tab代表几个空格数,默认就是2 useTabs: false, // 是否启用tab取代空格符缩进,.editorconfig设置空格缩进,所以设置为false semi: false, // 行尾是否使用分号,默认为true singleQuote: true, // 字符串是否使用单引号 trailingComma: 'none', // 对象或数组末尾是否添加逗号 none| es5| all jsxSingleQuote: true, // 在jsx里是否使用单引号 bracketSpacing: true, // 对象大括号直接是否有空格,默认为true,效果:{ foo: bar } arrowParens: 'avoid', // 箭头函数如果只有一个参数则省略括号 parser: 'typescript', plugins: [ // 可选(自动整理 imports) // "prettier-plugin-organize-imports" ], overrides: [ { files: ['*.json', '.vscode/*.json'], options: { parser: 'json' // 强制使用 JSON 解析器 } } ] } ``` ### 4.配置Eslint ```javascript pnpm install -D eslint eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-import ``` - eslint-plugin-react: React 组件相关规则(如 JSX 格式、组件生命周期检查) - eslint-plugin-react-hooks: React Hooks 规则(如 useState、useEffect 使用规范) - eslint-plugin-import: 模块导入规范(如路径格式、避免重复导入) - eslint: 代码质量检查工具(核心包) ```javascript const { version } = require('html-webpack-plugin') module.exports = { env: { browser: true, es2021: true, node: true }, plugins: ['react', 'prettier', '@typescript-eslint'], // 使用 Prettier 等规则 extends: [ 'editorconfig', 'react-app', 'eslint:recommended', 'plugin:react/recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react/jsx-runtime', 'plugin:react-hooks/recommended', 'prettier', 'plugin:prettier/recommended' ], // 自定义规则 rules: { // 禁止使用 console.log 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 自定义 React 组件命名规则(例如必须大写开头) 'react/jsx-component-name-type-check': ['error', { propName: 'PascalCase' }], // 允许数组解构中的剩余元素(React 旧版本兼容) 'no-param-reassign': ['error', { props: false }], // 允许在 TSX 中使用箭头函数 'react/tsx-no-bind': ['error', { allowArrowFunctions: true }], 'react/self-closing-comp': 'off', // 允许省略空格的 JSX 语法 'react/jsx-tag-spacing': [ 'error', { closingSlash: 'never', beforeSelfClosing: 'never', afterOpening: 'never', beforeClosing: 'never' } ], '@typescript-eslint/no-non-null-assertion': 'off', 'prettier/prettier': 'error' // 将 Prettier 的格式问题视为 ESLint 的 error }, // 指定解析器(支持 JSX 和 TypeScript) parserOptions: { ecmaVersion: 12, sourceType: 'module', ecmaFeatures: { tsx: true, jsx: true } }, settins: { react: { version: 'detect' } } } ``` ## 二、初始化 react项目 ### 1. 初始化项目 ```sh # 初始化项目 pnpm init # 安装 react 相关依赖 pnpm add -D react react-dom ``` ### 2.配置 typescript ```sh # 安装使用typescript pnpm add -D typescript ts-loader @types/react @types/react-dom # 初始化 typescript 配置文件 tsc --init ``` 修改`tsconfig.json`文件,修改如下内容 ```json { "compilerOptions": { "jsx": "preserve", "target": "ESNext", "module": "ESNext", "moduleResolution": "node", "rootDir": "./src", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "allowJs": true, "outDir": "./dist", "baseUrl": ".", "paths": { "@/*": [ "./src/*" ] }, "typeRoots":["./node_modules/@types",], }, "include": [ "./src" , "src/global.d.ts" ] } ``` ## 三、安装 webpack,并配置 ### (1) 安装 webpack、webpack-cli、webpack-merge ``` pnpm install -D webpack webpack-cli webpack-merge webpack-dev-server ``` - webpack-merge: 合并 webpack 配置 - webpack-cli: webpack 命令行工具 - webpack: webpack 核心库 - webpack-dev-server: webpack 开发服务器, 启动本地服务需要。 新建 `build` 文件夹,在 `build` 文件夹下新建 `webpack.base.js` 文件,用来存放`webpack`公共配置,文件内容如下 ```javascript const path = require('path') const srcDir = path.join(__dirname, '../src') // const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const TerserPlugin = require('terser-webpack-plugin') const os = require('os') const devMode = process.env.NODE_ENV === 'development' module.exports = { entry: { main: path.join(__dirname, '../src/main.tsx') }, output: { path: path.join(__dirname, '../dist'), filename: '[name].[chunkhash:8].js', // publicPath: "/", chunkFilename: 'chunk/[name].[chunkhash:8].js' }, optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { compress: { drop_console: true, // 移除 console.log drop_debugger: true // 移除 debugger }, format: { comments: false // 移除注释 } }, extractComments: false // 不将注释提取到单独的文件中 }) ] }, module: { rules: [ { test: /\.(js|jsx|tsx|ts)$/, include: [srcDir], exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { targets: 'iOS 9, Android 4.4, last 2 versions, > 0.2%, not dead', // 根据项目去配置 useBuiltIns: 'usage', // 会根据配置的目标环境找出需要的polyfill进行部分引入 corejs: 3 // 使用 core-js@3 版本 } ], ['@babel/preset-typescript'], ['@babel/preset-react'] ] } } }, { test: /\.s[ac]ss$/i, use: [ devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader' ] }, { test: /\.css$/, use: [ devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader' ] }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: ['url-loader'], include: [srcDir] }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i, use: ['url-loader'], include: [srcDir] }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, use: ['url-loader'], include: [srcDir] } ] }, plugins: [ new CopyWebpackPlugin({ patterns: [ { from: `${srcDir}/assets/images/**/*`, to: 'img/[name].[hash:8][ext]' } ] }) ], resolve: { // 配置 extensions 来告诉 webpack 在没有书写后缀时,以什么样的顺序去寻找文件 extensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.mjs'], // 如果项目中只有 tsx 或 ts 可以将其写在最前面 alias: { '@': srcDir, '@pages': `${srcDir}/pages` } } } ``` 在 `build` 文件夹下新建 `webpack.dev.js` 文件,用来存放`webpack`开发环境配置,文件内容如下 ```javascript const path = require('path') const { merge } = require('webpack-merge') const base = require('./webpack.base') module.exports = merge(base, { // 模式 mode: 'development', devtool: 'eval-cheap-module-source-map', // 推荐开发模式配置 optimization: { minimize: false, // 明确禁用压缩 minimizer: [] // 清空压缩插件 }, devServer: { open: true, // 编译完自动打开浏览器 port: 8080, hot: true, // 配置热更新 historyApiFallback: true // 支持单页应用 }, // 入口 entry: path.join(__dirname, '../src/main.tsx'), //入口文件 // 输出 output: { filename: 'static/js/[name].js', //每个输出的js文件的名称 path: path.join(__dirname, '../dist'), //打包结果输出的路径 clean: true, publicPath: '/' //打包后文件的公共前缀路径 }, // 加载器 module: {} }) ``` 文件夹下新建 `webpack.prod.js` 文件,用来存放`webpack`开发环境配置,文件内容如下 ```javascript const { merge } = require('webpack-merge') const TerserPlugin = require('terser-webpack-plugin') const base = require('./webpack.base') const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const os = require('os') const HappyPack = require('happypack') // 根据 CPU 核心数创建线程池(默认使用全部核心) const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }) module.exports = merge(base, { // 模式 mode: 'production', devtool: 'hidden-source-map', optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { compress: { drop_console: true, // 移除 console.log drop_debugger: true // 移除 debugger // pure_funcs: ['console.info'] // 保留特定 console 方法 }, format: { comments: false // 移除注释 } }, extractComments: false // 不将注释提取到单独的文件中 }) ] }, plugins: [ new HappyPack({ // id: /\.tsx?$/, id: 'tsx', loaders: ['babel-loader?cacheDirectory=true'], threadPool: happyThreadPool, // cache: true, verbose: true }), new HtmlWebpackPlugin({ template: './public/index.html', // 指定 HTML 模板文件 filename: 'index.html' // 输出文件名(默认就是 index.html) }), new MiniCssExtractPlugin({ filename: '[name].[contenthash:8].css', chunkFilename: '[id].[contenthash:8].css' }) ] }) ``` #### (2)配置balbel ``` pnpm add -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/plugin-transform-runtime ``` - babel-loader: 编译器,用来编译js文件 - @babel/core: Babel的核心库,负责代码的解析、转换和生成 - @babel/preset-env: 根据目标浏览器按需转换语法(如箭头函数、解构) - @babel/preset-react: 处理JSX语法和React特性 - @babel/preset-typescript: 处理TypeScript语法,移除类型注解。 - @babel/plugin-transform-runtime: 优化辅助代码复用方式,解决 @babel/preset-env 的重复注入问题 --- 在根目录下新建 babel.config.js 文件,并编写以下内容: ```javascript // babel.config.js module.exports = api => { api.cache(true) // 启用配置缓存 const presets = [ // 浏览器兼容性处理 [ '@babel/preset-env', { useBuiltIns: 'usage', // 按需加载 polyfill corejs: 3 // 指定 core-js 版本 } ], // React JSX 支持 '@babel/preset-react', // TypeScript 支持 '@babel/preset-typescript' ] const plugins = [ // 复用辅助代码,减少打包体积 '@babel/plugin-transform-runtime', // 开发环境热更新(可选) process.env.NODE_ENV === 'development' && 'react-refresh/babel' ].filter(Boolean) return { presets, plugins } } ``` --- --- ## 四、sass/scss/less 配置 ## 五、配置 webPack ### 1. 安装 webpack,并配置 ### 4.配置Eslint ### 2. 处理样式和加载器 ``` pnpm install -D style-loader css-loader sass sass-loader ``` - style-loader: 将样式插入到 DOM 中 - css-loader: 加载 css 文件 - sass: sass 核心库 - sass-loader: 加载 sass 文件 - postcss-loader: 对css进行转换和优化 --- ``` ``` ### 2. 安装 react-router 内容,并配置 ``` pnpm add -D react-router react-router-dom ``` ### 3. 安装 typescript,并配置 ### 4. 安装 mobx,并配置