├── src ├── locales │ ├── en.json │ └── fa.json ├── utils │ ├── index.ts │ └── i18n.ts ├── assets │ ├── logo.png │ ├── main.css │ └── logo.svg ├── App.vue ├── components │ ├── NewJsxFile │ │ ├── NewJsxFile.tsx │ │ └── NewJsxFile.cy.ts │ ├── markdown │ │ └── MDTest.vue │ └── HelloWorld │ │ ├── HelloWorld.cy.ts │ │ ├── HelloWorld.test.ts │ │ └── HelloWorld.vue ├── env.d.ts ├── store │ └── main.ts ├── pages │ ├── test.vue │ ├── markdown.md │ └── index.vue ├── layouts │ ├── default.vue │ └── sub.vue ├── components.d.ts ├── main.ts └── auto-imports.d.ts ├── .npmrc ├── .stylelintignore ├── vite-env.d.ts ├── .vscode ├── settings.json └── extensions.json ├── public ├── favicon.ico ├── maskable-icon-x192.png ├── maskable-icon-x512.png ├── android-chrome-192x192.png └── android-chrome-512x512.png ├── .husky └── pre-commit ├── renovate.json ├── .eslintignore ├── postcss.config.cjs ├── tsconfig.node.json ├── .gitignore ├── cypress ├── support │ ├── commands.js │ ├── component-index.html │ ├── e2e.js │ └── component.js ├── tsconfig.json └── e2e │ └── home.cy.ts ├── .editorconfig ├── cypress.config.ts ├── Dockerfile ├── index.html ├── cypress.d.ts ├── unocss.config.ts ├── shims.d.ts ├── LICENSE ├── .versionrc.js ├── tsconfig.json ├── .eslintrc ├── CHANGELOG.md ├── package.json ├── .stylelintrc.cjs ├── vite.config.ts └── README.md /src/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "button": "Button" 3 | } 4 | -------------------------------------------------------------------------------- /src/locales/fa.json: -------------------------------------------------------------------------------- 1 | { 2 | "button": "دکمه" 3 | } 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # after pnpm version 7 2 | strict-peer-dependencies=false -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import i18n from './i18n' 2 | 3 | export default { i18n } 4 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | dist 2 | coverage 3 | **/dist 4 | **/node_modules 5 | node_modules 6 | -------------------------------------------------------------------------------- /vite-env.d.ts: -------------------------------------------------------------------------------- 1 | // vite-env.d.ts 2 | /// -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "i18n-ally.localesPaths": [ 3 | "src/locales" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba-aero/vuilerplate/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba-aero/vuilerplate/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pnpm lint-staged 5 | -------------------------------------------------------------------------------- /public/maskable-icon-x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba-aero/vuilerplate/HEAD/public/maskable-icon-x192.png -------------------------------------------------------------------------------- /public/maskable-icon-x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba-aero/vuilerplate/HEAD/public/maskable-icon-x512.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba-aero/vuilerplate/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba-aero/vuilerplate/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/dist 3 | node_modules 4 | coverage 5 | .vscode 6 | vite.config.ts 7 | postcss.config.js 8 | cypress.config.ts 9 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-nested'), 5 | require('postcss-url'), 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /src/components/NewJsxFile/NewJsxFile.tsx: -------------------------------------------------------------------------------- 1 | function NewJsxFile() { 2 | return ( 3 |
4 | New JSX File 5 |
6 | ) 7 | } 8 | 9 | export default NewJsxFile 10 | -------------------------------------------------------------------------------- /src/components/NewJsxFile/NewJsxFile.cy.ts: -------------------------------------------------------------------------------- 1 | import Component from './NewJsxFile' 2 | 3 | describe('NewJsxFile', () => { 4 | it('should mount component correctly', () => { 5 | cy.mount(Component, {}) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .nuxt 4 | .DS_Store 5 | .idea 6 | coverage 7 | *-coverage 8 | *.log 9 | .nyc_output 10 | .env*.local 11 | tsconfig.tsbuildinfo 12 | stats.html 13 | .vite-ssg-temp 14 | .vite-ssg-dist 15 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import '@testing-library/cypress/add-commands' 3 | 4 | Cypress.Commands.add('getByTestId', (selector, ...args) => cy.get(`[data-testid=${selector}]`, ...args)) 5 | -------------------------------------------------------------------------------- /src/utils/i18n.ts: -------------------------------------------------------------------------------- 1 | import messages from '@intlify/vite-plugin-vue-i18n/messages' 2 | import { createI18n } from 'vue-i18n' 3 | 4 | const i18n = createI18n({ 5 | legacy: false, 6 | locale: 'en', 7 | globalInjection: true, 8 | messages, 9 | }) 10 | 11 | export default i18n 12 | -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "types": [ 6 | "cypress", 7 | "@testing-library/cypress" 8 | ] 9 | }, 10 | "exclude": [], 11 | "include": [ 12 | "**/*.ts", 13 | "../cypress.d.ts" 14 | ] 15 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.css] 12 | indent_size = 2 13 | 14 | [*.md] 15 | insert_final_newline = false 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "antfu.iconify", 4 | "antfu.unocss", 5 | "antfu.vite", 6 | "antfu.goto-alias", 7 | "csstools.postcss", 8 | "dbaeumer.vscode-eslint", 9 | "vue.volar", 10 | "lokalise.i18n-ally", 11 | "streetsidesoftware.code-spell-checker" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress' 2 | 3 | export default defineConfig({ 4 | e2e: { 5 | baseUrl: 'http://localhost:5173', 6 | chromeWebSecurity: false, 7 | specPattern: 'cypress/e2e/**/*.cy.*', 8 | }, 9 | component: { 10 | devServer: { 11 | framework: 'vue', 12 | bundler: 'vite', 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | declare module '*.vue' { 5 | import type { DefineComponent } from 'vue' 6 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 7 | const component: DefineComponent<{}, {}, any> 8 | export default component 9 | } 10 | -------------------------------------------------------------------------------- /src/store/main.ts: -------------------------------------------------------------------------------- 1 | import { acceptHMRUpdate, defineStore } from 'pinia' 2 | 3 | interface RootState { 4 | counter: number 5 | } 6 | 7 | export const useMainStore = defineStore('main', { 8 | state: (): RootState => ({ 9 | counter: 0, 10 | }), 11 | }) 12 | 13 | if (import.meta.hot) 14 | import.meta.hot.accept(acceptHMRUpdate(useMainStore, import.meta.hot)) 15 | 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine as build-stage 2 | 3 | WORKDIR /app 4 | RUN corepack enable 5 | 6 | COPY package.json pnpm-lock.yaml ./ 7 | RUN pnpm install --frozen-lockfile 8 | 9 | COPY . . 10 | RUN pnpm build 11 | 12 | FROM nginx:stable-alpine as production-stage 13 | 14 | COPY --from=build-stage /app/dist /usr/share/nginx/html 15 | EXPOSE 80 16 | 17 | CMD ["nginx", "-g", "daemon off;"] -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /cypress.d.ts: -------------------------------------------------------------------------------- 1 | import { mount } from 'cypress/vue'; 2 | 3 | type MountParams = Parameters; 4 | type OptionsParam = MountParams[1]; 5 | 6 | declare global { 7 | namespace Cypress { 8 | interface Chainable { 9 | /** 10 | * Get Element by data-testid 11 | * @example 12 | * cy.getByTestId('selector') 13 | */ 14 | getByTestId(selector: string): Chainable 15 | /** 16 | * Mount element 17 | * @example 18 | * cy.mount(Component) 19 | */ 20 | mount: typeof mount; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/pages/test.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 14 | 15 | 16 | { 17 | meta: { 18 | layout: "sub" 19 | } 20 | } 21 | 22 | 23 | 24 | { 25 | "en": { 26 | "testPage": "Test Page", 27 | "home": "Home" 28 | }, 29 | "fa": { 30 | "testPage": "صفحه تست", 31 | "home": "خانه" 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /cypress/e2e/home.cy.ts: -------------------------------------------------------------------------------- 1 | context('Home', () => { 2 | beforeEach(() => { 3 | cy.visit('/') 4 | }) 5 | 6 | it('go to test page', () => { 7 | cy.url().should('eq', 'http://localhost:5173/') 8 | 9 | cy.getByTestId('test-link') 10 | .should('have.attr', 'href') 11 | .and('eq', '/test') 12 | cy.getByTestId('test-link').click() 13 | 14 | cy.url().should('eq', 'http://localhost:5173/test') 15 | 16 | cy.getByTestId('home-link') 17 | .should('have.attr', 'href') 18 | .and('eq', '/') 19 | cy.getByTestId('home-link').click() 20 | 21 | cy.url().should('eq', 'http://localhost:5173/') 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /src/pages/markdown.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: My Markdown Page 3 | title: My Markdown Page 4 | meta: 5 | - name: description 6 | content: Hello World 7 | --- 8 | # Hello World 9 | 10 | Link to alibaba: https://alibaba.ir 11 | 12 | Link: [Alibaba](https://alibaba.ir) 13 | 14 | This is {{ frontmatter.name }} 15 | 16 | 17 | 18 | Home 19 |
20 | 21 | ```javascript 22 | function test() { 23 | return 0; 24 | } 25 | ``` 26 | 27 | 37 | -------------------------------------------------------------------------------- /src/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 26 | 27 | 28 | { 29 | "en": { 30 | "header": "Header", 31 | "footer": "Footer" 32 | }, 33 | "fa": { 34 | "header": "هدر", 35 | "footer": "فوتر" 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/layouts/sub.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 26 | 27 | 28 | { 29 | "en": { 30 | "header": "Header Sub", 31 | "footer": "Footer Sub" 32 | }, 33 | "fa": { 34 | "header": "هدر ساب", 35 | "footer": "فوتر ساب" 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/components.d.ts: -------------------------------------------------------------------------------- 1 | // generated by unplugin-vue-components 2 | // We suggest you to commit this file into source control 3 | // Read more: https://github.com/vuejs/core/pull/3399 4 | import '@vue/runtime-core' 5 | 6 | export {} 7 | 8 | declare module '@vue/runtime-core' { 9 | export interface GlobalComponents { 10 | HelloWorld: typeof import('./components/HelloWorld/HelloWorld.vue')['default'] 11 | MDTest: typeof import('./components/markdown/MDTest.vue')['default'] 12 | NewJsxFile: typeof import('./components/NewJsxFile/NewJsxFile.tsx')['default'] 13 | RouterLink: typeof import('vue-router')['RouterLink'] 14 | RouterView: typeof import('vue-router')['RouterView'] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /unocss.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineConfig, 3 | presetAttributify, 4 | presetIcons, 5 | presetTypography, 6 | presetUno, 7 | presetWebFonts, 8 | transformerDirectives, 9 | } from 'unocss' 10 | 11 | export default defineConfig({ 12 | presets: [ 13 | presetUno(), 14 | presetAttributify({ 15 | prefix: 'un-', 16 | }), 17 | presetIcons({ 18 | scale: 1.2, 19 | warn: true, 20 | }), 21 | presetTypography(), 22 | presetWebFonts({ 23 | fonts: { 24 | sans: 'DM Sans', 25 | serif: 'DM Serif Display', 26 | mono: 'DM Mono', 27 | }, 28 | }), 29 | ], 30 | transformers: [ 31 | transformerDirectives(), 32 | ], 33 | }) 34 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import generatedRoutes from 'virtual:generated-pages' 2 | import { setupLayouts } from 'virtual:generated-layouts' 3 | import { createPinia } from 'pinia' 4 | import { ViteSSG } from 'vite-ssg' 5 | import App from './App.vue' 6 | 7 | import '@unocss/reset/tailwind.css' 8 | import 'uno.css' 9 | 10 | const routes = setupLayouts(generatedRoutes) 11 | 12 | export const createApp = ViteSSG( 13 | App, 14 | { routes }, 15 | ({ app, router, initialState }) => { 16 | const pinia = createPinia() 17 | app.use(pinia) 18 | app.use(router) 19 | app.use(i18n) 20 | 21 | if (import.meta.env.SSR) 22 | initialState.pinia = pinia.state.value 23 | else 24 | pinia.state.value = initialState.pinia || {} 25 | }, 26 | ) 27 | -------------------------------------------------------------------------------- /cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /src/components/markdown/MDTest.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | 18 | 24 | 25 | 26 | { 27 | "en": { 28 | "testComponent": "Test Component in Markdown", 29 | "props": "Props:" 30 | }, 31 | "fa": { 32 | "testComponent": "تست کامپوننت در مارک داون", 33 | "props": "پراپس:" 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/pages/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | 24 | 25 | { 26 | "en": { 27 | "test": "Test" 28 | }, 29 | "fa": { 30 | "test": "تست" 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /cypress/support/component.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/component.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // eslint-disable-next-line import/no-extraneous-dependencies 17 | import { mount } from 'cypress/vue' 18 | // Import commands.js using ES2015 syntax: 19 | import './commands' 20 | 21 | // Ensure global styles are loaded 22 | import '../../src/assets/main.css' 23 | 24 | // Alternatively you can use CommonJS syntax: 25 | // require('./commands') 26 | 27 | Cypress.Commands.add('mount', mount) 28 | -------------------------------------------------------------------------------- /shims.d.ts: -------------------------------------------------------------------------------- 1 | declare interface Window { 2 | // extend the window 3 | } 4 | 5 | // with vite-plugin-vue-markdown, markdown files can be treated as Vue components 6 | declare module '*.md' { 7 | import { type DefineComponent } from 'vue' 8 | const component: DefineComponent<{}, {}, any> 9 | export default component 10 | } 11 | 12 | declare module '*.vue' { 13 | import { type DefineComponent } from 'vue' 14 | const component: DefineComponent<{}, {}, any> 15 | export default component 16 | } 17 | // Vite plugin to load SVG files as Vue components 18 | declare module 'vite-svg-loader' { 19 | import { Plugin } from 'vite' 20 | function svgLoader(options?: { svgoConfig?: Object, svgo?: boolean }): Plugin 21 | export default svgLoader 22 | } 23 | 24 | declare module '*.svg?component' { 25 | import { FunctionalComponent, SVGAttributes } from 'vue' 26 | const src: FunctionalComponent 27 | export default src 28 | } 29 | 30 | declare module '*.svg?url' { 31 | const src: String 32 | export default src 33 | } 34 | 35 | declare module '*.svg?raw' { 36 | const src: String 37 | export default src 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alibaba Travels Co Open Source 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.versionrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "releaseCommitMessageFormat": "misc(versions): add version {{currentTag}}", 3 | "types": [ 4 | { 5 | "type": "feat", 6 | "section": "Features" 7 | }, 8 | { 9 | "type": "fix", 10 | "section": "Bug Fixes" 11 | }, 12 | { 13 | "type": "test", 14 | "section": "Tests" 15 | }, 16 | { 17 | "type": "build", 18 | "section": "Build System" 19 | }, 20 | { 21 | "type": "docs", 22 | "section": "Documentation" 23 | }, 24 | { 25 | "type": "refactor", 26 | "section": "Refactors" 27 | }, 28 | { 29 | "type": "style", 30 | "section": "Style Changes" 31 | }, 32 | { 33 | "type": "perf", 34 | "section": "Performance Related" 35 | }, 36 | { 37 | "type": "ci", 38 | "section": "CI/CD Related" 39 | }, 40 | { 41 | "type": "misc", 42 | "section": "Miscellaneous" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "esModuleInterop": true, 12 | "lib": ["esnext", "dom"], 13 | "skipLibCheck": true, 14 | "types": [ 15 | "vitest", 16 | "vite/client", 17 | "vue/ref-macros", 18 | "vite-plugin-pages/client", 19 | "vite-plugin-vue-layouts/client", 20 | "@intlify/vite-plugin-vue-i18n/client" 21 | ], 22 | "allowSyntheticDefaultImports": true, 23 | "baseUrl": ".", 24 | "paths": { 25 | "@/*": ["src/*"], 26 | "@/utils/*": ["src/utils/*"] 27 | }, 28 | }, 29 | "include": [ 30 | "src/**/*.ts", 31 | "src/**/*.d.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "src/**/*.js", 35 | "*.ts", 36 | "*.js", 37 | "cypress", 38 | "cypress.d.ts", 39 | ], 40 | "exclude": [ 41 | "dist", 42 | "**/dist", 43 | "node_modules", 44 | "**/node_modules", 45 | "coverage" 46 | ], 47 | "references": [{ "path": "./tsconfig.node.json" }] 48 | } 49 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "airbnb", 4 | "airbnb-typescript/base", 5 | "plugin:vue/vue3-recommended", 6 | "plugin:cypress/recommended", 7 | "plugin:@intlify/vue-i18n/recommended", 8 | "@antfu" 9 | ], 10 | "env": { 11 | "cypress/globals": true 12 | }, 13 | "parser": "vue-eslint-parser", 14 | "parserOptions": { 15 | "parser": "@typescript-eslint/parser", 16 | "project": "./tsconfig.json", 17 | "extraFileExtensions": [ 18 | ".vue", 19 | ".tsx" 20 | ], 21 | "ecmaVersion": 2021, 22 | "ecmaFeatures": { 23 | "jsx": true 24 | }, 25 | "sourceType": "module", 26 | "allowImportExportEverywhere": true 27 | }, 28 | "rules": { 29 | "react/display-name": "off", 30 | "nonblock-statement-body-position": "off", 31 | "import/prefer-default-export": "off", 32 | "react/jsx-filename-extension": "off", 33 | "import/no-extraneous-dependencies": ["error", { 34 | "devDependencies": true 35 | }], 36 | "@intlify/vue-i18n/no-missing-keys": "off", 37 | "import/extensions": "off" 38 | }, 39 | "settings": { 40 | "vue-i18n": { 41 | "localeDir": "./locales/*.{json,json5,yaml,yml}", 42 | "messageSyntaxVersion": "^9.0.0" 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/components/HelloWorld/HelloWorld.cy.ts: -------------------------------------------------------------------------------- 1 | import { createTestingPinia } from '@pinia/testing' 2 | import Component from './HelloWorld.vue' 3 | 4 | const factory = (options: any) => cy.mount(Component, { 5 | global: { 6 | plugins: [createTestingPinia({ createSpy: cy.spy }), i18n], 7 | }, 8 | ...options, 9 | }) 10 | 11 | describe('HelloWorld', () => { 12 | it('should mount correctly', () => { 13 | factory({}) 14 | cy.getByTestId('counter-pinia').contains('Counter Pinia: 0') 15 | cy.getByTestId('add-btn-pinia') 16 | .contains('Add pinia') 17 | .click() 18 | .contains('Add pinia') 19 | cy.getByTestId('counter-pinia').contains('Counter Pinia: 1') 20 | 21 | cy.getByTestId('counter').contains('Counter: 0') 22 | cy.getByTestId('add-btn') 23 | .contains('Add') 24 | .click() 25 | .contains('Add') 26 | cy.getByTestId('counter').contains('Counter: 1') 27 | }) 28 | 29 | it('should change locale correctly', () => { 30 | factory({}) 31 | cy.getByTestId('local').contains('Local') 32 | cy.getByTestId('toggle-button') 33 | .contains('Button Change Locale') 34 | .click() 35 | .contains('دکمه تغییر زبان') 36 | cy.getByTestId('local').contains('محلی') 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import 'prism-theme-vars/base.css'; 2 | @import 'prism-theme-vars/themes/vitesse-dark.css'; 3 | 4 | html:not(.dark) { 5 | --prism-foreground: #393A34; 6 | --prism-background: #F8F8F8; 7 | --prism-comment: #758575; 8 | --prism-namespace: #444444; 9 | --prism-string: #BC8671; 10 | --prism-punctuation: #80817D; 11 | --prism-literal: #36ACAA; 12 | --prism-keyword: #248459; 13 | --prism-function: #849145; 14 | --prism-deleted: #9A050F; 15 | --prism-class: #2B91AF; 16 | --prism-builtin: maroon; 17 | --prism-property: #CE9178; 18 | --prism-regex: #AD502B; 19 | } 20 | 21 | html.dark { 22 | --prism-foreground: #D4D4D4; 23 | --prism-background: #1E1E1E; 24 | --prism-comment: #758575; 25 | --prism-namespace: #444444; 26 | --prism-string: #CE9178; 27 | --prism-punctuation: #D4D4D4; 28 | --prism-literal: #36ACAA; 29 | --prism-keyword: #38A776; 30 | --prism-function: #DCDCAA; 31 | --prism-deleted: #9A050F; 32 | --prism-class: #4EC9B0; 33 | --prism-builtin: #D16969; 34 | --prism-property: #CE9178; 35 | --prism-regex: #AD502B; 36 | } 37 | 38 | body { 39 | margin: 0; 40 | font-family: 'Avenir', 'Helvetica', 'Arial', sans-serif; 41 | -webkit-font-smoothing: antialiased; 42 | -moz-osx-font-smoothing: grayscale; 43 | text-align: center; 44 | color: #2C3E50; 45 | } 46 | -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | logo 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [0.0.3](https://github.com/alibaba-aero/vue-boilerplate/compare/v0.0.2...v0.0.3) (2022-07-08) 6 | 7 | 8 | ### Features 9 | 10 | * **cypress:** add cypress for e2e and component testing ([#24](https://github.com/alibaba-aero/vue-boilerplate/issues/24)) ([a9b1d4f](https://github.com/alibaba-aero/vue-boilerplate/commit/a9b1d4f34f7332af52eafb815f976282a1d9ef4d)) 11 | * **deployment:** add dockerfile ([#2](https://github.com/alibaba-aero/vue-boilerplate/issues/2)) ([b244d59](https://github.com/alibaba-aero/vue-boilerplate/commit/b244d598d33ded914b5b5361f1232740b94d0719)) 12 | * **markdown:** add markdown support ([#27](https://github.com/alibaba-aero/vue-boilerplate/issues/27)) ([d188931](https://github.com/alibaba-aero/vue-boilerplate/commit/d18893150bf1ca17faf0dfa6c5c46989c75d37ec)) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **deps:** update dependency @vueuse/core to v8.9.0 ([#19](https://github.com/alibaba-aero/vue-boilerplate/issues/19)) ([f2bd2c5](https://github.com/alibaba-aero/vue-boilerplate/commit/f2bd2c56948884ded069c905f1ecf5708a3d10cf)) 18 | * **deps:** update dependency @vueuse/core to v8.9.1 ([#25](https://github.com/alibaba-aero/vue-boilerplate/issues/25)) ([e7cf90c](https://github.com/alibaba-aero/vue-boilerplate/commit/e7cf90c319c13dd47e55f7bc771c84863f85f324)) 19 | * **deps:** update dependency vue-router to v4.1.1 ([#14](https://github.com/alibaba-aero/vue-boilerplate/issues/14)) ([12da71c](https://github.com/alibaba-aero/vue-boilerplate/commit/12da71c82053c3bbfdc9c1a32ef27a9fab5c306a)) 20 | 21 | ### [0.0.2](https://github.com/alibaba-aero/vue-boilerplate/compare/v0.0.1...v0.0.2) (2022-07-01) 22 | 23 | ### 0.0.1 (2022-07-01) 24 | 25 | 26 | ### Features 27 | 28 | * initialize project ([0633a85](https://github.com/alibaba-aero/vue-boilerplate/commit/0633a855d86b1b76b1e33ee99212b1c08e6a32af)) 29 | -------------------------------------------------------------------------------- /src/components/HelloWorld/HelloWorld.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it, vi } from 'vitest' 2 | import type { MountingOptions } from '@vue/test-utils' 3 | import { createTestingPinia } from '@pinia/testing' 4 | import { fireEvent, render } from '@testing-library/vue' 5 | 6 | import Component from './HelloWorld.vue' 7 | 8 | const factory = (options?: MountingOptions) => render(Component, { 9 | global: { 10 | plugins: [createTestingPinia({ createSpy: vi.fn }), i18n], 11 | }, 12 | ...options, 13 | }) 14 | 15 | describe('HelloWorld', () => { 16 | it('shold mount correctly', async () => { 17 | const wrapper = factory({}) 18 | expect(wrapper).toBeTruthy() 19 | wrapper.unmount() 20 | }) 21 | 22 | it('shold add counter correctly', async () => { 23 | const wrapper = factory({}) 24 | const { getByTestId } = wrapper 25 | const counterElement = getByTestId('counter') 26 | const counterPiniaElement = getByTestId('counter-pinia') 27 | const addElement = getByTestId('add-btn') 28 | const addPiniaElement = getByTestId('add-btn-pinia') 29 | 30 | expect(counterElement.innerHTML).toBe('Counter: 0') 31 | await fireEvent.click(addElement) 32 | expect(counterElement.innerHTML).toBe('Counter: 1') 33 | 34 | expect(counterPiniaElement.innerHTML).toBe('Counter Pinia: 0') 35 | await fireEvent.click(addPiniaElement) 36 | expect(counterPiniaElement.innerHTML).toBe('Counter Pinia: 1') 37 | wrapper.unmount() 38 | }) 39 | 40 | it('shold change locale correctly', async () => { 41 | const wrapper = factory({}) 42 | const { getByTestId } = wrapper 43 | const toggleElement = getByTestId('toggle-button') 44 | const localElement = getByTestId('local') 45 | 46 | expect(toggleElement.innerHTML).toBe('Button Change Locale') 47 | expect(localElement.innerHTML).toBe('Local') 48 | await fireEvent.click(toggleElement) 49 | expect(toggleElement.innerHTML).toBe('دکمه تغییر زبان') 50 | expect(localElement.innerHTML).toBe('محلی') 51 | 52 | wrapper.unmount() 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /src/components/HelloWorld/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 53 | 54 | 68 | 69 | 70 | { 71 | "en": { 72 | "local": "Local", 73 | "changeLocale": "Change Locale", 74 | "couterPinia": "Counter Pinia:", 75 | "addPinia": "Add pinia", 76 | "counter": "Counter:", 77 | "add": "Add", 78 | "postCssTest": "PostCSS Styling test", 79 | "inner": "Inner" 80 | }, 81 | "fa": { 82 | "local": "محلی", 83 | "changeLocale": "تغییر زبان", 84 | "couterPinia": "شمارشگر پینیا:", 85 | "addPinia": "اضافه کردن پینیا", 86 | "counter": "شمارشگر:", 87 | "add": "اضافه کردن", 88 | "postCssTest": "PostCSS تست استایل", 89 | "inner": "درونی" 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "name": "vuilerplate", 4 | "private": true, 5 | "version": "0.0.3", 6 | "scripts": { 7 | "build": "vue-tsc --noEmit && MODE=production vite-ssg build", 8 | "coverage": "vitest run --coverage", 9 | "dev": "vite", 10 | "lint:js": "eslint . --ext .js,.ts,.vue", 11 | "lint:style": "stylelint '**/*.{scss,css,vue}'", 12 | "lint": "pnpm lint:js && pnpm lint:style", 13 | "release:stg": "standard-version -s -a --prerelease beta && git push --follow-tags", 14 | "release:prod": "standard-version -s -a && git push --follow-tags", 15 | "preview": "vite preview", 16 | "test": "vitest", 17 | "test:e2e": "cypress open", 18 | "prepare": "husky install", 19 | "typecheck": "vue-tsc --noEmit" 20 | }, 21 | "lint-staged": { 22 | "*.{js,ts,vue}": [ 23 | "eslint --ext .js,.ts,.vue --fix", 24 | "pnpm vitest related --run" 25 | ], 26 | "*.{scss,vue}": "stylelint --fix" 27 | }, 28 | "dependencies": { 29 | "@unocss/reset": "0.47.5", 30 | "@vueuse/core": "9.1.1", 31 | "@vueuse/head": "0.9.8", 32 | "@vueuse/schema-org": "1.0.2", 33 | "pinia": "2.0.22", 34 | "prism-theme-vars": "0.2.4", 35 | "vue": "3.2.40", 36 | "vue-i18n": "9.2.2", 37 | "vue-router": "4.1.5" 38 | }, 39 | "devDependencies": { 40 | "@antfu/eslint-config": "0.27.0", 41 | "@iconify-json/carbon": "1.1.11", 42 | "@intlify/eslint-plugin-vue-i18n": "2.0.0", 43 | "@intlify/vite-plugin-vue-i18n": "6.0.3", 44 | "@pinia/testing": "0.0.14", 45 | "@testing-library/cypress": "8.0.7", 46 | "@testing-library/jest-dom": "5.16.5", 47 | "@testing-library/vue": "6.6.1", 48 | "@typescript-eslint/parser": "5.40.0", 49 | "@vitejs/plugin-vue": "3.1.0", 50 | "@vitejs/plugin-vue-jsx": "2.0.1", 51 | "@vue/test-utils": "2.1.0", 52 | "c8": "7.12.0", 53 | "critters": "0.0.16", 54 | "cypress": "10.9.0", 55 | "eslint": "8.27.0", 56 | "eslint-config-airbnb": "19.0.4", 57 | "eslint-config-airbnb-typescript": "17.0.0", 58 | "eslint-plugin-cypress": "2.12.1", 59 | "eslint-plugin-jsx-a11y": "6.6.1", 60 | "eslint-plugin-vue": "9.6.0", 61 | "happy-dom": "6.0.4", 62 | "husky": "8.0.2", 63 | "jsdom": "20.0.0", 64 | "lint-staged": "13.0.3", 65 | "markdown-it": "13.0.1", 66 | "markdown-it-prism": "2.3.0", 67 | "postcss": "8.4.17", 68 | "postcss-html": "1.5.0", 69 | "postcss-import": "14.1.0", 70 | "postcss-nested": "5.0.6", 71 | "postcss-url": "10.1.3", 72 | "rollup-plugin-visualizer": "5.8.3", 73 | "standard-version": "9.5.0", 74 | "stylelint": "14.13.0", 75 | "stylelint-config-recommended-vue": "1.4.0", 76 | "typescript": "4.8.4", 77 | "unocss": "0.45.26", 78 | "unplugin-auto-import": "0.11.2", 79 | "unplugin-vue-components": "0.22.8", 80 | "vite": "3.0.9", 81 | "vite-plugin-compression": "0.5.1", 82 | "vite-plugin-istanbul": "3.0.1", 83 | "vite-plugin-pages": "0.26.0", 84 | "vite-plugin-pwa": "0.13.1", 85 | "vite-plugin-vue-layouts": "0.7.0", 86 | "vite-plugin-vue-markdown": "0.21.1", 87 | "vite-ssg": "0.21.1", 88 | "vite-ssg-sitemap": "0.4.3", 89 | "vite-svg-loader": "3.6.0", 90 | "vitest": "0.23.4", 91 | "vue-eslint-parser": "9.1.0", 92 | "vue-tsc": "0.40.13" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /.stylelintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: "stylelint-config-recommended-vue", 3 | rules: { 4 | "block-opening-brace-space-before": "always", 5 | "block-no-empty": true, 6 | "declaration-colon-space-after": "always", 7 | "max-empty-lines": 1, 8 | "color-no-invalid-hex": true, 9 | "font-family-no-duplicate-names": true, 10 | "function-calc-no-unspaced-operator": true, 11 | "string-no-newline": true, 12 | "unit-no-unknown": true, 13 | "property-no-unknown": true, 14 | "keyframe-declaration-no-important": true, 15 | "declaration-block-no-duplicate-properties": true, 16 | "declaration-colon-space-before": "never", 17 | "declaration-block-no-shorthand-property-overrides": true, 18 | "selector-pseudo-element-no-unknown": [true, { 19 | "ignorePseudoElements": ["deep"] 20 | }], 21 | "selector-type-no-unknown": true, 22 | "media-feature-name-no-unknown": true, 23 | "at-rule-no-unknown": [true, { 24 | "ignoreAtRules": [ 25 | "/^use/", 26 | "/^include/", 27 | "/^extend/", 28 | "/^mixin/", 29 | "/^if/", 30 | "/^else/", 31 | "/^function/", 32 | "/^return/", 33 | "/^for/", 34 | "/^each/", 35 | "tailwind", 36 | "apply", 37 | "variants", 38 | "screen" 39 | ] 40 | }], 41 | "comment-no-empty": true, 42 | "no-duplicate-at-import-rules": true, 43 | "no-empty-source": true, 44 | "no-extra-semicolons": true, 45 | "no-invalid-double-slash-comments": true, 46 | "color-named": "always-where-possible", 47 | "shorthand-property-no-redundant-values": true, 48 | "declaration-block-no-redundant-longhand-properties": [true, { 49 | "ignoreShorthands": ["/flex-flow/"] 50 | }], 51 | "declaration-block-single-line-max-declarations": 1, 52 | "selector-max-empty-lines": 0, 53 | "color-hex-case": "upper", 54 | "font-family-name-quotes": "always-unless-keyword", 55 | "function-comma-space-after": "always", 56 | "function-max-empty-lines": 0, 57 | "function-whitespace-after": "always", 58 | "number-no-trailing-zeros": true, 59 | "string-quotes": "single", 60 | "length-zero-no-unit": true, 61 | "unit-case": "lower", 62 | "value-keyword-case": ["lower", { 63 | "ignoreKeywords": ["IranSans"], 64 | "ignoreProperties": ["font-family", "filter"] 65 | }], 66 | "value-list-comma-space-after": "always-single-line", 67 | "property-case": "lower", 68 | "declaration-bang-space-after": "never", 69 | "declaration-bang-space-before": "always", 70 | "declaration-empty-line-before": "never", 71 | "declaration-block-semicolon-newline-after": "always-multi-line", 72 | "declaration-block-semicolon-space-after": "always-single-line", 73 | "declaration-block-trailing-semicolon": "always", 74 | "block-closing-brace-empty-line-before": "never", 75 | "block-closing-brace-newline-after": ["always", { 76 | "ignoreAtRules": ["if", "else"] 77 | }], 78 | "block-closing-brace-newline-before": "always-multi-line", 79 | "block-closing-brace-space-before": "always-single-line", 80 | "block-opening-brace-space-after": "always-single-line", 81 | "selector-attribute-brackets-space-inside": "never", 82 | "selector-attribute-operator-space-after": "always", 83 | "selector-attribute-operator-space-before": "always", 84 | "selector-attribute-quotes": "always", 85 | "selector-combinator-space-after": "always", 86 | "selector-combinator-space-before": "always", 87 | "selector-descendant-combinator-no-non-space": true, 88 | "selector-pseudo-class-case": "lower", 89 | "selector-pseudo-class-parentheses-space-inside": "never", 90 | "selector-pseudo-element-case": "lower", 91 | "selector-pseudo-element-colon-notation": "double", 92 | "selector-type-case": "lower", 93 | "selector-list-comma-space-after": "always-single-line", 94 | "selector-list-comma-space-before": "never", 95 | "media-feature-colon-space-after": "always", 96 | "media-feature-colon-space-before": "never", 97 | "media-feature-name-case": "lower", 98 | "media-feature-parentheses-space-inside": "never", 99 | "media-feature-range-operator-space-after": "always", 100 | "media-feature-range-operator-space-before": "always", 101 | "media-query-list-comma-newline-after": "never-multi-line", 102 | "at-rule-name-case": "lower", 103 | "at-rule-name-space-after": "always", 104 | "at-rule-semicolon-newline-after": "always", 105 | "comment-whitespace-inside": "always", 106 | "indentation": 2, 107 | "no-eol-whitespace": true, 108 | "no-missing-end-of-source-newline": true, 109 | "no-empty-first-line": true, 110 | "comment-empty-line-before": "always", 111 | "number-leading-zero": "always" 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import path from 'path' 3 | import { defineConfig } from 'vitest/config' 4 | import Vue from '@vitejs/plugin-vue' 5 | import Layouts from 'vite-plugin-vue-layouts' 6 | import { VitePWA } from 'vite-plugin-pwa' 7 | import Pages from 'vite-plugin-pages' 8 | import Components from 'unplugin-vue-components/vite' 9 | import AutoImport from 'unplugin-auto-import/vite' 10 | import VueJsx from '@vitejs/plugin-vue-jsx' 11 | import { visualizer as Visualizer } from 'rollup-plugin-visualizer' 12 | import ViteCompression from 'vite-plugin-compression' 13 | import Markdown from 'vite-plugin-vue-markdown' 14 | import Prism from 'markdown-it-prism' 15 | import VueI18n from '@intlify/vite-plugin-vue-i18n' 16 | import SvgLoader from 'vite-svg-loader' 17 | import Unocss from 'unocss/vite' 18 | import generateSitemap from 'vite-ssg-sitemap' 19 | import istanbul from 'vite-plugin-istanbul'; 20 | 21 | function removeDataTestAttrs(node: any) { 22 | if (node.type === 1 /* NodeTypes.ELEMENT */) { 23 | node.props = node.props.filter((prop: any) => 24 | prop.type === 6 /* NodeTypes.ATTRIBUTE */ 25 | ? prop.name !== 'data-testid' 26 | : true 27 | ) 28 | } 29 | } 30 | // https://github.com/antfu/unplugin-icons 31 | // for our icons 32 | 33 | // https://vitejs.dev/config/ 34 | export default defineConfig(({ command }) => ({ 35 | resolve:{ 36 | alias:{ 37 | '@' : path.resolve(__dirname, './src'), 38 | '@/utils': path.resolve(__dirname, './src/utils') 39 | }, 40 | }, 41 | build: { 42 | sourcemap: true 43 | }, 44 | plugins: [ 45 | Vue({ 46 | include: [/\.vue$/, /\.md$/], 47 | reactivityTransform: true, 48 | template: { 49 | compilerOptions: { 50 | nodeTransforms: process.env.MODE === 'production' ? [removeDataTestAttrs] : [], 51 | } 52 | } 53 | }), 54 | Pages({ 55 | extensions: ['vue', 'md'], 56 | }), 57 | Components({ 58 | extensions: ['vue', 'md', 'tsx', 'jsx'], 59 | include: [/\.vue$/, /\.vue\?vue/, /\.md$/], 60 | dts: 'src/components.d.ts', 61 | }), 62 | Layouts(), 63 | VitePWA({ 64 | registerType: 'autoUpdate', 65 | includeAssets: ['favicon.svg', 'safari-pinned-tab.svg'], 66 | manifest: { 67 | name: 'Alibaba Travels', 68 | short_name: 'Alibaba', 69 | theme_color: '#FDB713', 70 | icons: [ 71 | { 72 | src: '/android-chrome-192x192.png', 73 | sizes: '192x192', 74 | type: 'image/png', 75 | }, 76 | { 77 | src: '/android-chrome-512x512.png', 78 | sizes: '512x512', 79 | type: 'image/png', 80 | }, 81 | { 82 | src: '/maskable-icon-x512.png', 83 | sizes: '512x512', 84 | type: 'image/png', 85 | purpose: 'maskable', 86 | }, 87 | { 88 | src: '/maskable-icon-x192.png', 89 | sizes: '192x192', 90 | type: 'image/png', 91 | purpose: 'maskable', 92 | }, 93 | ], 94 | }, 95 | }), 96 | AutoImport({ 97 | imports: [ 98 | 'vue', 99 | 'vue/macros', 100 | 'vue-router', 101 | '@vueuse/head', 102 | '@vueuse/core', 103 | 'pinia', 104 | 'vue-i18n', 105 | // 'vitest', 106 | ], 107 | dts: 'src/auto-imports.d.ts', 108 | dirs: [ 109 | 'src/composables', 110 | 'src/store', 111 | 'src/utils' 112 | ], 113 | vueTemplate: true, 114 | }), 115 | VueJsx({ optimize: true }), 116 | ...(command === 'build' 117 | ? [Visualizer({ filename: `stats.html` })] 118 | : [] 119 | ), 120 | ...(process.env.COMPRESS !== '0' 121 | ? [ViteCompression({}), ViteCompression({ algorithm: 'brotliCompress', ext: '.br' })] 122 | : [] 123 | ), 124 | Markdown({ 125 | wrapperClasses: 'markdown-wrapper', 126 | headEnabled: true, 127 | markdownItOptions: { 128 | html: true, 129 | linkify: true, 130 | typographer: true, 131 | }, 132 | markdownItSetup(md) { 133 | md.use(Prism) 134 | }, 135 | }), 136 | VueI18n({ 137 | include: path.resolve(__dirname, './src/locales/**'), 138 | }), 139 | SvgLoader({ 140 | svgo: true, 141 | svgoConfig: { 142 | multipass: true, 143 | plugins: [ 144 | { 145 | name: 'preset-default', 146 | params: { 147 | overrides: { 148 | inlineStyles: { 149 | onlyMatchedOnce: false, 150 | }, 151 | }, 152 | }, 153 | }, 154 | ], 155 | } 156 | }), 157 | Unocss(), 158 | istanbul({ 159 | include: 'src/*', 160 | exclude: ['node_modules', 'test/'], 161 | extension: [ '.js', '.ts', '.vue' , '.tsx'], 162 | requireEnv: true, 163 | }), 164 | ], 165 | server: { 166 | port: 5173, 167 | host: '127.0.0.1' 168 | }, 169 | ssgOptions: { 170 | script: 'async', 171 | formatting: 'minify', 172 | onFinished() { generateSitemap() }, 173 | }, 174 | ssr: { 175 | // TODO: workaround until they support native ESM 176 | noExternal: ['workbox-window', /vue-i18n/], 177 | }, 178 | test: { 179 | // environment: 'jsdom', 180 | environment: 'happy-dom', 181 | deps: { 182 | inline: ['@vue', '@vueuse', 'vue-demi'], 183 | }, 184 | outputFile: { 185 | json: './coverage/final.json', 186 | junit: './coverage/junit.xml', 187 | }, 188 | reporters: ['verbose', 'junit', 'json'], 189 | coverage: { 190 | clean: false, 191 | }, 192 | }, 193 | })) 194 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Alibaba Travels Vue 3 starter package with vite 2 | - Check Vitesse 3 |

4 | 5 | ## Features 6 | 7 | - ⚡️ [Vue 3](https://github.com/vuejs/core), [Vite 2](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [ESBuild](https://github.com/evanw/esbuild) 8 | 9 | - 🗂 [File based routing](./src/pages) 10 | 11 | - 📑 [Layout system](./src/layouts) 12 | 13 | - 📦 [Components auto importing](./src/components) 14 | 15 | - 📥 [APIs auto importing](https://github.com/antfu/unplugin-auto-import) - use Composition API and others directly 16 | 17 | - 📐 [JSX Support](https://www.npmjs.com/package/@vitejs/plugin-vue-jsx) 18 | 19 | - 🍍 [State Management via Pinia](https://pinia.vuejs.org/) 20 | 21 | - ⚖️ [Rollup Visualizer](https://github.com/btd/rollup-plugin-visualizer) 22 | 23 | - 🗜️ [File compression](https://github.com/vbenjs/vite-plugin-compression) - Use `gzip` or `brotli` to compress resources. 24 | 25 | - 🌍 [Vue i18n](https://github.com/intlify/vue-i18n-next) 26 | 27 | - 📲 [PWA](https://github.com/antfu/vite-plugin-pwa) 28 | 29 | - 📩 [Markdown Support](https://github.com/antfu/vite-plugin-md) 30 | 31 | - 🖨 Static-site generation (SSG) via [vite-ssg](https://github.com/antfu/vite-ssg) 32 | 33 | - 🦔 Critical CSS via [critters](https://github.com/GoogleChromeLabs/critters) 34 | 35 | - 💡 [PostCSS](https://postcss.org/) 36 | 37 | - ⚙️ Unit testing with [Vitest](https://github.com/vitest-dev/vitest) 38 | 39 | - ⚙️ E2E and component testing with [Cypress](https://www.cypress.io/) 40 | 41 | - 🦾 TypeScript 42 | 43 | - 🔥 Use the [new `