Pre Merge pull request !2 from Xydawn/master
commit
d984e6c73b
|
@ -1,5 +0,0 @@
|
||||||
# just a flag
|
|
||||||
ENV = 'development'
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VUE_APP_BASE_API = '/dev-api'
|
|
|
@ -1,6 +0,0 @@
|
||||||
# just a flag
|
|
||||||
ENV = 'production'
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VUE_APP_BASE_API = '/prod-api'
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
NODE_ENV = production
|
|
||||||
|
|
||||||
# just a flag
|
|
||||||
ENV = 'staging'
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VUE_APP_BASE_API = '/stage-api'
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
"vue/singleline-html-element-content-newline": "off",
|
"vue/singleline-html-element-content-newline": "off",
|
||||||
"vue/multiline-html-element-content-newline":"off",
|
"vue/multiline-html-element-content-newline": "off",
|
||||||
"vue/name-property-casing": ["error", "PascalCase"],
|
"vue/name-property-casing": ["error", "PascalCase"],
|
||||||
"vue/no-v-html": "off",
|
"vue/no-v-html": "off",
|
||||||
'accessor-pairs': 2,
|
'accessor-pairs': 2,
|
||||||
|
@ -47,7 +47,7 @@ module.exports = {
|
||||||
'curly': [2, 'multi-line'],
|
'curly': [2, 'multi-line'],
|
||||||
'dot-location': [2, 'property'],
|
'dot-location': [2, 'property'],
|
||||||
'eol-last': 2,
|
'eol-last': 2,
|
||||||
'eqeqeq': ["error", "always", {"null": "ignore"}],
|
'eqeqeq': ["error", "always", { "null": "ignore" }],
|
||||||
'generator-star-spacing': [2, {
|
'generator-star-spacing': [2, {
|
||||||
'before': true,
|
'before': true,
|
||||||
'after': true
|
'after': true
|
||||||
|
|
|
@ -14,3 +14,5 @@ tests/**/coverage/
|
||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
|
.pnpm-debug.log
|
||||||
|
pnpm-lock.yaml
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
const { run } = require('runjs')
|
|
||||||
const chalk = require('chalk')
|
|
||||||
const config = require('../vue.config.js')
|
|
||||||
const rawArgv = process.argv.slice(2)
|
|
||||||
const args = rawArgv.join(' ')
|
|
||||||
|
|
||||||
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
|
|
||||||
const report = rawArgv.includes('--report')
|
|
||||||
|
|
||||||
run(`vue-cli-service build ${args}`)
|
|
||||||
|
|
||||||
const port = 9526
|
|
||||||
const publicPath = config.publicPath
|
|
||||||
|
|
||||||
var connect = require('connect')
|
|
||||||
var serveStatic = require('serve-static')
|
|
||||||
const app = connect()
|
|
||||||
|
|
||||||
app.use(
|
|
||||||
publicPath,
|
|
||||||
serveStatic('./dist', {
|
|
||||||
index: ['index.html', '/']
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
app.listen(port, function () {
|
|
||||||
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
|
|
||||||
if (report) {
|
|
||||||
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
run(`vue-cli-service build ${args}`)
|
|
||||||
}
|
|
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,8 +1,8 @@
|
||||||
const Mock = require('mockjs')
|
import Mock from 'mockjs'
|
||||||
const { param2Obj } = require('./utils')
|
import utils from './utils'
|
||||||
|
|
||||||
const user = require('./user')
|
import user from './user'
|
||||||
const table = require('./table')
|
import table from './table'
|
||||||
|
|
||||||
const mocks = [
|
const mocks = [
|
||||||
...user,
|
...user,
|
||||||
|
@ -36,7 +36,7 @@ function mockXHR() {
|
||||||
result = respond({
|
result = respond({
|
||||||
method: type,
|
method: type,
|
||||||
body: JSON.parse(body),
|
body: JSON.parse(body),
|
||||||
query: param2Obj(url)
|
query: utils.param2Obj(url)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result = respond
|
result = respond
|
||||||
|
@ -50,7 +50,7 @@ function mockXHR() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
mocks,
|
mocks,
|
||||||
mockXHR
|
mockXHR
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ function unregisterRoutes() {
|
||||||
// for mock server
|
// for mock server
|
||||||
const responseFake = (url, type, respond) => {
|
const responseFake = (url, type, respond) => {
|
||||||
return {
|
return {
|
||||||
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
|
url: new RegExp(`${import.meta.env.VUE_APP_BASE_API}${url}`),
|
||||||
type: type || 'get',
|
type: type || 'get',
|
||||||
response(req, res) {
|
response(req, res) {
|
||||||
console.log('request invoke:' + req.path)
|
console.log('request invoke:' + req.path)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const Mock = require('mockjs')
|
import Mock from 'mockjs'
|
||||||
|
|
||||||
const data = Mock.mock({
|
const data = Mock.mock({
|
||||||
'items|30': [{
|
'items|30': [{
|
||||||
|
@ -11,7 +11,7 @@ const data = Mock.mock({
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = [
|
export default [
|
||||||
{
|
{
|
||||||
url: '/vue-admin-template/table/list',
|
url: '/vue-admin-template/table/list',
|
||||||
type: 'get',
|
type: 'get',
|
||||||
|
|
|
@ -23,7 +23,7 @@ const users = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = [
|
export default [
|
||||||
// user login
|
// user login
|
||||||
{
|
{
|
||||||
url: '/vue-admin-template/user/login',
|
url: '/vue-admin-template/user/login',
|
||||||
|
|
|
@ -20,6 +20,6 @@ function param2Obj(url) {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
param2Obj
|
param2Obj
|
||||||
}
|
}
|
||||||
|
|
73
package.json
73
package.json
|
@ -1,54 +1,41 @@
|
||||||
{
|
{
|
||||||
"name": "vue-admin-template",
|
"name": "vue-admin-template",
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
|
"description": "A vue admin template with Element UI & axios & vite & permission control & lint",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vue-cli-service serve",
|
"dev": "vite",
|
||||||
"build:prod": "vue-cli-service build",
|
"build": "vite build",
|
||||||
"build:stage": "vue-cli-service build --mode staging",
|
"preview": "vite preview",
|
||||||
"preview": "node build/index.js --preview",
|
"lint": "eslint --ext .js,.vue src"
|
||||||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
|
|
||||||
"lint": "eslint --ext .js,.vue src",
|
|
||||||
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
|
||||||
"test:ci": "npm run lint && npm run test:unit"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "0.18.1",
|
"axios": "^0.21.1",
|
||||||
"core-js": "3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"element-ui": "2.13.2",
|
"element-ui": "^2.13.2",
|
||||||
"js-cookie": "2.2.0",
|
"js-cookie": "^2.2.0",
|
||||||
"normalize.css": "7.0.0",
|
"normalize.css": "^7.0.0",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"path-to-regexp": "2.4.0",
|
"path-browserify": "^1.0.1",
|
||||||
"vue": "2.6.10",
|
"path-to-regexp": "^2.4.0",
|
||||||
"vue-router": "3.0.6",
|
"vue": "^2.6.10",
|
||||||
"vuex": "3.1.0"
|
"vue-router": "^3.0.6",
|
||||||
|
"vuex": "^3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "4.4.4",
|
"@vue/compiler-sfc": "^3.2.26",
|
||||||
"@vue/cli-plugin-eslint": "4.4.4",
|
"autoprefixer": "^9.5.1",
|
||||||
"@vue/cli-plugin-unit-jest": "4.4.4",
|
"babel-eslint": "^10.1.0",
|
||||||
"@vue/cli-service": "4.4.4",
|
"chalk": "^2.4.2",
|
||||||
"@vue/test-utils": "1.0.0-beta.29",
|
"eslint": "^6.7.2",
|
||||||
"autoprefixer": "9.5.1",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
"babel-eslint": "10.1.0",
|
"mockjs": "^1.0.1-beta3",
|
||||||
"babel-jest": "23.6.0",
|
"runjs": "^4.3.2",
|
||||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
"sass": "^1.26.8",
|
||||||
"chalk": "2.4.2",
|
"serve-static": "^1.13.2",
|
||||||
"connect": "3.6.6",
|
"svg-sprite-loader": "^6.0.11",
|
||||||
"eslint": "6.7.2",
|
"vite": "^2.7.10",
|
||||||
"eslint-plugin-vue": "6.2.2",
|
"vite-plugin-vue2": "^1.9.2",
|
||||||
"html-webpack-plugin": "3.2.0",
|
"vue-template-compiler": "^2.6.10"
|
||||||
"mockjs": "1.0.1-beta3",
|
|
||||||
"runjs": "4.3.2",
|
|
||||||
"sass": "1.26.8",
|
|
||||||
"sass-loader": "8.0.2",
|
|
||||||
"script-ext-html-webpack-plugin": "2.1.3",
|
|
||||||
"serve-static": "1.13.2",
|
|
||||||
"svg-sprite-loader": "4.1.3",
|
|
||||||
"svgo": "1.2.2",
|
|
||||||
"vue-template-compiler": "2.6.10"
|
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<title><%= webpackConfig.name %></title>
|
<title><%= webpackConfig.name %></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import SvgIcon from '@/components/SvgIcon'// svg component
|
import SvgIcon from '@/components/SvgIcon' // svg component
|
||||||
|
|
||||||
// register globally
|
// register globally
|
||||||
Vue.component('svg-icon', SvgIcon)
|
Vue.component('svg-icon', SvgIcon)
|
||||||
|
|
||||||
const req = require.context('./svg', false, /\.svg$/)
|
|
||||||
const requireAll = requireContext => requireContext.keys().map(requireContext)
|
|
||||||
requireAll(req)
|
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
<div class="right-menu">
|
<div class="right-menu">
|
||||||
<el-dropdown class="avatar-container" trigger="click">
|
<el-dropdown class="avatar-container" trigger="click">
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
|
<el-avatar shape="square" size="medium" :src="avatar+'?imageView2/1/w/80/h/80'" />
|
||||||
|
<!-- <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> -->
|
||||||
<i class="el-icon-caret-bottom" />
|
<i class="el-icon-caret-bottom" />
|
||||||
</div>
|
</div>
|
||||||
<el-dropdown-menu slot="dropdown" class="user-dropdown">
|
<el-dropdown-menu slot="dropdown" class="user-dropdown">
|
||||||
|
@ -118,12 +119,12 @@ export default {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.user-avatar {
|
// .user-avatar {
|
||||||
cursor: pointer;
|
// cursor: pointer;
|
||||||
width: 40px;
|
// width: 40px;
|
||||||
height: 40px;
|
// height: 40px;
|
||||||
border-radius: 10px;
|
// border-radius: 10px;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.el-icon-caret-bottom {
|
.el-icon-caret-bottom {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<template v-if="icon.includes('el-icon')">
|
||||||
|
<i :class="[icon, 'sub-el-icon']" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<svg-icon :icon-class="icon" />
|
||||||
|
</template>
|
||||||
|
<template v-if="title">
|
||||||
|
<span slot="title" style="padding-left: 5px;">{{ title }}</span>
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'MenuItem',
|
name: 'MenuItem',
|
||||||
functional: true,
|
|
||||||
props: {
|
props: {
|
||||||
icon: {
|
icon: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -11,24 +23,24 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
|
||||||
render(h, context) {
|
|
||||||
const { icon, title } = context.props
|
|
||||||
const vnodes = []
|
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
if (icon.includes('el-icon')) {
|
|
||||||
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
|
|
||||||
} else {
|
|
||||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (title) {
|
|
||||||
vnodes.push(<span slot='title'>{(title)}</span>)
|
|
||||||
}
|
|
||||||
return vnodes
|
|
||||||
}
|
}
|
||||||
|
/* render(h, context) {
|
||||||
|
const { icon, title } = context.props
|
||||||
|
const vnodes = []
|
||||||
|
|
||||||
|
if (icon) {
|
||||||
|
if (icon.includes('el-icon')) {
|
||||||
|
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
|
||||||
|
} else {
|
||||||
|
vnodes.push(<svg-icon icon-class={icon} />)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
vnodes.push(<span slot='title'>{(title)}</span>)
|
||||||
|
}
|
||||||
|
return vnodes
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import path from 'path'
|
import path from 'path-browserify '
|
||||||
import { isExternal } from '@/utils/validate'
|
import { isExternal } from '@/utils/validate'
|
||||||
import Item from './Item'
|
import Item from './Item'
|
||||||
import AppLink from './Link'
|
import AppLink from './Link'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{'has-logo':showLogo}">
|
<div :class="{ 'has-logo': showLogo }">
|
||||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||||
<el-menu
|
<el-menu
|
||||||
|
@ -12,7 +12,12 @@
|
||||||
:collapse-transition="false"
|
:collapse-transition="false"
|
||||||
mode="vertical"
|
mode="vertical"
|
||||||
>
|
>
|
||||||
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
|
<sidebar-item
|
||||||
|
v-for="route in routes"
|
||||||
|
:key="route.path"
|
||||||
|
:item="route"
|
||||||
|
:base-path="route.path"
|
||||||
|
/>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +27,6 @@
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import Logo from './Logo'
|
import Logo from './Logo'
|
||||||
import SidebarItem from './SidebarItem'
|
import SidebarItem from './SidebarItem'
|
||||||
import variables from '@/styles/variables.scss'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { SidebarItem, Logo },
|
components: { SidebarItem, Logo },
|
||||||
|
@ -46,7 +50,10 @@ export default {
|
||||||
return this.$store.state.settings.sidebarLogo
|
return this.$store.state.settings.sidebarLogo
|
||||||
},
|
},
|
||||||
variables() {
|
variables() {
|
||||||
return variables
|
return {
|
||||||
|
menuBg: '#304156',
|
||||||
|
menuText: 'white'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
isCollapse() {
|
isCollapse() {
|
||||||
return !this.sidebar.opened
|
return !this.sidebar.opened
|
||||||
|
|
|
@ -51,8 +51,8 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "~@/styles/mixin.scss";
|
@import "@/styles/mixin.scss";
|
||||||
@import "~@/styles/variables.scss";
|
@import "@/styles/variables.scss";
|
||||||
|
|
||||||
.app-wrapper {
|
.app-wrapper {
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
|
||||||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
||||||
|
|
||||||
import ElementUI from 'element-ui'
|
import ElementUI from 'element-ui'
|
||||||
import 'element-ui/lib/theme-chalk/index.css'
|
import 'element-ui/lib/theme-chalk/index.css'
|
||||||
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
|
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
|
||||||
|
@ -13,6 +12,7 @@ import store from './store'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
|
||||||
import '@/icons' // icon
|
import '@/icons' // icon
|
||||||
|
import mock from '../mock'
|
||||||
import '@/permission' // permission control
|
import '@/permission' // permission control
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,9 +23,9 @@ import '@/permission' // permission control
|
||||||
* Currently MockJs will be used in the production environment,
|
* Currently MockJs will be used in the production environment,
|
||||||
* please remove it before going online ! ! !
|
* please remove it before going online ! ! !
|
||||||
*/
|
*/
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
const { mockXHR } = require('../mock')
|
if (import.meta.env.MODE !== 'production') {
|
||||||
mockXHR()
|
mock.mockXHR()
|
||||||
}
|
}
|
||||||
|
|
||||||
// set ElementUI lang to EN
|
// set ElementUI lang to EN
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
import { readFileSync, readdirSync } from 'fs'
|
||||||
|
|
||||||
|
let idPerfix = ''
|
||||||
|
const svgTitle = /<svg([^>+].*?)>/
|
||||||
|
const clearHeightWidth = /(width|height)="([^>+].*?)"/g
|
||||||
|
|
||||||
|
const hasViewBox = /(viewBox="[^>+].*?")/g
|
||||||
|
|
||||||
|
const clearReturn = /(\r)|(\n)/g
|
||||||
|
|
||||||
|
function findSvgFile(dir) {
|
||||||
|
const svgRes = []
|
||||||
|
const dirents = readdirSync(dir, {
|
||||||
|
withFileTypes: true
|
||||||
|
})
|
||||||
|
for (const dirent of dirents) {
|
||||||
|
if (dirent.isDirectory()) {
|
||||||
|
svgRes.push(...findSvgFile(dir + dirent.name + '/'))
|
||||||
|
} else {
|
||||||
|
const svg = readFileSync(dir + dirent.name)
|
||||||
|
.toString()
|
||||||
|
.replace(clearReturn, '')
|
||||||
|
.replace(svgTitle, ($1, $2) => {
|
||||||
|
// console.log(++i)
|
||||||
|
// console.log(dirent.name)
|
||||||
|
let width = 0
|
||||||
|
let height = 0
|
||||||
|
let content = $2.replace(
|
||||||
|
clearHeightWidth,
|
||||||
|
(s1, s2, s3) => {
|
||||||
|
if (s2 === 'width') {
|
||||||
|
width = s3
|
||||||
|
} else if (s2 === 'height') {
|
||||||
|
height = s3
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (!hasViewBox.test($2)) {
|
||||||
|
content += `viewBox="0 0 ${width} ${height}"`
|
||||||
|
}
|
||||||
|
return `<symbol id="${idPerfix}-${dirent.name.replace(
|
||||||
|
'.svg',
|
||||||
|
''
|
||||||
|
)}" ${content}>`
|
||||||
|
})
|
||||||
|
.replace('</svg>', '</symbol>')
|
||||||
|
svgRes.push(svg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return svgRes
|
||||||
|
}
|
||||||
|
|
||||||
|
export const svgBuilder = (path, perfix = 'icon') => {
|
||||||
|
if (path === '') return
|
||||||
|
idPerfix = perfix
|
||||||
|
const res = findSvgFile(path)
|
||||||
|
// console.log(res.length)
|
||||||
|
// const res = []
|
||||||
|
return {
|
||||||
|
name: 'svg-transform',
|
||||||
|
transformIndexHtml(html) {
|
||||||
|
return html.replace(
|
||||||
|
'<body>',
|
||||||
|
`
|
||||||
|
<body>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
|
||||||
|
${res.join('')}
|
||||||
|
</svg>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
module.exports = {
|
export default {
|
||||||
|
|
||||||
title: 'Vue Admin Template',
|
title: 'Vue Admin Template',
|
||||||
|
|
||||||
|
@ -12,5 +12,5 @@ module.exports = {
|
||||||
* @type {boolean} true | false
|
* @type {boolean} true | false
|
||||||
* @description Whether show the logo in sidebar
|
* @description Whether show the logo in sidebar
|
||||||
*/
|
*/
|
||||||
sidebarLogo: false
|
sidebarLogo: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#app {
|
#app {
|
||||||
|
|
||||||
.main-container {
|
.main-container {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
transition: margin-left .28s;
|
transition: margin-left 0.28s;
|
||||||
margin-left: $sideBarWidth;
|
margin-left: $sideBarWidth;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +21,8 @@
|
||||||
|
|
||||||
// reset element-ui css
|
// reset element-ui css
|
||||||
.horizontal-collapse-transition {
|
.horizontal-collapse-transition {
|
||||||
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
|
transition: 0s width ease-in-out, 0s padding-left ease-in-out,
|
||||||
|
0s padding-right ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollbar-wrapper {
|
.scrollbar-wrapper {
|
||||||
|
@ -76,11 +76,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-active>.el-submenu__title {
|
.is-active > .el-submenu__title {
|
||||||
color: $subMenuActiveText !important;
|
color: $subMenuActiveText !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .nest-menu .el-submenu>.el-submenu__title,
|
& .nest-menu .el-submenu > .el-submenu__title,
|
||||||
& .el-submenu .el-menu-item {
|
& .el-submenu .el-menu-item {
|
||||||
min-width: $sideBarWidth !important;
|
min-width: $sideBarWidth !important;
|
||||||
background-color: $subMenuBg !important;
|
background-color: $subMenuBg !important;
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
margin-left: 54px;
|
margin-left: 54px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenu-title-noDropdown {
|
& > .submenu-title-noDropdown {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -117,10 +117,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-submenu {
|
& > .el-submenu {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&>.el-submenu__title {
|
& > .el-submenu__title {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
|
@ -137,10 +137,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-menu--collapse {
|
& > .el-menu--collapse {
|
||||||
.el-submenu {
|
.el-submenu {
|
||||||
&>.el-submenu__title {
|
& > .el-submenu__title {
|
||||||
&>span {
|
& > span {
|
||||||
height: 0;
|
height: 0;
|
||||||
width: 0;
|
width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -163,7 +163,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
transition: transform .28s;
|
transition: transform 0.28s;
|
||||||
width: $sideBarWidth !important;
|
width: $sideBarWidth !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +177,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.withoutAnimation {
|
.withoutAnimation {
|
||||||
|
|
||||||
.main-container,
|
.main-container,
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
transition: none;
|
transition: none;
|
||||||
|
@ -187,7 +186,7 @@
|
||||||
|
|
||||||
// when menu collapsed
|
// when menu collapsed
|
||||||
.el-menu--vertical {
|
.el-menu--vertical {
|
||||||
&>.el-menu {
|
& > .el-menu {
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
@ -197,7 +196,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nest-menu .el-submenu>.el-submenu__title,
|
.nest-menu .el-submenu > .el-submenu__title,
|
||||||
.el-menu-item {
|
.el-menu-item {
|
||||||
&:hover {
|
&:hover {
|
||||||
// you can use $subMenuHover
|
// you can use $subMenuHover
|
||||||
|
@ -206,7 +205,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// the scroll bar appears when the subMenu is too long
|
// the scroll bar appears when the subMenu is too long
|
||||||
>.el-menu--popup {
|
> .el-menu--popup {
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { getToken } from '@/utils/auth'
|
||||||
|
|
||||||
// create an axios instance
|
// create an axios instance
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
baseURL: import.meta.env.VUE_APP_BASE_API, // url = base url + request url
|
||||||
// withCredentials: true, // send cookies when cross-domain requests
|
// withCredentials: true, // send cookies when cross-domain requests
|
||||||
timeout: 5000 // request timeout
|
timeout: 5000 // request timeout
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
env: {
|
|
||||||
jest: true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
import { mount, createLocalVue } from '@vue/test-utils'
|
|
||||||
import VueRouter from 'vue-router'
|
|
||||||
import ElementUI from 'element-ui'
|
|
||||||
import Breadcrumb from '@/components/Breadcrumb/index.vue'
|
|
||||||
|
|
||||||
const localVue = createLocalVue()
|
|
||||||
localVue.use(VueRouter)
|
|
||||||
localVue.use(ElementUI)
|
|
||||||
|
|
||||||
const routes = [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'home',
|
|
||||||
children: [{
|
|
||||||
path: 'dashboard',
|
|
||||||
name: 'dashboard'
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/menu',
|
|
||||||
name: 'menu',
|
|
||||||
children: [{
|
|
||||||
path: 'menu1',
|
|
||||||
name: 'menu1',
|
|
||||||
meta: { title: 'menu1' },
|
|
||||||
children: [{
|
|
||||||
path: 'menu1-1',
|
|
||||||
name: 'menu1-1',
|
|
||||||
meta: { title: 'menu1-1' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu1-2',
|
|
||||||
name: 'menu1-2',
|
|
||||||
redirect: 'noredirect',
|
|
||||||
meta: { title: 'menu1-2' },
|
|
||||||
children: [{
|
|
||||||
path: 'menu1-2-1',
|
|
||||||
name: 'menu1-2-1',
|
|
||||||
meta: { title: 'menu1-2-1' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu1-2-2',
|
|
||||||
name: 'menu1-2-2'
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
|
|
||||||
const router = new VueRouter({
|
|
||||||
routes
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('Breadcrumb.vue', () => {
|
|
||||||
const wrapper = mount(Breadcrumb, {
|
|
||||||
localVue,
|
|
||||||
router
|
|
||||||
})
|
|
||||||
it('dashboard', () => {
|
|
||||||
router.push('/dashboard')
|
|
||||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
|
||||||
expect(len).toBe(1)
|
|
||||||
})
|
|
||||||
it('normal route', () => {
|
|
||||||
router.push('/menu/menu1')
|
|
||||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
|
||||||
expect(len).toBe(2)
|
|
||||||
})
|
|
||||||
it('nested route', () => {
|
|
||||||
router.push('/menu/menu1/menu1-2/menu1-2-1')
|
|
||||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
|
||||||
expect(len).toBe(4)
|
|
||||||
})
|
|
||||||
it('no meta.title', () => {
|
|
||||||
router.push('/menu/menu1/menu1-2/menu1-2-2')
|
|
||||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
|
||||||
expect(len).toBe(3)
|
|
||||||
})
|
|
||||||
// it('click link', () => {
|
|
||||||
// router.push('/menu/menu1/menu1-2/menu1-2-2')
|
|
||||||
// const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
|
|
||||||
// const second = breadcrumbArray.at(1)
|
|
||||||
// console.log(breadcrumbArray)
|
|
||||||
// const href = second.find('a').attributes().href
|
|
||||||
// expect(href).toBe('#/menu/menu1')
|
|
||||||
// })
|
|
||||||
// it('noRedirect', () => {
|
|
||||||
// router.push('/menu/menu1/menu1-2/menu1-2-1')
|
|
||||||
// const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
|
|
||||||
// const redirectBreadcrumb = breadcrumbArray.at(2)
|
|
||||||
// expect(redirectBreadcrumb.contains('a')).toBe(false)
|
|
||||||
// })
|
|
||||||
it('last breadcrumb', () => {
|
|
||||||
router.push('/menu/menu1/menu1-2/menu1-2-1')
|
|
||||||
const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
|
|
||||||
const redirectBreadcrumb = breadcrumbArray.at(3)
|
|
||||||
expect(redirectBreadcrumb.contains('a')).toBe(false)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,18 +0,0 @@
|
||||||
import { shallowMount } from '@vue/test-utils'
|
|
||||||
import Hamburger from '@/components/Hamburger/index.vue'
|
|
||||||
describe('Hamburger.vue', () => {
|
|
||||||
it('toggle click', () => {
|
|
||||||
const wrapper = shallowMount(Hamburger)
|
|
||||||
const mockFn = jest.fn()
|
|
||||||
wrapper.vm.$on('toggleClick', mockFn)
|
|
||||||
wrapper.find('.hamburger').trigger('click')
|
|
||||||
expect(mockFn).toBeCalled()
|
|
||||||
})
|
|
||||||
it('prop isActive', () => {
|
|
||||||
const wrapper = shallowMount(Hamburger)
|
|
||||||
wrapper.setProps({ isActive: true })
|
|
||||||
expect(wrapper.contains('.is-active')).toBe(true)
|
|
||||||
wrapper.setProps({ isActive: false })
|
|
||||||
expect(wrapper.contains('.is-active')).toBe(false)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { shallowMount } from '@vue/test-utils'
|
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue'
|
|
||||||
describe('SvgIcon.vue', () => {
|
|
||||||
it('iconClass', () => {
|
|
||||||
const wrapper = shallowMount(SvgIcon, {
|
|
||||||
propsData: {
|
|
||||||
iconClass: 'test'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(wrapper.find('use').attributes().href).toBe('#icon-test')
|
|
||||||
})
|
|
||||||
it('className', () => {
|
|
||||||
const wrapper = shallowMount(SvgIcon, {
|
|
||||||
propsData: {
|
|
||||||
iconClass: 'test'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(wrapper.classes().length).toBe(1)
|
|
||||||
wrapper.setProps({ className: 'test' })
|
|
||||||
expect(wrapper.classes().includes('test')).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,30 +0,0 @@
|
||||||
import { formatTime } from '@/utils/index.js'
|
|
||||||
|
|
||||||
describe('Utils:formatTime', () => {
|
|
||||||
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
|
|
||||||
const retrofit = 5 * 1000
|
|
||||||
|
|
||||||
it('ten digits timestamp', () => {
|
|
||||||
expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
|
|
||||||
})
|
|
||||||
it('test now', () => {
|
|
||||||
expect(formatTime(+new Date() - 1)).toBe('刚刚')
|
|
||||||
})
|
|
||||||
it('less two minute', () => {
|
|
||||||
expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
|
|
||||||
})
|
|
||||||
it('less two hour', () => {
|
|
||||||
expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
|
|
||||||
})
|
|
||||||
it('less one day', () => {
|
|
||||||
expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
|
|
||||||
})
|
|
||||||
it('more than one day', () => {
|
|
||||||
expect(formatTime(d)).toBe('7月13日17时54分')
|
|
||||||
})
|
|
||||||
it('format', () => {
|
|
||||||
expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
|
|
||||||
expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
|
|
||||||
expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { param2Obj } from '@/utils/index.js'
|
|
||||||
describe('Utils:param2Obj', () => {
|
|
||||||
const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'
|
|
||||||
|
|
||||||
it('param2Obj test', () => {
|
|
||||||
expect(param2Obj(url)).toEqual({
|
|
||||||
name: 'bill',
|
|
||||||
age: '29',
|
|
||||||
sex: '1',
|
|
||||||
field: window.btoa('test'),
|
|
||||||
key: '测试'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,35 +0,0 @@
|
||||||
import { parseTime } from '@/utils/index.js'
|
|
||||||
|
|
||||||
describe('Utils:parseTime', () => {
|
|
||||||
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
|
|
||||||
it('timestamp', () => {
|
|
||||||
expect(parseTime(d)).toBe('2018-07-13 17:54:01')
|
|
||||||
})
|
|
||||||
it('timestamp string', () => {
|
|
||||||
expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
|
|
||||||
})
|
|
||||||
it('ten digits timestamp', () => {
|
|
||||||
expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
|
|
||||||
})
|
|
||||||
it('new Date', () => {
|
|
||||||
expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
|
|
||||||
})
|
|
||||||
it('format', () => {
|
|
||||||
expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
|
|
||||||
expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
|
|
||||||
expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
|
|
||||||
})
|
|
||||||
it('get the day of the week', () => {
|
|
||||||
expect(parseTime(d, '{a}')).toBe('五') // 星期五
|
|
||||||
})
|
|
||||||
it('get the day of the week', () => {
|
|
||||||
expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
|
|
||||||
})
|
|
||||||
it('empty argument', () => {
|
|
||||||
expect(parseTime()).toBeNull()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('null', () => {
|
|
||||||
expect(parseTime(null)).toBeNull()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { validUsername, isExternal } from '@/utils/validate.js'
|
|
||||||
|
|
||||||
describe('Utils:validate', () => {
|
|
||||||
it('validUsername', () => {
|
|
||||||
expect(validUsername('admin')).toBe(true)
|
|
||||||
expect(validUsername('editor')).toBe(true)
|
|
||||||
expect(validUsername('xxxx')).toBe(false)
|
|
||||||
})
|
|
||||||
it('isExternal', () => {
|
|
||||||
expect(isExternal('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
|
|
||||||
expect(isExternal('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
|
|
||||||
expect(isExternal('github.com/PanJiaChen/vue-element-admin')).toBe(false)
|
|
||||||
expect(isExternal('/dashboard')).toBe(false)
|
|
||||||
expect(isExternal('./dashboard')).toBe(false)
|
|
||||||
expect(isExternal('dashboard')).toBe(false)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import { createVuePlugin } from 'vite-plugin-vue2'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
import { svgBuilder } from './src/plugins/svgBuilder';
|
||||||
|
// vite.config.js
|
||||||
|
export default defineConfig({
|
||||||
|
esbuild: {
|
||||||
|
jsxFactory: 'h',
|
||||||
|
jsxFragment: 'Fragment'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
svgBuilder('./src/icons/svg/'),
|
||||||
|
createVuePlugin({
|
||||||
|
jsx: true, vueTemplateOptions: { compilerOptions: { whitespace: 'condense' }},
|
||||||
|
jsxOptions: { compositionAPI: true }
|
||||||
|
})
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.vue', '.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
|
||||||
|
alias: {
|
||||||
|
// vue2项目别名一般都是@,vue3中一般使用/@/, 为方便使用
|
||||||
|
'@': resolve('src')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
123
vue.config.js
123
vue.config.js
|
@ -1,123 +0,0 @@
|
||||||
'use strict'
|
|
||||||
const path = require('path')
|
|
||||||
const defaultSettings = require('./src/settings.js')
|
|
||||||
|
|
||||||
function resolve(dir) {
|
|
||||||
return path.join(__dirname, dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = defaultSettings.title || 'vue Admin Template' // page title
|
|
||||||
|
|
||||||
// If your port is set to 80,
|
|
||||||
// use administrator privileges to execute the command line.
|
|
||||||
// For example, Mac: sudo npm run
|
|
||||||
// You can change the port by the following methods:
|
|
||||||
// port = 9528 npm run dev OR npm run dev --port = 9528
|
|
||||||
const port = process.env.port || process.env.npm_config_port || 9528 // dev port
|
|
||||||
|
|
||||||
// All configuration item explanations can be find in https://cli.vuejs.org/config/
|
|
||||||
module.exports = {
|
|
||||||
/**
|
|
||||||
* You will need to set publicPath if you plan to deploy your site under a sub path,
|
|
||||||
* for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
|
|
||||||
* then publicPath should be set to "/bar/".
|
|
||||||
* In most cases please use '/' !!!
|
|
||||||
* Detail: https://cli.vuejs.org/config/#publicpath
|
|
||||||
*/
|
|
||||||
publicPath: '/',
|
|
||||||
outputDir: 'dist',
|
|
||||||
assetsDir: 'static',
|
|
||||||
lintOnSave: process.env.NODE_ENV === 'development',
|
|
||||||
productionSourceMap: false,
|
|
||||||
devServer: {
|
|
||||||
port: port,
|
|
||||||
open: true,
|
|
||||||
overlay: {
|
|
||||||
warnings: false,
|
|
||||||
errors: true
|
|
||||||
},
|
|
||||||
before: require('./mock/mock-server.js')
|
|
||||||
},
|
|
||||||
configureWebpack: {
|
|
||||||
// provide the app's title in webpack's name field, so that
|
|
||||||
// it can be accessed in index.html to inject the correct title.
|
|
||||||
name: name,
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@': resolve('src')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
chainWebpack(config) {
|
|
||||||
// it can improve the speed of the first screen, it is recommended to turn on preload
|
|
||||||
config.plugin('preload').tap(() => [
|
|
||||||
{
|
|
||||||
rel: 'preload',
|
|
||||||
// to ignore runtime.js
|
|
||||||
// https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
|
|
||||||
fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
|
|
||||||
include: 'initial'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
// when there are many pages, it will cause too many meaningless requests
|
|
||||||
config.plugins.delete('prefetch')
|
|
||||||
|
|
||||||
// set svg-sprite-loader
|
|
||||||
config.module
|
|
||||||
.rule('svg')
|
|
||||||
.exclude.add(resolve('src/icons'))
|
|
||||||
.end()
|
|
||||||
config.module
|
|
||||||
.rule('icons')
|
|
||||||
.test(/\.svg$/)
|
|
||||||
.include.add(resolve('src/icons'))
|
|
||||||
.end()
|
|
||||||
.use('svg-sprite-loader')
|
|
||||||
.loader('svg-sprite-loader')
|
|
||||||
.options({
|
|
||||||
symbolId: 'icon-[name]'
|
|
||||||
})
|
|
||||||
.end()
|
|
||||||
|
|
||||||
config
|
|
||||||
.when(process.env.NODE_ENV !== 'development',
|
|
||||||
config => {
|
|
||||||
config
|
|
||||||
.plugin('ScriptExtHtmlWebpackPlugin')
|
|
||||||
.after('html')
|
|
||||||
.use('script-ext-html-webpack-plugin', [{
|
|
||||||
// `runtime` must same as runtimeChunk name. default is `runtime`
|
|
||||||
inline: /runtime\..*\.js$/
|
|
||||||
}])
|
|
||||||
.end()
|
|
||||||
config
|
|
||||||
.optimization.splitChunks({
|
|
||||||
chunks: 'all',
|
|
||||||
cacheGroups: {
|
|
||||||
libs: {
|
|
||||||
name: 'chunk-libs',
|
|
||||||
test: /[\\/]node_modules[\\/]/,
|
|
||||||
priority: 10,
|
|
||||||
chunks: 'initial' // only package third parties that are initially dependent
|
|
||||||
},
|
|
||||||
elementUI: {
|
|
||||||
name: 'chunk-elementUI', // split elementUI into a single package
|
|
||||||
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
|
|
||||||
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
|
|
||||||
},
|
|
||||||
commons: {
|
|
||||||
name: 'chunk-commons',
|
|
||||||
test: resolve('src/components'), // can customize your rules
|
|
||||||
minChunks: 3, // minimum common number
|
|
||||||
priority: 5,
|
|
||||||
reuseExistingChunk: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
|
|
||||||
config.optimization.runtimeChunk('single')
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue