项目模板
模板地址 如果急用,直接使用当前模板即可。点击右上角Use This Template即可创建一个新的项目。
背景
当我每每创建一个新的webpack项目时,总是需要经过繁琐的webpack配置来完成项目的init。如果从网络上搜寻快速的setup总会遇到各种各样的问题(由于包的版本有更新,有些配置已经废弃掉了)所有我决定搭建自己的webpack配置模板。
搭建步骤
1. pnpm 开启webpack项目
1.1 生成package.json
bash
pnpm init
1.2 引入webpack
bash
pnpm add -D webpack webpack-cli webpack-dev-server
1.3 引入typescript
bash
pnpm add -D typescript ts-node @types/node
1.4 引入react
bash
pnpm add react react-dom
bash
pnpm add -D @types/react @types/react-dom
2. 初始化react代码
2.1 创建src/app.tsx
ts
const App = () => {
return <div>Hello World</div>
}
export default App
2.2 创建src/index.tsx
ts
import { createRoot } from 'react-dom/client'
import App from './app'
createRoot(document.getElementById('root')!).render(<App />)
3. webpack配置
3.1 创建webpack.config.ts
ts
import path from 'path'
import { fileURLToPath } from 'url'
import type { Configuration } from 'webpack'
const rootDir = path.dirname(fileURLToPath(import.meta.url))
const config: Configuration = {
entry: './src/index.tsx',
output: {
path: path.resolve(rootDir, 'dist'),
filename: '[name].[contenthash].js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
devtool: 'source-map',
module: {},
mode: 'development'
}
export default config
3.2 设置webpack插件
bash
pnpm add -D html-webpack-plugin clean-webpack-plugin
在public下创建index.html
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Webpack React Template</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
webpack 补充插件配置以及devServer配置
ts
import path from 'path'
import { fileURLToPath } from 'url'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import { CleanWebpackPlugin } from 'clean-webpack-plugin'
import type { Configuration } from 'webpack'
import 'webpack-dev-server'
const rootDir = path.dirname(fileURLToPath(import.meta.url))
const config: Configuration = {
entry: './src/index.tsx',
output: {
path: path.resolve(rootDir, 'dist'),
filename: '[name].[contenthash].js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new CleanWebpackPlugin()
],
devtool: 'source-map',
devServer: {
static: {
directory: path.join(rootDir, 'public')
},
compress: true,
historyApiFallback: true
},
mode: 'development'
}
export default config
3.3 设置webpack loader(style)
bash
pnpm add -D style-loader css-loader sass sass-loader
引入到webpack config的rules中:
ts
const config: Configuration = {
entry: './src/index.tsx',
output: {
path: path.resolve(rootDir, 'dist'),
filename: '[name].[contenthash].js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new CleanWebpackPlugin()
],
devtool: 'source-map',
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/i,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/i,
type: 'asset/resource'
}
]
},
devServer: {
static: {
directory: path.join(rootDir, 'public')
},
compress: true,
historyApiFallback: true
},
mode: 'development'
}
export default config
这里还引入静态资源的rules直接从asset/resource中获取。 因为我们引入了sass,这里我们还需要定义sass文件(.sass,.scss)的模块类型,在src/types里创建index.d.ts:
ts
declare module '*.scss' {
const content: { [className: string]: string }
export default content
}
3.4 设置webpack babel
bash
pnpm add -D @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript babel-loader
在config进行如下配置
ts
import path from 'path'
import { fileURLToPath } from 'url'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import { CleanWebpackPlugin } from 'clean-webpack-plugin'
import type { Configuration } from 'webpack'
import 'webpack-dev-server'
const rootDir = path.dirname(fileURLToPath(import.meta.url))
const config: Configuration = {
entry: './src/index.tsx',
output: {
path: path.resolve(rootDir, 'dist'),
filename: '[name].[contenthash].js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new CleanWebpackPlugin()
],
devtool: 'source-map',
module: {
rules: [
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
['@babel/preset-react', { runtime: 'automatic' }],
'@babel/preset-typescript'
]
}
}
]
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/i,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/i,
type: 'asset/resource'
}
]
},
devServer: {
static: {
directory: path.join(rootDir, 'public')
},
compress: true,
historyApiFallback: true
},
mode: 'development'
}
export default config
4. typescript配置
根目录上创建tsconfg.json
ts
{
"compilerOptions": {
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"lib": ["dom", "dom.iterable", "esnext"],
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"strict": true,
"jsx": "react-jsx",
"jsxImportSource": "react",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true
}
}
通过上述配置,我们修改package.json的scripts
json
"scripts": {
"start": "webpack serve --open --port 3210",
"build": "webpack"
}
此时运行pnpm run start即可在3210端口访问项目。
接下来的内容是锦上添花:优化工程,即代码风格格式化,typescript eslint规则校验,使用git hooks触发生命周期钩子
5. 使用prettier格式化代码
bash
pnpm add -D prettier
在根目录创建.prettierrc
json
{
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"tabWidth": 4,
"useTabs": false,
"printWidth": 120,
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "auto"
}
在package.json配置格式化脚本
json
"scripts": {
"start": "webpack serve --open --port 3210",
"build": "webpack",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,md}\""
},
执行即可把src中所有代码文件格式化
6. 配置eslint
bash
pnpm add -D eslint typescript-eslint eslint-plugin-react eslint-plugin-react-hooks eslint-webpack-plugin
根目录创建eslint.config.js
javascript
import tseslint from 'typescript-eslint'
import reactPlugin from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
export default [
...tseslint.configs.recommended,
{
files: ['**/*.{ts,tsx}'],
plugins: {
react: reactPlugin,
'react-hooks': reactHooks
},
rules: {
...reactPlugin.configs.recommended.rules,
...reactHooks.configs.recommended.rules
},
settings: {
react: { version: 'detect' }
}
}
]
在packages的scripts脚本中写入
json
"scripts": {
"start": "webpack serve --open --port 3210",
"build": "webpack",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,md}\"",
"lint": "eslint --ext .ts,.tsx",
"lint:fix": "eslint --ext .ts,.tsx --fix"
},
7. husky 设置lint-staged
bash
pnpm add -D husky lint-staged
7.1 初始化git仓库
bash
git init
7.2 初始化husky
- npx方式
bash
npx husky init
- pnpm方式
bash
pnpm exec husky init
7.3 配置husky的pre-commit钩子
在.husky中创建pre-commit(无后缀)文件 写入
bash
npx lint-staged
并在package.json中的根object里写入lint-staged配置
json
"lint-staged": {
"src/**/*.{ts,tsx}": [
"eslint --fix"
]
}
此时,每当你git commit的时候它都会先执行eslint
8. husky设置commit message
为了规范每次提交记录的message,我们使用commitlint规范:
vbnet
feat: add new feature
fix: bug fix
docs: documentation changes
style: formatting changes
refactor: code refactoring
test: adding tests
chore: maintenance tasks
引入commit-lint
bash
pnpm add -D @commitlint/cli @commitlint/config-conventional
创建commitlint.config.js
javascript
export default {
extends: ['@commitlint/config-conventional']
}
在.husky目录中创建commit-msg(无后缀)文件并写入:
bash
pnpm exec commitlint --edit $1
此后后续的commit提交的message都会匹配是否以上述规范中的lint的title相匹配,比如我提交一个需求必须以:feat: 开头
9. 创建.gitignore
屏蔽掉常见的本地配置/依赖项
bash
# Dependencies
node_modules
.pnpm-store
# Build output
dist
# IDE
.idea
.vscode
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Logs
*.log
npm-debug.log*
# Environment
.env
.env.local
.env.*.local