├── .eslintignore ├── .eslintrc ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .lintstagedrc.js ├── .ls-lint.yml ├── .npmrc ├── .prettierignore ├── .stylelintignore ├── .vscode └── settings.json ├── commitlint.config.js ├── example ├── app.vue ├── index.html ├── main.ts ├── package.json └── vite.config.js ├── package.json ├── packages ├── components │ ├── button-group │ │ ├── index.ts │ │ └── src │ │ │ └── button-group.vue │ ├── button │ │ ├── index.ts │ │ └── src │ │ │ ├── button.ts │ │ │ ├── button.vue │ │ │ └── interface.d.ts │ ├── components.ts │ ├── index.ts │ └── package.json ├── eslint-config │ ├── eslint.rules.js │ ├── index.js │ ├── package.json │ ├── ts.rules.js │ └── vue.rules.js ├── theme-chalk │ ├── package.json │ └── src │ │ ├── button-group.scss │ │ ├── button.scss │ │ ├── common │ │ ├── color.scss │ │ ├── transition.scss │ │ └── var.scss │ │ ├── index.scss │ │ └── mixins │ │ ├── _button.scss │ │ ├── config.scss │ │ ├── function.scss │ │ ├── mixins.scss │ │ └── utils.scss └── utils │ ├── index.ts │ ├── package.json │ └── vue │ ├── index.ts │ ├── install.ts │ └── typescript.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── prettier.config.js ├── stylelint.config.js ├── tsconfig.json └── typings └── vue-shim.d.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["@brain-ui/eslint-config"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Editor directories and files 2 | .idea 3 | 4 | # Package Manager 5 | node_modules 6 | .pnpm-debug.log* 7 | 8 | # System 9 | .DS_Store 10 | 11 | # Bundle 12 | dist 13 | coverage 14 | 15 | # local env files 16 | *.local 17 | .eslintcache 18 | tmp -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'], 3 | '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'], 4 | 'package.json': ['prettier --write'], 5 | '*.vue': ['prettier --write', 'eslint --fix'], 6 | 'packages/theme-chalk/src/**/*.{scss,css}': ['stylelint --fix --custom-syntax postcss-scss', 'prettier --write'], 7 | '*.md': ['prettier --write'] 8 | }; 9 | -------------------------------------------------------------------------------- /.ls-lint.yml: -------------------------------------------------------------------------------- 1 | ls: 2 | packages/components/*: 3 | .dir: kebab-case 4 | .vue: kebab-case 5 | .js: kebab-case 6 | .ts: kebab-case 7 | .json: kebab-case 8 | .d.ts: kebab-case 9 | .tsx: kebab-case 10 | 11 | ignore: 12 | - .git 13 | - .vscode 14 | - node_modules 15 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | shell-emulator=true -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/* -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | /public/* 3 | /example/* -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": ["html", "vue", "javascript", "jsx"], 3 | "emmet.syntaxProfiles": { 4 | "vue-html": "html", 5 | "vue": "html" 6 | }, 7 | "editor.tabSize": 2, 8 | "eslint.alwaysShowStatus": true, 9 | "eslint.quiet": true, 10 | "editor.codeActionsOnSave": { 11 | "source.fixAll.eslint": true, 12 | "source.fixAll": true, 13 | "source.fixAll.stylelint": true 14 | }, 15 | "stylelint.customSyntax": "postcss-scss", 16 | "stylelint.validate": [ 17 | "css", 18 | "less", 19 | "postcss", 20 | "scss", 21 | "vue", 22 | "sass" 23 | ], 24 | } 25 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | /* https://commitlint.js.org/#/reference-rules */ 2 | module.exports = { 3 | ignores: [commit => commit.includes('init')], 4 | extends: ['@commitlint/config-conventional'], 5 | rules: { 6 | 'body-leading-blank': [2, 'always'], 7 | 'footer-leading-blank': [1, 'always'], 8 | 'header-max-length': [2, 'always', 108], 9 | 'subject-empty': [2, 'never'], 10 | 'type-empty': [2, 'never'], 11 | 'subject-case': [0] 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /example/app.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './app.vue'; 3 | import '@brain-ui/theme-chalk/src/index.scss'; 4 | import BrainUi from '@brain-ui/components'; 5 | 6 | const app = createApp(App); 7 | app.use(BrainUi); 8 | 9 | // app.use(BrainButton) 10 | // app.use(BrainButtonGroup) 11 | app.mount('#app'); 12 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "vite" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@vitejs/plugin-vue": "^3.1.2", 14 | "vite": "^3.1.8", 15 | "vite-plugin-eslint": "^1.8.1", 16 | "vite-plugin-vue-setup-extend": "^0.4.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import VueSetupExtend from 'vite-plugin-vue-setup-extend'; //用于给setup script组建增加name属性 4 | import viteEslint from 'vite-plugin-eslint'; 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | vue(), 9 | /* https://www.npmjs.com/package/vite-plugin-eslint */ 10 | viteEslint(), 11 | VueSetupExtend() 12 | ] 13 | }); 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brain-ui", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "pnpm -C example dev", 8 | "clear": "rimraf dist", 9 | "clear:cache": "rimraf node_modules/.cache/ rimraf node_modules/.vite", 10 | "clear:lib": "rimraf node_modules", 11 | "lint:fix": "eslint . --fix", 12 | "lint:eslint": "eslint .", 13 | "lint:prettier": "prettier --write .", 14 | "lint:css": "stylelint 'packages/theme-chalk/src/**/*.scss' --fix --custom-syntax postcss-scss", 15 | "lint:ls-lint": "ls-lint", 16 | "lint:staged": "lint-staged", 17 | "reinstall": "rimraf pnpm-lock.yarm && rimraf node_modules && pnpm install", 18 | "prepare": "husky install", 19 | "postinstall": "npx husky install", 20 | "commit": "git-cz" 21 | }, 22 | "keywords": [], 23 | "author": "SNine ", 24 | "license": "ISC", 25 | "config": { 26 | "commitizen": { 27 | "path": "cz-conventional-changelog" 28 | } 29 | }, 30 | "devDependencies": { 31 | "@commitlint/cli": "^17.2.0", 32 | "@commitlint/config-conventional": "^17.2.0", 33 | "@ls-lint/ls-lint": "^1.11.2", 34 | "@typescript-eslint/eslint-plugin": "^5.42.0", 35 | "@typescript-eslint/parser": "^5.42.0", 36 | "commitizen": "^4.2.5", 37 | "cz-conventional-changelog": "^3.3.0", 38 | "eslint": "^8.26.0", 39 | "eslint-config-prettier": "^8.5.0", 40 | "eslint-plugin-prettier": "^4.2.1", 41 | "eslint-plugin-vue": "^9.7.0", 42 | "husky": "^8.0.2", 43 | "lint-staged": "^13.0.3", 44 | "postcss-scss": "^4.0.5", 45 | "prettier": "^2.7.1", 46 | "rimraf": "^3.0.2", 47 | "sass": "^1.55.0", 48 | "stylelint": "^14.14.1", 49 | "stylelint-config-prettier": "^9.0.4", 50 | "stylelint-config-standard": "^29.0.0", 51 | "stylelint-order": "^5.0.0", 52 | "stylelint-scss": "^4.3.0", 53 | "typescript": "^4.8.4", 54 | "vue": "^3.2.36" 55 | }, 56 | "dependencies": { 57 | "@brain-ui/components": "workspace:^0.0.1", 58 | "@brain-ui/eslint-config": "workspace:^0.0.1", 59 | "@brain-ui/theme-chalk": "workspace:^0.0.1", 60 | "@brain-ui/utils": "workspace:^0.0.1" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/components/button-group/index.ts: -------------------------------------------------------------------------------- 1 | import buttonGroup from './src/button-group.vue'; 2 | import { withInstall } from '@brain-ui/utils'; 3 | 4 | export const BrainButtonGroup = withInstall(buttonGroup); 5 | 6 | export default BrainButtonGroup; 7 | -------------------------------------------------------------------------------- /packages/components/button-group/src/button-group.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /packages/components/button/index.ts: -------------------------------------------------------------------------------- 1 | import button from './src/button.vue'; 2 | 3 | import { withInstall } from '@brain-ui/utils'; 4 | 5 | export const BrainButton = withInstall(button); 6 | 7 | export default BrainButton; 8 | -------------------------------------------------------------------------------- /packages/components/button/src/button.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import type { ButtonNativeType, ButtonSizeType, ButtonType } from './interface'; 3 | 4 | export const Props = { 5 | type: { 6 | type: String as PropType, 7 | default: (): ButtonType => 'default', 8 | validator(value: ButtonType): boolean { 9 | return (['default', 'primary', 'success', 'info', 'danger', 'warning'] as const).includes(value); 10 | } 11 | }, 12 | size: { 13 | type: String as PropType, 14 | validator(value: ButtonSizeType): boolean { 15 | return (['default', 'medium', 'small', 'mini', 'tiny'] as const).includes(value); 16 | } 17 | }, 18 | plain: { 19 | type: Boolean, 20 | default: (): boolean => false 21 | }, 22 | round: { 23 | type: Boolean, 24 | default: (): boolean => false 25 | }, 26 | circle: { 27 | type: Boolean, 28 | default: (): boolean => false 29 | }, 30 | loading: { 31 | type: Boolean, 32 | default: (): boolean => false 33 | }, 34 | disabled: { 35 | type: Boolean, 36 | default: (): boolean => false 37 | }, 38 | icon: { 39 | type: String, 40 | default: (): String => '' 41 | }, 42 | autoFocus: { 43 | type: Boolean, 44 | default: (): boolean => false 45 | }, 46 | nativeType: { 47 | type: String as PropType, 48 | default: (): ButtonNativeType => 'button', 49 | validator(value): boolean { 50 | return (['button', 'submit', 'reset'] as const).includes(value); 51 | } 52 | } 53 | }; 54 | 55 | export const Emits = { 56 | click: (evt: MouseEvent): MouseEvent => evt 57 | }; 58 | 59 | export type ButtonPropsType = ExtractPropTypes; 60 | -------------------------------------------------------------------------------- /packages/components/button/src/button.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 40 | -------------------------------------------------------------------------------- /packages/components/button/src/interface.d.ts: -------------------------------------------------------------------------------- 1 | import type { ButtonHTMLAttributes } from 'vue'; 2 | 3 | export type ButtonSizeType = 'default' | 'medium' | 'small' | 'mini' | 'tiny'; 4 | 5 | export type ButtonType = 'default' | 'primary' | 'success' | 'info' | 'danger' | 'warning'; 6 | 7 | export type ButtonNativeType = NonNullable; 8 | -------------------------------------------------------------------------------- /packages/components/components.ts: -------------------------------------------------------------------------------- 1 | export { BrainButton } from './button'; 2 | export { BrainButtonGroup } from './button-group'; 3 | -------------------------------------------------------------------------------- /packages/components/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import * as components from './components'; 3 | import { version } from './package.json'; 4 | 5 | const install = function (app: App): void { 6 | Object.entries(components).forEach(([key, value]) => { 7 | app.component(key, value); 8 | }); 9 | }; 10 | 11 | export default { 12 | install, 13 | version 14 | }; 15 | -------------------------------------------------------------------------------- /packages/components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@brain-ui/components", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC" 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-config/eslint.rules.js: -------------------------------------------------------------------------------- 1 | /* eslint配置规则 https://eslint.org/docs/latest/rules/ */ 2 | module.exports = { 3 | 'prettier/prettier': 'error', 4 | 'arrow-body-style': 'off', 5 | 'prefer-arrow-callback': 'off', 6 | 'no-console': 2, 7 | // 不允许不必要的转义字符 https://eslint.org/docs/latest/rules/no-useless-escape 8 | 'no-useless-escape': 'off', 9 | // 10 | 'comma-dangle': 'off', 11 | // 禁止使用 var https://eslint.org/docs/latest/rules/no-var#rule-details 12 | 'no-var': 'error', 13 | // 使用单引号 https://eslint.org/docs/latest/rules/quotes#version 14 | quotes: ['error', 'single'], 15 | // 禁止分号 https://eslint.org/docs/latest/rules/semi#rule-details 16 | // semi: 'error', 17 | // 禁止 debugger https://eslint.org/docs/latest/rules/no-debugger#rule-details 18 | 'no-debugger': 'error', 19 | // 禁止未使用的变量 https://eslint.org/docs/latest/rules/no-unused-vars#rule-details 20 | 'no-unused-vars': 'error', 21 | // 不允许使用未声明的变量 https://eslint.org/docs/latest/rules/no-undef 22 | 'no-undef': 'off', 23 | // 函数括号前的空格 https://eslint.org/docs/latest/rules/space-before-function-paren 24 | 'space-before-function-paren': 'off', 25 | // 禁止多个空行 https://eslint.org/docs/latest/rules/no-multiple-empty-lines#rule-details 26 | 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0, maxBOF: 0 }], 27 | // 在文件末尾要求或禁止换行 https://eslint.org/docs/latest/rules/eol-last#rule-details 28 | 'eol-last': 'error', 29 | // 禁止所有选项卡 https://eslint.org/docs/latest/rules/no-tabs#rule-details 30 | 'no-tabs': 'error', 31 | 'default-param-last': 'off' 32 | }; 33 | -------------------------------------------------------------------------------- /packages/eslint-config/index.js: -------------------------------------------------------------------------------- 1 | const eslintRules = require('./eslint.rules'); 2 | const tsRules = require('./ts.rules'); 3 | const vueRules = require('./vue.rules'); 4 | 5 | module.exports = { 6 | env: { 7 | browser: true, 8 | es2021: true, 9 | node: true 10 | }, 11 | /* 'plugin:prettier/recommended' 可手动配置 */ 12 | extends: ['plugin:vue/vue3-essential', 'prettier', 'plugin:@typescript-eslint/recommended'], 13 | overrides: [], 14 | parser: 'vue-eslint-parser', 15 | parserOptions: { 16 | ecmaVersion: 'latest', 17 | sourceType: 'module', 18 | parser: '@typescript-eslint/parser' 19 | }, 20 | plugins: ['vue', '@typescript-eslint', 'prettier'], 21 | rules: { 22 | ...eslintRules, 23 | ...tsRules, 24 | ...vueRules 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@brain-ui/eslint-config", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "SNine ", 11 | "license": "MIT" 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-config/ts.rules.js: -------------------------------------------------------------------------------- 1 | /* ts配置规则 https://typescript-eslint.io/rules */ 2 | module.exports = { 3 | // 规定数组类型定义方式 https://typescript-eslint.io/rules/array-type 4 | '@typescript-eslint/array-type': 'error', 5 | // 禁止使用大写 String、Number 定义类型 https://typescript-eslint.io/rules/ban-types 6 | '@typescript-eslint/ban-types': 'off', // beta 7 | // 不允许尾随逗号 https://typescript-eslint.io/rules/comma-dangle 8 | '@typescript-eslint/comma-dangle': 'error', 9 | // 强制使用 interface 定义类型 https://typescript-eslint.io/rules/consistent-type-definitions 10 | '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], 11 | // 统一导出规则 https://typescript-eslint.io/rules/consistent-type-exports 12 | // '@typescript-eslint/consistent-type-exports': 'error', 13 | // 自定义对象类型样式 https://typescript-eslint.io/rules/consistent-indexed-object-style 14 | '@typescript-eslint/consistent-indexed-object-style': ['warn', 'record'], 15 | // !禁止使用后缀运算符的非空断言 https://typescript-eslint.io/rules/no-non-null-assertion/ 16 | '@typescript-eslint/no-non-null-assertion': 'error', 17 | // 强制一致地使用类型导入 https://typescript-eslint.io/rules/consistent-type-imports 18 | '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }], 19 | // 禁止未使用的变量 https://typescript-eslint.io/rules/no-unused-vars 20 | '@typescript-eslint/no-unused-vars': 'error', 21 | // 不可以有 any https://typescript-eslint.io/rules/no-explicit-any/ 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | // 不可以有 require https://typescript-eslint.io/rules/no-var-requires/ 24 | '@typescript-eslint/no-var-requires': 'off', 25 | // 带有默认值的函数参数在最后 https://typescript-eslint.io/rules/default-param-last 26 | '@typescript-eslint/default-param-last': 'error', 27 | // 必须标记函数返回值 https://typescript-eslint.io/rules/explicit-function-return-type 28 | '@typescript-eslint/explicit-function-return-type': 'off' 29 | }; 30 | -------------------------------------------------------------------------------- /packages/eslint-config/vue.rules.js: -------------------------------------------------------------------------------- 1 | /* vue配置规则 https://eslint.vuejs.org/rules/ */ 2 | module.exports = { 3 | /* 禁止在模板中使用 this https://eslint.vuejs.org/rules/this-in-template.html */ 4 | 'vue/this-in-template': 'error', 5 | /* 关闭名称校验 https://eslint.vuejs.org/rules/multi-word-component-names.html */ 6 | 'vue/multi-word-component-names': 'off', 7 | 'vue/max-attributes-per-line': ['error', { singleline: { max: 30 }, multiline: { max: 30 } }], 8 | /* 组件标签顺序 https://eslint.vuejs.org/rules/component-tags-order.html */ 9 | 'vue/component-tags-order': ['error', { order: ['template', 'script', 'style'] }], 10 | /* 只允许使用ts类型的script https://eslint.vuejs.org/rules/block-lang.html */ 11 | 'vue/block-lang': ['error', { script: { lang: 'ts' } }], 12 | /* 只允许使用 setup script类型的语法 https://eslint.vuejs.org/rules/component-api-style.html */ 13 | 'vue/component-api-style': ['error', ['script-setup', 'composition']], 14 | /* 自定义事件强制使用中划线连接 https://eslint.vuejs.org/rules/custom-event-name-casing.html */ 15 | 'vue/custom-event-name-casing': ['error', 'kebab-case', { ignores: [] }], 16 | /* 禁止使用 v-html https://eslint.vuejs.org/rules/no-v-html.html */ 17 | 'vue/no-v-html': 'error', 18 | /* bind绑定时能简写就直接简写 https://eslint.vuejs.org/rules/prefer-true-attribute-shorthand.html */ 19 | 'vue/prefer-true-attribute-shorthand': 'error', 20 | /* 模板中未使用的组建不允许注册 https://eslint.vuejs.org/rules/no-unused-components.html */ 21 | 'vue/no-unused-components': 'error', 22 | /* 单标签禁止改写成双标签 https://eslint.vuejs.org/rules/html-self-closing.html */ 23 | 'vue/html-self-closing': 'off', 24 | /* 强制标签闭合 https://eslint.vuejs.org/rules/html-end-tags.html */ 25 | 'vue/html-end-tags': 'error', 26 | /* 模板缩进规则 */ 27 | 'vue/html-indent': ['error', 2, { attribute: 1, baseIndent: 1, closeBracket: 0, alignAttributesVertically: true }], 28 | /* 模板中使用组建必须使用中划线小写形式 https://eslint.vuejs.org/rules/component-name-in-template-casing.html */ 29 | 'vue/component-name-in-template-casing': ['error', 'kebab-case', { registeredComponentsOnly: false }], 30 | // 对模板中的自定义组件强制执行属性命名样式 https://eslint.vuejs.org/rules/attribute-hyphenation.html#vue-attribute-hyphenation 31 | 'vue/attribute-hyphenation': 'error', 32 | // Prop 名称强制使用特定大小写 https://eslint.vuejs.org/rules/prop-name-casing.html 33 | 'vue/prop-name-casing': 'error', 34 | // 强制执行 v-on 事件命名样式 https://eslint.vuejs.org/rules/v-on-event-hyphenation.html 35 | 'vue/v-on-event-hyphenation': 'error', 36 | // 不允许字段名称重复 https://eslint.vuejs.org/rules/no-dupe-keys.html 37 | 'vue/no-dupe-keys': 'error', 38 | // 禁止 v-if / v-else-if 链中的重复条件 39 | 'vue/no-dupe-v-else-if': 'error', 40 | // 不允许重复属性 https://eslint.vuejs.org/rules/no-duplicate-attributes.html 41 | 'vue/no-duplicate-attributes': [ 42 | 'error', 43 | { 44 | allowCoexistClass: true, 45 | allowCoexistStyle: true 46 | } 47 | ], 48 | // 不允许 export 进入