项目目录
很多报错情况,本篇配置已解决,练习时可以直接用。正式项目可根据自己需求做相应调整和自定义优化。
package.json
{
"name": "common_backstage",
"version": "1.0.0",
"description": "backstage of all stage",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack serve --config webpack.dev.js",
"prettier": "prettier --write .",
"build": "webpack"
},
"repository": {
"type": "git",
"url": "https://gitee.com/guozia007/common_backstage.git"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.21.3",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@types/react": "^18.0.31",
"@types/react-dom": "^18.0.11",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"babel-loader": "^9.1.2",
"core-js": "^3.29.1",
"css-loader": "^6.7.3",
"css-minimizer-webpack-plugin": "^5.0.0",
"eslint": "^8.37.0",
"eslint-plugin-react": "^7.32.2",
"eslint-webpack-plugin": "^4.0.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.5",
"postcss": "^8.4.21",
"postcss-loader": "^7.1.0",
"postcss-preset-env": "^8.2.0",
"prettier": "^2.8.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-refresh": "^0.14.0",
"style-loader": "^3.3.2",
"terser-webpack-plugin": "^5.3.7",
"ts-loader": "^9.4.2",
"typescript": "^5.0.2",
"webpack": "^5.76.3",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.13.1"
},
"dependencies": {},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
public
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>common backstage</title>
</head>
<body>
<noscript>
You need to enable javascript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>
src
src/types/typings.d.ts
/**
* 自定义ts声明
*/
// 支持less scss等的模块化
declare module '*.module.scss' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.module.less' {
const classes: { [key: string]: string };
export default classes;
}
// 支持各种图片
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.svg'
src/index.tsx
import { createRoot } from 'react-dom/client';
import App from '@/App';
const root = createRoot(document.getElementById('root'));
root.render(
<App />
)
src/App.tsx
import { useState } from "react";
import './app.less';
const App = () => {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
}
return <>
<h3>hello react!</h3>
<button
className="btn"
onClick={handleClick}
>You click it {count} times.</button>
</>
}
export default App;
src/app.less
.btn {
display: inline-block;
box-sizing: border-box;
border: 1px solid #ddd;
border-radius: 6px;
background-color: #fff;
outline: none;
padding: 5px 10px;
font-family: cursive;
user-select: none;
-webkit-user-select: none;
cursor: pointer;
}
eslintrc
.eslintrc.js
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
// 配置后 不通过import引入React也不会报错了
// 无需额外安装
"plugin:react/jsx-runtime",
"plugin:@typescript-eslint/recommended"
],
"overrides": [
{
files: ["**/*.tsx"],
// react默认使用prop-types来检查类型
// 如果使用了typescript,就把这个关掉,
// 不然会报一些没有意义的错误
rules: {
"react/prop-types": "off"
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint"
],
"rules": {
}
}
.gitignore
node_modules
dist
lib
.idea
.vscode
prettier
.prettierrc.json
{
"printWidth": 80,
"tabWidth": 4,
"useTabs": true,
"semi": true,
"singleQuote": false,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve"
}
.prettierignore
node_modules
build
dist
lib
*.md
babel
babel.config.js
module.exports = {
presets: [
[
'@babel/preset-env',
{
// 配置该项后,就不需要使用@babel/plugin-transform-plugin了
// 因为useBuiltIns和它一样的作用
useBuiltIns: 'usage',
corejs: {
version: '3.29.1',
proposals: true
}
}
],
[
'@babel/preset-react',
{
// 使用最新的react/jsx-runtime来解析jsx,
// 而非React.createElement
// 此时不需要import引入React
runtime: 'automatic'
}
]
]
}
postcss
postcss.config.js
module.exports = {
plugins: [
'postcss-preset-env'
]
}
tsconfig
{
"compilerOptions": {
// "outDir": "./dist/",
// "sourceMap": true,
"noImplicitAny": true,
// 浏览器不支持CommonJS,所以这里选用ESNext
"module": "ESNext",
"target": "es5",
// 不import引入React也不会报错了
// 相当于支持了react/jsx-runtime功能
"jsx": "react-jsx",
// es模块引入和导出
"esModuleInterop": true,
// 类型声明文件所在目录
"typeRoots": [
"./src/types",
"./node_modules/@types"
],
// paths配置项的前缀目录
"baseUrl": "./",
// 配置文件别名
"paths": {
// @对应src,但是一定要同时配置@和@/*,不然会报错
"@": ["src"],
"@/*": ["src/*"]
}
},
// 编译范围
"include": [
"./src/**/*"
]
}
webpack
webpack.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const EslintWebpackPlugin = require("eslint-webpack-plugin");
// 抽取公共部分
const getStyleOptions = (importLoaders, loader) => {
return [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders
}
},
"postcss-loader",
loader
].filter(Boolean);
}
module.exports = {
mode: 'development',
// 入口文件不再是./src/index.js了
entry: './src/index.tsx',
module: {
rules: [
{
oneOf: [
{
test: /\.css$/,
use: getStyleOptions(1)
},
{
test: /\.less$/,
use: getStyleOptions(2, 'less-loader')
},
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false
}
},
'ts-loader'
]
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/index.html')
}),
// open HMR
new ReactRefreshPlugin(),
new EslintWebpackPlugin({
exclude: 'node_modules',
// 检查jsx js json文件
extensions: ["jsx", "js", "json", 'ts', 'tsx'],
// 只对修改内容的文件做检查
lintDirtyModulesOnly: true,
// 开启多线程
threads: true
})
],
optimization: {},
devtool: 'cheap-module-source-map',
devServer: {
port: 3000
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src')
}
}
}
webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
// 抽取公共部分
const getStyleOptions = (importLoaders, loader) => {
return [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
importLoaders
}
},
"postcss-loader",
loader
].filter(Boolean);
}
module.exports = {
mode: 'production',
entry: {
index: './src/index.tsx'
},
output: {
path: path.resolve(__dirname, 'lib'),
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js'
},
module: {
rules: [
{
oneOf: [
{
test: /\.css$/,
use: getStyleOptions(1)
},
{
test: /\.less$/,
use: getStyleOptions(2, 'less-loader')
},
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
// 开启缓存
cacheDirectory: true,
// 开启压缩
cacheCompression: true
}
},
'ts-loader'
]
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:8].css',
chunkFilename: '[name].[contenthash:8].chunk.css',
runtime: true
}),
],
optimization: {
// 使用代码分割
splitChunks: {
chunks: 'all'
},
minimizer: [
new CssMinimizerPlugin({
exclude: /node_modules/,
// 多进程压缩
parallel: true,
minimizerOptions: {
// 移除css注释
preset: [
"default",
{
discardComments: { removeAll: true },
}
]
}
}),
// 开启压缩
new TerserPlugin({
exclude: /node_modules/,
// 开启多进程压缩
parallel: true,
// 删除注释
terserOptions: {
// 开启gzip压缩
compress: true,
format: {
comments: false,
},
},
extractComments: false
})
]
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src')
}
}
}
测试
npm start
启动项目
打包成功后,打开页面即可看到效果