河北省做網(wǎng)站哪家公司好國(guó)際新聞界期刊
1、用vite搭建項(xiàng)目
使用npm create vite@latest構(gòu)建項(xiàng)目,配置項(xiàng)選項(xiàng)react->ts+SWC即可。
讓后打開項(xiàng)目npm i。
2、項(xiàng)目配置
2.1、vite配置
主要是配置用到的插件(plugins--比如:svg、mock等)、路徑、環(huán)境變量的使用、打包、路徑重寫等操作。
// 導(dǎo)入React插件,使用Swc作為JSX到JS的轉(zhuǎn)換器,提高構(gòu)建速度
import react from '@vitejs/plugin-react-swc'
// 導(dǎo)入Vite的類型定義,用于類型安全的配置
import type { ConfigEnv, UserConfig } from 'vite'
// 導(dǎo)入Vite的環(huán)境變量加載函數(shù)
import { loadEnv } from 'vite'
// 導(dǎo)入自定義的環(huán)境變量處理函數(shù)
import { wrapperEnv } from './scripts/utils'
// 導(dǎo)入SVG圖標(biāo)插件
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
// 導(dǎo)入Vite的模擬請(qǐng)求插件
import { viteMockServe } from 'vite-plugin-mock'
// 導(dǎo)入Node.js的路徑解析模塊
import { resolve } from 'path'// 定義并導(dǎo)出配置函數(shù),接收命令和模式參數(shù),返回用戶配置對(duì)象
export default({command, mode}: ConfigEnv): UserConfig => {// 獲取項(xiàng)目根目錄的絕對(duì)路徑const root = process.cwd()// 判斷當(dāng)前命令是否為構(gòu)建命令const isBuild = command === 'build'// 根據(jù)模式加載環(huán)境變量const env = loadEnv(mode, root)// 使用自定義函數(shù)處理環(huán)境變量,可能包括類型轉(zhuǎn)換或邏輯處理const viteEnv: any = wrapperEnv(env)// 解構(gòu)賦值,從處理后的環(huán)境變量中提取端口號(hào)和控制臺(tái)日志開關(guān)const { VITE_PORT, VITE_DROP_CONSOLE } = viteEnv// 返回配置對(duì)象return {// 部署路徑,空字符串意味著部署在根目錄base : '',// 服務(wù)器配置server: {// 監(jiān)聽所有網(wǎng)絡(luò)接口host: '0.0.0.0',// 設(shè)置服務(wù)器端口port: VITE_PORT,// 啟動(dòng)服務(wù)器時(shí)自動(dòng)打開瀏覽器open: true,// 關(guān)閉HTTPShttps: false,// 代理配置,此處未配置代理規(guī)則proxy: {},},// 插件配置plugins: [// 啟用React插件react(),// 配置SVG圖標(biāo)插件createSvgIconsPlugin({// 指定圖標(biāo)目錄iconDirs: [resolve(process.cwd(), 'src/assets/icons')],// 設(shè)置生成的SVG圖標(biāo)ID前綴symbolId: 'icon-[dir]-[name]'}),// 配置模擬請(qǐng)求插件viteMockServe({// 模擬數(shù)據(jù)目錄mockPath: 'mock',// 忽略以_開頭的文件ignore: /^_/,// 開發(fā)環(huán)境啟用模擬數(shù)據(jù)localEnabled: !isBuild,// 生產(chǎn)環(huán)境啟用模擬數(shù)據(jù)prodEnabled: isBuild,// 注入代碼,用于初始化生產(chǎn)環(huán)境的模擬數(shù)據(jù)injectCode: `import { setupProdMockServer } from 'mock/_createProductionServer';setupProdMockServer()`})],// 構(gòu)建配置build: {// 設(shè)置目標(biāo)ES版本target: 'es2015',// 設(shè)置CSS兼容性目標(biāo)cssTarget: 'chrome86',// 使用Terser進(jìn)行代碼壓縮minify: 'terser',// Terser的配置選項(xiàng)terserOptions: {// 壓縮選項(xiàng)compress: {// 保留Infinity關(guān)鍵字keep_infinity: true,// 生產(chǎn)環(huán)境刪除控制臺(tái)日志drop_console: VITE_DROP_CONSOLE}},// 設(shè)置警告的代碼塊大小限制chunkSizeWarningLimit: 2000},// 路徑別名配置resolve: {// 設(shè)置@別名指向src目錄alias: {'@': resolve(__dirname, './src')}}}
}utils.js
declare type Recordable<T = any> = Record<string, T>interface ViteEnv {VITE_PORT: numberVITE_PROXY: [string, string][]VITE_DROP_CONSOLE: boolean
}// read all environment variable configuration files to process.env
export function wrapperEnv(envConf: Recordable): ViteEnv {const result: any = {}for (const envName of Object.keys(envConf)) {let realName = envConf[envName].replace(/\\n/g, '\n')realName = realName === 'true' ? true : realName === 'false' ? false : realNameif (envName === 'VITE_PORT') {realName = Number(realName)}if (envName === 'VITE_PROXY' && realName) {try {realName = JSON.parse(realName.replace(/'/g, '"'))} catch (error) {realName = ''}}result[envName] = realNameif (typeof realName === 'string') {process.env[envName] = realName} else if (typeof realName === 'object') {process.env[envName] = JSON.stringify(realName)}}return result
}
2.2、eslint+prettier代碼檢測(cè)
在json配置文件中的scripts執(zhí)行操作下添加:
? ? "lint:eslint": "eslint --cache \"{src,mock,build}/**/*.{js,ts,tsx}\" --fix",
? ? "lint:prettier": "prettier --write \"src/**/*.{js,json,ts,tsx,css,less,html,md}\"",
2.2.1、eslint
用到的庫(kù):
? ? "eslint": "^8.56.0",
? ? "eslint-config-prettier": "^9.0.0",
? ? "eslint-define-config": "^2.1.0",
? ? "eslint-plugin-prettier": "^5.0.1",
? ? "eslint-plugin-react": "^7.33.2",
? ? "eslint-plugin-react-hooks": "^4.6.0",
? ? "vite-plugin-eslint": "^1.8.1",
?eslint.config.js配置文件--文件是 ESLint 的配置文件之一,它以 JavaScript 文件的形式存在,用于定義 ESLint 的配置規(guī)則。在早期版本的 ESLint 中,配置文件可能被命名為?.eslintrc
、.eslintrc.json
?或?.eslintrc.yml
?等,但在 ESLint 8.0.0 版本之后,默認(rèn)推薦使用?eslint.config.{js,cjs,mjs}
?這樣的命名方式
// 配置文檔: https://eslint.nodejs.cn/
import { defineFlatConfig } from 'eslint-define-config'
import configPrettier from 'eslint-config-prettier'
import pluginPrettier from 'eslint-plugin-prettier'
import * as parserTypeScript from '@typescript-eslint/parser'
import pluginTypeScript from '@typescript-eslint/eslint-plugin'
import js from '@eslint/js'/** @type {import('eslint-define-config').FlatESLintConfig} */
export default defineFlatConfig([{...js.configs.recommended,ignores: ['src/assets/**'],plugins: {prettier: pluginPrettier},rules: {...configPrettier.rules,...pluginPrettier.configs.recommended.rules,/** Eslint規(guī)則配置* 配置文檔: https://eslint.nodejs.cn/docs/latest/rules/*/// 需要 let 或 const 而不是 var'no-var': 'error',// 禁止在定義變量之前使用變量'no-use-before-define': 'off',// 聲明后永遠(yuǎn)不會(huì)重新分配的變量需要 const 聲明'prefer-const': 'error',// 禁止不規(guī)則空格'no-irregular-whitespace': 'off',// 禁止使用 debugger'no-debugger': 'off',// 禁止未使用的變量'no-unused-vars': ['error',{argsIgnorePattern: '^_',varsIgnorePattern: '^_'}],// 使用 prettier 插件'prettier/prettier': ['error',{endOfLine: 'auto'}]}},{files: ["**/*.?([cm])ts", "**/*.?([cm])tsx"],languageOptions: {parser: parserTypeScript,parserOptions: {ecmaVersion: 2020,sourceType: 'module',jsxPragma: 'React',ecmaFeatures: {jsx: true}},},plugins: {'@typescript-eslint': pluginTypeScript},rules: {...pluginTypeScript.configs.recommended.rules,/** TypeScript規(guī)則配置* 配置文檔: https://typescript-eslint.nodejs.cn/rules/)*/// 根據(jù)參數(shù)、屬性和變量的默認(rèn)值或初始值推斷其類型'@typescript-eslint/no-inferrable-types': 'off',// 禁止使用自定義 ts 模塊和命名空間'@typescript-eslint/no-namespace': 'off',// 禁止使用 any 類型'@typescript-eslint/no-explicit-any': 'off',// 禁止使用特定類型'@typescript-eslint/ban-types': 'off',// 不允許對(duì)初始化為數(shù)字、字符串或布爾值的變量或參數(shù)進(jìn)行顯式返回類型聲明'@typescript-eslint/explicit-function-return-type': 'off',// 不允許在 import 語句中使用 require 語句'@typescript-eslint/no-var-requires': 'off',// 禁止空函數(shù)'@typescript-eslint/no-empty-function': 'off',// 禁止在變量定義之前使用它們'@typescript-eslint/no-use-before-define': 'off',// 禁止 @ts-<directive> 注釋代碼'@typescript-eslint/ban-ts-comment': 'off',// 不允許使用后綴運(yùn)算符的非空斷言(!)'@typescript-eslint/no-non-null-assertion': 'off',// 要求導(dǎo)出函數(shù)和類的公共類方法的顯式返回和參數(shù)類型'@typescript-eslint/explicit-module-boundary-types': 'off',// 使用頂層 type 限定符進(jìn)行導(dǎo)入'@typescript-eslint/no-import-type-side-effects': 'error',// 不允許在可選鏈表達(dá)式后使用非空斷言'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',// 禁止定義未使用的變量'@typescript-eslint/no-unused-vars': ['warn',{argsIgnorePattern: '^_',varsIgnorePattern: '^_'}],// 允許在導(dǎo)入上指定 type 關(guān)鍵字'@typescript-eslint/consistent-type-imports': ['error',{disallowTypeAnnotations: false,fixStyle: 'inline-type-imports'}],// 允許枚舉成員的值是多種不同類型的有效 js 表達(dá)式'@typescript-eslint/prefer-literal-enum-member': ['error',{allowBitwiseExpressions: true}]}},{files: ['*.d.ts'],rules: {'eslint-comments/no-unlimited-disable': 'off','import/no-duplicates': 'off','unused-imports/no-unused-vars': 'off'}},{files: ['*.?([cm])js'],rules: {'@typescript-eslint/no-require-imports': 'off','@typescript-eslint/no-var-requires': 'off'}}
])// export default {
// root: true,
// env: {
// browser: true,
// node: true,
// es6: true
// },
// settings: {
// react: {
// version: 'detect'
// }
// },
// // 指定如何解析語法
// parser: '@typescript-eslint/parser',
// // 優(yōu)先級(jí)低于 parse 的語法解析配置
// parserOptions: {
// ecmaVersion: 7,
// sourceType: 'module',
// jsxPragma: 'React',
// ecmaFeatures: {
// jsx: true
// }
// },
// plugins: ['react', '@typescript-eslint', 'react-hooks', 'prettier'],
// // 繼承某些已有的規(guī)則
// extends: [
// 'eslint:recommended',
// 'plugin:react/recommended',
// 'plugin:@typescript-eslint/recommended',
// 'plugin:react/jsx-runtime',
// 'plugin:react-hooks/recommended',
// 'prettier',
// 'plugin:prettier/recommended'
// ],
// /*
// * 'off' 或 0 ==> 關(guān)閉規(guī)則
// * 'warn' 或 1 ==> 規(guī)則提示為警告(不影響代碼執(zhí)行)
// * 'error' 或 2 ==> 規(guī)則提示為錯(cuò)誤(代碼不能執(zhí)行,界面報(bào)錯(cuò))
// */
// rules: {
// /*
// * Eslint規(guī)則配置
// * 配置文檔: https://eslint.nodejs.cn/docs/latest/rules/
// */
// // 需要 let 或 const 而不是 var
// 'no-var': 'error',
// // 禁止在定義變量之前使用變量
// 'no-use-before-define': 'off',
// // 聲明后永遠(yuǎn)不會(huì)重新分配的變量需要 const 聲明
// 'prefer-const': 'error',
// // 禁止不規(guī)則空格
// 'no-irregular-whitespace': 'off',
// // 禁止使用 debugger
// 'no-debugger': 'off',
// // 禁止未使用的變量
// 'no-unused-vars': [
// 'error',
// {
// argsIgnorePattern: '^_',
// varsIgnorePattern: '^_'
// }
// ],
// // 使用 prettier 插件
// 'prettier/prettier': [
// 'error',
// {
// endOfLine: 'auto'
// }
// ],// /*
// * TypeScript規(guī)則配置
// * 配置文檔: https://typescript-eslint.nodejs.cn/rules/)
// */
// // 根據(jù)參數(shù)、屬性和變量的默認(rèn)值或初始值推斷其類型
// '@typescript-eslint/no-inferrable-types': 'off',
// // 禁止使用自定義 ts 模塊和命名空間
// '@typescript-eslint/no-namespace': 'off',
// // 禁止使用 any 類型
// '@typescript-eslint/no-explicit-any': 'off',
// // 禁止使用特定類型
// '@typescript-eslint/ban-types': 'off',
// // 不允許對(duì)初始化為數(shù)字、字符串或布爾值的變量或參數(shù)進(jìn)行顯式返回類型聲明
// '@typescript-eslint/explicit-function-return-type': 'off',
// // 不允許在 import 語句中使用 require 語句
// '@typescript-eslint/no-var-requires': 'off',
// // 禁止空函數(shù)
// '@typescript-eslint/no-empty-function': 'off',
// // 禁止在變量定義之前使用它們
// '@typescript-eslint/no-use-before-define': 'off',
// // 禁止 @ts-<directive> 注釋代碼
// '@typescript-eslint/ban-ts-comment': 'off',
// // 不允許使用后綴運(yùn)算符的非空斷言(!)
// '@typescript-eslint/no-non-null-assertion': 'off',
// // 要求導(dǎo)出函數(shù)和類的公共類方法的顯式返回和參數(shù)類型
// '@typescript-eslint/explicit-module-boundary-types': 'off',
// // 使用頂層 type 限定符進(jìn)行導(dǎo)入
// '@typescript-eslint/no-import-type-side-effects': 'error',
// // 禁止定義未使用的變量
// '@typescript-eslint/no-unused-vars': [
// 'error',
// {
// argsIgnorePattern: '^_',
// varsIgnorePattern: '^_'
// }
// ],
// // 允許在導(dǎo)入上指定 type 關(guān)鍵字
// '@typescript-eslint/consistent-type-imports': [
// 'error',
// {
// disallowTypeAnnotations: false,
// fixStyle: 'inline-type-imports'
// }
// ],
// // 允許枚舉成員的值是多種不同類型的有效 js 表達(dá)式
// '@typescript-eslint/prefer-literal-enum-member': [
// 'error',
// {
// allowBitwiseExpressions: true
// }
// ],// 'react-hooks/rules-of-hooks': 'off',
// 'react-hooks/exhaustive-deps': 'off'
// }
// }
.eslintignore配置--用于指定 ESLint 應(yīng)該忽略不進(jìn)行 lint 檢查的文件或目錄
.vscode
.idea
.husky
.local/public
/docs
/src/assets
dist
node_modules
pnpm-lock.yaml
Dockerfileeslint.config.js
postcss.config.js
prettier.config.js
commitlint.config.js*.md
*.woff
*.ttf
2.2.1、prettier
用到的插件:
? "eslint-config-prettier": "^9.0.0",
? ? "eslint-plugin-prettier": "^5.0.1",
"prettier": "^3.1.0",
prettier.config.js配置文件
// 配置文檔: https://prettier.nodejs.cn//** @type {import('prettier').Config} */
export default {// 每行最大寬度,超過換行printWidth: 120,// 縮進(jìn)級(jí)別的空格數(shù)tabWidth: 2,// 用制表符而不是空格縮進(jìn)行useTabs: false,// 語句末尾用分號(hào)semi: false,// 使用單引號(hào)而不是雙引號(hào)singleQuote: true,// 在 JSX 中使用單引號(hào)而不是雙引號(hào)jsxSingleQuote: true,// 尾隨逗號(hào)trailingComma: 'none',// 對(duì)象字面量中括號(hào)之間有空格 { foo: bar }bracketSpacing: true,// 將多行 HTML(HTML、JSX)元素的 > 放在最后一行的末尾,而不是單獨(dú)放在下一行bracketSameLine: false,// 在唯一的箭頭函數(shù)參數(shù)周圍包含括號(hào)(avoid:省略括號(hào), always:不省略括號(hào))arrowParens: 'avoid',// 換行符使用 lf 結(jié)尾 可選值 auto|lf|crlf|crendOfLine: 'lf'
}
.prettierignore配置文件
/dist/*
/public/*
/node_modules/**.local
**/*.svgeslint.config.js
postcss.config.js
prettier.config.js
commitlint.config.js
2.3、husky
作為提交的代碼檢測(cè)工具
配置如下:
執(zhí)行文件:
"prepare": "husky install"
安裝包:
? ?"husky": "^8.0.3",
安裝過后執(zhí)行prepare就行了,會(huì)生成husky文件。
3、開發(fā)配置
3.1、axios二次封裝
/utils/axios
import type { InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import axios from 'axios'
import { message } from 'antd'
import { getToken, clearAuthCache } from '@/utils/auth'// Create axios instance
const service = axios.create({baseURL: '/api',timeout: 10 * 1000
})// Handle Error
const handleError = (error: AxiosError): Promise<AxiosError> => {if (error.response?.status === 401 || error.response?.status === 504) {//登錄失效,這里自己處理clearAuthCache()location.href = '/login'}message.error(error.message || 'error')return Promise.reject(error)
}// Request interceptors configuration
service.interceptors.request.use((config: InternalAxiosRequestConfig) => {const token = getToken()if (token) {;(config as Recordable).headers['Authorization'] = `${token}`};(config as Recordable).headers['Content-Type'] = 'application/json'return config
}, handleError)// Respose interceptors configuration
service.interceptors.response.use((response: AxiosResponse) => {const data = response.dataif (data.code === 0) {return data.data} else {message.error(data.message)return Promise.reject('error')}
}, handleError)export { service }
3.2、包安裝
根據(jù)項(xiàng)目而定,需要什么包可以提前規(guī)劃好,初始化項(xiàng)目
3.3、配置所需要掛載的包
在main里面:
import React from 'react'
import ReactDOM from 'react-dom/client'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import { store, persistor } from './stores'
import App from './App'
import '@/design/index.less'// register svg icon
import 'virtual:svg-icons-register'ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<React.StrictMode><Provider store={store}><PersistGate persistor={persistor}><App /></PersistGate></Provider></React.StrictMode>
)
3.4、配置env
這里配置的env,還有.env.development、.env.production都可以配置,根據(jù)需要而定。
.env
VITE_GLOB_APP_TITLE = 'react-admin-design'VITE_PORT = 8203VITE_BUILD_GZIP = falseVITE_DROP_CONSOLE = true
3.5、mook配置
安裝mookjs
一個(gè)是mock數(shù)據(jù)的,一個(gè)是掛載vite的
"mockjs": "^1.1.0","vite-plugin-mock": "2.9.8",
在vite的plugins里面添加如下:
里面包含mock路徑,一般跟src同級(jí)
viteMockServe({mockPath: 'mock',ignore: /^_/,localEnabled: !isBuild,prodEnabled: isBuild,injectCode: `import { setupProdMockServer } from 'mock/_createProductionServer';setupProdMockServer()`})
具體的使用去倉(cāng)庫(kù)看:https://github.com/goodkets/react-admin-design
大概配置就是這樣,還有很多大項(xiàng)目的配置肯定不止如此,比如多語言、測(cè)試工具、打包優(yōu)化、包管理限制等啥的,我這里只用到了基本項(xiàng)目的配置。