Skip to content

Latest commit

 

History

History
1373 lines (982 loc) · 31.7 KB

README_EN.md

File metadata and controls

1373 lines (982 loc) · 31.7 KB

dishait https://pc.dishait.cn/

vite + vue3 + ts out-of-the-box modern development template



Features 🐳

  1. Vite-based
  2. Vue3-compatible
  3. File-based routing
  4. Layout system
  5. Mock support
  6. Auto import APIs
  7. Auto import components
  8. Auto import icons
  9. VueUse support
  10. TypeScript-friendly
  11. UnoCss integration
  12. Dark mode support
  13. SWR request support
  14. Pinia state management
  15. pnpm package manager
  16. Progress bar for navigation
  17. Devtools panel support
  18. Plugin auto-loading support
  19. Vitest unit testing support
  20. Markdown rendering support
  21. Path aliases support
  22. Command line auto creation and deletion
  23. i18n internationalization support
  24. Beautiful 404 page support
  25. TSX support
  26. Gzip resource compression support
  27. Environment variable configuration support
  28. Unified code style and formatting support
  29. Production environment automatically removes development logs
  30. defineOptions support
  31. Echarts integration
  32. Global toast notifications
  33. Global axios request wrapping
  34. Auto generate type declarations for environment variables
  35. renovate automatic dependency updates
  36. Auto version update and generate CHANGELOG
  37. Fastest and smallest dockerfile for static go service with minimal configuration
  38. base secure path resolution
  39. lightningcss support
  40. Vite configuration layer support (experimental)


Clone Template 🦕

  1. Github
git clone git@github.com:dishait/tov-template.git
  1. Gitee
git clone git@gitee.com:dishait/tov-template.git
  1. degit
npx degit https://github.com/dishait/tov-template#main
  1. New Github repository 👉 Use this template



Node version recommendation 🐎

Since this template is fully geared towards modern development, it is recommended to use the current long-term maintenance version of node, which is v20.




Use 🐂

This template only supports the pnpm package manager. 👉 Installation guide

  1. Install dependencies
pnpm install
  1. Development
pnpm dev

# Open host
pnpm dev:host

# Auto-open browser
pnpm dev:open
  1. Preview
pnpm preview

# Open host
pnpm preview:host

# Auto-open browser
pnpm preview:open
  1. Build
pnpm build

pnpm build:debug
  1. Unit testing
pnpm test
  1. Unit test report generation
pnpm coverage
  1. Type checking
pnpm typecheck
  1. Auto creation
pnpm auto:create
  1. Auto removal
pnpm auto:remove
  1. Dependency updates
# Update dependency version
pnpm deps:fresh
# The above commands only write to the package information file package.json, and need to re-execute the package installation command.
pnpm i
  1. Code style checking
pnpm lint

# Fix errors during linting
pnpm lint:fix
  1. Safe Init
pnpm safe:init


Motivation 🐗

Why did we create this template?

  1. Save time on configuration for future development projects.
  2. Integrate modern development architecture with mainstream plugins to improve development efficiency.


Use Cases 🐻

When should you use this template?

  1. Don't want to waste time on project configuration.
  2. Want to try developing web applications in a more modern way and improve development efficiency.


Inspiration 🐃

This template is inspired by vitesse. If you have an SSR scenario, we recommend that you use vitesse.



Organization 🦔

Welcome to follow dishait

Details 🐳

This template uses Vite as the build tool. You can configure the project's build in vite.config.ts at the root directory.

For the introduction of many mainstream plugins and complex configurations, they have been integrated into the presets under the root directory. In most cases, you do not need to reconfigure them.



The directory structure is the route.

For example:

  • src/pages/index.vue => /
  • src/pages/about.vue => /about
  • src/pages/users/index.vue => /users
  • src/pages/users/profile.vue => /users/profile
  • src/pages/users/[id].vue => /users/:id
  • src/pages/[user]/settings.vue => /:user/settings
  • src/pages/[...notFound].vue => 404 route

For more details, please refer to unplugin-vue-router.


Default Layout

src/layouts/default.vue will be used as the default layout.

<!-- src/layouts/default.vue -->
<template>
    default
    <router-view />
    <!-- Page view outlet -->
</template>

At this point, src/pages/index.vue:

<!-- src/pages/index.vue -->
<template>
    <div>home</div>
</template>

When routing to /, the page will render:

default home

Now, src/pages/about.vue:

<!-- src/pages/about.vue -->
<template>
    <div>about</div>
</template>

When routing to /about, the page will render:

default about

Non-Default Layout

Create a src/layouts/custom.vue randomly:

<!-- src/layouts/custom.vue -->
<template>
    custom
    <router-view />
    <!-- Page view outlet -->
</template>

At this point, in src/pages/index.vue:

<!-- src/pages/index.vue -->
<template>
    <div>home</div>
</template>

<!-- Add custom block &#128071; -->
<route lang="json">
{
    "meta": {
        "layout": "custom"
    }
}
</route>

When routing to /, the page will render:

custom home

See specifically 👉 vite-plugin-vue-meta-layouts


In the mock directory under the root directory, you can export default api resources in modules.

For example, export from mock/test.ts:

import { MockMethod } from "vite-plugin-mock";
export default [
  {
    url: "/api/mock/get",
    method: "get",
    response: () => {
      return {
        code: 0,
        data: {
          name: "vben",
        },
      };
    },
  },
] as MockMethod[];

You can then make mock requests in the src directory.

<template>
  <div>data: {{data}}</div>
  <div>loading: {{loading}}</div>
  <div>error: {{error}}</div>
</template>

Here we use vue-request to make requests, but since this mock intercepts an entire interface, it is also possible to use request libraries such as axios.


The original vue api needs to be manually imported.

import { computed, ref } from "vue";
const count = ref(0);
const doubled = computed(() => count.value * 2);

Now it can be directly used.

const count = ref(0);
const doubled = computed(() => count.value * 2);

And the above api is automatically imported on demand.

Currently, the template supports automatic import of libraries that support auto-importing api.

  • vue
  • vuex
  • pinia
  • vue-i18n
  • vue-router
  • @vueuse/core
  • @vueuse/head
  • @vueuse/math

Just make sure to install the dependencies and see the specific details here 👉 vite-auto-import-resolvers,

Of course, there are also automatic imports in projects, just need to meet the following specifications.

  1. The export from src/composables will be automatically imported as needed.

For example, there is a src/composables/foo.ts file:

// default export
export default 1000;
  1. No need for import at this point.
<script setup lang="ts">
	console.log(foo) // output 1000
</script>

<template>
  <div @click="store.inc()">{{store.counter}}</div>
</template>
  1. The export from src/stores will be automatically imported as needed.

For example, there is a src/stores/counterStore.ts file:

// default export
export default defineStore("counter", {
  state() {
    return {
      counter: 1,
    };
  },
  actions: {
    inc() {
      this.counter++;
    },
  },
});

At this point, there is no need for import anymore.

<script setup lang="ts">
	const store = counterStore()
</script>

<template>
	<div @click="store.inc()">{{store.counter}}</div>
</template>
  1. src/api is also automatically imported on demand, similar to the above.

You can see more details in the unplugin-auto-import documentation.


It turns out that import is required.

<!-- src/pages/index.vue -->
<script setup lang="ts">
	import Hello from '../components/Hello.vue'
</script>

<template>
	<Hello />
</template>

Now, any components defined in the src/components directory will be automatically imported on demand, meaning that import statements are not required.

<!-- src/pages/index.vue -->
<template>
	<Hello />
</template>

Of course, it also supports nested components, such as src/components/foo/bar.vue 👇

<!-- src/pages/index.vue -->
<template>
	<FooBar />
</template>

Automatic importing of popular component libraries is also supported, such as Naive ui.

You only need to install the dependency.

pnpm add naive-ui

Then you can use it in your templates.

<!-- src/pages/index.vue -->
<template>
	<n-button type="success">Success</n-button>
</template>

Currently supported component libraries are:

Please refer to 👉 unplugin-vue-components


You can go to icones and click on any icon library you like.

icons-first-step

Then click on one of the icons you like.

icons-second-step

Copy its name.

icons-third-step

In the template, you can use it directly through the class method, remember to add the prefix i-.

<template>
	<div class="i-mdi:account-box-multiple"></div>
</template>

After saving, wait for the automatic download of theAfter saving, wait for the automatic download of the icon library and you can see the corresponding icon in the page.

I also recommend using the vscode plugin Iconify IntelliSense.

This plugin displays a preview of the icons in the template.

Of course, dynamic loading of icons is also supported:

<script>
	const icon = ref("i-ep:arrow-left")

	// Change to another icon after two seconds.
	setTimeout(() => {
		icon.value = 'i-icon-park-outline:arrow-circle-down'
	}, 2000)
</script>

<template>
	<div :class="icon"></div>
</template>

Please note that for dynamic icons, make sure to test all the icons in the development environment.

For more information, please refer to unocss/presets/icons.


VueUse is a powerful hooks library. For example, if you want to get the mouse position, you only need to do this:

<script setup lang="ts">
	// The `useMouse` hook is automatically imported on demand, so thereThe `useMouse` hook is automatically imported on demand, so there's no need for an `import` statement.
	const { x, y } = useMouse()
</script>

<template>
	<div>x {{x}}</div>
	<div>y {{y}}</div>
</template>

Please refer to 👉 VueUse


You don't need to reconfigure, just write it in ts directly.


unocss is a faster development atomic CSS library.

You can use it directly in the template, no configuration is needed.

<template>
	<div class="bg-red-500 text-white">I am white text on a red background.</div>
</template>

The above template will render white text on a red background.

It also supports attribute mode, which means you can use shorthand notation.

<template>
	<div text="white" bg="red-500">I am white text on a red background.</div>
</template>

This can reduce the amount of code when adjusting margin sizes, among other things.

For more information, please refer to unocss.


Dark mode is implemented by vue-dark-switch.

<script setup>
import { SwitchIcon } from "vue-dark-swicth"
</script>

<template>
	<!-- Dark switch, one-click to switch to dark mode. -->
	<SwitchIcon /> 
</template>

Please refer to 👉 vue-dark-switch


SWR is a more modern way of making requests, for more information please refer to the article 👉 SWR.

And vue-request is a Vue version request library for SWR.

You can use it like this, for example, to request /api/test

<script setup lang="ts">
	import { useRequest } from 'vue-request'
	const { data, loading, error } = useRequest('/api/test')
</script>

<template>
	<div>data: {{data}}</div>
	<div>error: {{error}}</div>
	<div>loading: {{loading}}</div>
</template>

All the basic data, state, and caching are handled for you, so there's no need to re-wrap things.

For more information, please refer to vue-request.


Pinia is the next-generation state management library, which is simpler than Vuex and has better TypeScript support.

You can define your states in the src/stores directory.

For example, create a src/stores/counter.ts file:

// src/stores/counter.ts
import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", {
  state() {
    return { count: 0 };
  },
  actions: {
    inc() {
      this.count++;
    },
  },
});

After defining it, you can use it directly in the setup.

<!-- src/pages/index.vue -->
<script setup lang="ts">
    const Counter = useCounterStore()
<script>

<template>
    <div @click="Counter.inc">{{Counter.count}}</div>
</template>

For more specific usage, please refer to Pinia.


pnpm is an excellent package manager that is faster, more space-efficient, and more reasonable.

For more information, please refer to pnpm.

The jumping progress bar is implemented by nprogress, and you can adjust the color scheme in src/styles/main.css.

/** src/styles/main.css **/

/** Omit other styles. **/
#nprogress .bar {
	@apply bg-blue-700 bg-opacity-75; /** color **/

	position: fixed;
	z-index: 1031;
	top: 0;
	left: 0;

	width: 100%;
	height: 2px;
}

About @apply, it is implemented by @unocss/transformer-directives.

For more information, please refer to 👉 nprogress.


17. Development panel support

This panel allows you to understand various aspects of the project during development, and it is currently only effective in the development environment.

For more information, please refer to vite-plugin-vue-devtools.


You only need to export the default function in the module located in src/plugins.

For example, with pinia, you only need to do this:

// src/plugins/pinia.ts
// Export the default interface
export default createPinia(); // pinia will be automatically installed

Or with vue-router:

// src/plugins/router.ts
// Omit various configurations

// Export the default interface
export default router; // The router will be automatically installed

Of course, pinia and vue-router are already preset, so you don't need to worry about them again.

For more information, please refer to vite-plugin-use-modules.


You can write unit tests in the src/test directory.

import { assert, describe, expect, it } from "vitest";

describe("suite name", () => {
  it("foo", () => {
    expect(1 + 1).toEqual(2);
    expect(true).to.be.true;
  });

  it("bar", () => {
    assert.equal(Math.sqrt(4), 2);
  });

  it("snapshot", () => {
    expect({ foo: "bar" }).toMatchSnapshot();
  });
});

Then you can run the tests by entering the following command in the terminal:

pnpm test

Or generate a report:

pnpm coverage

For more information, please refer to Vitest.


Markdown rendering can be used to write some simple instructions.

You only need to change the file extension of pages in the src/pages directory from .vue to .md, and then modify it to use markdown syntax.

For example, src/pages/about.md:

## About Page

> The page is a markdown file

When you route to /about, you can see the corresponding markdown rendering.

Of course, it also supports embedding Vue components in markdown.

For more information, please refer to unplugin-vue-markdown.


21. Path Alias Support

The ~ or @ path will be directed to the src directory of the project, while providing better type hinting.

<!-- src/pages/index.vue -->
<script lang="ts" setup>
	import { useDarks } from '~/composables/dark'

	// Is equivalent to
	// import { useDarks } from "../composables/dark"
</script>


22. Command Line Auto Create and Remove

To create a standard page or component just enter 👇,

pnpm auto:create

Of course, you can also delete 👇,

pnpm auto:remove


In daily business, there may be some scenarios that require internationalization. Then you only need to define different languages' yml in the locales directory at the root level to achieve out-of-the-box internationalization support in the project.

For example, locales/en.yml is used to define the English content that requires internationalization support.

# locales/en.yml
# English

index: index
about: about
not-found: Notfound

For example, locales/简体中文.yml is used to define the Chinese content that requires internationalization support.

# locales/简体中文.yml
# 中文

index: 主页
about: 关于
not-found: 未找到页面

You can use it in components like this at this time 👇

<script setup>
	// This API is globally imported on demand, so it can be used directly.
	// t is used to bind specific language blocks.
	const { t, locale } = useI18n()

	const toggleLocale = () => {
		// locale.value is used to represent the current language, and it can be modified for language switching.
		locale.value = locale.value === '简体中文' ? 'en' : '简体中文'
	}
</script>

<template>
	<div m="6" cursor="pointer" @click="toggleLocale()">
		language: {{ t('index') }} click me!!
	</div>
</template>

For more detailed instructions, please refer to the @intlify/vite-plugin-vue-i18n and vue-i18n.

In addition, yml is a popular configuration file format in frontend development, and you can find its syntax in Mr. Ruan Yifeng's tutorial: YAML Language Tutorial.

Here are some recommended VS Code plugins:



For more detailed instructions, please refer to the @intlify/vite-plugin-vue-i18n and vue-i18n.

In addition, yml is a popular configuration file format in frontend development, and you can find its syntax in Mr. Ruan Yifeng's tutorial: YAML Language Tutorial.

Here are some recommended VS Code plugins:

Multifunctional i18n support: i18n Ally



24. Beautiful 404 Page Support

In daily business, when a user visits a non-existent page, they should be given an information prompt that the page does not exist, and this prompt page is the 404 page.

You can visit any non-existent page at random, for example /bucunzai

notFound

Of course, there is also dark mode adaptation.

notFound-dark

It also supports simple responsive adaptation. For example, it will display correctly on mobile browsers.

If the cover of this 404 page does not meet your taste, you can modify the src attribute of the img tag in pages/[...notFound].vue. The default is 32.svg, supporting 1 ~ 33 svg.

For example, the default is:

<!-- Omitting various codes -->
<template>
	<img src="/notFound/32.svg" class="cover" alt="page not found" />
</template>

To change the cover to /notFound/33.svg, modify it as follows:

<!-- Omitting various codes-->
<template>
	<img src="/notFound/33.svg" class="cover" alt="page not found" />
</template>

This will switch the cover to:

notFound-other



You only need to place the .tsx file under src/components, and you can directly use it in the template.

For example, if you have a src/components/foo.tsx file, you can directly use it in the template.

// src/components/foo.tsx
export default defineComponent({
  render() {
    return <div>Test</div>;
  },
});
<template>
	<foo />
</template>

For more details, please refer to: @vitejs/plugin-vue-jsx



Out-of-the-box gzip resource compression in production environment, no configuration required.

For more details, please refer to: vite-plugin-compression



The .env file in the root directory is used to configure environment variables for the project.



28. Unified Code Standards and Style Support

Code style verification provided by eslint and code standardization using prettier.

Provided by husky + lint-staged during commit verification.



In the production environment, logs such as console.log, console.warn, and console.error will be automatically removed to avoid the leakage of development logs.

For more details, please refer to: vite-plugin-removelog



<script setup lang="ts">
	// Define additional options
	defineOptions({
		name: 'Foo',
	})
</script>


A simple integration with vue-echarts, please refer to the documentation of echarts and vue-echarts.



Integrated with vue-toastification, you can use it in all files under the src directory:

// Any file under the `src` directory is available.
toast.info("info");
toast.error("error");
toast.warning("warning");
toast.success("success");

For more details, please refer to: Global Toast Notification



The axios is wrapped, and you can use it in all files under the src directory:

// Available in any file under src
http.get("...");
http.post("...", { name: "张三", age: 20 });
// ... and so on

The above http is an instance created separately by axios, with simple error prompts and response data conversion. For more details, please refer to src/composables/http.ts.

If you prefer a reactive style and swr, you can use it together with vue-request.

import { useRequest } from "vue-request";

const { data, error, loading } = useRequest(() => http.get("..."));

loading.value; // loading

error.value; // error

data.value; // data

The http instance's baseURL takes the value from the environment variable file .env for VITE_API_BASE_URL, defaulting to /api, which can be changed according to your needs.

For more details, please refer to 👉 axios.



In Vite projects, we can set environment variables in .env and use them in the frontend source code through import.meta.env, but the type hinting is poor. This feature can automatically generate type declarations to achieve real-time type hinting, so you don't need to worry about and manage them manually.

For more details, please refer to: vite-plugin-env-types.



The renovate bot on GitHub will periodically check dependencies on GitHub and raise a pr to update the repository, with the update strategy available at: unjs/renovate-config.

Of course, you can also manually execute it to update:

pnpm deps:fresh

For more details, please refer to: renovate



When we execute pnpm run release, it will automatically update the version and update the CHANGELOG.md file.

For more details, please refer to: unjs/changelogen.



The dockerfile in the root directory configures the smallest and fastest container for a static go service, making it more convenient for cloud container services.

For more details, please refer to: PierreZ/goStatic.



38. Base Secure Path Resolution

In Vite, if we change the base in vite.config.ts, it causes the resource paths and route paths to become invalid. Using safeResolve can ensure that the same base is used in both development and production environments.

<script setup lang="ts">
const path = safeResolve("your route path")
</script>

<template>
	<!-- Applications in templates are also allowed. -->
	<img :src="safeResolve('/notFound/32.svg')"/>
</template>


39. lightningcss Support

Now it will automatically detect whether the current project supports lightningcss and enable it intelligently.



40. Vite Config Layer Support (Experimental)

Now in tov-template, we can use the form of vite.config.[mode].ts to support configuration files for different environments.

  1. Only vite.config.ts is selected when there is no specific mode.
  2. When both vite.config.ts and vite.config.dev.ts exist, their configurations are merged during development, with the configuration in vite.config.dev.ts having higher priority.
  3. When both vite.config.ts and vite.config.prod.ts exist, their configurations are merged during production, with the configuration in vite.config.prod.ts having higher priority.

This feature is supported by vite-layers.




License

Made with markthree

Published under MIT License.