init: init
|
|
@ -0,0 +1,4 @@
|
|||
# Build target (browser compatible) https://github.com/browserslist/browserslist
|
||||
> 1%
|
||||
last 3 versions
|
||||
ie > 8
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset=utf-8
|
||||
end_of_line=lf
|
||||
insert_final_newline=false
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
# post
|
||||
VUE_APP_PORT=9988
|
||||
|
||||
# static resource dir
|
||||
VUE_APP_ASSETS_DIR=static
|
||||
|
||||
# spa-title
|
||||
GLOB_APP_TITLE=vben admin
|
||||
|
||||
# spa shortname
|
||||
GLOB_APP_SHORT_NAME=vben_admin
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Modify the configuration file must be re-run to work
|
||||
# import() => require() Increase hot update speed
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES=true
|
||||
|
||||
# vue public path
|
||||
VUE_APP_PUBLIC_PATH=/
|
||||
|
||||
# Cross-domain proxy, you can configure multiple
|
||||
VUE_APP_PROXY=[["/app","http://localhost:3000"]]
|
||||
|
||||
# Whether to use cache for development TRUE or FALSE
|
||||
VUE_APP_USE_CACHE=FALSE
|
||||
|
||||
# Development environment supports ie environment TRUE or FALSE
|
||||
VUE_APP_SUPPORT_IE=TRUE
|
||||
|
||||
# Whether to open the mock TRUE or FALSE
|
||||
VUE_APP_USE_MOCK=TRUE
|
||||
|
||||
# Basic interface address SPA
|
||||
GLOB_API_URL=/app
|
||||
|
||||
# Interface prefix
|
||||
GLOB_API_URL_PREFIX=/v1.0
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# The production environment configuration at the beginning of GLOB will be extracted into a js file and added to the window variable
|
||||
|
||||
# delete or not console.log TRUE or FALSE
|
||||
BUILD_ON_CLEAN_CONSOLE=TRUE
|
||||
|
||||
# vue public path
|
||||
VUE_APP_PUBLIC_PATH=./
|
||||
|
||||
# Whether to use cache to compile TRUE or FALSE
|
||||
VUE_APP_USE_CACHE=TRUE
|
||||
|
||||
# Whether to enable gzip compression TRUE or FALSE
|
||||
BUILD_ON_GZIP=FALSE
|
||||
|
||||
# Production environment support ie environment TRUE or FALSE
|
||||
VUE_APP_SUPPORT_IE=TRUE
|
||||
|
||||
# Whether to open the mock TRUE or FALSE
|
||||
VUE_APP_USE_MOCK=TRUE
|
||||
|
||||
# interface address
|
||||
GLOB_API_URL=/app
|
||||
|
||||
# Interface prefix
|
||||
GLOB_API_URL_PREFIX=/v1.0
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
*.sh
|
||||
node_modules
|
||||
lib
|
||||
*.md
|
||||
*.scss
|
||||
*.woff
|
||||
*.ttf
|
||||
.vscode
|
||||
.idea
|
||||
/dist/
|
||||
/mock/
|
||||
/public
|
||||
/docs
|
||||
.vscode
|
||||
.local
|
||||
/bin
|
||||
/build
|
||||
/config
|
||||
Dockerfile
|
||||
vue.config.js
|
||||
commit-lint.js
|
||||
/src/assets/iconfont/
|
||||
/types/shims
|
||||
/src/types/shims
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
|
||||
extends: [
|
||||
'plugin:vue/essential',
|
||||
'eslint:recommended',
|
||||
'@vue/standard',
|
||||
'@vue/typescript/recommended',
|
||||
],
|
||||
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
'no-debugger': 'off',
|
||||
'no-new': 'off',
|
||||
'vue/no-side-effects-in-computed-properties': 'off',
|
||||
|
||||
'no-useless-constructor': 'off',
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'always',
|
||||
normal: 'always',
|
||||
component: 'always',
|
||||
},
|
||||
svg: 'always',
|
||||
math: 'always',
|
||||
},
|
||||
],
|
||||
'prefer-const': [
|
||||
'error',
|
||||
{
|
||||
destructuring: 'all',
|
||||
ignoreReadBeforeAssign: false,
|
||||
},
|
||||
],
|
||||
'vue/attribute-hyphenation': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'vue/attributes-order': [
|
||||
'error',
|
||||
{
|
||||
order: [
|
||||
'DEFINITION',
|
||||
'LIST_RENDERING',
|
||||
'CONDITIONALS',
|
||||
'RENDER_MODIFIERS',
|
||||
'GLOBAL',
|
||||
'UNIQUE',
|
||||
'TWO_WAY_BINDING',
|
||||
'OTHER_DIRECTIVES',
|
||||
'OTHER_ATTR',
|
||||
'EVENTS',
|
||||
'CONTENT',
|
||||
],
|
||||
alphabetical: false,
|
||||
},
|
||||
],
|
||||
'comma-dangle': ['error', 'only-multiline'],
|
||||
indent: 'off',
|
||||
'no-mixed-spaces-and-tabs': 'error',
|
||||
semi: ['error', 'always'],
|
||||
'arrow-spacing': [
|
||||
'error',
|
||||
{
|
||||
before: true,
|
||||
after: true,
|
||||
},
|
||||
],
|
||||
'consistent-this': ['error', 'that'],
|
||||
'eol-last': ['error', 'always'],
|
||||
'wrap-iife': 'error',
|
||||
'@typescript-eslint/ban-ts-ignore': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'no-use-before-define': [
|
||||
'error',
|
||||
{
|
||||
functions: false,
|
||||
classes: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-use-before-define': [
|
||||
'error',
|
||||
{
|
||||
functions: false,
|
||||
classes: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^h$',
|
||||
varsIgnorePattern: '^h$',
|
||||
},
|
||||
],
|
||||
'no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^h$',
|
||||
varsIgnorePattern: '^h$',
|
||||
},
|
||||
],
|
||||
'space-before-function-paren': 'off',
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
* text=auto eol=lf
|
||||
|
||||
# Images
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.tiff binary
|
||||
|
||||
# Fonts
|
||||
*.oft binary
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
||||
# Videos
|
||||
*.mov binary
|
||||
*.mp4 binary
|
||||
*.webm binary
|
||||
*.ogg binary
|
||||
*.mpg binary
|
||||
*.3gp binary
|
||||
*.avi binary
|
||||
*.wmv binary
|
||||
*.flv binary
|
||||
*.asf binary
|
||||
|
||||
# Audio
|
||||
*.mp3 binary
|
||||
*.wav binary
|
||||
*.flac binary
|
||||
|
||||
# Compressed
|
||||
*.gz binary
|
||||
*.zip binary
|
||||
*.7z binary
|
||||
|
||||
*.html text eol=lf
|
||||
*.css text eol=lf
|
||||
*.js text eol=lf
|
||||
*.scss text eol=lf
|
||||
*.vue text eol=lf
|
||||
*.hbs text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.md text eol=lf
|
||||
*.json text eol=lf
|
||||
*.yml text eol=lf
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
/build/.cache
|
||||
|
||||
.local
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/dist/*
|
||||
.local
|
||||
/public/**
|
||||
.output.js
|
||||
/node_modules/**
|
||||
|
||||
**/*.svg
|
||||
**/*.sh
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
*.js
|
||||
*.png
|
||||
*.eot
|
||||
*.ttf
|
||||
*.woff
|
||||
|
||||
/dist/
|
||||
/src/assets/iconfont/
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# test directories
|
||||
__tests__
|
||||
test
|
||||
tests
|
||||
powered-test
|
||||
|
||||
# asset directories
|
||||
docs
|
||||
doc
|
||||
website
|
||||
images
|
||||
assets
|
||||
|
||||
# examples
|
||||
example
|
||||
examples
|
||||
|
||||
# code coverage directories
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# build scripts
|
||||
Makefile
|
||||
Gulpfile.js
|
||||
Gruntfile.js
|
||||
|
||||
# configs
|
||||
appveyor.yml
|
||||
circle.yml
|
||||
codeship-services.yml
|
||||
codeship-steps.yml
|
||||
wercker.yml
|
||||
.tern-project
|
||||
.gitattributes
|
||||
.editorconfig
|
||||
.*ignore
|
||||
.eslintrc
|
||||
.jshintrc
|
||||
.flowconfig
|
||||
.documentup.json
|
||||
.yarn-metadata.json
|
||||
.travis.yml
|
||||
|
||||
# misc
|
||||
*.md
|
||||
|
||||
!istanbul-reports/lib/html/assets
|
||||
!istanbul-api/node_modules/istanbul-reports/lib/html/assets
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# VBEN ADMIN
|
||||
|
||||
一个基于`ant-design-vue`,`typescript`,`vue-composition-api`实现的 vue3 风格的后台管理系统,用 vue3 的写法写 vue2
|
||||
|
||||
兼容 vue2 的浏览器,一切免费,不收取任何费用,请放心使用。后续定期提供更新及维护,可供参考与学习
|
||||
|
||||
## 为什么写这个
|
||||
|
||||
目前在网上暂时没有找到相关的使用 composition-api 写的后台系统,所以就把自己写的分享出来,后续会陆续加上新的功能,并且等`vue3`完全稳定的时候
|
||||
|
||||
会提供`vue3`版本,该项目后续切换 vue3 的成本相对较低,后续会做成一键切换 2 和 3 的版本
|
||||
|
||||
## 为什么要使用 vue-composition-api
|
||||
|
||||
最大的原因是我们还要兼容`ie10` 和`ie11`,`ie9` 需要自己修改 css 兼容性,就算 `vue3`稳定下来最多也就支持`ie11`,所以使用了`vue-composition-api`进行开发
|
||||
|
||||
## 安装
|
||||
|
||||
```js
|
||||
// 拉取项目代码
|
||||
|
||||
git clone https://github.com/anncwb/vben-admin.git
|
||||
|
||||
cd vben-admin
|
||||
|
||||
// 最好使用yarn,否则热更新可能出现问题
|
||||
yarn install
|
||||
|
||||
```
|
||||
|
||||
## 开发计划
|
||||
|
||||
由于开发时间较短,所以功能暂时较少
|
||||
|
||||
后续会逐步完善,有需要什么组件可以提出来
|
||||
|
||||
- [x] 项目搭建(基于 vue-cli4)已经优化
|
||||
- [x] 登陆页(已 mock)
|
||||
- [x] 菜单(可以搜索及拖拽以及菜单布局)
|
||||
- [x] 多标签页(面包屑没做,后续可以加)
|
||||
- [x] 基于角色的权限管理
|
||||
- [] 基于后台的权限管理
|
||||
- [] 组件封装(目前想到的只有 modal table form upload 等) 其余的可以在想我提出
|
||||
- [] 常用页面实现及例子
|
||||
- [] 首页设计
|
||||
- [] 项目可配置
|
||||
- [] 工具封装
|
||||
- [] vue3 一键切换
|
||||
- [] 主题配置
|
||||
- 更多功能
|
||||
|
||||
## 讨论群
|
||||
|
||||
QQ: 569291866
|
||||
|
||||
由于项目刚开始几天,群还没什么人,有兴趣的可以加群一起讨论
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
const { isProductionFn } = require('./build/utils');
|
||||
|
||||
const plugins = [];
|
||||
|
||||
if (isProductionFn() && process.env.BUILD_ON_CLEAN_CONSOLE === 'TRUE') {
|
||||
plugins.push('transform-remove-console');
|
||||
} else {
|
||||
plugins.push([
|
||||
'captains-log',
|
||||
{
|
||||
injectVariableName: true,
|
||||
injectFileName: false,
|
||||
ignorePatterns: [
|
||||
'node_modules',
|
||||
'build',
|
||||
'config',
|
||||
'mock',
|
||||
'dist',
|
||||
'docs',
|
||||
'public',
|
||||
'.spec.js',
|
||||
],
|
||||
},
|
||||
]);
|
||||
}
|
||||
module.exports = (api) => {
|
||||
return {
|
||||
plugins: [
|
||||
'@vue/babel-plugin-transform-vue-jsx',
|
||||
[
|
||||
'babel-plugin-component',
|
||||
{
|
||||
libraryName: '@ylz/ele-ui',
|
||||
styleLibraryName: 'theme-chalk',
|
||||
},
|
||||
],
|
||||
[
|
||||
'babel-plugin-import',
|
||||
{ libraryName: 'ant-design-vue', libraryDirectory: 'es', style: true },
|
||||
'ant-design-vue',
|
||||
],
|
||||
...plugins,
|
||||
],
|
||||
presets: [
|
||||
require('./build/lib/jsx/index.js'),
|
||||
// 'babel-preset-vca-jsx',
|
||||
[
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
{
|
||||
// 对ES6的模块文件不做转化,以便使用tree shaking、sideEffects等
|
||||
modules: false,
|
||||
// browserslist环境不支持的所有垫片都导入
|
||||
useBuiltIns: 'entry',
|
||||
corejs: { version: 3, proposals: true },
|
||||
forceAllTransforms: api.env('production'),
|
||||
targets: {
|
||||
chrome: '58',
|
||||
ie: '9',
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
const { join } = require('path');
|
||||
|
||||
module.exports = function (dir) {
|
||||
return join(process.cwd(), dir);
|
||||
};
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
const resolve = require('./getCwdPath');
|
||||
const dotenv = require('dotenv');
|
||||
const fs = require('fs-extra');
|
||||
const { readFileSync } = fs;
|
||||
|
||||
/**
|
||||
* @description: 获取环境变量
|
||||
* @Date: 2020-06-16 17:09:07
|
||||
*/
|
||||
function getEnvConfig(match = 'GLOB_', confFiles = ['.env', '.env.production']) {
|
||||
let envConfig = {};
|
||||
confFiles.forEach((item) => {
|
||||
try {
|
||||
const env = dotenv.parse(readFileSync(resolve(item)));
|
||||
|
||||
envConfig = { ...envConfig, ...env };
|
||||
} catch (error) {}
|
||||
});
|
||||
Object.keys(envConfig).forEach((key) => {
|
||||
const reg = new RegExp(`^(${match})`);
|
||||
if (!reg.test(key)) {
|
||||
Reflect.deleteProperty(envConfig, key);
|
||||
}
|
||||
});
|
||||
return envConfig;
|
||||
}
|
||||
/**
|
||||
* @description: 获取多页标题
|
||||
* @Date: 2020-06-16 17:09:00
|
||||
*/
|
||||
function getMpaTitles() {
|
||||
const { GLOB_APP_TITLE_MPA } = getEnvConfig('GLOB_', ['.env']);
|
||||
try {
|
||||
const titleObj = JSON.parse(GLOB_APP_TITLE_MPA);
|
||||
return titleObj;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getEnvConfig,
|
||||
getMpaTitles,
|
||||
};
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
const syntaxJsx = require('@babel/plugin-syntax-jsx').default;
|
||||
|
||||
const importSource = '@/setup/vue';
|
||||
|
||||
const hasJSX = (t, path) => {
|
||||
const JSXChecker = {
|
||||
hasJSX: false,
|
||||
};
|
||||
path.traverse(
|
||||
{
|
||||
JSXElement() {
|
||||
this.hasJSX = true;
|
||||
},
|
||||
},
|
||||
JSXChecker
|
||||
);
|
||||
return JSXChecker.hasJSX;
|
||||
};
|
||||
|
||||
// remove `var h = this.$createElement;` in `setup()`
|
||||
const remove$createElement = (t, path) => {
|
||||
path.traverse({
|
||||
ObjectMethod(p) {
|
||||
const isSetup = p.node.key.name === 'setup';
|
||||
if (!isSetup) return;
|
||||
p.traverse({
|
||||
VariableDeclaration(varPath) {
|
||||
varPath.traverse({
|
||||
MemberExpression(p) {
|
||||
if (
|
||||
t.isThisExpression(p.node.object) &&
|
||||
t.isIdentifier(p.node.property) &&
|
||||
p.node.property.name === '$createElement'
|
||||
) {
|
||||
varPath.remove();
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// auto import `createElement as h` from `@vue/composition-api`
|
||||
const autoImportH = (t, path) => {
|
||||
if (hasJSX(t, path)) {
|
||||
const importNodes = path
|
||||
.get('body')
|
||||
.filter((p) => p.isImportDeclaration())
|
||||
.map((p) => p.node);
|
||||
const vcaImportNodes = importNodes.filter((p) => p.source.value === importSource);
|
||||
const hasH = vcaImportNodes.some((p) =>
|
||||
p.specifiers.some((s) => t.isImportSpecifier(s) && s.local.name === 'h')
|
||||
);
|
||||
if (!hasH) {
|
||||
const vcaImportSpecifier = t.importSpecifier(t.identifier('h'), t.identifier('h'));
|
||||
if (vcaImportNodes.length > 0) {
|
||||
vcaImportNodes[0].specifiers.push(vcaImportSpecifier);
|
||||
} else {
|
||||
path.unshiftContainer(
|
||||
'body',
|
||||
t.importDeclaration([vcaImportSpecifier], t.stringLiteral(importSource))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ({ types: t }) => {
|
||||
return {
|
||||
inherits: syntaxJsx,
|
||||
visitor: {
|
||||
Program(path) {
|
||||
remove$createElement(t, path);
|
||||
autoImportH(t, path);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* Convert object to functional component
|
||||
* @param t
|
||||
* @param path
|
||||
*/
|
||||
const convertSetupFunctionalComponent = (t, path) => {
|
||||
const properties = path.node.properties;
|
||||
const nameProp = properties.find(node => node.key.name === 'name');
|
||||
const renderProp = properties.find(node => node.key.name === 'render');
|
||||
const renderBody = renderProp.value.body;
|
||||
const renderParams = renderProp.value.params;
|
||||
const name = nameProp && nameProp.value.value;
|
||||
const params = [...renderParams.slice(renderParams.length && renderParams[0].name === 'h' ? 1 : 0)];
|
||||
|
||||
const props = [
|
||||
t.objectProperty(t.identifier('setup'), t.arrowFunctionExpression(params, renderBody))
|
||||
];
|
||||
if (name) {
|
||||
props.unshift(t.objectProperty(t.identifier('name'), t.stringLiteral(name)));
|
||||
}
|
||||
path.replaceWith(t.objectExpression(props));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it's a setup functional componet declarator
|
||||
* @param t
|
||||
* @param path
|
||||
* @returns boolean
|
||||
*/
|
||||
const isSetupFunctionalComponentDeclarator = (t, path) => {
|
||||
const properties = path.node.properties;
|
||||
|
||||
const isFunctional = properties.filter(node => {
|
||||
return (
|
||||
t.isObjectProperty(node) &&
|
||||
((node.key.name === 'functional' && node.value.value === true) || node.key.name === 'render')
|
||||
);
|
||||
}).length === 2;
|
||||
|
||||
if (!isFunctional) return false;
|
||||
|
||||
const renderBody = properties.find(node => node.key.name === 'render').value.body;
|
||||
|
||||
const returnStatement = t.isBlockStatement(renderBody) && renderBody.body.find(node => t.isReturnStatement(node));
|
||||
|
||||
return (
|
||||
t.isArrowFunctionExpression(renderBody) ||
|
||||
t.isFunctionExpression(renderBody) ||
|
||||
(returnStatement && t.isArrowFunctionExpression(returnStatement.argument)) ||
|
||||
(returnStatement && t.isFunctionExpression(returnStatement.argument))
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = ({ types: t }) => {
|
||||
return {
|
||||
visitor: {
|
||||
Program(path) {
|
||||
path.traverse({
|
||||
ExportDefaultDeclaration(path) {
|
||||
const declaration = path.get('declaration');
|
||||
if (
|
||||
!t.isObjectExpression(declaration) ||
|
||||
!isSetupFunctionalComponentDeclarator(t, declaration)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
convertSetupFunctionalComponent(t, declaration);
|
||||
},
|
||||
VariableDeclaration(path) {
|
||||
if (
|
||||
path.node.declarations.length !== 1 ||
|
||||
!t.isVariableDeclarator(path.node.declarations[0]) ||
|
||||
!t.isObjectExpression(path.node.declarations[0].init)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const declarator = path.get('declarations')[0];
|
||||
const init = declarator.get('init');
|
||||
if (!isSetupFunctionalComponentDeclarator(t, init)) {
|
||||
return;
|
||||
}
|
||||
convertSetupFunctionalComponent(t, init);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* Definition like `const root = ref(null);`.
|
||||
* @param {*} t
|
||||
* @param {*} path
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isRefCallee = (t, path) => {
|
||||
if (!t.isVariableDeclaration(path)) return;
|
||||
const declarations = path.get('declarations');
|
||||
if (declarations.length !== 1) return;
|
||||
const init = declarations[0].get('init');
|
||||
if (!t.isCallExpression(init)) return;
|
||||
return init.node.callee.name === 'ref' && t.isNullLiteral(init.get('arguments')[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Match definedRefs in JSX
|
||||
* @param {*} t
|
||||
* @param {*} path ObjectMethod
|
||||
* @returns {*} `refs` to be processed
|
||||
*/
|
||||
const matchRefsInJSX = (t, path, definedRefs = []) => {
|
||||
const refs = [];
|
||||
path.traverse({
|
||||
// Definition like `h('h1', { ref: ... })`.
|
||||
CallExpression(path) {
|
||||
if (path.node.callee.name !== 'h') return;
|
||||
const [, obj] = path.get('arguments');
|
||||
if (!obj || !t.isObjectExpression(obj)) return;
|
||||
const props = obj.get('properties');
|
||||
const refProp = props.find((path) => path.node.key.name === 'ref');
|
||||
if (!refProp) return;
|
||||
const value = refProp.get('value');
|
||||
if (t.isIdentifier(value)) {
|
||||
const ref = value.node.name;
|
||||
if (definedRefs.indexOf(ref) > -1) {
|
||||
refs.push(ref);
|
||||
value.replaceWith(t.stringLiteral(ref));
|
||||
}
|
||||
} else if (t.isStringLiteral(value)) {
|
||||
const ref = value.node.value;
|
||||
if (definedRefs.indexOf(ref) > -1) {
|
||||
refs.push(ref);
|
||||
}
|
||||
}
|
||||
},
|
||||
// Definition like `<h1 ref={...}></h1>`.
|
||||
JSXAttribute(path) {
|
||||
if (path.node.name.name !== 'ref') return;
|
||||
const value = path.get('value');
|
||||
if (t.isJSXExpressionContainer(value)) {
|
||||
const exp = value.get('expression');
|
||||
if (!exp || !t.isIdentifier(exp)) return;
|
||||
const ref = exp.node.name;
|
||||
if (definedRefs.indexOf(ref) > -1) {
|
||||
refs.push(ref);
|
||||
value.replaceWith(t.stringLiteral(ref));
|
||||
}
|
||||
} else if (t.isStringLiteral(value)) {
|
||||
const ref = value.node.value;
|
||||
if (definedRefs.indexOf(ref) > -1) {
|
||||
refs.push(ref);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
return refs;
|
||||
};
|
||||
|
||||
const autoImportVue = (t, path) => {
|
||||
const importSource = 'vue';
|
||||
const imports = path.node.body.filter(t.isImportDeclaration);
|
||||
const imported = imports.find((node) => node.source.value === importSource);
|
||||
const autoImport = () =>
|
||||
path.unshiftContainer(
|
||||
'body',
|
||||
t.importDeclaration(
|
||||
[t.importDefaultSpecifier(t.identifier('Vue'))],
|
||||
t.stringLiteral(importSource)
|
||||
)
|
||||
);
|
||||
if (!imported) {
|
||||
autoImport();
|
||||
return;
|
||||
}
|
||||
const defaultSpecifier = imported.specifiers.find(t.isImportDefaultSpecifier);
|
||||
if (!defaultSpecifier) {
|
||||
imported.specifiers.push(t.importDefaultSpecifier(t.identifier('Vue')));
|
||||
} else if (defaultSpecifier.local.name !== 'Vue') {
|
||||
autoImport();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* auto import lifeCycle
|
||||
* @param {*} t
|
||||
* @param {*} path Program
|
||||
* @param {*} lifeCycles
|
||||
*/
|
||||
const autoImportLifeCycle = (t, path, lifeCycles = []) => {
|
||||
const importSource = '@/setup/vue';
|
||||
const imports = path.node.body.filter(t.isImportDeclaration);
|
||||
const imported = imports.find((node) => node.source.value === importSource);
|
||||
const genImportSpecifiers = (list) =>
|
||||
list.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
|
||||
if (!imported) {
|
||||
path.unshiftContainer(
|
||||
'body',
|
||||
t.importDeclaration(genImportSpecifiers(lifeCycles), t.stringLiteral(importSource))
|
||||
);
|
||||
return lifeCycles;
|
||||
}
|
||||
const specifiers = imported.specifiers.filter(t.isImportSpecifier);
|
||||
const names = lifeCycles.map((name) => {
|
||||
const node = specifiers.find((node) => name === node.imported.name);
|
||||
if (node) {
|
||||
return node.local.name;
|
||||
} else {
|
||||
imported.specifiers.push(...genImportSpecifiers([name]));
|
||||
return name;
|
||||
}
|
||||
});
|
||||
return names;
|
||||
};
|
||||
|
||||
/**
|
||||
* inject onMounted(() => {
|
||||
* Vue.$nextTick(() => {
|
||||
* ...
|
||||
* });
|
||||
* });
|
||||
* @param {*} t
|
||||
* @param {*} path ObjectMethod
|
||||
* @param {*} lifeCycles
|
||||
* @param {*} refs
|
||||
*/
|
||||
const injectLifeCycle = (t, path, lifeCycles = [], refs = []) => {
|
||||
const [prop, ctx] = path.get('params');
|
||||
const props = ['refs'];
|
||||
const getProperties = () =>
|
||||
props.map((val) => t.objectProperty(t.identifier(val), t.identifier(val), false, true));
|
||||
if (!prop) {
|
||||
path.node.params.push(t.identifier('_'));
|
||||
}
|
||||
if (!ctx) {
|
||||
path.node.params.push(t.objectPattern(getProperties()));
|
||||
} else {
|
||||
if (t.isObjectPattern(ctx)) {
|
||||
const refsProp = ctx.node.properties.find((node) => node.key.name === props[0]);
|
||||
if (!refsProp) {
|
||||
ctx.node.properties.push(...getProperties());
|
||||
} else {
|
||||
props[0] = refsProp.value.name;
|
||||
}
|
||||
} else {
|
||||
props.unshift(ctx.node.name);
|
||||
}
|
||||
}
|
||||
|
||||
const identifiers = props.map((val) => t.identifier(val));
|
||||
const statements = refs.map((val) => {
|
||||
return t.expressionStatement(
|
||||
t.assignmentExpression(
|
||||
'=',
|
||||
t.memberExpression(t.identifier(val), t.identifier('value')),
|
||||
t.logicalExpression(
|
||||
'||',
|
||||
t.memberExpression(
|
||||
identifiers.length > 1 ? t.memberExpression(...identifiers) : identifiers[0],
|
||||
t.identifier(val)
|
||||
),
|
||||
t.nullLiteral()
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
const nextTick = t.expressionStatement(
|
||||
t.callExpression(t.memberExpression(t.identifier('Vue'), t.identifier('nextTick')), [
|
||||
t.arrowFunctionExpression([], t.blockStatement(statements)),
|
||||
])
|
||||
);
|
||||
|
||||
const content = lifeCycles.map((val) =>
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.identifier(val), [
|
||||
t.arrowFunctionExpression([], t.blockStatement([...statements, nextTick])),
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
path.get('body').unshiftContainer('body', content);
|
||||
};
|
||||
|
||||
module.exports = ({ types: t }) => {
|
||||
return {
|
||||
visitor: {
|
||||
Program(p) {
|
||||
p.traverse({
|
||||
'ObjectMethod|ObjectProperty'(path) {
|
||||
if (path.node.key.name !== 'setup') return;
|
||||
let container = path;
|
||||
if (t.isObjectProperty(path)) {
|
||||
container = path.get('value');
|
||||
}
|
||||
if (!t.isBlockStatement(container.get('body'))) return;
|
||||
const body = container.get('body').get('body');
|
||||
const definedRefs = body
|
||||
.filter((path) => isRefCallee(t, path))
|
||||
.map((path) => path.get('declarations')[0].node.id.name);
|
||||
if (!definedRefs.length) return;
|
||||
|
||||
const refs = matchRefsInJSX(t, container, definedRefs);
|
||||
|
||||
if (!refs.length) return;
|
||||
autoImportVue(t, p);
|
||||
const lifeCycles = autoImportLifeCycle(t, p, ['onMounted', 'onUpdated']);
|
||||
|
||||
injectLifeCycle(t, container, lifeCycles, refs);
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
const autoImportVue = (t, path) => {
|
||||
const importSource = "vue";
|
||||
const imports = path.node.body.filter(t.isImportDeclaration);
|
||||
const imported = imports.find(node => node.source.value === importSource);
|
||||
const autoImport = () =>
|
||||
path.unshiftContainer(
|
||||
"body",
|
||||
t.importDeclaration(
|
||||
[t.importDefaultSpecifier(t.identifier("Vue"))],
|
||||
t.stringLiteral(importSource)
|
||||
)
|
||||
);
|
||||
if (!imported) {
|
||||
autoImport();
|
||||
return;
|
||||
}
|
||||
const defaultSpecifier = imported.specifiers.find(t.isImportDefaultSpecifier);
|
||||
if (!defaultSpecifier) {
|
||||
imported.specifiers.push(t.importDefaultSpecifier(t.identifier("Vue")));
|
||||
} else if (defaultSpecifier.local.name !== "Vue") {
|
||||
autoImport();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ({ types: t }) => {
|
||||
return {
|
||||
visitor: {
|
||||
Program(p) {
|
||||
p.traverse({
|
||||
"ObjectMethod|ObjectProperty"(path) {
|
||||
if (path.node.key.name !== "setup") return;
|
||||
path.traverse({
|
||||
JSXAttribute(path) {
|
||||
const n = path.get("name");
|
||||
const isInputOrModel = n.node.name === "on-input" || n.node.name === "on-change" || n.node.name === "model";
|
||||
if (!isInputOrModel) return;
|
||||
path.traverse({
|
||||
MemberExpression(path) {
|
||||
const obj = path.get("object");
|
||||
const prop = path.get("property");
|
||||
if (t.isThisExpression(obj) && t.isIdentifier(prop) && prop.node.name === "$set") {
|
||||
autoImportVue(t, p);
|
||||
obj.replaceWith(t.identifier("Vue"));
|
||||
prop.replaceWith(t.identifier("set"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
module.exports = function () {
|
||||
return {
|
||||
plugins: [
|
||||
require('./babel-sugar-inject-h'),
|
||||
require('./babel-sugar-setup-functional'),
|
||||
require('./babel-sugar-setup-ref'),
|
||||
require('./babel-sugar-v-model-v1.1.2-patch'),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
/**
|
||||
* mock service middleware, modified from umijs
|
||||
*/
|
||||
const { existsSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
const bodyParser = require('body-parser');
|
||||
const glob = require('glob');
|
||||
const assert = require('assert');
|
||||
const chokidar = require('chokidar');
|
||||
const pathToRegexp = require('path-to-regexp');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const VALID_METHODS = ['get', 'post', 'put', 'patch', 'delete'];
|
||||
const BODY_PARSED_METHODS = ['post', 'put', 'patch'];
|
||||
|
||||
/**
|
||||
* mockPath: mock目录地址
|
||||
* configPath: mock导入文件配置,如果没有则会遍历mockPath地址进行获取
|
||||
* ignoreFiles: 遍历地址时候忽略的文件
|
||||
* ignoreStartsWith: 遍历地址的时候忽略以什么开头的文件
|
||||
* handleWrap 包装返回结果函数
|
||||
*/
|
||||
module.exports = function createMockMiddleware({
|
||||
mockPath = 'mock',
|
||||
configPath = 'mock.config.js',
|
||||
ignoreFiles = [],
|
||||
ignoreStartsWith = '_',
|
||||
handleWrap = null,
|
||||
} = {}) {
|
||||
const cwd = process.cwd();
|
||||
const absMockPath = join(cwd, mockPath);
|
||||
const absConfigPath = join(cwd, configPath);
|
||||
|
||||
require('@babel/register');
|
||||
let mockData = getConfig();
|
||||
|
||||
watch();
|
||||
|
||||
function watch() {
|
||||
if (process.env.WATCH_FILES === 'none') return;
|
||||
const watcher = chokidar.watch([absConfigPath, absMockPath], {
|
||||
ignoreInitial: true,
|
||||
});
|
||||
watcher.on('all', (event, file) => {
|
||||
console.log(chalk.green(`mock file ${event}.`));
|
||||
// console.log(chalk.green(`mock file ${event}, reload mock data${file}`));
|
||||
// console.log(`file: ${file}`);
|
||||
mockData = getConfig();
|
||||
});
|
||||
}
|
||||
|
||||
function getConfig() {
|
||||
cleanRequireCache();
|
||||
let ret = null;
|
||||
if (existsSync(absConfigPath)) {
|
||||
// console.log(chalk.blue(`load mock data from ${absConfigPath}`));
|
||||
ret = require(absConfigPath);
|
||||
} else {
|
||||
// 如果没有mock文件夹,则读取配置文件内所有文件
|
||||
const mockFiles = glob
|
||||
.sync('**/*.js', {
|
||||
cwd: absMockPath,
|
||||
ignore: ignoreFiles,
|
||||
})
|
||||
.filter((mf) => !mf.startsWith(ignoreStartsWith));
|
||||
// including files ${JSON.stringify(
|
||||
// mockFiles
|
||||
// )}
|
||||
// console.log(chalk.blue(`load mock data from ${absMockPath}`));
|
||||
try {
|
||||
ret = mockFiles.reduce((memo, mockFile) => {
|
||||
const mod = require(join(absMockPath, mockFile));
|
||||
memo = {
|
||||
...memo,
|
||||
...mod.default,
|
||||
};
|
||||
return memo;
|
||||
}, {});
|
||||
} catch (error) {
|
||||
ret = {};
|
||||
console.log(`${chalk.red('mock reload error!')}`);
|
||||
}
|
||||
}
|
||||
|
||||
return normalizeConfig(ret);
|
||||
}
|
||||
function randomFrom(lowerValue, upperValue) {
|
||||
return Math.floor(Math.random() * (upperValue - lowerValue + 1) + lowerValue);
|
||||
}
|
||||
function parseKey(key) {
|
||||
const len = key.length - key.replace(/\s/g, '').length;
|
||||
let method = 'get';
|
||||
let path = key;
|
||||
let timeout = 0;
|
||||
if (len > 0) {
|
||||
const splitEd = key.split(' ');
|
||||
method = splitEd[0].toLowerCase();
|
||||
path = splitEd[1];
|
||||
if (len === 2) {
|
||||
timeout = splitEd[2];
|
||||
}
|
||||
}
|
||||
|
||||
assert(
|
||||
VALID_METHODS.includes(method),
|
||||
`Invalid method ${method} for path ${path}, please check your mock files.`
|
||||
);
|
||||
return {
|
||||
method,
|
||||
path,
|
||||
timeout,
|
||||
};
|
||||
}
|
||||
|
||||
function createHandler(method, path, handler, timeout) {
|
||||
return function (req, res, next) {
|
||||
if (BODY_PARSED_METHODS.includes(method)) {
|
||||
bodyParser.json({ limit: '5mb', strict: false })(req, res, () => {
|
||||
bodyParser.urlencoded({ limit: '5mb', extended: true })(req, res, () => {
|
||||
sendData(req);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
sendData();
|
||||
}
|
||||
|
||||
async function sendData(iReq) {
|
||||
try {
|
||||
if (timeout) {
|
||||
await sleep(timeout);
|
||||
}
|
||||
if (typeof handler === 'function') {
|
||||
const { body = {}, query = {} } = iReq || req || {};
|
||||
res.json(
|
||||
handler({
|
||||
body,
|
||||
method,
|
||||
query,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
res.json(handler);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(
|
||||
chalk.red('mock handle error: 处理您的函数时候出现了错误,请检查你的mock函数!')
|
||||
);
|
||||
res.json({});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function sleep(time) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
function normalizeConfig(config) {
|
||||
return Object.keys(config).reduce((memo, key) => {
|
||||
const handler = config[key];
|
||||
const type = typeof handler;
|
||||
assert(
|
||||
type === 'function' || type === 'object',
|
||||
`mock value of ${key} should be function or object, but got ${type}`
|
||||
);
|
||||
let { method, path, timeout } = parseKey(key);
|
||||
if (timeout && timeout.indexOf('-')) {
|
||||
let [a, b] = timeout.split('-');
|
||||
if (a > b) {
|
||||
[b, a] = [a, b];
|
||||
}
|
||||
timeout = randomFrom(~~a, ~~b);
|
||||
}
|
||||
const keys = [];
|
||||
const re = pathToRegexp(path, keys);
|
||||
memo.push({
|
||||
method,
|
||||
path,
|
||||
re,
|
||||
keys,
|
||||
handler: createHandler(method, path, handler, timeout),
|
||||
});
|
||||
return memo;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function cleanRequireCache() {
|
||||
Object.keys(require.cache).forEach((file) => {
|
||||
if (file === absConfigPath || file.indexOf(absMockPath) > -1) {
|
||||
delete require.cache[file];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求是否匹配
|
||||
* @param {*} req
|
||||
*/
|
||||
function matchMock(req) {
|
||||
const { path: exceptPath } = req;
|
||||
const exceptMethod = req.method.toLowerCase();
|
||||
for (const mock of mockData) {
|
||||
const { method, re, keys } = mock;
|
||||
if (method === exceptMethod) {
|
||||
const match = re.exec(req.path);
|
||||
if (match) {
|
||||
const params = {};
|
||||
|
||||
for (let i = 1; i < match.length; i = i + 1) {
|
||||
const key = keys[i - 1];
|
||||
const prop = key.name;
|
||||
const val = decodeParam(match[i]);
|
||||
|
||||
if (val !== undefined || !hasOwnProperty.call(params, prop)) {
|
||||
params[prop] = val;
|
||||
}
|
||||
}
|
||||
req.params = params;
|
||||
return mock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decodeParam(val) {
|
||||
if (typeof val !== 'string' || val.length === 0) {
|
||||
return val;
|
||||
}
|
||||
|
||||
try {
|
||||
return decodeURIComponent(val);
|
||||
} catch (err) {
|
||||
if (err instanceof URIError) {
|
||||
err.message = `Failed to decode param ' ${val} '`;
|
||||
err.status = err.statusCode = 400;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return mockData.filter(({ method, re }) => {
|
||||
return method === exceptMethod && re.test(exceptPath);
|
||||
})[0];
|
||||
}
|
||||
|
||||
return (req, res, next) => {
|
||||
const match = matchMock(req);
|
||||
if (match) {
|
||||
console.log(
|
||||
`${chalk.yellow('mock matched:')} ${chalk.green.bold(
|
||||
match.method.toUpperCase()
|
||||
)} ${chalk.blue.bold(match.path)}`
|
||||
);
|
||||
const wrapIsFunc = typeof handleWrap === 'function';
|
||||
const result = match.handler(req, res, next);
|
||||
return wrapIsFunc ? wrapIsFunc(result) : result;
|
||||
} else {
|
||||
return next();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* 使用cnpm 来安装image-webpack-loader
|
||||
*/
|
||||
// const shelljs = require('shelljs');
|
||||
// const { exec } = shelljs;
|
||||
|
||||
// /**
|
||||
// * @description: 判断是否装了cnpm
|
||||
// * @Date: 2020-06-10 13:46:40
|
||||
// */
|
||||
// function isInstallCnpm() {
|
||||
// return new Promise((resolve) => {
|
||||
// const runSuccess = exec('cnpm -v').code === 0;
|
||||
// resolve(runSuccess);
|
||||
// });
|
||||
// }
|
||||
// /**
|
||||
// * @description: 尝试安装cnpm
|
||||
// * @Date: 2020-06-10 13:47:05
|
||||
// */
|
||||
// function tryInstallCnpm() {
|
||||
// return new Promise((resolve) => {
|
||||
// if (exec('npm install -g cnpm --registry=https://registry.npm.taobao.org').code === 0) {
|
||||
// resolve();
|
||||
// } else {
|
||||
// shell.echo('请安装 cnpm');
|
||||
// shell.exit(1);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// /**
|
||||
// * @description: 安装插件
|
||||
// * @Date: 2020-06-10 13:46:47
|
||||
// */
|
||||
// async function installImageWebpack() {
|
||||
// const installCnpm = await isInstallCnpm();
|
||||
|
||||
// if (!installCnpm) {
|
||||
// await tryInstallCnpm();
|
||||
// installImageWebpack();
|
||||
// return;
|
||||
// }
|
||||
// if (exec('cnpm install image-webpack-loader -D').code !== 0) {
|
||||
// //执行npm run build 命令
|
||||
// shell.echo('请安装 cnpm');
|
||||
// shell.exit(1);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @description: 使git对文件名大小写敏感
|
||||
// * @Date: 2020-06-11 11:07:04
|
||||
// */
|
||||
// function ignoreCaseGit() {
|
||||
// exec('git config core.ignorecase false ');
|
||||
// }
|
||||
// installImageWebpack();
|
||||
|
||||
// ignoreCaseGit();
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// 安装之前先行删除image-webpack-loader,防止yarn 安装失败
|
||||
|
||||
// const { join } = require('path');
|
||||
|
||||
// const pkg = require('../../package.json');
|
||||
// const { writeFileSync } = require('fs');
|
||||
|
||||
// function deleteDep() {
|
||||
// delete pkg.devDependencies['image-webpack-loader'];
|
||||
|
||||
// writeFileSync(join(process.cwd(), 'package.json'), JSON.stringify(pkg, null, 2), {
|
||||
// encoding: 'utf8',
|
||||
// });
|
||||
// }
|
||||
// deleteDep();
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const resolve = require('../getCwdPath');
|
||||
const { successTip, errorTip } = require('../utils');
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const mkdirp = require('mkdirp');
|
||||
const { getEnvConfig, getMpaTitles } = require('../getEnvConfig');
|
||||
const { writeFileSync } = fs;
|
||||
const getShortName = (env) => {
|
||||
return `__PRODUCTION__${env.GLOB_APP_SHORT_NAME || '__APP'}__CONF__`.toUpperCase();
|
||||
};
|
||||
const pages = getMpaTitles();
|
||||
const pageKeys = Object.keys(pages);
|
||||
const MPA_END_REG = /(?<=_MPA)$/;
|
||||
/**
|
||||
* @description: 获取多页文件配置
|
||||
* @Date: 2020-06-16 16:49:34
|
||||
*/
|
||||
function getMpaConfig(config) {
|
||||
const formatConfig = {};
|
||||
const result = {};
|
||||
try {
|
||||
Object.keys(config).forEach((key) => {
|
||||
if (MPA_END_REG.test(key)) {
|
||||
formatConfig[key] = JSON.parse(config[key]);
|
||||
} else {
|
||||
formatConfig[key] = config[key];
|
||||
}
|
||||
});
|
||||
pageKeys.forEach((page) => {
|
||||
const pageConfigItem = {};
|
||||
Object.keys(formatConfig).forEach((key) => {
|
||||
if (!MPA_END_REG.test(key)) {
|
||||
const mpaKey = `${key}_MPA`;
|
||||
pageConfigItem[key] = formatConfig[key];
|
||||
if (formatConfig[mpaKey]) {
|
||||
pageConfigItem[key] = formatConfig[mpaKey][page] || formatConfig[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
result[page] = pageConfigItem;
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @description: 创建配置文件
|
||||
* @Date: 2020-06-16 17:29:58
|
||||
*/
|
||||
function createConfig({ configName, config, configFileName = 'window-glob.js' } = {}) {
|
||||
try {
|
||||
const configStr = `window.${configName}=${JSON.stringify(config)};`;
|
||||
mkdirp.sync(resolve('dist'), {});
|
||||
writeFileSync(resolve(`dist/${configFileName}`), configStr);
|
||||
successTip('The configuration file is packaged successfully!');
|
||||
} catch (error) {
|
||||
errorTip('Configuration file configuration file failed to package', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @description: 打包配置文件
|
||||
* @Date: 2020-03-18 09:27:17
|
||||
*/
|
||||
async function buildConfig(moduleStr = '') {
|
||||
const config = getEnvConfig();
|
||||
|
||||
// 是否为单页应用
|
||||
// const appConfig = getEnvConfig('VUE_APP');
|
||||
// const isSpa = appConfig.VUE_APP_MODE === 'SPA';
|
||||
|
||||
let CONFIG_NAME;
|
||||
let CONFIG_OBJ = [];
|
||||
// // 单页应用配置文件抽取
|
||||
// if (isSpa) {
|
||||
Object.keys(config).forEach((key) => {
|
||||
if (MPA_END_REG.test(key)) {
|
||||
Reflect.deleteProperty(config, key);
|
||||
}
|
||||
});
|
||||
CONFIG_NAME = getShortName(config);
|
||||
// }
|
||||
// else {
|
||||
// // 多页应用配置文件抽取
|
||||
// CONFIG_OBJ = getMpaConfig(config);
|
||||
// }
|
||||
|
||||
// 打包成dist
|
||||
// if (isSpa) {
|
||||
createConfig({ config, configName: CONFIG_NAME });
|
||||
// }
|
||||
// else {
|
||||
// // 多页
|
||||
// pageKeys.forEach((key) => {
|
||||
// if (moduleStr && !moduleStr.split(',').includes(key)) {
|
||||
// return;
|
||||
// }
|
||||
// const _configName = getShortName({
|
||||
// GLOB_APP_SHORT_NAME: `${config.GLOB_APP_SHORT_NAME}`,
|
||||
// });
|
||||
|
||||
// const _config = CONFIG_OBJ[key];
|
||||
// createConfig({
|
||||
// config: _config,
|
||||
// configName: _configName,
|
||||
// configFileName: `window-glob-${key}.js`,
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
}
|
||||
module.exports = { buildConfig, getEnvConfig };
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
const compressing = require('compressing');
|
||||
const fs = require('fs-extra');
|
||||
const moment = require('moment');
|
||||
|
||||
const { successTip, errorTip } = require('../utils');
|
||||
const resolve = require('../getCwdPath');
|
||||
const { readFile } = fs;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @Date: 2020-03-17 15:14:55
|
||||
*/
|
||||
function buildZip(dir, zipName) {
|
||||
readFile(resolve('package.json'), (err, res) => {
|
||||
if (err) {
|
||||
errorTip('压缩报错' + err);
|
||||
return;
|
||||
}
|
||||
const pkg = JSON.parse(res.toString());
|
||||
compressing.zip
|
||||
.compressDir(
|
||||
resolve(dir),
|
||||
resolve(`${zipName}_${moment().format('MMDD')}_v${pkg.version}.zip`)
|
||||
)
|
||||
.then(() => {
|
||||
successTip(
|
||||
`The file was successfully compressed and has been compressed to【${resolve(zipName)}】`
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
errorTip(' Compression error\n' + err);
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
module.exports = { buildZip };
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
const runjs = require('runjs');
|
||||
const yargs = require('yargs');
|
||||
const mkdirp = require('mkdirp');
|
||||
const { buildConfig } = require('./build-conf');
|
||||
const { updateVersion } = require('./update-version');
|
||||
const { buildZip } = require('./build-zip');
|
||||
const { successTip, errorTip, isReportModeFn } = require('../utils');
|
||||
const resolve = require('../getCwdPath');
|
||||
const { selectBuildModule } = require('./selectBuildModule');
|
||||
const { getEnvConfig } = require('../getEnvConfig');
|
||||
|
||||
const { run } = runjs;
|
||||
|
||||
async function build(v) {
|
||||
const argvList = yargs.argv._;
|
||||
try {
|
||||
if (!argvList.includes('no-uv')) {
|
||||
await updateVersion();
|
||||
}
|
||||
|
||||
let command = `cross-env --max_old_space_size=4096 vue-cli-service build --no-clean --mode=production ${argvList.join(
|
||||
' '
|
||||
)} `;
|
||||
// 多页模式
|
||||
|
||||
// const env = getEnvConfig('VUE_APP');
|
||||
// const isSpa = env.VUE_APP_MODE === 'SPA';
|
||||
// let str = '';
|
||||
// if (!isSpa) {
|
||||
// const _module = yargs.argv.module;
|
||||
// if (_module) {
|
||||
// command += ` --module=${_module}`;
|
||||
// str = _module;
|
||||
// } else {
|
||||
// const moduleStr = await selectBuildModule('请选择需要打包的模块');
|
||||
// str = moduleStr;
|
||||
// command += ` --module=${moduleStr}`;
|
||||
// }
|
||||
// }
|
||||
// 更新配置文件
|
||||
if (!argvList.includes('no-conf')) {
|
||||
await buildConfig();
|
||||
}
|
||||
await run(command, {
|
||||
async: true,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
if (!isReportModeFn()) {
|
||||
const zipPath = '.local/output/dist/';
|
||||
mkdirp.sync(resolve(zipPath));
|
||||
buildZip('dist/', zipPath);
|
||||
}
|
||||
successTip('Packaged successfully!');
|
||||
} catch (error) {
|
||||
errorTip('Packaging failed', error);
|
||||
}
|
||||
}
|
||||
|
||||
build();
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// #!/usr/bin/env node
|
||||
|
||||
const { runjs } = require('@ylz/script-node-utils');
|
||||
const { successTip, errorTip } = require('../utils');
|
||||
|
||||
const { run } = runjs;
|
||||
|
||||
const createChangeLog = async () => {
|
||||
try {
|
||||
await run(
|
||||
`conventional-changelog -p --config ./node_modules/@ylz/script-code-lint/lib/log/index.js -i CHANGELOG.md -s && git add ./CHANGELOG.md`,
|
||||
{
|
||||
async: true,
|
||||
stdio: 'inherit',
|
||||
}
|
||||
);
|
||||
await run('prettier --write **/CHANGELOG.md ', {
|
||||
async: true,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
successTip('CHANGE_LOG generated successfully');
|
||||
} catch (error) {
|
||||
errorTip('CHANGE_LOG generated error\n' + error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
createChangeLog();
|
||||
module.exports = {
|
||||
createChangeLog,
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
const resolve = require('../getCwdPath');
|
||||
const { getIPAddress, inquirerPrompt } = require('../utils');
|
||||
const Koa = require('koa');
|
||||
const chalk = require('chalk');
|
||||
const runjs = require('runjs');
|
||||
const portfinder = require('portfinder');
|
||||
const staticServer = require('koa-static');
|
||||
|
||||
const { run } = runjs;
|
||||
const BUILD = 1;
|
||||
const NO_BUILD = 2;
|
||||
// const util = require('../util');
|
||||
|
||||
// 启动服务器
|
||||
const startApp = () => {
|
||||
const port = 9680;
|
||||
portfinder.basePort = port;
|
||||
const app = new Koa();
|
||||
// const connect = require('connect');
|
||||
// const serveStatic = require('serve-static');
|
||||
// const app = connect();
|
||||
|
||||
app.use(staticServer(resolve(`./dist`)));
|
||||
|
||||
portfinder.getPort(async (err, port) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
const publicPath = process.env.BASE_URL;
|
||||
app.listen(port, function () {
|
||||
const empty = ' ';
|
||||
const common = `The preview program is already running:
|
||||
- LOCAL: http://localhost:${port}/
|
||||
- NETWORK: http://${getIPAddress()}:${port}/
|
||||
`;
|
||||
console.log(chalk.cyan('\n' + empty + common));
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const preview = async () => {
|
||||
const prompt = inquirerPrompt({
|
||||
type: 'list',
|
||||
message: 'Please select a preview method',
|
||||
name: 'type',
|
||||
choices: [
|
||||
{
|
||||
name: 'Preview after packaging',
|
||||
value: BUILD,
|
||||
},
|
||||
{
|
||||
name: `No packaging, preview directly (need to have dist file after packaging)`,
|
||||
value: NO_BUILD,
|
||||
},
|
||||
],
|
||||
});
|
||||
const { type } = await prompt;
|
||||
if (type === BUILD) {
|
||||
await run('npm run build no-uv', { async: true });
|
||||
await build({ noUv: true });
|
||||
}
|
||||
startApp();
|
||||
};
|
||||
|
||||
preview();
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const { inquirerPrompt } = require('../utils');
|
||||
|
||||
const { getMpaTitles } = require('../getEnvConfig');
|
||||
async function selectBuildModule(msg = '') {
|
||||
const pages = getMpaTitles();
|
||||
const keys = Object.keys(pages);
|
||||
const prompt = inquirerPrompt({
|
||||
type: 'list',
|
||||
message: msg,
|
||||
name: 'type',
|
||||
choices: [
|
||||
{
|
||||
name: 'All modules',
|
||||
value: keys.join(','),
|
||||
},
|
||||
...keys.map((key) => {
|
||||
return {
|
||||
name: pages[key] || '',
|
||||
value: key,
|
||||
};
|
||||
}),
|
||||
],
|
||||
});
|
||||
const { type } = await prompt;
|
||||
return type;
|
||||
}
|
||||
module.exports = {
|
||||
selectBuildModule,
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const { selectBuildModule } = require('./selectBuildModule');
|
||||
const { getEnvConfig } = require('../getEnvConfig');
|
||||
const runjs = require('runjs');
|
||||
const yargs = require('yargs');
|
||||
const { run } = runjs;
|
||||
async function devServer() {
|
||||
const argvList = yargs.argv._;
|
||||
|
||||
let command = `cross-env --max_old_space_size=4096 vue-cli-service serve --mode development ${argvList.join(
|
||||
' '
|
||||
)} `;
|
||||
|
||||
// const env = getEnvConfig('VUE_APP');
|
||||
// const isSpa = env.VUE_APP_MODE === 'SPA';
|
||||
// if (!isSpa) {
|
||||
// const _module = yargs.argv.module;
|
||||
// if (_module) {
|
||||
// command += ` --module=${_module}`;
|
||||
// } else {
|
||||
// const moduleStr = await selectBuildModule('请选择要运行的模块');
|
||||
// command += ` --module=${moduleStr}`;
|
||||
// }
|
||||
// }
|
||||
await run(command, {
|
||||
async: true,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
devServer();
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const pkg = require('../../package.json');
|
||||
const runjs = require('runjs');
|
||||
const fs = require('fs-extra');
|
||||
const resolve = require('../getCwdPath');
|
||||
const { inquirerPrompt, successTip, errorTip } = require('../utils');
|
||||
|
||||
const { run } = runjs;
|
||||
const { writeFileSync } = fs;
|
||||
|
||||
const MAJOR = 1;
|
||||
const FEAT = 2;
|
||||
const FIX = 3;
|
||||
const SKIP = 4;
|
||||
const updateVersion = async (msg = 'Please select this update to submit changes') => {
|
||||
try {
|
||||
const prompt = inquirerPrompt({
|
||||
type: 'list',
|
||||
message: msg,
|
||||
name: 'type',
|
||||
choices: [
|
||||
{
|
||||
name: 'Some other features (such as bug fixes, style adjustments)',
|
||||
value: FIX,
|
||||
},
|
||||
{
|
||||
name: 'New features added',
|
||||
value: FEAT,
|
||||
},
|
||||
{
|
||||
name: 'Major version changes',
|
||||
value: MAJOR,
|
||||
},
|
||||
{
|
||||
name: 'jump over',
|
||||
value: SKIP,
|
||||
},
|
||||
],
|
||||
});
|
||||
const { type } = await prompt;
|
||||
|
||||
const versionString = pkg.version.split('.');
|
||||
|
||||
const versionNumber = versionString.map((vs) => Number(vs));
|
||||
if (type !== SKIP) {
|
||||
if (type === MAJOR) {
|
||||
versionNumber[0]++;
|
||||
versionNumber[1] = 0;
|
||||
versionNumber[2] = 0;
|
||||
} else if (type === FEAT) {
|
||||
versionNumber[1]++;
|
||||
versionNumber[2] = 0;
|
||||
} else {
|
||||
versionNumber[2]++;
|
||||
}
|
||||
|
||||
pkg.version = versionNumber.join('.');
|
||||
|
||||
writeFileSync(resolve('package.json'), JSON.stringify(pkg, null, 2), {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
}
|
||||
|
||||
await run(` git add ./package.json `, {
|
||||
async: true,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
successTip(
|
||||
`The version number has been updated successfully! The current version is ${pkg.version}!`
|
||||
);
|
||||
} catch (err) {
|
||||
errorTip('Version number update failed\n' + err);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
updateVersion,
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "../tsconfig",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
const { networkInterfaces, NetworkInterfaceInfo } = require('os');
|
||||
|
||||
const ora = require('ora');
|
||||
const chalk = require('chalk');
|
||||
const inquirer = require('inquirer');
|
||||
|
||||
const spinner = ora();
|
||||
|
||||
/**
|
||||
* @description: success tip
|
||||
* @Date: 2020-03-16 13:06:12
|
||||
*/
|
||||
function successTip(msg) {
|
||||
spinner.succeed(
|
||||
console.log(
|
||||
chalk.blue.bold('**************** ') +
|
||||
chalk.green.bold(msg) +
|
||||
chalk.blue.bold(' ****************') +
|
||||
'. 🎉 🎉 🎉 🎉\n'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: error tip
|
||||
* @Date: 2020-03-16 13:06:12
|
||||
*/
|
||||
function errorTip(msg, err) {
|
||||
spinner.fail(
|
||||
console.error('\n') +
|
||||
console.error(msg + '\n') +
|
||||
console.error(chalk.magenta('The specific error message is as follows \n')) +
|
||||
chalk.red(err) +
|
||||
'. 😭\n'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
function inquirerPrompt(question) {
|
||||
return inquirer.prompt(question);
|
||||
}
|
||||
/**
|
||||
* @description: get env
|
||||
* @Date: 2020-06-07 22:32:25
|
||||
*/
|
||||
function getEnvFn() {
|
||||
return process.env;
|
||||
}
|
||||
/**
|
||||
* @description: get mode
|
||||
* @Date: 2020-06-07 22:32:56
|
||||
*/
|
||||
function getModeFn() {
|
||||
return getEnvFn().NODE_ENV;
|
||||
}
|
||||
/**
|
||||
* @description: Whether it is a production mode
|
||||
* @Date: 2020-06-07 22:33:35
|
||||
*/
|
||||
function isProductionFn() {
|
||||
return getModeFn() === 'production';
|
||||
}
|
||||
/**
|
||||
* @description: Whether to develop mode
|
||||
* @Date: 2020-06-07 22:34:11
|
||||
*/
|
||||
function isDevFn() {
|
||||
return getModeFn() === 'development';
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Whether to support ie
|
||||
*
|
||||
* @Date: 2020-06-15 11:06:12
|
||||
*/
|
||||
function supportIeFn() {
|
||||
return process.env.VUE_APP_SUPPORT_IE === 'TRUE';
|
||||
}
|
||||
/**
|
||||
* @description: Whether it is report mode
|
||||
* @Date: 2020-06-15 11:06:18
|
||||
*/
|
||||
function isReportModeFn() {
|
||||
return !!process.env.REPORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Get local ip
|
||||
* @Date: 2020-06-15 11:06:35
|
||||
*/
|
||||
function getIPAddress() {
|
||||
let interfaces = networkInterfaces();
|
||||
for (let devName in interfaces) {
|
||||
let iFace = interfaces[devName];
|
||||
for (let i = 0; i < iFace.length; i++) {
|
||||
let alias = iFace[i];
|
||||
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
|
||||
return alias.address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getEnvFn,
|
||||
getModeFn,
|
||||
isProductionFn,
|
||||
isDevFn,
|
||||
errorTip,
|
||||
successTip,
|
||||
inquirerPrompt,
|
||||
supportIeFn,
|
||||
isReportModeFn,
|
||||
getIPAddress,
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
build:The main purpose is to modify the submission of the project build system (such as the configuration of glup, webpack, rollup, etc.)
|
||||
ci:The main purpose is to modify the project to continue the integration process (such as Travis, Jenkins, GitLab CI, Circle, etc.) submission
|
||||
docs:update doc
|
||||
merge:Merge branch ? of ?
|
||||
update: Update a function
|
||||
feat:new features
|
||||
fix:bug fix
|
||||
perf:Performance optimization
|
||||
refactor:Refactored code (no new features or bug fixes)
|
||||
style:Code modification that does not affect the program logic (modify blank characters, complete missing semicolons, etc.)
|
||||
test:Add test cases or update existing tests
|
||||
revert:Roll back an earlier commit
|
||||
chore:Other types that are not of the above type
|
||||
wip:Remove files or code
|
||||
*/
|
||||
|
||||
module.exports = require('./config/lint/commit-lint');
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { GlobConfig, GlobEnvConfig } from '../src/types/config';
|
||||
|
||||
import { isDevMode } from '../src/utils/envUtil';
|
||||
import { getShortName } from './getShortName';
|
||||
|
||||
export default (): GlobConfig => {
|
||||
const ENV_NAME = getShortName(process.env);
|
||||
const ENV = ((isDevMode() ? process.env : window[ENV_NAME]) as unknown) as GlobEnvConfig;
|
||||
const { GLOB_APP_TITLE, GLOB_API_URL, GLOB_APP_SHORT_NAME, GLOB_API_URL_PREFIX } = ENV;
|
||||
return {
|
||||
title: GLOB_APP_TITLE,
|
||||
apiUrl: GLOB_API_URL,
|
||||
shortName: GLOB_APP_SHORT_NAME,
|
||||
urlPrefix: GLOB_API_URL_PREFIX,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export const getShortName = (env) => {
|
||||
return `__PRODUCTION__${env.GLOB_APP_SHORT_NAME || '__APP'}__CONF__`.toUpperCase();
|
||||
};
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* less global variable
|
||||
*/
|
||||
const primaryColor = '#0593FF';
|
||||
|
||||
const modifyVars = {
|
||||
// -------- Colors -----------
|
||||
'primary-color': primaryColor, // 全局主色 Global dominant color
|
||||
'info-color': primaryColor, // 默认颜色 Default color
|
||||
'success-color': '#55D187', // 成功色 Success color
|
||||
'error-color': '#ED6F6F', // 错误色 False color
|
||||
'warning-color': '#FFD164', // 警告色 Warning color
|
||||
|
||||
'link-color': primaryColor, // 链接色 Link color
|
||||
'disabled-color': '#C2C2CC', // 失效色 Failure color
|
||||
'heading-color': '#2C3A61', // 标题色 Title color
|
||||
|
||||
'text-color': '#2C3A61', // 主文本色 Main text color
|
||||
'text-color-secondary ': '#606266', // Subtext color
|
||||
|
||||
'background-color-base': '#F0F2F5', // background color
|
||||
|
||||
'font-size-base': '14px', // 主字号 Main font size
|
||||
|
||||
'box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)', // 浮层阴影 Floating shadow
|
||||
|
||||
'border-color-base': '#CECECE', // 边框色 Border color,
|
||||
'border-color-split': '#CECECE', // 边框色 Border color,
|
||||
'border-radius-base': '2px', // 组件/浮层圆角 Component/float fillet
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
modifyVars,
|
||||
primaryColor,
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
module.exports = {
|
||||
ignores: [(commit) => commit.includes('init')],
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
parserPreset: {
|
||||
parserOpts: {
|
||||
headerPattern: /^(\w*|[\u4e00-\u9fa5]*)(?:[\(\(](.*)[\)\)])?[\:\:] (.*)/,
|
||||
headerCorrespondence: ['type', 'scope', 'subject'],
|
||||
referenceActions: [
|
||||
'close',
|
||||
'closes',
|
||||
'closed',
|
||||
'fix',
|
||||
'fixes',
|
||||
'fixed',
|
||||
'resolve',
|
||||
'resolves',
|
||||
'resolved',
|
||||
],
|
||||
issuePrefixes: ['#'],
|
||||
noteKeywords: ['BREAKING CHANGE', '不兼容变更'],
|
||||
fieldPattern: /^-(.*?)-$/,
|
||||
revertPattern: /^Revert\s"([\s\S]*)"\s*This reverts commit (\w*)\./,
|
||||
revertCorrespondence: ['header', 'hash'],
|
||||
warn() {},
|
||||
mergePattern: null,
|
||||
mergeCorrespondence: null,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'body-leading-blank': [2, 'always'],
|
||||
'footer-leading-blank': [1, 'always'],
|
||||
'header-max-length': [2, 'always', 108],
|
||||
'subject-empty': [2, 'never'],
|
||||
'type-empty': [2, 'never'],
|
||||
'type-enum': [
|
||||
2,
|
||||
'always',
|
||||
[
|
||||
'init',
|
||||
'update',
|
||||
'feat',
|
||||
'fix',
|
||||
'perf',
|
||||
'merge',
|
||||
'style',
|
||||
'docs',
|
||||
'test',
|
||||
'refactor',
|
||||
'build',
|
||||
'ci',
|
||||
'chore',
|
||||
'revert',
|
||||
'wip',
|
||||
],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const wrap = require('word-wrap');
|
||||
const longest = require('longest');
|
||||
const rightPad = require('right-pad');
|
||||
const chalk = require('chalk');
|
||||
const filter = (array) => {
|
||||
return array.filter((x) => {
|
||||
return x;
|
||||
});
|
||||
};
|
||||
// 获取选择列表
|
||||
const getList = (obj) => {
|
||||
const objLen = longest(Object.keys(obj)).length * 2 + 1;
|
||||
return Object.keys(obj).map((key) => ({
|
||||
name: `${rightPad(`${key}:`, objLen / 2, ' ')} ${obj[key].description}`,
|
||||
value: key,
|
||||
}));
|
||||
};
|
||||
exports.default = (options) => {
|
||||
const typeList = getList(options.types);
|
||||
const scopeList = getList(options.scopes);
|
||||
return {
|
||||
prompter(cz, commit) {
|
||||
console.log(chalk.yellow('\n标题会在100个字符后进行裁剪。 主体内容每行会在100个字符后自动换行,手动换行请直接输入"\\n"。\n'));
|
||||
cz.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'type',
|
||||
message: '(必选)选择你提交的信息类型:',
|
||||
choices: typeList,
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'scope',
|
||||
message: '(必填)本次提交的改变所影响的范围(整个项目,UI,数据,构建,具体那个模块)?',
|
||||
validate(str) {
|
||||
return str ? true : console.log(chalk.yellow(`请输入影响范围`));
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'subject',
|
||||
validate(str) {
|
||||
const charLen = 3;
|
||||
if (str.length > charLen) {
|
||||
return str.length > charLen;
|
||||
}
|
||||
else {
|
||||
console.log(chalk.yellow(`字符长度大于${charLen}`));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
message: '(必填)写一个的变化描述:',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'body',
|
||||
message: '(非必填)提供更详细的变更描述(没有则直接回车):',
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'isBreaking',
|
||||
message: '是否存在不兼容变更(没有则直接回车)?',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'breaking',
|
||||
message: '列出所有的不兼容变更:\n',
|
||||
default: false,
|
||||
when(answers) {
|
||||
return answers.isBreaking;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'isIssueAffected',
|
||||
message: '此次变更是否影响某些打开的 issue(没有则直接回车) ?',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'issues',
|
||||
message: '列出此次改动引用的所有 issues (如:"fix #123", "Closes #123, #124"):\n',
|
||||
when(answers) {
|
||||
return answers.isIssueAffected;
|
||||
},
|
||||
},
|
||||
]).then((answers) => {
|
||||
const maxLineWidth = 100;
|
||||
const wrapOptions = {
|
||||
trim: true,
|
||||
newline: '\n',
|
||||
indent: '',
|
||||
width: maxLineWidth,
|
||||
};
|
||||
// 判断影响范围是否输入
|
||||
const scope = answers.scope ? `(${answers.scope.trim()})` : '';
|
||||
// 限制短描述为 100 个字符
|
||||
const head = `${answers.type + scope}: ${answers.subject.trim()}`.slice(0, maxLineWidth);
|
||||
// 限制详细描述最长宽度为 100 个字符串
|
||||
const body = wrap(answers.body, wrapOptions);
|
||||
// Apply breaking change prefix, removing it if already present
|
||||
let breaking = answers.breaking ? answers.breaking.trim() : '';
|
||||
// 如果手动输入了 不兼容变更,则过滤掉,最后进行长度限制
|
||||
breaking = breaking ? `不兼容变更: ${breaking.replace(/^不兼容变更: /, '')}` : '';
|
||||
breaking = wrap(breaking, wrapOptions);
|
||||
const issues = answers.issues ? wrap(answers.issues, wrapOptions) : '';
|
||||
const footer = filter([breaking, issues]).join('\n\n');
|
||||
commit(`${head}\n\n${body}\n\n${footer}`);
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
module.exports = exports.default;
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const engine = require('./engine');
|
||||
exports.default = engine({
|
||||
types: {
|
||||
feat: {
|
||||
description: '🌟 一个新功能',
|
||||
title: '🌟 新功能',
|
||||
},
|
||||
update: {
|
||||
description: '✅ 更新某个模块,跟fix和feat不一样',
|
||||
title: '✅ 更新',
|
||||
},
|
||||
fix: {
|
||||
description: '🐛 一个 bug 修复',
|
||||
title: '🐛 Bug 修复',
|
||||
},
|
||||
style: {
|
||||
description: '🎨 对代码含义无影响的改动(空格,格式化,等,非 UI 变动)',
|
||||
title: '🎨 代码样式',
|
||||
},
|
||||
chore: {
|
||||
description: '🏠 影响构建系统或外部依赖的更改(例如:gulp,npm,webpack)',
|
||||
title: '🏠 构建',
|
||||
},
|
||||
docs: {
|
||||
description: '📝 只有文档发生改变',
|
||||
title: '📝 文档',
|
||||
},
|
||||
build: {
|
||||
description: '🎉 修改项目构建系统(如 glup,webpack,rollup 的配置等)的提交',
|
||||
title: '🎉 项目构建',
|
||||
},
|
||||
refactor: {
|
||||
description: '♻️ 既不是修复 bug 也不是添加新功能的代码更改',
|
||||
title: '♻️ 代码重构',
|
||||
},
|
||||
perf: {
|
||||
description: '🚀 提升性能的代码更改',
|
||||
title: '🚀 性能优化',
|
||||
},
|
||||
test: {
|
||||
description: '🔧 添加一些缺失的测试或者修正已存在的测试',
|
||||
title: '🔧 测试',
|
||||
},
|
||||
ci: {
|
||||
description: '📦 持续集成的配置文件和脚本的改变(例如: Travis, Circle)',
|
||||
title: '📦 持续集成',
|
||||
},
|
||||
revert: {
|
||||
description: '⏪ 撤销上一次的提交',
|
||||
title: '⏪ 撤销',
|
||||
},
|
||||
wip: {
|
||||
description: '🔒 删除某些文件',
|
||||
title: '🔒 删除',
|
||||
},
|
||||
},
|
||||
scopes: {
|
||||
global: {
|
||||
description: '影响整个项目',
|
||||
title: 'global',
|
||||
},
|
||||
ui: {
|
||||
description: 'UI 界面',
|
||||
title: 'ui',
|
||||
},
|
||||
data: {
|
||||
description: '数据变化',
|
||||
title: 'data',
|
||||
},
|
||||
component: {
|
||||
description: '影响公共组件使用',
|
||||
title: 'component',
|
||||
},
|
||||
build: {
|
||||
description: '影响构建',
|
||||
title: 'build',
|
||||
},
|
||||
unknown: {
|
||||
description: '不知道影响范围',
|
||||
title: 'unknown',
|
||||
},
|
||||
},
|
||||
});
|
||||
module.exports = exports.default;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
'*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
|
||||
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
|
||||
'package.json': ['prettier --write'],
|
||||
'*.vue': ['eslint --fix', 'stylelint --fix', 'prettier --write', 'git add .'],
|
||||
'*.{scss,less,styl,css,html}': ['stylelint --fix', 'prettier --write', 'git add .'],
|
||||
'*.md': ['prettier --write'],
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
module.exports = {
|
||||
printWidth: 100,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: true,
|
||||
vueIndentScriptAndStyle: true,
|
||||
singleQuote: true,
|
||||
quoteProps: 'as-needed',
|
||||
bracketSpacing: true,
|
||||
trailingComma: 'es5',
|
||||
jsxBracketSameLine: false,
|
||||
jsxSingleQuote: false,
|
||||
arrowParens: 'always',
|
||||
insertPragma: false,
|
||||
requirePragma: false,
|
||||
proseWrap: 'never',
|
||||
htmlWhitespaceSensitivity: 'strict',
|
||||
endOfLine: 'lf',
|
||||
rangeStart: 0,
|
||||
overrides: [
|
||||
{
|
||||
files: '*.md',
|
||||
options: {
|
||||
tabWidth: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
plugins: ['stylelint-order'],
|
||||
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
|
||||
rules: {
|
||||
'selector-pseudo-class-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignorePseudoClasses: ['global'],
|
||||
},
|
||||
],
|
||||
'at-rule-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignoreAtRules: ['function', 'if', 'each', 'include', 'mixin'],
|
||||
},
|
||||
],
|
||||
'no-empty-source': null,
|
||||
'unicode-bom': 'never',
|
||||
'no-descending-specificity': null,
|
||||
'font-family-no-missing-generic-family-keyword': null,
|
||||
'declaration-colon-space-after': 'always-single-line',
|
||||
'declaration-colon-space-before': 'never',
|
||||
'declaration-block-trailing-semicolon': 'always',
|
||||
'rule-empty-line-before': [
|
||||
'always',
|
||||
{
|
||||
ignore: ['after-comment', 'first-nested'],
|
||||
},
|
||||
],
|
||||
// 指定声明块内属性的字母顺序
|
||||
'order/properties-order': [
|
||||
'position',
|
||||
'top',
|
||||
'right',
|
||||
'bottom',
|
||||
'left',
|
||||
'z-index',
|
||||
'display',
|
||||
'float',
|
||||
'width',
|
||||
'height',
|
||||
'max-width',
|
||||
'max-height',
|
||||
'min-width',
|
||||
'min-height',
|
||||
'padding',
|
||||
'padding-top',
|
||||
'padding-right',
|
||||
'padding-bottom',
|
||||
'padding-left',
|
||||
'margin',
|
||||
'margin-top',
|
||||
'margin-right',
|
||||
'margin-bottom',
|
||||
'margin-left',
|
||||
'margin-collapse',
|
||||
'margin-top-collapse',
|
||||
'margin-right-collapse',
|
||||
'margin-bottom-collapse',
|
||||
'margin-left-collapse',
|
||||
'overflow',
|
||||
'overflow-x',
|
||||
'overflow-y',
|
||||
'clip',
|
||||
'clear',
|
||||
'font',
|
||||
'font-family',
|
||||
'font-size',
|
||||
'font-smoothing',
|
||||
'osx-font-smoothing',
|
||||
'font-style',
|
||||
'font-weight',
|
||||
'hyphens',
|
||||
'src',
|
||||
'line-height',
|
||||
'letter-spacing',
|
||||
'word-spacing',
|
||||
'color',
|
||||
'text-align',
|
||||
'text-decoration',
|
||||
'text-indent',
|
||||
'text-overflow',
|
||||
'text-rendering',
|
||||
'text-size-adjust',
|
||||
'text-shadow',
|
||||
'text-transform',
|
||||
'word-break',
|
||||
'word-wrap',
|
||||
'white-space',
|
||||
'vertical-align',
|
||||
'list-style',
|
||||
'list-style-type',
|
||||
'list-style-position',
|
||||
'list-style-image',
|
||||
'pointer-events',
|
||||
'cursor',
|
||||
'background',
|
||||
'background-attachment',
|
||||
'background-color',
|
||||
'background-image',
|
||||
'background-position',
|
||||
'background-repeat',
|
||||
'background-size',
|
||||
'border',
|
||||
'border-collapse',
|
||||
'border-top',
|
||||
'border-right',
|
||||
'border-bottom',
|
||||
'border-left',
|
||||
'border-color',
|
||||
'border-image',
|
||||
'border-top-color',
|
||||
'border-right-color',
|
||||
'border-bottom-color',
|
||||
'border-left-color',
|
||||
'border-spacing',
|
||||
'border-style',
|
||||
'border-top-style',
|
||||
'border-right-style',
|
||||
'border-bottom-style',
|
||||
'border-left-style',
|
||||
'border-width',
|
||||
'border-top-width',
|
||||
'border-right-width',
|
||||
'border-bottom-width',
|
||||
'border-left-width',
|
||||
'border-radius',
|
||||
'border-top-right-radius',
|
||||
'border-bottom-right-radius',
|
||||
'border-bottom-left-radius',
|
||||
'border-top-left-radius',
|
||||
'border-radius-topright',
|
||||
'border-radius-bottomright',
|
||||
'border-radius-bottomleft',
|
||||
'border-radius-topleft',
|
||||
'content',
|
||||
'quotes',
|
||||
'outline',
|
||||
'outline-offset',
|
||||
'opacity',
|
||||
'filter',
|
||||
'visibility',
|
||||
'size',
|
||||
'zoom',
|
||||
'transform',
|
||||
'box-align',
|
||||
'box-flex',
|
||||
'box-orient',
|
||||
'box-pack',
|
||||
'box-shadow',
|
||||
'box-sizing',
|
||||
'table-layout',
|
||||
'animation',
|
||||
'animation-delay',
|
||||
'animation-duration',
|
||||
'animation-iteration-count',
|
||||
'animation-name',
|
||||
'animation-play-state',
|
||||
'animation-timing-function',
|
||||
'animation-fill-mode',
|
||||
'transition',
|
||||
'transition-delay',
|
||||
'transition-duration',
|
||||
'transition-property',
|
||||
'transition-timing-function',
|
||||
'background-clip',
|
||||
'backface-visibility',
|
||||
'resize',
|
||||
'appearance',
|
||||
'user-select',
|
||||
'interpolation-mode',
|
||||
'direction',
|
||||
'marks',
|
||||
'page',
|
||||
'set-link-source',
|
||||
'unicode-bidi',
|
||||
'speak',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
const resolve = require('../../build/getCwdPath');
|
||||
|
||||
const baseAlias = {
|
||||
examples: 'examples',
|
||||
config: 'config',
|
||||
'#': 'src/types',
|
||||
'@': 'src',
|
||||
'@ant-design/icons/lib/dist$': 'src/assets/icons/setupIcon.ts',
|
||||
'@design': 'src/design/index.less',
|
||||
};
|
||||
|
||||
function configAlias(config) {
|
||||
// 单页应用
|
||||
Object.keys(baseAlias).forEach((key) => {
|
||||
config.resolve.alias.set(key, resolve(baseAlias[key]));
|
||||
});
|
||||
}
|
||||
module.exports = {
|
||||
configAlias,
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
const webpack = require('webpack');
|
||||
const pkg = require('../../package.json');
|
||||
const { isProductionFn } = require('../../build/utils');
|
||||
|
||||
function createBannerPlugin(config) {
|
||||
// bannerPlugin
|
||||
|
||||
config.when(isProductionFn(), (config) => {
|
||||
config
|
||||
.plugin('banner')
|
||||
.use(webpack.BannerPlugin, [
|
||||
{
|
||||
banner:
|
||||
`Build by ${pkg.author || 'vben'} ,Version:${process.env.VUE_APP_VERSION} ` +
|
||||
new Date().toLocaleDateString(),
|
||||
},
|
||||
])
|
||||
.end();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createBannerPlugin,
|
||||
};
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
const { modifyVars } = require('../glob/lessModifyVars');
|
||||
const { isProductionFn } = require('../../build/utils');
|
||||
|
||||
function createCss(isProd) {
|
||||
return {
|
||||
requireModuleExtension: true,
|
||||
extract: isProd ? { ignoreOrder: true } : false,
|
||||
sourceMap: false,
|
||||
loaderOptions: {
|
||||
css: {
|
||||
modules: {
|
||||
// https://github.com/webpack/loader-utils#interpolatename
|
||||
localIdentName: isProductionFn()
|
||||
? '[contenthash:5]'
|
||||
: '[folder]__[name]_[local]-[emoji]$',
|
||||
},
|
||||
},
|
||||
less: {
|
||||
lessOptions: {
|
||||
modifyVars: modifyVars,
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createCss,
|
||||
};
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
const path = require('path');
|
||||
const { getEnvFn } = require('../../build/utils');
|
||||
const mockMiddleware = require('../../build/middleware/mockMiddleware.js');
|
||||
|
||||
const ENV = getEnvFn();
|
||||
|
||||
let proxyList = ENV.VUE_APP_PROXY || [];
|
||||
|
||||
function createProxy() {
|
||||
const proxyResult = {};
|
||||
try {
|
||||
proxyList = JSON.parse(proxyList);
|
||||
if (!Array.isArray(proxyList) || proxyList.length <= 0) {
|
||||
return {};
|
||||
}
|
||||
for (const [key, target] of proxyList) {
|
||||
proxyResult[key] = {
|
||||
target: target,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
pathRewrite: {
|
||||
['^' + key]: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
proxy: proxyResult,
|
||||
};
|
||||
} catch (error) {}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
function createDevServer() {
|
||||
const { VUE_APP_USE_MOCK } = ENV;
|
||||
|
||||
return {
|
||||
disableHostCheck: true,
|
||||
open: false,
|
||||
host: '0.0.0.0',
|
||||
port: ENV.VUE_APP_PORT,
|
||||
https: false,
|
||||
hotOnly: true,
|
||||
clientLogLevel: 'warn',
|
||||
overlay: {
|
||||
warnings: true,
|
||||
errors: true,
|
||||
},
|
||||
before: (app) => {
|
||||
VUE_APP_USE_MOCK === 'TRUE' && app.use(mockMiddleware());
|
||||
},
|
||||
historyApiFallback: {
|
||||
rewrites: [
|
||||
{
|
||||
from: /.*/,
|
||||
to: path.posix.join('/', 'index.html'),
|
||||
},
|
||||
],
|
||||
},
|
||||
...createProxy(),
|
||||
};
|
||||
}
|
||||
module.exports = {
|
||||
createDevServer,
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
const { configPolyfill } = require('./polyfill');
|
||||
|
||||
const { getEnvFn } = require('../../build/utils');
|
||||
|
||||
function configEntry(config) {
|
||||
const entry = ['./src/main.ts'];
|
||||
config.entry = configPolyfill(entry);
|
||||
|
||||
const { VUE_APP_USE_MOCK } = getEnvFn();
|
||||
// use mock
|
||||
if (VUE_APP_USE_MOCK === 'TRUE') {
|
||||
config.entry.unshift('./mock/_util/mock.config.js');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
configEntry,
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
function configEnv() {
|
||||
// version
|
||||
process.env.VUE_APP_VERSION = require('../../package.json').version;
|
||||
// build time
|
||||
process.env.VUE_APP_BUILD_TIME = require('moment')().format('YYYY-M-D HH:mm:ss');
|
||||
}
|
||||
module.exports = configEnv;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
const resolve = require('../../build/getCwdPath');
|
||||
const { getEnvFn } = require('../../build/utils');
|
||||
|
||||
const ENV = getEnvFn();
|
||||
function getPublicPath() {
|
||||
return ENV.VUE_APP_PUBLIC_PATH;
|
||||
}
|
||||
function getAssetsPath(dir) {
|
||||
return resolve(ENV.VUE_APP_ASSETS_DIR + dir);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPublicPath,
|
||||
getAssetsPath,
|
||||
};
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
const { isProductionFn, isDevFn, getEnvFn } = require('../../build/utils');
|
||||
const { getPublicPath } = require('./getPath');
|
||||
const HtmlWebpackHardDiskPlugin = require('html-webpack-harddisk-plugin');
|
||||
|
||||
// Write html to disk, which is good for hmr
|
||||
function createHardDiskPlugin(config) {
|
||||
config.plugin('hard-disk').after('html').use(HtmlWebpackHardDiskPlugin).end();
|
||||
}
|
||||
/**
|
||||
* @description: 通用配置
|
||||
*/
|
||||
function getMergeCommonOptions(filename = '') {
|
||||
const isDev = isDevFn();
|
||||
const ENV = getEnvFn();
|
||||
// Sort the chunks in the order in which they were introduced. Without this, the JS introduced into the html may be sorted out of order
|
||||
const chunksSortMode = 'none';
|
||||
// const chunksSortMode = 'manual';
|
||||
const title = ENV.GLOB_APP_TITLE || 'APP';
|
||||
const minify = {
|
||||
html5: true,
|
||||
ignoreCustomComments: [/^!/], // 保留的注释
|
||||
sortClassName: true, // class排序
|
||||
sortAttributes: true, // 属性排序
|
||||
processConditionalComments: true, // 处理条件注释(IE)
|
||||
removeStyleLinkTypeAttributes: true, // 去 link type="text/css"
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
removeComments: true, // 移除注释
|
||||
collapseWhitespace: true, // 去多余空格
|
||||
removeAttributeQuotes: true, // 去属性括号
|
||||
collapseBooleanAttributes: true, // Boolean属性简写
|
||||
removeScriptTypeAttributes: true, // 去script type属性
|
||||
minifyJS: { output: { comments: /^!/ } }, // 压缩script标签里的js
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
};
|
||||
|
||||
const addToHead = isDev
|
||||
? ''
|
||||
: `<script src='${getPublicPath()}window-glob.js?v=${
|
||||
ENV.VUE_APP_VERSION
|
||||
}-${new Date().getTime()}'></script>`;
|
||||
return { addToHead, chunksSortMode, title, minify, inject: true };
|
||||
}
|
||||
function configHtml(config) {
|
||||
config.when(isDevFn(), (config) => {
|
||||
config.plugin('html').tap((args) => {
|
||||
args[0].alwaysWriteToDisk = true;
|
||||
return args;
|
||||
});
|
||||
createHardDiskPlugin(config);
|
||||
});
|
||||
config.when(isProductionFn(), (config) => {
|
||||
config.plugin('html').tap((args) => {
|
||||
const { addToHead, chunksSortMode, title, minify, inject } = getMergeCommonOptions();
|
||||
args[0].addToHead = addToHead;
|
||||
// args[0].chunksSortMode = chunksSortMode;
|
||||
args[0].title = title;
|
||||
args[0].minify = minify;
|
||||
return args;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
configHtml,
|
||||
getMergeCommonOptions,
|
||||
};
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
require('./env')();
|
||||
const { isProductionFn, getEnvFn } = require('../../build/utils');
|
||||
|
||||
const { createDevServer } = require('./devServer');
|
||||
const { configAlias } = require('./alias');
|
||||
const { createCss } = require('./css');
|
||||
const { configSourceMap } = require('./sourceMap');
|
||||
const { createBannerPlugin } = require('./banner');
|
||||
const { configPerformance } = require('./performance');
|
||||
const { configOptimization } = require('./optimization');
|
||||
const { configHtml } = require('./html');
|
||||
const { getPublicPath } = require('./getPath');
|
||||
const { configEntry } = require('./entry');
|
||||
|
||||
const { configVueLoader } = require('./loader/vue-loader');
|
||||
const { createSvgLoader } = require('./loader/svg-loader');
|
||||
const { createImageLoader } = require('./loader/image-webpack');
|
||||
const { createWorkerLoader } = require('./loader/worker-loader');
|
||||
|
||||
const { createGzip } = require('./plugins/gzip');
|
||||
const { createHardSourcePlugin } = require('./plugins/hardSource');
|
||||
const { configIgnorePlugin } = require('./plugins/ignore');
|
||||
const { createReport } = require('./plugins/report');
|
||||
const { configClean } = require('./plugins/clean');
|
||||
const { createWebpackBar } = require('./plugins/processBar');
|
||||
const { createStyleLintPlugin } = require('./plugins/stylelint');
|
||||
const { configDefinePlugin } = require('./plugins/define');
|
||||
const { createSkeletonPlugin } = require('./plugins/skeleton');
|
||||
const { createThemeColorReplacerPlugin } = require('./plugins/theme');
|
||||
const isProd = isProductionFn();
|
||||
const ENV = getEnvFn();
|
||||
|
||||
function createVueConfig() {
|
||||
return {
|
||||
publicPath: getPublicPath(),
|
||||
lintOnSave: !isProd,
|
||||
assetsDir: ENV.VUE_APP_ASSETS_DIR,
|
||||
productionSourceMap: false,
|
||||
devServer: createDevServer(),
|
||||
pluginOptions: {
|
||||
lintStyleOnBuild: true,
|
||||
stylelint: {},
|
||||
},
|
||||
css: createCss(isProd),
|
||||
configureWebpack: (config) => {
|
||||
config.resolve.extensions = ['.js', '.jsx', '.tsx', '.ts'];
|
||||
configEntry(config);
|
||||
},
|
||||
chainWebpack: (config) => {
|
||||
config.name = ENV.GLOB_APP_SHORT_NAME;
|
||||
|
||||
configIgnorePlugin(config);
|
||||
// alias
|
||||
configAlias(config);
|
||||
// sourceMap设置
|
||||
configSourceMap(config);
|
||||
// Performance
|
||||
configPerformance(config);
|
||||
// Optimization
|
||||
configOptimization(config);
|
||||
// env
|
||||
configDefinePlugin(config);
|
||||
// html config
|
||||
configHtml(config);
|
||||
// vue-loader config
|
||||
configVueLoader(config);
|
||||
// icon
|
||||
createSvgLoader(config);
|
||||
// web-worker
|
||||
createWorkerLoader(config);
|
||||
// banner
|
||||
createBannerPlugin(config);
|
||||
// build report
|
||||
createReport(config);
|
||||
// cache
|
||||
createHardSourcePlugin(config);
|
||||
// clean build dist
|
||||
configClean(config);
|
||||
|
||||
// build process bar
|
||||
createWebpackBar(config);
|
||||
// Picture compression
|
||||
// createImageLoader(config);
|
||||
// stlyelint
|
||||
createStyleLintPlugin(config);
|
||||
// gzip
|
||||
createGzip(config);
|
||||
// Skeleton screen
|
||||
createSkeletonPlugin(config);
|
||||
createThemeColorReplacerPlugin(config);
|
||||
},
|
||||
};
|
||||
}
|
||||
module.exports = {
|
||||
createVueConfig,
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
const { isProductionFn } = require('../../../build/utils');
|
||||
|
||||
// Turn on image compression
|
||||
function createImageLoader(config) {
|
||||
config.when(isProductionFn(), (config) => {
|
||||
config.module
|
||||
.rule('images')
|
||||
.use('image-webpack-loader')
|
||||
.loader('image-webpack-loader')
|
||||
.options({
|
||||
bypassOnDebug: true,
|
||||
})
|
||||
.end();
|
||||
});
|
||||
}
|
||||
module.exports = {
|
||||
createImageLoader,
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
const resolve = require('../../../build/getCwdPath');
|
||||
|
||||
const createSvgLoader = (config) => {
|
||||
config.module.rule('svg').exclude.add(resolve('src/assets/icons/svg/')).end();
|
||||
config.module
|
||||
.rule('svg-sprite-loader')
|
||||
.test(/\.svg(\?[a-z0-9=\.]+)?$/)
|
||||
.include.add(resolve('src/assets/icons/svg/'))
|
||||
.end()
|
||||
.use('svg-sprite-loader')
|
||||
.loader('svg-sprite-loader')
|
||||
.options({
|
||||
symbolId: 'icon-[name]',
|
||||
})
|
||||
.end();
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createSvgLoader,
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const configVueLoader = (config) => {
|
||||
config.module
|
||||
.rule('vue')
|
||||
.use('vue-loader')
|
||||
.loader('vue-loader')
|
||||
.tap((options) =>
|
||||
merge(options, {
|
||||
compilerOptions: {
|
||||
preserveWhitespace: true,
|
||||
},
|
||||
})
|
||||
)
|
||||
.end();
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
configVueLoader,
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
const { getPublicPath } = require('../getPath');
|
||||
const { getEnvFn } = require('../../../build/utils');
|
||||
const resolve = require('../../../build/getCwdPath');
|
||||
|
||||
function createWorkerLoader(config) {
|
||||
config.module
|
||||
.rule('web-workers')
|
||||
.merge(config.module.rule('ts').toConfig())
|
||||
.test(/(?:\.worker|[\\/]workers[\\/]\w+)\.[tj]s$/)
|
||||
.include.add(resolve('src'))
|
||||
.end()
|
||||
.use('worker-loader')
|
||||
.loader('worker-loader')
|
||||
.options({
|
||||
name: getEnvFn().VUE_APP_ASSETS_DIR + '/js/[name].[hash:3].worker.js',
|
||||
fallback: true,
|
||||
publicPath: getPublicPath(),
|
||||
})
|
||||
.after('0');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createWorkerLoader,
|
||||
};
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
// const { isProductionFn, isDevFn } = require('../../build/utils');
|
||||
// const resolve = require('../../build/getCwdPath');
|
||||
// const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
|
||||
// function createScriptExtPlugin(config) {
|
||||
// config
|
||||
// .plugin('ext-script')
|
||||
// .after('html')
|
||||
// .use(ScriptExtHtmlWebpackPlugin, [
|
||||
// {
|
||||
// inline: /\_r.*\.js$/,
|
||||
// // defer: /\.js$/,
|
||||
// },
|
||||
// ])
|
||||
// .end();
|
||||
// }
|
||||
|
||||
function configOptimization(config) {
|
||||
// config.when(isProductionFn(), (config) => {
|
||||
// createScriptExtPlugin(config);
|
||||
|
||||
config.optimization.runtimeChunk({
|
||||
name: (entry) => `_r-${entry.name}`,
|
||||
});
|
||||
// config.optimization.runtimeChunk('single');
|
||||
config.optimization.splitChunks({
|
||||
chunks: 'all',
|
||||
maxAsyncRequests: 6, //分割后,按需加载的代码块最多允许的并行请求数,在webpack5里默认值变为6
|
||||
maxInitialRequests: 4, //分割后,入口代码块最多允许的并行请求数,在webpack5里默认值变为4
|
||||
// maxInitialRequests: Infinity,
|
||||
automaticNameMaxLength: 15, // 分割chunk自动命名最大长度
|
||||
automaticNameDelimiter: '.', // 分割chunk自动命名分隔符
|
||||
minSize: 30000, // 大小超过30kb的模块才会被提取
|
||||
maxSize: 0, // 只是提示,可以被违反,会尽量将chunk分的比maxSize小,当设为0代表能分则分,分不了不会强制
|
||||
minChunks: 1, //某个模块至少被多少代码块引用,才会被提取成新的chunk
|
||||
name: true, //每个缓存组打包得到的代码块的名称
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
// light: {
|
||||
// name: 'theme-light',
|
||||
// test: (m, c) => {
|
||||
// return (
|
||||
// m.constructor.name === 'CssModule' &&
|
||||
// new RegExp('-light.less|theme=light').test(m._identifier)
|
||||
// );
|
||||
// },
|
||||
// chunks: 'all',
|
||||
// enforce: true,
|
||||
// priority: 40,
|
||||
// },
|
||||
// dark: {
|
||||
// name: 'theme-dark',
|
||||
// test: (m, c) => {
|
||||
// return (
|
||||
// m.constructor.name === 'CssModule' &&
|
||||
// new RegExp('-dark.less|theme=dark').test(m._identifier)
|
||||
// );
|
||||
// },
|
||||
// chunks: 'all',
|
||||
// enforce: true,
|
||||
// priority: 40,
|
||||
// },
|
||||
styles: {
|
||||
name: 'styles',
|
||||
test: /\.(css|scss|sass|less|styl)$/,
|
||||
chunks: 'async',
|
||||
// enforce: true,
|
||||
priority: 30,
|
||||
},
|
||||
vendor: {
|
||||
priority: 10,
|
||||
reuseExistingChunk: true,
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name(module) {
|
||||
const match = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)(.*?)([\\/]|$)/);
|
||||
let packageName = match[1];
|
||||
// if (match[1] === '@xxx') {
|
||||
// packageName += `-${match[3]}`;
|
||||
// }
|
||||
if (
|
||||
packageName.indexOf('axios') !== -1 ||
|
||||
packageName.indexOf('babel') !== -1 ||
|
||||
packageName.indexOf('crypto-js') !== -1 ||
|
||||
packageName.indexOf('moment') !== -1 ||
|
||||
packageName.indexOf('lodash') !== -1 ||
|
||||
packageName.indexOf('mutationobserver') !== -1 ||
|
||||
packageName.indexOf('resize-observer-polyfill') !== -1 ||
|
||||
packageName.indexOf('vue') !== -1 ||
|
||||
packageName.indexOf('dom-align') !== -1 ||
|
||||
packageName.indexOf('async-validator') !== -1 ||
|
||||
packageName.indexOf('tinycolor2') !== -1 ||
|
||||
packageName.indexOf('asn1') !== -1 ||
|
||||
packageName.indexOf('readable-stream') !== -1 ||
|
||||
packageName.indexOf('browserify-sign') !== -1 ||
|
||||
packageName.indexOf('bn') !== -1 ||
|
||||
packageName.indexOf('buffer') !== -1 ||
|
||||
packageName.indexOf('elliptic') !== -1 ||
|
||||
packageName.indexOf('regenerator-runtime') !== -1 ||
|
||||
packageName.indexOf('core-js') !== -1
|
||||
) {
|
||||
packageName = 'entry-lib';
|
||||
} else if (packageName.indexOf('ant-design') !== -1) {
|
||||
packageName = 'design';
|
||||
} else {
|
||||
packageName = 'vendor';
|
||||
}
|
||||
// const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
|
||||
return `${packageName.replace('@', '')}.chunk`;
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
configOptimization,
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// const webpack = require('webpack');
|
||||
const { isProductionFn, isDevFn } = require('../../build/utils');
|
||||
module.exports = {
|
||||
configPerformance(config) {
|
||||
config.optimization.minimize(isProductionFn());
|
||||
config.cache(true);
|
||||
config.resolve.symlinks(true);
|
||||
config.performance.hints(false);
|
||||
config.module.noParse(/^(vue|vue-router|vuex|lodash|moment|vuex-router-sync|normalize.css)$/);
|
||||
|
||||
config.when(isProductionFn(), (config) => {
|
||||
config.merge({ recordsPath: require('path').resolve('build/.cache/~records') });
|
||||
config.plugins.delete('prefetch').delete('preload');
|
||||
});
|
||||
|
||||
config.when(isDevFn(), (config) => {
|
||||
config.watchOptions({ ignored: /node_modules/ });
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
|
||||
const { isProductionFn } = require('../../../build/utils');
|
||||
function configClean(config) {
|
||||
config.when(isProductionFn(), (config) => {
|
||||
let noCleanDir = ['**/*', '!window-glob.js'];
|
||||
config.plugin('clean').use(CleanWebpackPlugin, [
|
||||
{
|
||||
cleanOnceBeforeBuildPatterns: noCleanDir, // Do not delete files in the dll directory
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
configClean,
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const configDefinePlugin = (config) => {
|
||||
config.plugin('define').tap((args) => {
|
||||
// Incorporate dynamic configuration into process.env
|
||||
const name = 'process.env';
|
||||
const ENV = process.env;
|
||||
const conf = {};
|
||||
Object.keys(ENV).forEach((key) => {
|
||||
if (/^(GLOB_)/.test(key)) {
|
||||
conf[key] = JSON.stringify(ENV[key]);
|
||||
}
|
||||
});
|
||||
args[0][name] = merge(args[0][name], conf);
|
||||
return args;
|
||||
});
|
||||
};
|
||||
module.exports = {
|
||||
configDefinePlugin,
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const { isProductionFn } = require('../../../build/utils');
|
||||
const { gzip: zopGzip } = require('@gfx/zopfli');
|
||||
const CompressionWebpackPlugin = require('compression-webpack-plugin');
|
||||
|
||||
const productionGzipExtensions = /\.(js|css|svg|woff|ttf|json|html)(\?.*)?$/i;
|
||||
|
||||
function createGzip(config) {
|
||||
config.when(isProductionFn() && process.env.BUILD_ON_GZIP === 'TRUE', (config) => {
|
||||
config.plugin('compression').use(CompressionWebpackPlugin, [
|
||||
{
|
||||
cache: true,
|
||||
exclude: /.+\.html$/,
|
||||
algorithm(input, compressionOptions, callback) {
|
||||
return zopGzip(input, compressionOptions, callback);
|
||||
},
|
||||
compressionOptions: {
|
||||
numiterations: 15,
|
||||
},
|
||||
threshold: 5120,
|
||||
minRatio: 0.7,
|
||||
test: productionGzipExtensions,
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createGzip,
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
const { isDevFn, getEnvFn } = require('../../../build/utils');
|
||||
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
|
||||
|
||||
const notCache = getEnvFn().VUE_APP_USE_CACHE !== 'TRUE';
|
||||
|
||||
function createHardSourcePlugin(config) {
|
||||
if (notCache || isDevFn()) {
|
||||
return;
|
||||
}
|
||||
config.plugin('hard-source').use(HardSourceWebpackPlugin);
|
||||
const tests = isDevFn()
|
||||
? [{ test: /[\\/]src[\\/]/ }]
|
||||
: [
|
||||
{ test: /[\\/]mini-css-extract-plugin[\\/]dist[\\/]loader/ },
|
||||
{ test: /[\\/]file-loader[\\/]/ },
|
||||
{ test: /[\\/]url-loader[\\/]/ },
|
||||
];
|
||||
config.plugin('hard-source-exclude').use(HardSourceWebpackPlugin.ExcludeModulePlugin, tests);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createHardSourcePlugin,
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
const webpack = require('webpack');
|
||||
const { isProductionFn } = require('../../../build/utils');
|
||||
|
||||
module.exports = {
|
||||
configIgnorePlugin(config) {
|
||||
config.when(isProductionFn(), (config) => {
|
||||
config.plugin('ignore').use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
const Webpackbar = require('webpackbar');
|
||||
const { isProductionFn } = require('../../../build/utils');
|
||||
|
||||
function createWebpackBar(config) {
|
||||
config.when(isProductionFn(), (config) => {
|
||||
config.plugin('bar').use(Webpackbar, [
|
||||
{
|
||||
name: 'TOOLKIT',
|
||||
color: 'blue',
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
module.exports = {
|
||||
createWebpackBar,
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer');
|
||||
function createReport(config) {
|
||||
config.when(process.env.REPORT, (config) => {
|
||||
config.plugin('webpack-bundle-analyzer').use(BundleAnalyzerPlugin.BundleAnalyzerPlugin, [
|
||||
{
|
||||
analyzerPort: 8888,
|
||||
generateStatsFile: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
module.exports = {
|
||||
createReport,
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin');
|
||||
const { isProductionFn } = require('../../../build/utils');
|
||||
const resolve = require('../../../build/getCwdPath');
|
||||
|
||||
function createSkeletonPlugin(config) {
|
||||
config.when(isProductionFn(), (config) => {
|
||||
const main = resolve('src/setup/skeleton/index.js');
|
||||
config.plugin('skeleton').use(SkeletonWebpackPlugin, [
|
||||
{
|
||||
webpackConfig: {
|
||||
entry: {
|
||||
main: main,
|
||||
},
|
||||
},
|
||||
minimize: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
module.exports = {
|
||||
createSkeletonPlugin,
|
||||
};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
const StyleLintPlugin = require('stylelint-webpack-plugin');
|
||||
|
||||
const { isDevFn } = require('../../../build/utils');
|
||||
|
||||
function createStyleLintPlugin(config) {
|
||||
config.when(isDevFn(), (config) => {
|
||||
config.plugin('stylelint').use(StyleLintPlugin, [
|
||||
{
|
||||
fix: true,
|
||||
cache: true,
|
||||
lintDirtyModulesOnly: true,
|
||||
files: ['**/*.vue', '**/*.less', , '**/*.scss', '**/*.css'],
|
||||
cacheLocation: 'node_modules/.cache/stylelint/',
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createStyleLintPlugin,
|
||||
};
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
const ThemeColorReplacer = require('webpack-theme-color-replacer');
|
||||
const generate = require('@ant-design/colors/lib/generate').default;
|
||||
const { primaryColor } = require('../../glob/lessModifyVars.js');
|
||||
|
||||
const getAntdSerials = (color) => {
|
||||
const lightens = new Array(9).fill().map((t, i) => {
|
||||
return ThemeColorReplacer.varyColor.lighten(color, i / 10);
|
||||
});
|
||||
const colorPalettes = generate(color);
|
||||
return lightens.concat(colorPalettes);
|
||||
};
|
||||
|
||||
const themePluginOption = {
|
||||
fileName: 'css/theme-colors-[contenthash:8].css',
|
||||
matchColors: getAntdSerials(primaryColor),
|
||||
changeSelector(selector, util) {
|
||||
switch (selector) {
|
||||
case '.ant-calendar-today .ant-calendar-date':
|
||||
return ':not(.ant-calendar-selected-date):not(.ant-calendar-selected-day)' + selector;
|
||||
case '.ant-btn:focus,.ant-btn:hover':
|
||||
return '.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger)';
|
||||
case '.ant-btn.active,.ant-btn:active':
|
||||
return '.ant-btn.active:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:active:not(.ant-btn-primary):not(.ant-btn-danger)';
|
||||
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
|
||||
return ':not(.ant-steps-item-process)' + selector;
|
||||
case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
|
||||
case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
|
||||
return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover';
|
||||
case '.ant-menu-horizontal > .ant-menu-item-selected > a':
|
||||
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item-selected > a';
|
||||
case '.ant-menu-horizontal > .ant-menu-item > a:hover':
|
||||
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item > a:hover';
|
||||
case 'a:hover':
|
||||
return 'body .ant-menu-item > a:hover';
|
||||
default:
|
||||
return util.changeEach(selector, '', 'body ');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const createThemeColorReplacerPlugin = (config) => {
|
||||
config.plugin('theme-color-replace').use(ThemeColorReplacer, [themePluginOption]);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createThemeColorReplacerPlugin,
|
||||
};
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* 兼容ie 10 11
|
||||
*/
|
||||
const { supportIeFn } = require('../../build/utils');
|
||||
|
||||
function configPolyfill(entry) {
|
||||
if (supportIeFn()) {
|
||||
entry.unshift(...['core-js/stable', 'regenerator-runtime/runtime']);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
module.exports = { configPolyfill };
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
const { isProductionFn } = require('../../build/utils');
|
||||
module.exports = {
|
||||
configSourceMap(config) {
|
||||
config.devtool(isProductionFn() ? false : 'cheap-eval-source-map');
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
|
||||
moduleNameMapper: {
|
||||
'^config/(.*)$': '<rootDir>/src/config/$1',
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('./config/lint/lint-staged');
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* @param {string} url
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function param2Obj(url) {
|
||||
const search = url.split('?')[1];
|
||||
if (!search) {
|
||||
return {};
|
||||
}
|
||||
return JSON.parse(
|
||||
'{"' +
|
||||
decodeURIComponent(search)
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/&/g, '","')
|
||||
.replace(/=/g, '":"')
|
||||
.replace(/\+/g, ' ') +
|
||||
'"}'
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import Mock from 'mockjs';
|
||||
import { param2Obj } from './index';
|
||||
|
||||
const mockApiMethods = require.context('../', true, /^[^\_]*\.js$/);
|
||||
let modules = {};
|
||||
mockApiMethods.keys().forEach((key) => {
|
||||
if (key) {
|
||||
const mods = mockApiMethods(key);
|
||||
key = key.replace(/^\.\//, '').replace(/\.js$/, '');
|
||||
Object.keys(mods).forEach((mod) => {
|
||||
modules = { ...modules, ...mods[mod] };
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function getModuleInfo(mockModules) {
|
||||
const moduleInfo = [];
|
||||
Object.keys(mockModules).forEach((key) => {
|
||||
const handle = mockModules[key];
|
||||
const { path, method, timeout } = parseKey(key);
|
||||
moduleInfo.push({ handle, path, method, timeout });
|
||||
});
|
||||
return moduleInfo;
|
||||
}
|
||||
function parseKey(key) {
|
||||
const len = key.length - key.replace(/\s/g, '').length;
|
||||
let method = 'get';
|
||||
let path = key;
|
||||
let timeout = 0;
|
||||
if (len > 0) {
|
||||
const splitEd = key.split(' ');
|
||||
method = splitEd[0].toLowerCase();
|
||||
path = splitEd[1];
|
||||
if (len === 2) {
|
||||
timeout = splitEd[2];
|
||||
}
|
||||
}
|
||||
return {
|
||||
method,
|
||||
path,
|
||||
timeout,
|
||||
};
|
||||
}
|
||||
function XHR2ExpressReqWrap(handle, timeout = 0) {
|
||||
return function (options) {
|
||||
let result = null;
|
||||
if (handle instanceof Function) {
|
||||
const { body, type, url } = options;
|
||||
result = handle({
|
||||
method: type,
|
||||
body: JSON.parse(body),
|
||||
query: param2Obj(url),
|
||||
});
|
||||
} else {
|
||||
result = handle;
|
||||
}
|
||||
|
||||
return Mock.mock(result);
|
||||
};
|
||||
}
|
||||
function mockXHR() {
|
||||
const mockMethods = getModuleInfo(modules);
|
||||
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send;
|
||||
Mock.XHR.prototype.send = function () {
|
||||
if (this.custom.xhr) {
|
||||
this.custom.xhr.withCredentials = this.withCredentials || false;
|
||||
|
||||
if (this.responseType) {
|
||||
this.custom.xhr.responseType = this.responseType;
|
||||
}
|
||||
}
|
||||
this.proxy_send(...arguments);
|
||||
};
|
||||
|
||||
for (const { path, method, handle, timeout } of mockMethods) {
|
||||
setupMock(timeout);
|
||||
Mock.mock(new RegExp(path), method || 'get', XHR2ExpressReqWrap(handle, timeout));
|
||||
}
|
||||
}
|
||||
function setupMock(timeout = 0) {
|
||||
if (timeout) {
|
||||
Mock.setup({
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
}
|
||||
mockXHR();
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
export default class ResultUtil {
|
||||
static success(result, { message = 'ok' } = {}) {
|
||||
return {
|
||||
code: 0,
|
||||
result,
|
||||
message,
|
||||
type: 'success',
|
||||
};
|
||||
}
|
||||
static pageSuccess(items, total, { message = 'ok' } = {}) {
|
||||
return {
|
||||
code: 0,
|
||||
result: {
|
||||
items,
|
||||
total,
|
||||
},
|
||||
message,
|
||||
type: 'success',
|
||||
};
|
||||
}
|
||||
static error(message = 'Request failed', { code = -1, result = null } = {}) {
|
||||
return {
|
||||
code,
|
||||
result,
|
||||
message,
|
||||
type: 'error',
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @description: 分页
|
||||
*/
|
||||
static pagination(pageNo, pageSize, array) {
|
||||
let offset = (pageNo - 1) * pageSize;
|
||||
return offset + pageSize >= array.length
|
||||
? array.slice(offset, array.length)
|
||||
: array.slice(offset, offset + pageSize);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
import ResultUtil from '../_util/resultUtil';
|
||||
|
||||
const fakeUserList = [
|
||||
{
|
||||
userId: '2',
|
||||
username: 'admin',
|
||||
realName: '管理员',
|
||||
desc: 'vben admin 管理员',
|
||||
password: '123456',
|
||||
token: 'fakeToken1',
|
||||
},
|
||||
{
|
||||
userId: '1',
|
||||
username: 'vben',
|
||||
password: '123456',
|
||||
realName: '测试用户',
|
||||
desc: 'vben admin 测试员',
|
||||
token: 'fakeToken2',
|
||||
},
|
||||
];
|
||||
const fakeRoles = [
|
||||
{
|
||||
// 只是模拟
|
||||
userId: '1',
|
||||
roleName: '普通用户',
|
||||
value: 'normal',
|
||||
},
|
||||
{
|
||||
userId: '2',
|
||||
roleName: '管理员',
|
||||
value: 'admin',
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
'POST /login 300': ({ body }) => {
|
||||
const { username, password } = body;
|
||||
|
||||
const checkUser = fakeUserList.find(
|
||||
(item) => item.username === username && password === item.password
|
||||
);
|
||||
if (!checkUser) {
|
||||
return ResultUtil.error('Incorrect account or password(vben/123456,test1/123456)!');
|
||||
}
|
||||
const { userId, username: _username, token, realName, desc } = checkUser;
|
||||
const roles = fakeRoles.filter((item) => item.userId === userId);
|
||||
return ResultUtil.success({
|
||||
roles,
|
||||
userId,
|
||||
username: _username,
|
||||
token,
|
||||
realName,
|
||||
desc,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
{
|
||||
"name": "vben-admin",
|
||||
"version": "1.0.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"bootstrap": "yarn && cd ./mock && yarn --registry https://registry.npm.taobao.org && cd ../",
|
||||
"serve": "node ./build/task/serve",
|
||||
"build": "node ./build/task/build",
|
||||
"build:no-cache": "npm run clean:cache && npm run build",
|
||||
"report": "cross-env REPORT=true npm run build ",
|
||||
"log": "node ./build/task/log",
|
||||
"preview": "node ./build/task/preview",
|
||||
"reinstall": "npx rimraf node_modules && yarn run bootstrap",
|
||||
"clean:cache": "npx rimraf node_modules/.cache/",
|
||||
"clean:lib": "npx rimraf node_modules",
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"lint": "cross-env --max_old_space_size=4096 vue-cli-service lint --mode=production --fix",
|
||||
"lint:eslint": "cross-env --max_old_space_size=4096 eslint --fix --ext \"src/**/*.{vue,less,css,scss}\"",
|
||||
"lint:stylelint": "cross-env --max_old_space_size=4096 stylelint --fix \"**/*.{vue,less,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||
"lint:prettier": "cross-env --max_old_space_size=4096 prettier --write --loglevel warn \"src/**/*.{js,json,css,less,scss,vue,html,md}\"",
|
||||
"preinstall": "node ./build/npm-hook/preinstall.js",
|
||||
"postinstall": "node ./build/npm-hook/postinstall.js && npm run clean:cache"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/composition-api": "^1.0.0-beta.2",
|
||||
"ant-design-vue": "^1.6.3",
|
||||
"axios": "^0.19.2",
|
||||
"core-js": "^3.6.5",
|
||||
"crypto-js": "^3.3.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.3.4",
|
||||
"vuex": "^3.4.0",
|
||||
"vuex-module-decorators": "^0.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/register": "^7.10.4",
|
||||
"@commitlint/cli": "^9.0.1",
|
||||
"@commitlint/config-conventional": "^9.0.1",
|
||||
"@gfx/zopfli": "^1.0.14",
|
||||
"@typescript-eslint/eslint-plugin": "^3.6.0",
|
||||
"@typescript-eslint/parser": "^3.6.0",
|
||||
"@vue/babel-plugin-transform-vue-jsx": "^1.1.2",
|
||||
"@vue/cli-plugin-babel": "~4.4.6",
|
||||
"@vue/cli-plugin-eslint": "~4.4.6",
|
||||
"@vue/cli-plugin-router": "~4.4.6",
|
||||
"@vue/cli-plugin-typescript": "~4.4.6",
|
||||
"@vue/cli-plugin-unit-jest": "~4.4.6",
|
||||
"@vue/cli-plugin-vuex": "~4.4.6",
|
||||
"@vue/cli-service": "~4.4.6",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"@vue/eslint-config-typescript": "^5.0.2",
|
||||
"@vue/test-utils": "^1.0.3",
|
||||
"babel-plugin-captains-log": "^1.2.0",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||
"babel-preset-vca-jsx": "^0.3.5",
|
||||
"cache-loader": "^4.1.0",
|
||||
"chalk": "^4.1.0",
|
||||
"chokidar": "^3.4.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"commitizen": "^4.1.2",
|
||||
"compressing": "^1.5.1",
|
||||
"compression-webpack-plugin": "^4.0.0",
|
||||
"conventional-changelog-cli": "^2.0.34",
|
||||
"copy-webpack-plugin": "^6.0.2",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-loader": "^3.6.0",
|
||||
"eslint": "^7.4.0",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-import": "^2.21.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"file-loader": "^6.0.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob": "^7.1.6",
|
||||
"hard-source-webpack-plugin": "^0.13.1",
|
||||
"html-webpack-harddisk-plugin": "^1.0.1",
|
||||
"html-webpack-plugin": "4.3.0",
|
||||
"husky": "^4.2.5",
|
||||
"inquirer": "^7.3.0",
|
||||
"koa": "^2.12.1",
|
||||
"koa-static": "^5.0.0",
|
||||
"less": "^3.11.3",
|
||||
"less-loader": "^6.2.0",
|
||||
"less-plugin-functions": "^1.0.0",
|
||||
"lint-staged": "^10.2.10",
|
||||
"markdownlint-cli": "^0.23.1",
|
||||
"postcss-flexbugs-fixes": "^4.2.1",
|
||||
"prettier": "^2.0.5",
|
||||
"rimraf": "^3.0.2",
|
||||
"runjs": "^4.4.2",
|
||||
"script-ext-html-webpack-plugin": "^2.1.4",
|
||||
"shelljs": "^0.8.4",
|
||||
"style-loader": "^1.2.1",
|
||||
"stylelint": "^13.6.0",
|
||||
"stylelint-config-prettier": "^8.0.1",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"stylelint-order": "^4.1.0",
|
||||
"stylelint-webpack-plugin": "^2.0.0",
|
||||
"svg-sprite-loader": "^5.0.0",
|
||||
"terser-webpack-plugin": "^3.0.4",
|
||||
"thread-loader": "^2.1.3",
|
||||
"typescript": "^3.9.5",
|
||||
"vue-skeleton-webpack-plugin": "^1.2.2",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vue-tsx-support": "^2.3.3",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-bundle-analyzer": "^3.8.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-merge": "^5.0.7",
|
||||
"webpack-theme-color-replacer": "^1.3.13",
|
||||
"webpackbar": "^4.0.0",
|
||||
"worker-loader": "^2.0.0",
|
||||
"yargs": "^15.4.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged",
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./config/lint/cz/index.js"
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
module.exports = {
|
||||
plugins: [
|
||||
require('postcss-flexbugs-fixes')({
|
||||
remove: false,
|
||||
}),
|
||||
require('autoprefixer')({
|
||||
remove: false,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('./config/lint/prettier');
|
||||
|
After Width: | Height: | Size: 894 B |
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no" />
|
||||
|
||||
<link rel="icon" href="./favicon.ico" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<%= htmlWebpackPlugin.options.addToHead %>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import http from '@/utils/http/axios';
|
||||
import { LoginParams, LoginResultModel } from './model/LoginModel';
|
||||
|
||||
enum Api {
|
||||
Login = '/login',
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 用户登陆
|
||||
*/
|
||||
export function loginApi(params: LoginParams) {
|
||||
return http.request<LoginResultModel>(
|
||||
{
|
||||
url: Api.Login,
|
||||
method: 'POST',
|
||||
params,
|
||||
},
|
||||
{
|
||||
// 登陆接口不加 /v1.0
|
||||
joinPrefix: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @description: 登陆接口参数
|
||||
*/
|
||||
export interface LoginParams {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 登陆接口返回值
|
||||
*/
|
||||
export interface LoginResultModel {
|
||||
// 角色值数组
|
||||
roles: { roleName: string; value: string }[];
|
||||
// 用户id
|
||||
userId: string | number;
|
||||
// 用户名
|
||||
username: string;
|
||||
// token
|
||||
token: string;
|
||||
// 真实名字
|
||||
realName: string;
|
||||
// 介绍
|
||||
desc?: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg viewBox="0 0 200 200" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<style type="text/css">
|
||||
.left-linear {
|
||||
fill: url(#left-linear);
|
||||
}
|
||||
|
||||
.right-linear {
|
||||
fill: url(#right-linear);
|
||||
}
|
||||
|
||||
.top {
|
||||
fill: #1c6cc7;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
fill: #9dbfe4;
|
||||
}
|
||||
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tip {
|
||||
display: block;
|
||||
min-width: 100px;
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
<circle cx="97" cy="97" r="81" stroke-width="16" stroke="#4d83c6" fill="none"></circle>
|
||||
<g class="load">
|
||||
<!--右半圆环-->
|
||||
<linearGradient id="left-linear" gradientUnits="userSpaceOnUse" x1="50" y1="0" x2="100" y2="180">
|
||||
<stop offset="0" style="stop-color: #1c6cc7;" />
|
||||
<stop offset="1" style="stop-color: #9DBFE4;" />
|
||||
</linearGradient>
|
||||
<path class="left-linear" d="M20,100c0-44.1,35.9-80,80-80V0C44.8,0,0,44.8,0,100s44.8,100,100,100v-20C55.9,180,20,144.1,20,100z" />
|
||||
<!--左半圆环-->
|
||||
<circle class="bottom" cx="100" cy="190" r="10" />
|
||||
<linearGradient id="right-linear" gradientUnits="userSpaceOnUse" x1="100" y1="120" x2="100" y2="180">
|
||||
<stop offset="0" style="stop-color: transparent;" />
|
||||
<stop offset="1" style="stop-color: transparent;" />
|
||||
</linearGradient>
|
||||
<path class="right-linear" d="M100,0v20c44.1,0,80,35.9,80,80c0,44.1-35.9,80-80,80v20c55.2,0,100-44.8,100-100S155.2,0,100,0z" />
|
||||
<!--左半圆环-->
|
||||
<circle class="top" cx="100" cy="10" r="10" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1,67 @@
|
|||
// export what you need
|
||||
export { default as SmileOutline } from '@ant-design/icons/lib/outline/SmileOutline';
|
||||
export { default as MehOutline } from '@ant-design/icons/lib/outline/MehOutline';
|
||||
|
||||
// upload
|
||||
export { default as ZoomInOutline } from '@ant-design/icons/lib/outline/ZoomInOutline';
|
||||
export { default as SettingOutline } from '@ant-design/icons/lib/outline/SettingOutline';
|
||||
|
||||
// 复制
|
||||
export { default as CopyOutline } from '@ant-design/icons/lib/outline/CopyOutline';
|
||||
|
||||
// 锁定
|
||||
export { default as LockOutline } from '@ant-design/icons/lib/outline/LockOutline';
|
||||
// 解锁
|
||||
export { default as UnlockOutline } from '@ant-design/icons/lib/outline/UnlockOutline';
|
||||
|
||||
// 全屏
|
||||
export { default as FullscreenOutline } from '@ant-design/icons/lib/outline/FullscreenOutline';
|
||||
// 退出全屏
|
||||
export { default as FullscreenExitOutline } from '@ant-design/icons/lib/outline/FullscreenExitOutline';
|
||||
// 刷新
|
||||
export { default as ReloadOutline } from '@ant-design/icons/lib/outline/ReloadOutline';
|
||||
// 关闭其他
|
||||
export { default as PicCenterOutline } from '@ant-design/icons/lib/outline/PicCenterOutline';
|
||||
// 关闭左侧
|
||||
export { default as PicLeftOutline } from '@ant-design/icons/lib/outline/PicLeftOutline';
|
||||
// 关闭右侧
|
||||
export { default as PicRightOutline } from '@ant-design/icons/lib/outline/PicRightOutline';
|
||||
// 关闭全部
|
||||
export { default as LineOutline } from '@ant-design/icons/lib/outline/LineOutline';
|
||||
|
||||
// 以下为ant-design需要的图标,请勿删除;额外引入的图标,添加在上方,并备注用途
|
||||
// export what antd other components need
|
||||
export { default as CloseOutline } from '@ant-design/icons/lib/outline/CloseOutline';
|
||||
export { default as CheckOutline } from '@ant-design/icons/lib/outline/CheckOutline';
|
||||
export { default as LoadingOutline } from '@ant-design/icons/lib/outline/LoadingOutline';
|
||||
export { default as CheckCircleOutline } from '@ant-design/icons/lib/outline/CheckCircleOutline';
|
||||
export { default as InfoCircleOutline } from '@ant-design/icons/lib/outline/InfoCircleOutline';
|
||||
export { default as QuestionCircleOutline } from '@ant-design/icons/lib/outline/QuestionCircleOutline';
|
||||
export { default as CloseCircleOutline } from '@ant-design/icons/lib/outline/CloseCircleOutline';
|
||||
export { default as ExclamationCircleOutline } from '@ant-design/icons/lib/outline/ExclamationCircleOutline';
|
||||
export { default as CheckCircleFill } from '@ant-design/icons/lib/fill/CheckCircleFill';
|
||||
export { default as InfoCircleFill } from '@ant-design/icons/lib/fill/InfoCircleFill';
|
||||
export { default as CloseCircleFill } from '@ant-design/icons/lib/fill/CloseCircleFill';
|
||||
export { default as ExclamationCircleFill } from '@ant-design/icons/lib/fill/ExclamationCircleFill';
|
||||
export { default as UpOutline } from '@ant-design/icons/lib/outline/UpOutline';
|
||||
export { default as DownOutline } from '@ant-design/icons/lib/outline/DownOutline';
|
||||
export { default as LeftOutline } from '@ant-design/icons/lib/outline/LeftOutline';
|
||||
export { default as DoubleLeftOutline } from '@ant-design/icons/lib/outline/DoubleLeftOutline';
|
||||
export { default as RightOutline } from '@ant-design/icons/lib/outline/RightOutline';
|
||||
export { default as DoubleRightOutline } from '@ant-design/icons/lib/outline/DoubleRightOutline';
|
||||
export { default as RedoOutline } from '@ant-design/icons/lib/outline/RedoOutline';
|
||||
export { default as CalendarOutline } from '@ant-design/icons/lib/outline/CalendarOutline';
|
||||
export { default as SearchOutline } from '@ant-design/icons/lib/outline/SearchOutline';
|
||||
export { default as BarsOutline } from '@ant-design/icons/lib/outline/BarsOutline';
|
||||
export { default as StarFill } from '@ant-design/icons/lib/fill/StarFill';
|
||||
export { default as FilterOutline } from '@ant-design/icons/lib/outline/FilterOutline';
|
||||
export { default as CaretUpOutline } from '@ant-design/icons/lib/outline/CaretUpOutline';
|
||||
export { default as CaretDownOutline } from '@ant-design/icons/lib/outline/CaretDownOutline';
|
||||
export { default as PlusOutline } from '@ant-design/icons/lib/outline/PlusOutline';
|
||||
export { default as FileOutline } from '@ant-design/icons/lib/outline/FileOutline';
|
||||
export { default as FolderOpenOutline } from '@ant-design/icons/lib/outline/FolderOpenOutline';
|
||||
export { default as FolderOutline } from '@ant-design/icons/lib/outline/FolderOutline';
|
||||
export { default as PaperClipOutline } from '@ant-design/icons/lib/outline/PaperClipOutline';
|
||||
export { default as PictureOutline } from '@ant-design/icons/lib/outline/PictureOutline';
|
||||
export { default as EyeOutline } from '@ant-design/icons/lib/outline/EyeOutline';
|
||||
export { default as DeleteOutline } from '@ant-design/icons/lib/outline/DeleteOutline';
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* 引入svgicon图片
|
||||
*/
|
||||
|
||||
export default (): void => {
|
||||
const requireAll = (requireContext) => {
|
||||
requireContext.keys().map(requireContext);
|
||||
};
|
||||
const req = require.context('./svg', true, /\.svg$/);
|
||||
requireAll(req);
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
# 关于图标存放请按模块命名文件夹,公共图标放 common 文件夹,大于 20k 以上的 svg 请压缩或者单独引入,不要放于该文件夹
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1589522763496" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2137" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M937.173333 984.32a6.997333 6.997333 0 0 1-4.224-1.365333l-128.853333-94.933334-129.706667 94.762667a7.125333 7.125333 0 0 1-7.381333 0.597333 7.082667 7.082667 0 0 1-3.84-6.314666v-191.488a7.082667 7.082667 0 0 1 9.258667-6.698667l45.824 15.146667c2.986667 0.853333 5.205333 3.584 5.205333 6.826666v71.338667l76.629333-55.978667a7.082667 7.082667 0 0 1 8.362667 0l75.434667 55.637334v-71.04c0-2.986667 1.92-5.674667 4.778666-6.656l46.165334-15.957334a7.04 7.04 0 0 1 9.386666 6.656v192.426667a7.082667 7.082667 0 0 1-7.04 7.04z m-802.432-33.024A109.226667 109.226667 0 0 1 25.6 842.154667V147.968A109.269333 109.269333 0 0 1 134.741333 38.741333h605.568a109.269333 109.269333 0 0 1 109.184 109.141334v216.576a7.082667 7.082667 0 0 1-7.082666 7.082666H797.44a7.082667 7.082667 0 0 1-7.082667-7.082666V147.968c0-27.605333-22.442667-50.048-50.005333-50.048H134.741333c-27.562667 0-50.005333 22.442667-50.005333 50.048v694.186667c0 27.562667 22.442667 50.005333 50.005333 50.005333H605.013333c3.882667 0 7.04 3.157333 7.04 7.082667v44.970666a7.082667 7.082667 0 0 1-7.04 7.082667H134.741333z m668.928-150.613333a203.605333 203.605333 0 0 1-203.392-203.392 203.605333 203.605333 0 0 1 203.392-203.349334 203.605333 203.605333 0 0 1 203.392 203.349334 203.605333 203.605333 0 0 1-203.392 203.392z m0-346.453334A143.232 143.232 0 0 0 660.608 597.333333a143.232 143.232 0 0 0 143.061333 143.061334A143.232 143.232 0 0 0 946.730667 597.333333a143.232 143.232 0 0 0-143.061334-143.018666z m-610.133333 306.645334a7.082667 7.082667 0 0 1-7.082667-7.082667v-49.194667c0-3.925333 3.2-7.082667 7.082667-7.082666h356.096c3.925333 0 7.082667 3.157333 7.082667 7.082666v49.194667a7.082667 7.082667 0 0 1-7.082667 7.082667H193.536z m610.133333-75.648a88.021333 88.021333 0 0 1-87.893333-87.893334c0-48.512 39.424-87.936 87.893333-87.936 48.469333 0 87.893333 39.424 87.893334 87.893334 0 48.469333-39.424 87.893333-87.893334 87.893333z m0-138.581334c-27.904 0-50.645333 22.698667-50.645333 50.645334a50.773333 50.773333 0 0 0 50.688 50.688 50.730667 50.730667 0 0 0 0-101.333334z m-610.133333 57.728a7.082667 7.082667 0 0 1-7.082667-7.082666v-49.237334c0-3.882667 3.2-7.04 7.082667-7.04h356.096c3.925333 0 7.082667 3.157333 7.082667 7.04V597.333333a7.082667 7.082667 0 0 1-7.082667 7.082667H193.536z m0-155.306666a7.082667 7.082667 0 0 1-7.082667-7.04V392.832c0-3.925333 3.2-7.082667 7.082667-7.082667h356.096c3.925333 0 7.082667 3.157333 7.082667 7.082667v49.194667a7.082667 7.082667 0 0 1-7.082667 7.082666H193.536z m0-156.501334a7.082667 7.082667 0 0 1-7.082667-7.04V236.288c0-3.882667 3.2-7.04 7.082667-7.04h488.021333c3.925333 0 7.082667 3.157333 7.082667 7.04v49.237333a7.082667 7.082667 0 0 1-7.082667 7.04H193.536z" p-id="2138" fill="#45657F"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1555985440062" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1939" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M940.032 102.4H83.968C37.888 102.4 0 140.288 0 186.88v650.752c0 46.592 37.888 83.968 83.968 83.968h855.552c46.592 0 83.968-37.888 83.968-83.968V186.88c0.512-46.592-37.376-84.48-83.456-84.48z m-322.56 145.408c46.592 0 84.48 37.888 84.48 84.48s-37.888 84.48-84.48 84.48-84.48-37.888-84.48-84.48 37.888-84.48 84.48-84.48zM83.968 809.472s69.12-402.432 229.376-402.432c157.184 0 197.12 281.088 307.712 281.088 69.632 0 62.464-126.976 173.056-126.976 79.36 0 130.048 247.808 130.048 247.808l-840.192 0.512z" p-id="1940"></path></svg>
|
||||
|
After Width: | Height: | Size: 913 B |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1589955512947" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2141" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css"></style></defs><path d="M513.442909 1002.914909A488.634182 488.634182 0 0 0 1002.914909 513.396364c0-180.596364-96.162909-337.92-238.917818-422.446546-46.592-26.205091-72.843636 29.137455-32.023273 55.389091a423.563636 423.563636 0 0 1 209.733818 367.057455c0 235.985455-192.232727 428.264727-428.218181 428.264727-235.985455 0-428.311273-192.232727-428.311273-428.218182a423.563636 423.563636 0 0 1 209.780363-367.104c37.841455-26.251636 14.568727-81.594182-32.069818-55.389091C117.201455 175.522909 21.085091 332.846545 21.085091 513.442909c0 270.941091 221.416727 489.472 492.357818 489.472z m0-981.829818c20.386909 0 40.820364 17.501091 40.820364 37.888v550.632727c0 20.386909-20.433455 37.888-40.820364 37.888-23.272727 0-40.773818-17.501091-40.773818-37.888V58.973091c0-20.386909 17.501091-37.888 40.773818-37.888z" p-id="2142" ></path></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1589271287315" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1983" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M203.1 599.3c-48.9 0-88.6-39.6-88.6-88.5s39.6-88.5 88.6-88.5c48.9 0 88.6 39.6 88.6 88.5-0.1 48.9-39.7 88.5-88.6 88.5z m309.9 0c-48.9 0-88.6-39.6-88.6-88.5s39.6-88.5 88.6-88.5c48.9 0 88.6 39.6 88.6 88.5s-39.7 88.5-88.6 88.5z m309.9 0c-48.9 0-88.6-39.6-88.6-88.5s39.6-88.5 88.6-88.5c48.9 0 88.6 39.6 88.6 88.5s-39.6 88.5-88.6 88.5z" p-id="1984" fill="#91939a"></path></svg>
|
||||
|
After Width: | Height: | Size: 746 B |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1589279146592" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1961" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M711.871126 512.00224h182.527201v365.6944h94.463587V1024H39.810066v-146.30336h672.06106V512.00224z m-109.439522 0v365.6944h-182.399202V512.00224H602.431604zM310.400882 512.00224v365.6944H127.873681V512.00224H310.400882zM512 0.00448c3.839983 0 7.743966 0.767997 11.32795 2.36799l4.991979 2.751988 483.453884 346.238485a26.559884 26.559884 0 0 1 9.663958 30.719865 27.903878 27.903878 0 0 1-20.223911 17.983922l-5.759975 0.639997H28.546115a25.919887 25.919887 0 0 1-26.047886-18.687918 26.367885 26.367885 0 0 1 5.311977-26.623884L12.162187 351.362943 495.616072 5.124458A28.031877 28.031877 0 0 1 512 0.00448z" p-id="1962" fill="#0064BF"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg t="1589279096702" class="icon" viewBox="0 0 1102 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1803"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="68.875" height="64">
|
||||
<defs>
|
||||
<style type="text/css"></style>
|
||||
</defs>
|
||||
<path d="M663.236923 652.996923a301.371077 301.371077 0 1 0-221.105231 0c-199.286154 34.816-362.023385 161.949538-431.576615 330.200615H1094.892308c-69.553231-168.251077-232.290462-295.384615-431.576616-330.200615z" p-id="1804" fill="#67C23A"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 649 B |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1589699877718" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2139" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css"></style></defs><path d="M512 0a512 512 0 0 0-512 512 512 512 0 0 0 512 512 512 512 0 0 0 512-512 512 512 0 0 0-512-512z m0 192a31.963429 31.963429 0 1 1 0 63.926857 31.963429 31.963429 0 0 1 0-63.926857z m95.524571 640H416.475429a31.963429 31.963429 0 1 1 0-64h62.025142V445.44h-62.976a31.963429 31.963429 0 1 1 0-63.926857h94.939429c17.700571 0 32.036571 14.262857 32.036571 31.963428V768h65.024c17.700571 0 32.914286 14.336 32.914286 32.036571 0 17.627429-15.213714 31.963429-32.914286 31.963429z" p-id="2140" fill="#F56C6C"></path></svg>
|
||||
|
After Width: | Height: | Size: 891 B |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1587884014415" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2035" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M500.487915 683.510886a340.246081 340.246081 0 0 1-241.344476-99.924901 338.199488 338.199488 0 0 1-73.114534-108.469428 338.455312 338.455312 0 0 1-26.810368-132.875048 340.246081 340.246081 0 0 1 99.924902-241.344476A338.199488 338.199488 0 0 1 367.612866 27.7825 338.455312 338.455312 0 0 1 500.539079 0.972132a340.246081 340.246081 0 0 1 241.344476 99.924901 338.199488 338.199488 0 0 1 73.165699 108.469428c17.805359 42.10865 26.759203 86.775542 26.759203 132.875048a340.246081 340.246081 0 0 1-99.924902 241.344476 340.246081 340.246081 0 0 1-241.344476 99.924901z m0-620.271163a279.308775 279.308775 0 0 0-278.848292 279.001786 279.206446 279.206446 0 0 0 278.848292 278.848292 279.206446 279.206446 0 0 0 278.848291-278.848292 279.308775 279.308775 0 0 0-278.848291-279.001786z" fill="#5B8FC9" p-id="2036"></path><path d="M33.711224 1023.296484a31.210543 31.210543 0 0 1-29.675598-41.136519 522.392855 522.392855 0 0 1 74.495984-143.261508 523.109162 523.109162 0 0 1 113.27892-113.023096 519.322965 519.322965 0 0 1 308.677385-100.692374c111.89747 0 218.627294 34.79208 308.728549 100.692374a525.30925 525.30925 0 0 1 187.72374 256.284604 31.159378 31.159378 0 1 1-59.146537 19.800787 460.585747 460.585747 0 0 0-437.305752-314.35668 460.636912 460.636912 0 0 0-437.254588 314.45901 31.210543 31.210543 0 0 1-29.522103 21.233402z" fill="#5B8FC9" p-id="2037"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588923316927" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2381" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css"></style></defs><path d="M192.350316 202.698105V89.249684c0.053895-17.084632 13.904842-30.935579 31.043368-30.989473H800.121263c17.084632 0 30.935579 13.904842 30.989474 30.989473v113.448421H889.047579v-140.665263C889.047579 27.917474 861.130105 0 827.014737 0H196.500211C162.438737 0 134.521263 27.917474 134.521263 61.978947v140.719158h57.829053z m638.814316 604.752842v123.580632a31.097263 31.097263 0 0 1-30.989474 30.989474H223.393684a31.097263 31.097263 0 0 1-31.043368-30.989474v-123.580632H134.521263v150.797474c0 34.115368 27.917474 62.032842 61.978948 62.032842H827.068632c34.115368 0 61.978947-27.917474 61.978947-61.978947v-150.851369h-57.829053zM269.312 661.611789H210.512842V439.888842A203.506526 203.506526 0 0 1 134.521263 484.513684V431.157895c15.36-5.066105 32.013474-14.551579 50.014316-28.618106 18.000842-14.012632 30.342737-30.396632 37.025684-49.04421h47.750737v308.11621z m328.272842-54.649263v54.649263H391.437474c2.209684-20.641684 8.946526-40.205474 20.102737-58.745263 11.156211-18.485895 33.199158-43.008 66.128842-73.566315 26.516211-24.683789 42.738526-41.498947 48.774736-50.229895 8.084211-12.126316 12.126316-24.144842 12.126316-36.001684 0-13.096421-3.503158-23.174737-10.563368-30.234948-7.060211-7.006316-16.707368-10.563368-29.210948-10.563368-12.234105 0-22.042947 3.664842-29.264842 11.048421-7.275789 7.383579-11.479579 19.671579-12.557473 36.864l-58.637474-5.874526c3.503158-32.336842 14.443789-55.565474 32.875789-69.685895 18.378105-14.066526 41.445053-21.126737 69.039158-21.126737 30.288842 0 54.056421 8.138105 71.410527 24.46821 17.300211 16.330105 25.923368 36.648421 25.923368 60.901053 0.053895 13.473684-2.479158 26.947368-7.437474 39.450947a160.768 160.768 0 0 1-23.552 39.289264c-7.114105 9.054316-19.941053 22.096842-38.480842 39.181473-18.539789 16.976842-30.288842 28.348632-35.247158 33.845895a101.322105 101.322105 0 0 0-12.072421 16.384h116.789895z m87.578947-26.785684l56.966737-6.898526c1.778526 14.551579 6.682947 25.6 14.605474 33.253052a40.205474 40.205474 0 0 0 28.887579 11.533474 39.720421 39.720421 0 0 0 30.666105-13.797053c8.299789-9.216 12.449684-21.665684 12.449684-37.295157 0-14.767158-3.988211-26.516211-11.910736-35.139369a37.995789 37.995789 0 0 0-29.103158-13.042526c-7.545263 0-16.545684 1.509053-27.001263 4.419368l6.467368-47.966316c15.952842 0.431158 28.025263-3.018105 36.432842-10.293894a36.917895 36.917895 0 0 0 12.557474-29.210948 33.522526 33.522526 0 0 0-9.162106-24.737684 33.253053 33.253053 0 0 0-24.522105-9.162105 35.408842 35.408842 0 0 0-25.761684 10.455579c-7.114105 6.952421-11.425684 17.138526-12.934737 30.558316l-54.218105-9.216c3.772632-18.539789 9.431579-33.414737 17.030737-44.517053 7.653053-11.048421 18.216421-19.779368 31.797894-26.138947 13.635368-6.359579 28.887579-9.539368 45.810527-9.539369 28.833684 0 51.954526 9.216 69.470316 27.648 14.336 15.090526 21.557895 32.121263 21.557894 51.092211 0 26.947368-14.767158 48.397474-44.193684 64.458105 17.569684 3.772632 31.636211 12.234105 42.199579 25.330526 10.509474 13.096421 15.791158 28.941474 15.791158 47.481263 0 26.947368-9.862737 49.906526-29.534316 68.877474-19.671579 18.970947-44.139789 28.456421-73.458526 28.456421-27.755789 0-50.768842-7.976421-69.039158-23.929263-18.324211-15.952842-28.887579-36.864-31.797895-62.679579z" p-id="2382" fill="#1B65B9"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1587884026333" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2185" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css"></style></defs><path d="M49.777778 494.250667v479.971555c0 19.626667 15.928889 35.555556 35.555555 35.555556h853.333334c19.626667 0 35.555556-15.928889 35.555555-35.555556V494.193778a35.555556 35.555556 0 0 0-35.555555-35.498667h-853.333334a35.555556 35.555556 0 0 0-35.555555 35.498667z m853.333333 444.416H120.888889V529.749333h782.222222V938.666667z m-36.181333-575.544889A355.555556 355.555556 0 0 0 155.875556 369.208889v124.984889H227.555556V369.777778a284.444444 284.444444 0 0 1 568.888888 0 35.555556 35.555556 0 1 0 70.485334-6.656z" fill="#5B8FC9" p-id="2186"></path></svg>
|
||||
|
After Width: | Height: | Size: 935 B |