├── .env.development ├── .browserslistrc ├── .env.analyz ├── .env.production ├── src ├── store │ ├── root-state.ts │ ├── mutation-types.ts │ ├── states.ts │ ├── getters.ts │ ├── index.ts │ └── modules │ │ ├── app.ts │ │ └── user.ts ├── utils │ ├── week-util.ts │ └── request.ts ├── hooks │ └── demoState.ts ├── layouts │ ├── BasicLayout.module.less │ └── BasicLayout.tsx ├── core │ └── polyfills.js ├── views │ ├── Test.module.less │ ├── Page2.tsx │ └── Test.tsx ├── default.less ├── App.less ├── router │ ├── router-guards.ts │ └── index.ts ├── App.tsx ├── shims-tsx.d.ts ├── locales │ ├── lang │ │ ├── zh-CN.ts │ │ └── en-US.ts │ └── index.ts ├── main.ts ├── shims-app.d.ts ├── icons.ts └── components │ └── NProgress │ └── nprogress.less ├── public ├── favicon.ico └── index.html ├── jest.config.js ├── .editorconfig ├── Dockerfile ├── docker └── default.conf ├── .gitignore ├── tests └── unit │ └── example.spec.ts ├── babel.config.js ├── tsconfig.json ├── README.md ├── .eslintrc.js ├── package.json ├── .gitlab-ci.yml └── vue.config.js /.env.development: -------------------------------------------------------------------------------- 1 | VUE_APP_API_URL=/api 2 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.env.analyz: -------------------------------------------------------------------------------- 1 | NODE_ENV=production 2 | IS_ANALYZ=true 3 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV=production 2 | VUE_APP_API_URL=/api 3 | -------------------------------------------------------------------------------- /src/store/root-state.ts: -------------------------------------------------------------------------------- 1 | export interface RootState { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const ACCESS_TOKEN = 'access-token' 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendya/vue3-tsx/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel' 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | RUN rm /etc/nginx/conf.d/default.conf 4 | 5 | ADD docker/default.conf /etc/nginx/conf.d/ 6 | COPY dist/ /usr/share/nginx/html/ 7 | -------------------------------------------------------------------------------- /src/store/states.ts: -------------------------------------------------------------------------------- 1 | import { AppState } from './modules/app' 2 | import { UserState } from './modules/user' 3 | 4 | export interface States extends AppState, UserState { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/week-util.ts: -------------------------------------------------------------------------------- 1 | export const weekMapping: any = { 2 | 1: 'mon', 3 | 2: 'tue', 4 | 3: 'wed', 5 | 4: 'thu', 6 | 5: 'fri', 7 | 6: 'sat', 8 | 7: 'sun' 9 | } 10 | -------------------------------------------------------------------------------- /src/hooks/demoState.ts: -------------------------------------------------------------------------------- 1 | import { reactive, ref } from '@vue/composition-api' 2 | 3 | export const demoState = reactive({ 4 | clickNum: ref(0), 5 | name: ref(null) 6 | }) 7 | -------------------------------------------------------------------------------- /src/layouts/BasicLayout.module.less: -------------------------------------------------------------------------------- 1 | .BasicLayout { 2 | background: #fff; 3 | padding: 0; 4 | margin: 0; 5 | } 6 | 7 | .nav { 8 | font-size: 24px; 9 | text-align: center; 10 | margin: 10px; 11 | text-decoration: none; 12 | } -------------------------------------------------------------------------------- /src/core/polyfills.js: -------------------------------------------------------------------------------- 1 | import 'core-js/features/array/from' 2 | import 'core-js/features/array/flat' 3 | import 'core-js/features/array/find' 4 | import 'core-js/features/set' 5 | import 'core-js/features/promise' 6 | import 'core-js/features/object/entries' 7 | 8 | import 'regenerator-runtime/runtime' 9 | -------------------------------------------------------------------------------- /src/views/Test.module.less: -------------------------------------------------------------------------------- 1 | .TestPage { 2 | text-align: center; 3 | 4 | > h1 { 5 | font-size: 3rem; 6 | } 7 | } 8 | 9 | .locale { 10 | text-align: center; 11 | } 12 | 13 | .example { 14 | text-align: center; 15 | &.mgr { 16 | margin: 12px 0; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/store/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex' 2 | import { getters as appGetters } from './modules/app' 3 | import { getters as userGetters } from './modules/user' 4 | import { States } from './states' 5 | 6 | export const getters: GetterTree = { 7 | ...appGetters, 8 | ...userGetters 9 | } 10 | -------------------------------------------------------------------------------- /docker/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name _; 4 | index index.html index.htm; 5 | root /usr/share/nginx/html; 6 | 7 | #charset koi8-r; 8 | #access_log /var/log/nginx/host.access.log main; 9 | 10 | location / { 11 | try_files $uri $uri/ /index.html =404; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | public/cache 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /tests/unit/example.spec.ts: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils' 2 | import Test from '@/views/Test.tsx' 3 | 4 | describe('Test.tsx', () => { 5 | it('renders props.msg when passed', () => { 6 | const msg = 'new message' 7 | const wrapper = shallowMount(Test, { 8 | propsData: { msg } 9 | }) 10 | expect(wrapper.text()).toMatch(msg) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /src/default.less: -------------------------------------------------------------------------------- 1 | @import "~ant-design-vue/lib/style/themes/default"; 2 | 3 | // The prefix to use on all css classes from noa-aka. 4 | @noa-prefix-cls: noa; 5 | @noa-default-bg: #f5f8fa; 6 | @noa-layout-width: 1280px; 7 | @noa-global-header-top-nav-height: 65px; 8 | 9 | @noa-layout-padding: 12px; 10 | 11 | .content-layout-mixin() { 12 | max-width: @noa-layout-width; 13 | margin: 0 auto; 14 | } 15 | -------------------------------------------------------------------------------- /src/App.less: -------------------------------------------------------------------------------- 1 | @import "default.less"; 2 | 3 | body { 4 | background-color: @noa-default-bg; 5 | } 6 | 7 | /** 页面过场动画 */ 8 | .slide-fade-enter-active { 9 | transition: all .3s ease .5s; 10 | } 11 | .slide-fade-leave-active { 12 | transition: all .5s cubic-bezier(1.0, 0.5, 0.8, 1.9); 13 | } 14 | .slide-fade-enter, .slide-fade-leave-to { 15 | transform: translateX(10px); 16 | opacity: 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/router/router-guards.ts: -------------------------------------------------------------------------------- 1 | import router from './index' 2 | import NProgress from 'nprogress' // progress bar 3 | import '@/components/NProgress/nprogress.less' // progress bar custom style 4 | 5 | router.beforeEach((to, from, next) => { 6 | NProgress.start() // start progress bar 7 | console.info('Router:', to) 8 | next() 9 | }) 10 | 11 | router.afterEach(() => { 12 | NProgress.done() // finish progress bar 13 | }) 14 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent } from '@vue/composition-api' 2 | import { ConfigProvider } from 'ant-design-vue' 3 | import { langState } from '@/locales' 4 | 5 | export default defineComponent({ 6 | name: 'App', 7 | setup () { 8 | return () => ( 9 | 10 |
11 | 12 |
13 |
14 | ) 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | 'vca-jsx', 4 | '@vue/cli-plugin-babel/preset', 5 | [ 6 | '@babel/preset-env', 7 | { 8 | 'useBuiltIns': 'entry', 9 | 'corejs': 3 10 | } 11 | ] 12 | ], 13 | plugins: [ 14 | ['import', { 15 | 'libraryName': 'ant-design-vue', 16 | 'libraryDirectory': 'es', 17 | 'style': true // `style: true` 会加载 less 文件 18 | }] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex, { StoreOptions } from 'vuex' 3 | import { app } from './modules/app' 4 | import { user } from './modules/user' 5 | import { RootState } from '@/store/root-state' 6 | import { getters } from '@/store/getters' 7 | 8 | Vue.use(Vuex) 9 | 10 | const defaultStore: StoreOptions = { 11 | state: { 12 | }, 13 | modules: { 14 | app, 15 | user 16 | }, 17 | mutations: { 18 | }, 19 | actions: { 20 | } 21 | } 22 | 23 | const store = new Vuex.Store(defaultStore) 24 | 25 | export function useStore () { 26 | return store 27 | } 28 | 29 | export default store 30 | -------------------------------------------------------------------------------- /src/layouts/BasicLayout.tsx: -------------------------------------------------------------------------------- 1 | import styles from './BasicLayout.module.less' 2 | import { defineComponent } from '@vue/composition-api' 3 | import { Divider } from 'ant-design-vue' 4 | import { i18nRender } from '@/locales' 5 | 6 | export default defineComponent({ 7 | name: 'BasicLayout', 8 | setup () { 9 | return () => ( 10 |
11 |
12 | { i18nRender('main.nav.home')} 13 | 14 | { i18nRender('main.nav.page2') } 15 |
16 | 17 |
18 | ) 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue' 2 | import { ComponentRenderProxy } from '@vue/composition-api' 3 | 4 | declare global { 5 | namespace JSX { 6 | // tslint:disable no-empty-interface 7 | interface Element extends VNode {} 8 | // tslint:disable no-empty-interface 9 | interface ElementClass extends ComponentRenderProxy {} 10 | interface ElementAttributesProperty { 11 | $props: any; // specify the property name to use 12 | } 13 | interface IntrinsicElements { 14 | [elem: string]: any 15 | } 16 | } 17 | } 18 | 19 | // TypeScript SetupContext 20 | declare module '@vue/composition-api/dist/component/component' { 21 | interface SetupContext { 22 | readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/locales/lang/zh-CN.ts: -------------------------------------------------------------------------------- 1 | import zhCN from 'ant-design-vue/es/locale-provider/zh_CN' 2 | import momentZHCN from 'moment/locale/zh-cn' 3 | 4 | export default { 5 | antLocale: zhCN, 6 | momentName: 'zh-cn', 7 | momentLocale: momentZHCN, 8 | main: { 9 | test: '测试', 10 | lang: { 11 | zhCN: 'Simplified Chinese', 12 | zhTW: 'Traditional Chinese', 13 | enUS: 'English' 14 | }, 15 | nav: { 16 | home: '首页', 17 | page2: '页面2' 18 | }, 19 | dropMenu: { 20 | member: '个人中心', 21 | subscribe: '订阅', 22 | language: '语言选择', 23 | logout: '登出' 24 | }, 25 | week: { 26 | mon: '星期一', 27 | tue: '星期二', 28 | wed: '星期三', 29 | thu: '星期四', 30 | fri: '星期五', 31 | sat: '星期六', 32 | sun: '星期日' 33 | }, 34 | clickme: '点击我!', 35 | clickmsg: '你点击了 {number} 次.' 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "webpack-env", 16 | "jest" 17 | ], 18 | "paths": { 19 | "@/*": [ 20 | "src/*" 21 | ] 22 | }, 23 | "lib": [ 24 | "esnext", 25 | "dom", 26 | "dom.iterable", 27 | "scripthost" 28 | ] 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "tests/**/*.ts", 35 | "tests/**/*.tsx" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import './core/polyfills' 2 | 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | import store from './store' 7 | import i18n from './locales' 8 | import storage from 'store' 9 | import VueCompositionApi from '@vue/composition-api' 10 | import Base from 'ant-design-vue/es/base' 11 | // NavigationGuard 12 | import './router/router-guards' 13 | import expirePlugin from 'store/plugins/expire' 14 | 15 | import './App.less' 16 | 17 | Vue.config.productionTip = false 18 | 19 | Vue.use(VueCompositionApi) 20 | Vue.use(Base) 21 | storage.addPlugin(expirePlugin) 22 | 23 | new Vue({ 24 | router, 25 | store, 26 | i18n, 27 | mounted () { 28 | const language = storage.get('language') 29 | console.log('language', language) 30 | store.dispatch('app/SET_LANG', language) 31 | }, 32 | render: h => h(App) 33 | }).$mount('#root') 34 | -------------------------------------------------------------------------------- /src/locales/lang/en-US.ts: -------------------------------------------------------------------------------- 1 | import enUS from 'ant-design-vue/es/locale-provider/en_US' 2 | import momentENUS from 'moment/locale/eu' 3 | 4 | export default { 5 | antLocale: enUS, 6 | momentName: 'eu', 7 | momentLocale: momentENUS, 8 | main: { 9 | test: 'Test', 10 | lang: { 11 | zhCN: '简体中文', 12 | zhTW: '繁体中文', 13 | enUS: '英文' 14 | }, 15 | nav: { 16 | home: 'Home', 17 | page2: 'Page2' 18 | }, 19 | dropMenu: { 20 | member: 'My', 21 | subscribe: 'Subscribe', 22 | language: 'Language', 23 | logout: 'Log out' 24 | }, 25 | week: { 26 | mon: 'Monday', 27 | tue: 'Tuesday', 28 | wed: 'Wednesday', 29 | thu: 'Thursday', 30 | fri: 'Friday', 31 | sat: 'Saturday', 32 | sun: 'Sunday' 33 | }, 34 | clickme: 'Click Me!', 35 | clickmsg: 'You clicked {number}.' 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/views/Page2.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent } from '@vue/composition-api' 2 | import { demoState } from '@/hooks/demoState' 3 | import { Button, Divider, Input, Popover } from 'ant-design-vue' 4 | 5 | export default defineComponent({ 6 | setup () { 7 | return () => ( 8 |
9 |

simple page2

10 | 13 |

{demoState.clickNum}

14 | 15 |

16 | 你的名字:{demoState.name} 17 |

18 | { 20 | demoState.name = (e.target as HTMLInputElement).value 21 | } 22 | } /> 23 | )}> 24 | 25 | 26 | 27 |
28 | ) 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /src/store/modules/app.ts: -------------------------------------------------------------------------------- 1 | import { loadLanguageAsync } from '@/locales' 2 | import { ActionTree, GetterTree, Module, MutationTree } from 'vuex' 3 | import { RootState } from '@/store/root-state' 4 | 5 | export const SET_LANG = 'SET_LANG' 6 | 7 | export interface AppState { 8 | lang: string 9 | } 10 | 11 | const state: AppState = { 12 | lang: 'en-US' 13 | } 14 | 15 | const mutations: MutationTree = { 16 | [SET_LANG]: (state, lang: string) => { 17 | state.lang = lang 18 | } 19 | } 20 | 21 | const actions: ActionTree = { 22 | [SET_LANG] ({ commit }, lang: string) { 23 | return new Promise((resolve, reject) => { 24 | commit(SET_LANG, lang) 25 | loadLanguageAsync(lang).then(resolve).catch(e => { 26 | reject(e) 27 | }) 28 | }) 29 | } 30 | } 31 | 32 | export const getters: GetterTree = { 33 | lang: state => state.lang 34 | } 35 | 36 | export const app: Module = { 37 | namespaced: true, 38 | state, 39 | mutations, 40 | actions, 41 | getters 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Vue TypeScript 2 | ---- 3 | 4 | 5 | 6 | ## Project setup 7 | 8 | ```bash 9 | # Modules download 10 | $ yarn install 11 | 12 | # Compiles and hot-reloads for development 13 | $ yarn serve 14 | 15 | #Compiles and minifies for production 16 | $ yarn build 17 | 18 | # Run your unit tests 19 | $ yarn test:unit 20 | 21 | # Lints and fixes files 22 | yarn lint 23 | ``` 24 | 25 | ### Directory Structure 26 | 27 | ```tree 28 | - docker Docker config 29 | - public Project resource 30 | - src 31 | - api Api vars 32 | - assets static 33 | - components 34 | - layouts BasicLayout 35 | - locales Vue-i18n 36 | - router Vue-Router 37 | - store Vuex 38 | - styles Global styles 39 | - utils Ajax/Fetch/DateUtil 40 | - views Pages 41 | - App.less 42 | - App.tsx 43 | - default.less 44 | - icons.ts 45 | - main.ts 46 | - shims-app.d.ts 47 | - shims-tsx.d.ts 48 | - tests Jest 49 | - .browserslistrc 50 | - .editorconfig 51 | - .env.* 52 | - .eslintrc.js 53 | - .gitlab-ci.yml 54 | - package.json 55 | - vue.config.js 56 | ``` 57 | 58 | 59 | ### Customize configuration 60 | See [Configuration Reference](https://cli.vuejs.org/config/). -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue CompositionAPI 9 | 10 | <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %> 11 | 12 | <% } %> 13 | 14 | 15 | 18 |
19 | 20 | 21 | <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %> 22 | 23 | <% } %> 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/shims-app.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.bmp' { 2 | const src: string 3 | export default src 4 | } 5 | 6 | declare module '*.gif' { 7 | const src: string 8 | export default src 9 | } 10 | 11 | declare module '*.jpg' { 12 | const src: string 13 | export default src 14 | } 15 | 16 | declare module '*.jpeg' { 17 | const src: string 18 | export default src 19 | } 20 | 21 | declare module '*.png' { 22 | const src: string 23 | export default src 24 | } 25 | 26 | declare module '*.webp' { 27 | const src: string 28 | export default src 29 | } 30 | 31 | declare module '*.module.css' { 32 | const classes: { readonly [key: string]: string } 33 | export default classes 34 | } 35 | 36 | declare module '*.module.scss' { 37 | const classes: { readonly [key: string]: string } 38 | export default classes 39 | } 40 | 41 | declare module '*.module.less' { 42 | const classes: { readonly [key: string]: string } 43 | export default classes 44 | } 45 | 46 | declare module '*.module.sass' { 47 | const classes: { readonly [key: string]: string } 48 | export default classes 49 | } 50 | 51 | declare module 'moment/locale/*' { 52 | const LocaleMessage: { [key: string]: any } 53 | export default LocaleMessage 54 | } 55 | 56 | declare module 'ant-design-vue/es/locale-provider/*' { 57 | const LocaleMessage: { [key: string]: any } 58 | export default LocaleMessage 59 | } 60 | 61 | // ant-design-vue/es/base 62 | declare module 'ant-design-vue/es/base' { 63 | class Base { 64 | static install(vue: typeof Vue): void; 65 | } 66 | export default Base 67 | } 68 | 69 | declare module '*.vue' { 70 | import Vue from 'vue' 71 | export default Vue 72 | } 73 | -------------------------------------------------------------------------------- /src/icons.ts: -------------------------------------------------------------------------------- 1 | /* basic */ 2 | export { 3 | default as SettingOutline 4 | } from '@ant-design/icons/lib/outline/SettingOutline' 5 | export { 6 | default as GithubOutline 7 | } from '@ant-design/icons/lib/outline/GithubOutline' 8 | export { 9 | default as CopyrightOutline 10 | } from '@ant-design/icons/lib/outline/CopyrightOutline' 11 | export { 12 | default as DownOutline 13 | } from '@ant-design/icons/lib/outline/DownOutline' 14 | export { 15 | default as UpOutline 16 | } from '@ant-design/icons/lib/outline/UpOutline' 17 | export { 18 | default as LeftOutline 19 | } from '@ant-design/icons/lib/outline/LeftOutline' 20 | export { 21 | default as RightOutline 22 | } from '@ant-design/icons/lib/outline/RightOutline' 23 | export { 24 | default as GlobalOutline 25 | } from '@ant-design/icons/lib/outline/GlobalOutline' 26 | export { 27 | default as LeftCircleOutline 28 | } from '@ant-design/icons/lib/outline/LeftCircleOutline' 29 | export { 30 | default as RightCircleOutline 31 | } from '@ant-design/icons/lib/outline/RightCircleOutline' 32 | 33 | /* Notification */ 34 | export { 35 | default as CloseOutline 36 | } from '@ant-design/icons/lib/outline/CloseOutline' 37 | export { 38 | default as CheckCircleOutline 39 | } from '@ant-design/icons/lib/outline/CheckCircleOutline' 40 | export { 41 | default as InfoCircleOutline 42 | } from '@ant-design/icons/lib/outline/InfoCircleOutline' 43 | export { 44 | default as CloseCircleOutline 45 | } from '@ant-design/icons/lib/outline/CloseCircleOutline' 46 | export { 47 | default as ExclamationCircleOutline 48 | } from '@ant-design/icons/lib/outline/ExclamationCircleOutline' 49 | 50 | export { 51 | default as HomeOutline 52 | } from '@ant-design/icons/lib/outline/HomeOutline' 53 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/strongly-recommended', 8 | '@vue/standard', 9 | '@vue/typescript' 10 | ], 11 | rules: { 12 | 'no-console': 'off', 13 | 'no-debugger': 'off', 14 | 'generator-star-spacing': 'off', 15 | 'no-mixed-operators': 0, 16 | 'vue/max-attributes-per-line': [ 17 | 2, 18 | { 19 | 'singleline': 5, 20 | 'multiline': { 21 | 'max': 1, 22 | 'allowFirstLine': false 23 | } 24 | } 25 | ], 26 | 'vue/attribute-hyphenation': 0, 27 | 'vue/html-self-closing': 0, 28 | 'vue/component-name-in-template-casing': 0, 29 | 'vue/html-closing-bracket-spacing': 0, 30 | 'vue/singleline-html-element-content-newline': 0, 31 | 'vue/no-unused-components': 0, 32 | 'vue/multiline-html-element-content-newline': 0, 33 | 'vue/no-use-v-if-with-v-for': 0, 34 | 'vue/html-closing-bracket-newline': 0, 35 | 'vue/no-parsing-error': 0, 36 | 'no-tabs': 0, 37 | 'quotes': [ 38 | 2, 39 | 'single', 40 | { 41 | 'avoidEscape': true, 42 | 'allowTemplateLiterals': true 43 | } 44 | ], 45 | 'semi': ['error', 'never'], 46 | 'no-delete-var': 2, 47 | 'prefer-const': [ 48 | 2, 49 | { 50 | 'ignoreReadBeforeAssign': false 51 | } 52 | ] 53 | }, 54 | parserOptions: { 55 | parser: '@typescript-eslint/parser' 56 | }, 57 | overrides: [ 58 | { 59 | files: [ 60 | '**/__tests__/*.{j,t}s?(x)', 61 | '**/tests/unit/**/*.spec.{j,t}s?(x)' 62 | ], 63 | env: { 64 | jest: true 65 | } 66 | } 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-tsx3", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "test:unit": "vue-cli-service test:unit", 9 | "lint": "vue-cli-service lint", 10 | "analyz": "vue-cli-service build --mode analyz" 11 | }, 12 | "dependencies": { 13 | "@vue/composition-api": "^0.4.0", 14 | "ant-design-vue": "^1.5.0-rc.4", 15 | "core-js": "^3.4.4", 16 | "lodash.throttle": "^4.1.1", 17 | "moment": "^2.24.0", 18 | "noa-player": "^1.0.8-1", 19 | "nprogress": "^0.2.0", 20 | "store": "^2.0.12", 21 | "umi-request": "^1.2.17", 22 | "vue": "^2.6.10", 23 | "vue-class-component": "^7.0.2", 24 | "vue-i18n": "^8.15.3", 25 | "vue-property-decorator": "^8.3.0", 26 | "vue-router": "^3.1.3", 27 | "vuex": "^3.1.2" 28 | }, 29 | "devDependencies": { 30 | "@types/jest": "^24.0.19", 31 | "@types/nprogress": "^0.2.0", 32 | "@types/store": "^2.0.2", 33 | "@vue/cli-plugin-babel": "^4.1.0", 34 | "@vue/cli-plugin-eslint": "^4.1.0", 35 | "@vue/cli-plugin-router": "^4.1.0", 36 | "@vue/cli-plugin-typescript": "^4.1.0", 37 | "@vue/cli-plugin-unit-jest": "^4.1.0", 38 | "@vue/cli-plugin-vuex": "^4.1.0", 39 | "@vue/cli-service": "^4.1.0", 40 | "@vue/eslint-config-standard": "^4.0.0", 41 | "@vue/eslint-config-typescript": "^4.0.0", 42 | "@vue/test-utils": "1.0.0-beta.29", 43 | "babel-plugin-import": "^1.13.0", 44 | "babel-preset-vca-jsx": "^0.3.4", 45 | "eslint": "^5.16.0", 46 | "eslint-plugin-vue": "^5.0.0", 47 | "less": "^3.0.4", 48 | "less-loader": "^5.0.0", 49 | "typescript": "~3.5.3", 50 | "vue-template-compiler": "^2.6.10", 51 | "webpack-bundle-analyzer": "^3.6.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | before_script: 2 | - export SERVICE_NAME=$(echo $CI_JOB_NAME | awk '{split($0,a,":");print a[1]}') 3 | - export IMAGE_FULL_NAME=${CI_REGISTRY_IMAGE}/$SERVICE_NAME:${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHA} 4 | 5 | stages: 6 | - install 7 | - build 8 | - preview 9 | - prod 10 | 11 | cache: 12 | key: ${CI_COMMIT_REF_SLUG} 13 | paths: 14 | - node_modules/ 15 | 16 | aka:install: 17 | image: node:12.14.1 18 | stage: install 19 | tags: 20 | - docker 21 | artifacts: 22 | expire_in: 1 week 23 | paths: 24 | - dist 25 | before_script: 26 | - yarn config set registry https://registry.npm.taobao.org -g 27 | - yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g 28 | script: 29 | - node -v 30 | - yarn -v 31 | - yarn 32 | - yarn build 33 | only: 34 | - /^release.*$/ 35 | 36 | aka:build: 37 | image: docker:stable 38 | stage: build 39 | services: 40 | - docker:dind 41 | dependencies: 42 | - aka:install 43 | tags: 44 | - docker 45 | script: 46 | - docker login -u $CI_DEPLOY_SECRET_USER -p $CI_DEPLOY_SECRET_PWD $CI_REGISTRY 47 | - docker build --rm --pull -t "$IMAGE_FULL_NAME" . 48 | - docker push "$IMAGE_FULL_NAME" 49 | only: 50 | - /^release.*$/ 51 | 52 | aka:preview: 53 | variables: 54 | GIT_STRATEGY: none 55 | GIT_CHECKOUT: "false" 56 | stage: preview 57 | when: manual 58 | dependencies: [] 59 | tags: 60 | - deploy-pre 61 | script: 62 | - echo "deploy preview" 63 | only: 64 | - /^release.*$/ 65 | 66 | aka:prod: 67 | variables: 68 | GIT_STRATEGY: none 69 | GIT_CHECKOUT: "false" 70 | stage: prod 71 | when: manual 72 | dependencies: [] 73 | tags: 74 | - prod 75 | script: 76 | - echo "deploy prod" 77 | only: 78 | - /^release.*$/ -------------------------------------------------------------------------------- /src/components/NProgress/nprogress.less: -------------------------------------------------------------------------------- 1 | @import url('../../default.less'); 2 | 3 | /* Make clicks pass-through */ 4 | #nprogress { 5 | pointer-events: none; 6 | } 7 | 8 | #nprogress .bar { 9 | background: @primary-color; 10 | 11 | position: fixed; 12 | z-index: 1031; 13 | top: 0; 14 | left: 0; 15 | 16 | width: 100%; 17 | height: 2px; 18 | } 19 | 20 | /* Fancy blur effect */ 21 | #nprogress .peg { 22 | display: block; 23 | position: absolute; 24 | right: 0px; 25 | width: 100px; 26 | height: 100%; 27 | box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color; 28 | opacity: 1.0; 29 | 30 | -webkit-transform: rotate(3deg) translate(0px, -4px); 31 | -ms-transform: rotate(3deg) translate(0px, -4px); 32 | transform: rotate(3deg) translate(0px, -4px); 33 | } 34 | 35 | /* Remove these to get rid of the spinner */ 36 | #nprogress .spinner { 37 | display: block; 38 | position: fixed; 39 | z-index: 1031; 40 | top: 15px; 41 | right: 15px; 42 | } 43 | 44 | #nprogress .spinner-icon { 45 | width: 18px; 46 | height: 18px; 47 | box-sizing: border-box; 48 | 49 | border: solid 2px transparent; 50 | border-top-color: @primary-color; 51 | border-left-color: @primary-color; 52 | border-radius: 50%; 53 | 54 | -webkit-animation: nprogress-spinner 400ms linear infinite; 55 | animation: nprogress-spinner 400ms linear infinite; 56 | } 57 | 58 | .nprogress-custom-parent { 59 | overflow: hidden; 60 | position: relative; 61 | } 62 | 63 | .nprogress-custom-parent #nprogress .spinner, 64 | .nprogress-custom-parent #nprogress .bar { 65 | position: absolute; 66 | } 67 | 68 | @-webkit-keyframes nprogress-spinner { 69 | 0% { -webkit-transform: rotate(0deg); } 70 | 100% { -webkit-transform: rotate(360deg); } 71 | } 72 | @keyframes nprogress-spinner { 73 | 0% { transform: rotate(0deg); } 74 | 100% { transform: rotate(360deg); } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/utils/request.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * umi-request: 3 | * https://github.com/umijs/umi-request/blob/master/README_zh-CN.md 4 | */ 5 | import request, { extend, ResponseError } from 'umi-request' 6 | import { notification } from 'ant-design-vue' 7 | 8 | /** 9 | * GLOBAL REQUEST URI 10 | * @type string 11 | */ 12 | export const BASE_URL: string = process.env.VUE_APP_API_URL || '/api/v2' 13 | 14 | type HttpCode = { 15 | [key: number]: string 16 | } 17 | 18 | const codeMessage: HttpCode = { 19 | 200: '服务器成功返回请求的数据。', 20 | 201: '新建或修改数据成功。', 21 | 202: '一个请求已经进入后台排队(异步任务)。', 22 | 204: '删除数据成功。', 23 | 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', 24 | 401: '用户没有权限(令牌、用户名、密码错误)。', 25 | 403: '用户得到授权,但是访问是被禁止的。', 26 | 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', 27 | 406: '请求的格式不可得。', 28 | 410: '请求的资源被永久删除,且不会再得到的。', 29 | 422: '当创建一个对象时,发生一个验证错误。', 30 | 500: '服务器发生错误,请检查服务器。', 31 | 502: '网关错误。', 32 | 503: '服务不可用,服务器暂时过载或维护。', 33 | 504: '网关超时。' 34 | } 35 | 36 | const errorHandler = (error: ResponseError) => { 37 | const errorText = (error.response && codeMessage[error.response.status]) || error.message 38 | 39 | notification.error({ 40 | message: `请求错误 ${status}: ${error.request.url}`, 41 | description: errorText 42 | }) 43 | } 44 | 45 | const customRequest = extend({ 46 | prefix: BASE_URL, 47 | timeout: 1000, 48 | errorHandler 49 | }) 50 | 51 | // request 拦截器 52 | customRequest.interceptors.request.use((url, options) => { 53 | return ( 54 | { 55 | url, 56 | options: { ...options, interceptors: true } 57 | } 58 | ) 59 | }) 60 | 61 | // response 拦截器 62 | customRequest.interceptors.response.use(async (response) => { 63 | const data = await response.clone().json() 64 | if (data && data.REQUEST_LOGIN) { 65 | console.log('response:data', data) 66 | // useRouter().push('/auth/login') 67 | } 68 | return response 69 | }) 70 | 71 | export { 72 | request, 73 | extend 74 | } 75 | 76 | export default customRequest 77 | -------------------------------------------------------------------------------- /src/locales/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import storage from 'store' 3 | import VueI18n, { LocaleMessage } from 'vue-i18n' 4 | import VueCompositionApi, { reactive, ref, Ref } from '@vue/composition-api' 5 | import moment from 'moment' 6 | import enUS from './lang/en-US' 7 | 8 | Vue.use(VueCompositionApi) 9 | Vue.use(VueI18n) 10 | 11 | export const defaultLang = 'en-US' 12 | 13 | const messages = { 14 | 'en-US': { 15 | ...enUS 16 | } 17 | } 18 | 19 | const loadedLanguages: string[] = [ 20 | defaultLang 21 | ] 22 | 23 | /* Ant Design LocaleProvider */ 24 | export const langState = reactive({ 25 | locale: ref(defaultLang), 26 | ant: ref({}) 27 | }) 28 | 29 | const i18n = new VueI18n({ 30 | locale: defaultLang, 31 | fallbackLocale: defaultLang, 32 | messages 33 | }) 34 | 35 | export default i18n 36 | 37 | export const i18nRender = (key: string) => i18n.t(key) 38 | 39 | const setI18nLanguage = (lang: string) => { 40 | i18n.locale = lang 41 | langState.locale = lang 42 | // AntDesign LocaleProvider 43 | langState.ant = i18n.getLocaleMessage(lang).antLocale 44 | // @ts-ignore 45 | // document.getElementsByTagName('html')[0].setAttribute('lang', lang) 46 | return true 47 | } 48 | 49 | export const loadLanguageAsync = (lang: string = defaultLang) => { 50 | return new Promise(resolve => { 51 | // Save to storage 52 | storage.set('language', lang) 53 | if (i18n.locale !== lang) { 54 | if (!loadedLanguages.includes(lang)) { 55 | return import(/* webpackChunkName: "lang-[request]" */ `./lang/${lang}`).then(msg => { 56 | console.log('loadedLanguages', msg) 57 | const locale = msg.default 58 | i18n.setLocaleMessage(lang, locale) 59 | loadedLanguages.push(lang) 60 | langState.locale = lang 61 | langState.ant = locale.antLocale 62 | moment.locale(locale.momentName, locale.momentLocale) 63 | return resolve(setI18nLanguage(lang)) 64 | }) 65 | } 66 | return resolve(setI18nLanguage(lang)) 67 | } 68 | return resolve(lang) 69 | }) 70 | } 71 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import Vue, { AsyncComponent } from 'vue' 2 | import VueRouter, { RouteConfig } from 'vue-router' 3 | 4 | // hack router push/replace callback 5 | ['push', 'replace'].map(key => { 6 | // @ts-ignore 7 | return { k: key, prop: VueRouter.prototype[key] } 8 | }).forEach(item => { 9 | // @ts-ignore 10 | VueRouter.prototype[item.k] = function newCall (location, onResolve, onReject) { 11 | if (onResolve || onReject) return item.prop.call(this, location, onResolve, onReject) 12 | return item.prop.call(this, location).catch((err: Error) => { throw err }) 13 | } 14 | }) 15 | 16 | Vue.use(VueRouter) 17 | 18 | const BasicLayout: AsyncComponent = () => import(/* webpackChunkName: "base-layout" */'../layouts/BasicLayout') 19 | 20 | export const memberRouters: RouteConfig[] = [ 21 | // route level code-splitting 22 | // this generates a separate chunk (about.[hash].js) for this route 23 | // which is lazy-loaded when the route is visited. 24 | { 25 | path: 'my', 26 | name: 'my', 27 | meta: { 28 | title: 'member.menu.my', 29 | icon: 'user' 30 | }, 31 | component: () => import(/* webpackChunkName: "member" */ '../views/Test') 32 | } 33 | ] 34 | 35 | export const homeRouters: RouteConfig[] = [ 36 | { 37 | path: '/', 38 | name: 'home', 39 | meta: { 40 | title: 'main.nav.home', 41 | icon: 'home' 42 | }, 43 | component: () => import(/* webpackChunkName: "aaka" */'../views/Test') 44 | }, 45 | { 46 | path: '/page2', 47 | name: 'page2', 48 | meta: { 49 | title: 'main.nav.page2', 50 | icon: '' 51 | }, 52 | component: () => import(/* webpackChunkName: "aaka" */'../views/Page2') 53 | } 54 | ] 55 | 56 | const routes: RouteConfig[] = [ 57 | { 58 | path: '', 59 | name: 'index', 60 | component: BasicLayout, 61 | redirect: '/', 62 | children: homeRouters 63 | } 64 | ] 65 | 66 | const router = new VueRouter({ 67 | mode: 'history', 68 | base: process.env.BASE_URL, 69 | routes 70 | }) 71 | 72 | export function useRouter () { 73 | return router 74 | } 75 | 76 | export default router 77 | -------------------------------------------------------------------------------- /src/views/Test.tsx: -------------------------------------------------------------------------------- 1 | import styles from './Test.module.less' 2 | 3 | import { defineComponent, onMounted, reactive, ref, SetupContext } from '@vue/composition-api' 4 | import { Pagination, Select, Radio, DatePicker, TimePicker, Divider, Button } from 'ant-design-vue' 5 | import { useStore } from '@/store' 6 | import { i18nRender } from '@/locales' 7 | 8 | const useState = reactive({ 9 | name: ref(null), 10 | clicked: ref(false), 11 | clickNumber: ref(0) 12 | }) 13 | 14 | export default defineComponent({ 15 | setup (props: {}, { root: { $i18n } }: SetupContext) { 16 | const store = useStore() 17 | 18 | onMounted(() => { 19 | console.log('Test onMounted.') 20 | }) 21 | 22 | return () => ( 23 |
24 |

{ $i18n.t('main.test') }

25 |
26 | { 29 | const localeValue = (e.target as HTMLInputElement).value 30 | store.dispatch('app/SET_LANG', localeValue) 31 | }} 32 | > 33 | English 34 | 中文 35 | 36 |
37 |
38 |
39 | 40 |
41 |
42 | 46 | 47 | 48 |
49 | i18n example 50 |

{ i18nRender('main.week.mon') }

51 |

{ i18nRender('main.week.tue') }

52 |

53 | {useState.clickNumber > 0 && ( 54 | 55 | )} 56 | 57 |
58 |
59 | ) 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /src/store/modules/user.ts: -------------------------------------------------------------------------------- 1 | import { ACCESS_TOKEN } from '../mutation-types' 2 | import { ActionTree, Getter, GetterTree, Module, MutationTree } from 'vuex' 3 | import { RootState } from '@/store/root-state' 4 | import { AppState } from '@/store/modules/app' 5 | 6 | export const SET_TOKEN = 'SET_TOKEN' 7 | export const SET_INFO = 'SET_INFO' 8 | export const DESTROY_USER_STATE = 'D_USER_STATE' 9 | export const TOKEN_TIMEOUT = 1000 * 60 * 60 * 11 10 | 11 | export interface UserState { 12 | token: string, 13 | nickname: string, 14 | avatar: string, 15 | role: number, 16 | fetched: boolean, 17 | extra: any 18 | } 19 | 20 | const state: UserState = { 21 | token: '', 22 | nickname: '', 23 | avatar: '', 24 | role: 3, 25 | fetched: false, 26 | extra: {} 27 | } 28 | 29 | const mutations: MutationTree = { 30 | [SET_TOKEN]: (state, token: string) => { 31 | state.token = token 32 | }, 33 | [SET_INFO]: (state, info: any) => { 34 | const { nickname, avatar, role_id: roleId } = info 35 | state.nickname = nickname 36 | state.avatar = avatar 37 | state.role = roleId 38 | state.extra = info 39 | state.fetched = true 40 | }, 41 | [DESTROY_USER_STATE]: (state) => { 42 | state.nickname = '' 43 | state.avatar = '' 44 | state.extra = {} 45 | state.fetched = false 46 | state.token = '' 47 | state.role = 3 48 | // Vue.storage.remove(ACCESS_TOKEN) 49 | } 50 | } 51 | 52 | const actions: ActionTree = { 53 | Login ({ commit }, formData) { 54 | console.log('dispatch:: data: ', formData) 55 | return new Promise((resolve, reject) => { 56 | // axios post 57 | resolve() 58 | }) 59 | }, 60 | 61 | GetInfo ({ commit }) { 62 | return new Promise(resolve => { 63 | // axios get 64 | resolve({ 65 | token: '1' 66 | }) 67 | }) 68 | }, 69 | 70 | Logout ({ commit }) { 71 | return new Promise(resolve => { 72 | /* logout().then((res: any) => { 73 | console.log('logout:', res) 74 | }).finally(() => { 75 | commit(DESTROY_USER_STATE) 76 | resolve(true) 77 | }) */ 78 | resolve(true) 79 | }) 80 | } 81 | } 82 | 83 | export const getters: GetterTree = { 84 | userFetched: state => state.fetched, 85 | nickname: state => state.nickname, 86 | avatar: state => state.avatar, 87 | role: state => state.role, 88 | extra: state => state.extra 89 | } 90 | 91 | export const user: Module = { 92 | namespaced: true, 93 | state, 94 | mutations, 95 | actions, 96 | getters 97 | } 98 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | 2 | const path = require('path') 3 | const { IgnorePlugin } = require('webpack') 4 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') 5 | 6 | const isProd = process.env.NODE_ENV === 'production' 7 | const isAnalyz = process.env.IS_ANALYZ === 'true' 8 | 9 | function resolve (dir) { 10 | return path.join(__dirname, dir) 11 | } 12 | 13 | const assetsCDN = { 14 | externals: { 15 | 'vue': 'Vue', 16 | 'vuex': 'Vuex', 17 | 'vue-router': 'VueRouter' 18 | }, 19 | assets: { 20 | css: [], 21 | // https://unpkg.com/:package@:version/:file 22 | // https://cdn.jsdelivr.net/package:version/:file 23 | js: [ 24 | '//cdn.jsdelivr.net/npm/vue@latest/dist/vue.min.js', 25 | '//cdn.jsdelivr.net/npm/vue-router@latest/dist/vue-router.min.js', 26 | '//cdn.jsdelivr.net/npm/vuex@latest/dist/vuex.min.js' 27 | ] 28 | } 29 | } 30 | 31 | // vue.config 32 | const defaultConfig = { 33 | configureWebpack: { 34 | plugins: [ 35 | // Ignore all locale files of moment.js 36 | new IgnorePlugin(/^\.\/locale$/, /moment$/) 37 | ], 38 | resolve: { 39 | alias: { 40 | '@ant-design/icons/lib/dist$': resolve('./src/icons.ts') 41 | } 42 | }, 43 | externals: isProd ? assetsCDN.externals : {} 44 | }, 45 | chainWebpack: config => { 46 | // set alias 47 | config.resolve.alias.set('@config', resolve('./config')) 48 | 49 | // if `production` env require on cdn assets 50 | isProd && config.plugin('html').tap(args => { 51 | args[0].cdn = assetsCDN.assets 52 | return args 53 | }) 54 | 55 | // if `IS_ANALYZ` env is TRUE on report bundle info 56 | isAnalyz && config.plugin('webpack-report').use(BundleAnalyzerPlugin, [ 57 | { 58 | analyzerMode: 'static' 59 | } 60 | ]) 61 | }, 62 | css: { 63 | loaderOptions: { 64 | less: { 65 | modifyVars: { 66 | // less vars,customize ant design theme 67 | 68 | 'primary-color': '#225797', 69 | 'link-color': '#225797', 70 | 'border-radius-base': '2px' 71 | }, 72 | // DO NOT REMOVE THIS LINE 73 | javascriptEnabled: true 74 | } 75 | } 76 | }, 77 | devServer: { 78 | // development server port 8000 79 | port: 8000, 80 | // If you want to turn on the proxy, please remove the mockjs /src/main.jsL11 81 | // proxy: { 82 | // '/api': { 83 | // target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro', 84 | // ws: false, 85 | // changeOrigin: true 86 | // } 87 | // } 88 | proxy: { 89 | '/api/resource': { 90 | target: 'https://anime.srsg.moe/', // http://localhost:8084/webapi/ 91 | ws: false, 92 | changeOrigin: true 93 | }, 94 | '/api/v1': { 95 | target: 'https://anime.srsg.moe/api', // http://localhost:8084/webapi/ 96 | ws: false, 97 | changeOrigin: true, 98 | pathRewrite: { 99 | '^/api/v1': '' 100 | } 101 | }, 102 | '/api/gateway': { 103 | target: 'http://anime.srsg.moe/gateway', // http://localhost:8094/account/ 104 | ws: false, 105 | changeOrigin: true, 106 | pathRewrite: { 107 | '^/api/gateway': '' 108 | } 109 | } 110 | } 111 | }, 112 | // disable source map in production 113 | productionSourceMap: false, 114 | lintOnSave: undefined, 115 | // babel-loader no-ignore node_modules/* 116 | transpileDependencies: [] 117 | } 118 | 119 | module.exports = defaultConfig 120 | --------------------------------------------------------------------------------