vite vue3 TypeScript 项目工程化配置
1.ESLint
安装 ESLint
1 | yarn add eslint -D |
初始化 ESLint
1 | npx eslint --init |
以下选择仅供参考
1 | √ How would you like to use ESLint? · style |
2 | √ What type of modules does your project use? · none |
3 | √ Which framework does your project use? · vue |
4 | √ Does your project use TypeScript? · No / Yes |
5 | √ Where does your code run? · browser, node |
6 | √ How would you like to define a style for your project? · guide |
7 | √ Which style guide do you want to follow? · standard |
8 | √ What format do you want your config file to be in? · JavaScript |
9 | Checking peerDependencies of eslint-config-standard@latest |
10 | The config that you've selected requires the following dependencies: |
11 |
|
12 | eslint-plugin-vue@latest @typescript-eslint/eslint-plugin@latest eslint-config-standard@latest eslint@^7.12.1 eslint-plugin-import@^2.22.1 eslint-plugin-node@^11.1.0 eslint-plugin-promise@^4.2.1 || ^5.0.0 @typescript-eslint/parser@latest |
13 | √ Would you like to install them now with npm? · No / Yes |
配置 .eslintrc.js
实战项目配置
需安装
1 | yarn add eslint-define-config vue-eslint-parser -D |
eslint-define-config
用来提供配置提示
.eslintrc.js
1 | /* eslint-disable @typescript-eslint/no-var-requires */ |
2 | // @ts-check |
3 | const { defineConfig } = require('eslint-define-config') |
4 | module.exports = defineConfig({ |
5 | parser: 'vue-eslint-parser', |
6 | env: { |
7 | browser: true, |
8 | es2021: true, |
9 | node: true |
10 | }, |
11 | extends: [ |
12 | 'eslint:recommended', |
13 | 'plugin:vue/vue3-recommended', |
14 | 'plugin:@typescript-eslint/recommended' |
15 | ], |
16 | parserOptions: { |
17 | ecmaVersion: 12, |
18 | parser: '@typescript-eslint/parser' |
19 | }, |
20 | plugins: ['vue', '@typescript-eslint', 'import'], |
21 | rules: { |
22 | // vue base |
23 | 'vue/no-unused-vars': [ |
24 | 'error', |
25 | { |
26 | ignorePattern: '^_' |
27 | } |
28 | ], |
29 | 'vue/singleline-html-element-content-newline': 'off', |
30 | 'vue/multiline-html-element-content-newline': 'off', |
31 | 'vue/name-property-casing': ['error', 'PascalCase'], |
32 | 'vue/no-v-html': 'off', |
33 | 'vue/html-closing-bracket-newline': 'off', |
34 | 'vue/html-indent': 0, |
35 | 'vue/html-self-closing': 'off', |
36 | 'vue/max-attributes-per-line': 0, |
37 | 'vue/custom-event-name-casing': 0, |
38 | 'vue/eqeqeq': [2, 'always', { null: 'ignore' }], |
39 | // common |
40 | 'no-unused-vars': ['error', { args: 'none' }], |
41 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', |
42 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', |
43 | semi: [2, 'never'], |
44 | 'semi-spacing': [ |
45 | 2, |
46 | { |
47 | before: false, |
48 | after: true |
49 | } |
50 | ], |
51 | quotes: [ |
52 | 2, |
53 | 'single', |
54 | { |
55 | avoidEscape: true, |
56 | allowTemplateLiterals: true |
57 | } |
58 | ], |
59 | 'comma-dangle': [2, 'never'], |
60 | 'comma-spacing': [ |
61 | 2, |
62 | { |
63 | before: false, |
64 | after: true |
65 | } |
66 | ], |
67 | 'comma-style': [2, 'last'], |
68 | 'arrow-parens': [2, 'as-needed'], |
69 | 'arrow-spacing': [ |
70 | 2, |
71 | { |
72 | before: true, |
73 | after: true |
74 | } |
75 | ], |
76 | 'jsx-quotes': 2, |
77 | 'no-async-promise-executor': 0, |
78 | 'space-before-function-paren': 0, |
79 | 'no-empty': 0, |
80 | 'spaced-comment': ['error', 'always'], |
81 | 'no-undef': 0, |
82 | // import |
83 | 'import/order': 2, |
84 | 'import/first': 2, |
85 | // typescript |
86 | '@typescript-eslint/no-explicit-any': 0 |
87 | } |
88 | }) |
package.json scripts
中添加
1 | { |
2 | "scripts": { |
3 | "lint": "eslint ./src --ext .js,.jsx,.ts,.tsx --fix" |
4 | } |
5 | } |
添加.eslintignore
文件
1 | build |
2 | src/assets |
3 | public |
4 | dist |
5 | tests/ |
6 | types |
2.prettier
1 | yarn add prettier -D |
添加.prettierrc.js
1 | module.exports = { |
2 | trailingComma: 'none', |
3 | tabWidth: 2, |
4 | semi: false, |
5 | printWidth: 100, |
6 | singleQuote: true, |
7 | jsxSingleQuote: true, |
8 | bracketSpacing: true, |
9 | arrowParens: 'avoid' |
10 | } |
添加.prettierignore
1 | node_modules |
2 | dist |
3 | build |
4 | static |
5 | public |
package.json scripts
中添加
1 | { |
2 | "scripts": { |
3 | "prettier": "prettier . --write" |
4 | } |
5 | } |
3.stylelint
1 | yarn add stylelint stylelint-config-standard stylelint-order |
2 | stylelint-scss -D |
添加.stylelintrc.js
1 | module.exports = { |
2 | defaultSeverity: 'error', |
3 | ignoreFiles: [ |
4 | 'node_modules/**', |
5 | 'dist/**', |
6 | '*.min.css', |
7 | 'tests/**', |
8 | 'coverage/**' |
9 | ], |
10 | extends: ['stylelint-config-standard'], |
11 | plugins: ['stylelint-scss', 'stylelint-order'], |
12 | rules: { |
13 | 'order/order': [ |
14 | 'declarations', |
15 | 'custom-properties', |
16 | 'dollar-variables', |
17 | 'rules', |
18 | 'at-rules' |
19 | ], |
20 | 'order/properties-order': [ |
21 | 'position', |
22 | 'top', |
23 | 'right', |
24 | 'bottom', |
25 | 'left', |
26 | 'float' |
27 | ], |
28 | 'media-feature-name-no-vendor-prefix': true, |
29 | 'selector-no-vendor-prefix': null, |
30 | 'property-no-vendor-prefix': null, |
31 | 'rule-empty-line-before': null, |
32 | 'no-missing-end-of-source-newline': null, |
33 | 'selector-pseudo-class-no-unknown': null, |
34 | 'font-family-no-missing-generic-family-keyword': null, |
35 | 'no-descending-specificity': null, |
36 | 'declaration-empty-line-before': null, |
37 | 'declaration-block-trailing-semicolon': null, |
38 | 'selector-combinator-space-before': null, |
39 | 'selector-combinator-space-after': null, |
40 | 'block-closing-brace-newline-before': null, |
41 | 'at-rule-no-unknown': null, |
42 | 'property-case': null, |
43 | 'property-no-unknown': null, |
44 | 'declaration-block-single-line-max-declarations': null, |
45 | 'value-no-vendor-prefix': null, |
46 | 'no-empty-source': null, |
47 | 'at-rule-no-vendor-prefix': null, |
48 | 'selector-pseudo-element-no-unknown': [ |
49 | true, |
50 | { |
51 | ignorePseudoElements: ['v-deep'] |
52 | } |
53 | ], |
54 | 'function-calc-no-unspaced-operator': null |
55 | } |
56 | } |
package.json scripts
中添加
1 | { |
2 | "scripts": { |
3 | "stylelint": "stylelint ./src/**/*.{scss,css,less,vue} --fix" |
4 | } |
5 | } |
4.git hooks 的添加
安装依赖
1 | yarn add husky @commitlint/cli @commitlint/config-conventional commitizen cz-conventional-changelog cz-customizable lint-staged -D |
执行
1 | npx husky install |
添加提交信息校验 git hooks
1 | npx husky add .husky/commit-msg 'npx commitlint --edit $1' |
添加提交前校验 git hooks
1 | npx husky add .husky/pre-commit 'npx lint-staged' |
添加文件 commitlint.config.js
1 | module.exports = { |
2 | extends: ['@commitlint/config-conventional'], |
3 | rules: { |
4 | // 提交主题类型 |
5 | 'type-enum': [ |
6 | 2, |
7 | 'always', |
8 | [ |
9 | 'feat', |
10 | 'fix', |
11 | 'delete', |
12 | 'docs', |
13 | 'test', |
14 | 'style', |
15 | 'ci', |
16 | 'refactor', |
17 | 'perf', |
18 | 'chore', |
19 | 'revert' |
20 | ] |
21 | ], |
22 | 'subject-full-stop': [0, 'never'], // 主题句号 |
23 | 'subject-case': [0, 'never'] // 主题案例 |
24 | } |
25 | } |
添加文件 .cz-config.js
按项目配置
1 | module.exports = { |
2 | // 修改主题选择 |
3 | types: [ |
4 | { value: 'feat', name: 'feat:添加新功能' }, |
5 | { value: 'fix', name: 'fix:Bug修复' }, |
6 | { value: 'delete', name: 'delete:删除代码,接口' }, |
7 | { |
8 | value: 'docs', |
9 | name: 'docs: 变更的只有文档,比如README.md等' |
10 | }, |
11 | { value: 'test', name: 'test:添加一个测试,包括单元测试、集成测试等' }, |
12 | { |
13 | value: 'style', |
14 | name: 'style: 空格, 分号等格式修复(注意不是 css 修改)' |
15 | }, |
16 | { value: 'ci', name: 'ci:ci配置,脚本文件等更新' }, |
17 | { |
18 | value: 'refactor', |
19 | name: 'refactor:代码重构(即不是新增功能,也不是修改bug的代码变动)' |
20 | }, |
21 | { value: 'perf', name: 'perf:优化相关,比如提升性能、体验' }, |
22 | { value: 'chore', name: 'chore:改变构建流程、或者增加依赖库、工具等' }, |
23 | { value: 'revert', name: 'revert:代码回退' } |
24 | ], |
25 | // 构建对话 |
26 | messages: { |
27 | type: '选择一种你的提交类型(必选):', |
28 | scope: '选择一个更改范围(可选):', |
29 | // used if allowCustomScopes is true |
30 | customScope: '自定义更改范围(可选):', |
31 | subject: '提交说明(必填):\n', |
32 | body: '长说明,使用"|"换行(可选):\n', |
33 | breaking: '非兼容性说明 (可选):\n', |
34 | footer: '关联关闭的issue,例如:#31, #34(可选):\n', |
35 | confirmCommit: '确定提交说明?' |
36 | }, |
37 | // 是否允许自定义更改范围 |
38 | allowCustomScopes: true, |
39 | // 允许中断的改变 |
40 | allowBreakingChanges: ['feat', 'fix'], |
41 | // 修改主题描述字数限制 |
42 | subjectLimit: 100, |
43 | // 选择跳过的步骤 |
44 | skipQuestions: ['scope', 'customScope', 'body', 'breaking', 'footer'] |
45 | } |
package.json scripts 中添加
1 | { |
2 | "scripts": { |
3 | "prepare": "husky install", |
4 | "commit": "git-cz" |
5 | } |
6 | } |
package.json 中添加
1 | { |
2 | "config": { |
3 | "commitizen": { |
4 | "path": "node_modules/cz-customizable" |
5 | } |
6 | }, |
7 | "husky": { |
8 | "hooks": { |
9 | "pre-commit": "lint-staged", |
10 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" |
11 | } |
12 | }, |
13 | "lint-staged": { |
14 | "src/**/*.{js,jsx,ts,tsx,vue}": ["npm run lint"], |
15 | "src/**/*.{html,vue,css,sass,scss}": ["npm run stylelint"] |
16 | } |
17 | } |
添加文件 update.sh
1 |
|
2 | success="更新成功" |
3 | set -e |
4 | git add . |
5 | npm run commit |
6 | git pull |
7 | git push |
8 | echo -e "\n\033[32m$success\033[0m" |
项目代码提交 使用
1 | ./update.sh |
package.json 完整配置
1 | { |
2 | "name": "vite-vue3-element-plus-admin", |
3 | "version": "1.0.0", |
4 | "license": "ISC", |
5 | "author": "xiaofei", |
6 | "main": "src/main.ts", |
7 | "scripts": { |
8 | "dev": "vite --host", |
9 | "tsc": "vue-tsc --noEmit", |
10 | "build:prod": "vite build --mode production", |
11 | "report": "cross-env REPORT=true yarn build:prod", |
12 | "dev:staging": "vite --host --mode staging", |
13 | "build:staging": "vite build --mode staging", |
14 | "serve": "vite preview", |
15 | "prepare": "husky install", |
16 | "commit": "git-cz", |
17 | "lint": "eslint ./src --ext .js,.jsx,.ts,.tsx,.vue --fix", |
18 | "stylelint": "stylelint ./src/**/*.{scss,css,less,vue} --fix", |
19 | "prettier": "prettier . --write", |
20 | "test:unit": "jest --coverage" |
21 | }, |
22 | "dependencies": { |
23 | "accounting": "^0.4.1", |
24 | "auto-drawing": "^0.0.31", |
25 | "axios": "^0.21.1", |
26 | "crypto-js": "^4.1.1", |
27 | "dayjs": "^1.10.4", |
28 | "echarts": "^5.1.1", |
29 | "element-plus": "^1.1.0-beta.7", |
30 | "file-saver": "^2.0.5", |
31 | "good-storage": "^1.1.1", |
32 | "js-cookie": "^2.2.1", |
33 | "js-md5": "^0.7.3", |
34 | "jsencrypt": "^3.2.0", |
35 | "lodash-es": "^4.17.21", |
36 | "normalize.css": "^8.0.1", |
37 | "nprogress": "^0.2.0", |
38 | "numeral": "^2.0.6", |
39 | "qs": "^6.10.1", |
40 | "uuid": "^8.3.2", |
41 | "vue": "^3.2.2", |
42 | "vue-cropperjs": "^5.0.0", |
43 | "vue-i18n": "^9.1.2", |
44 | "vue-router": "^4.0.11", |
45 | "vuex": "^4.0.2" |
46 | }, |
47 | "devDependencies": { |
48 | "@babel/plugin-syntax-jsx": "^7.14.5", |
49 | "@babel/preset-env": "^7.14.1", |
50 | "@babel/preset-react": "^7.14.5", |
51 | "@commitlint/cli": "^13.1.0", |
52 | "@commitlint/config-conventional": "^13.1.0", |
53 | "@rollup/plugin-eslint": "^8.0.1", |
54 | "@testing-library/jest-dom": "^5.12.0", |
55 | "@types/accounting": "^0.4.1", |
56 | "@types/crypto-js": "^4.0.2", |
57 | "@types/file-saver": "^2.0.1", |
58 | "@types/good-storage": "^1.1.0", |
59 | "@types/jest": "^26.0.23", |
60 | "@types/js-cookie": "^2.2.6", |
61 | "@types/js-md5": "^0.4.2", |
62 | "@types/lodash-es": "^4.17.4", |
63 | "@types/node": "^14.14.37", |
64 | "@types/nprogress": "^0.2.0", |
65 | "@types/numeral": "^2.0.1", |
66 | "@types/qs": "^6.9.6", |
67 | "@types/uuid": "^8.3.1", |
68 | "@types/vue-cropperjs": "^4.1.1", |
69 | "@typescript-eslint/eslint-plugin": "^4.21.0", |
70 | "@typescript-eslint/parser": "^4.21.0", |
71 | "@vitejs/plugin-legacy": "^1.3.2", |
72 | "@vitejs/plugin-vue": "^1.2.1", |
73 | "@vitejs/plugin-vue-jsx": "^1.1.4", |
74 | "@vue/compiler-sfc": "3.0.11", |
75 | "@vue/eslint-config-typescript": "7.0.0", |
76 | "@vue/test-utils": "^2.0.0-rc.6", |
77 | "autoprefixer": "^8.6.5", |
78 | "babel-plugin-transform-import-meta": "^2.0.0", |
79 | "babel-preset-vite": "^1.0.4", |
80 | "chalk": "^4.1.0", |
81 | "commitizen": "^4.2.4", |
82 | "cross-env": "^7.0.3", |
83 | "cz-conventional-changelog": "^3.3.0", |
84 | "cz-customizable": "^6.3.0", |
85 | "eslint": "^7.0.0", |
86 | "eslint-config-standard": "^16.0.2", |
87 | "eslint-define-config": "^1.0.9", |
88 | "eslint-plugin-import": "^2.22.1", |
89 | "eslint-plugin-jest": "^24.3.6", |
90 | "eslint-plugin-node": "^11.1.0", |
91 | "eslint-plugin-promise": "^4.3.1", |
92 | "eslint-plugin-vue": "^7.8.0", |
93 | "husky": "^7.0.2", |
94 | "jest": "^26.6.3", |
95 | "jest-transform-stub": "^2.0.0", |
96 | "lint-staged": "^11.1.2", |
97 | "mockjs": "^1.1.0", |
98 | "postcss": "^7.0.35", |
99 | "postcss-import": "^14.0.1", |
100 | "postcss-px-to-viewport": "^1.1.1", |
101 | "prettier": "^2.3.0", |
102 | "rollup-plugin-visualizer": "^5.5.2", |
103 | "sass": "^1.37.5", |
104 | "stylelint": "^13.12.0", |
105 | "stylelint-config-standard": "^21.0.0", |
106 | "stylelint-order": "^4.1.0", |
107 | "stylelint-scss": "^3.19.0", |
108 | "ts-jest": "^26.5.6", |
109 | "typescript": "^4.3.5", |
110 | "vite": "^2.5.0", |
111 | "vite-plugin-compression": "^0.2.4", |
112 | "vite-plugin-element-plus": "^0.0.12", |
113 | "vite-plugin-html": "^2.0.6", |
114 | "vite-plugin-imagemin": "^0.4.3", |
115 | "vite-plugin-mock": "^2.5.0", |
116 | "vite-plugin-svg-icons": "^0.4.1", |
117 | "vue-eslint-parser": "^7.6.0", |
118 | "vue-jest": "^5.0.0-alpha.7", |
119 | "vue-tsc": "^0.0.15", |
120 | "xml2js": "^0.4.23" |
121 | }, |
122 | "config": { |
123 | "commitizen": { |
124 | "path": "node_modules/cz-customizable" |
125 | } |
126 | }, |
127 | "husky": { |
128 | "hooks": { |
129 | "pre-commit": "lint-staged", |
130 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" |
131 | } |
132 | }, |
133 | "lint-staged": { |
134 | "src/**/*.{js,jsx,ts,tsx,vue}": ["npm run lint"], |
135 | "src/**/*.{html,vue,css,sass,scss}": ["npm run stylelint"] |
136 | }, |
137 | "resolutions": { |
138 | "bin-wrapper": "npm:bin-wrapper-china" |
139 | } |
140 | } |