This is the third day of my participation in the More text Challenge. For details, see more text Challenge
preface
Since the release of the official version of Vue3, the project began to use Vue3+TS+Vite mode, Vite fast is really let people can no longer give up, no longer need to change a line of code waiting for half a day, this TM is really too happy, development happiness index directly dry full. (a. ^ – ^ -)
The following is a record of the recent development of the Vue3+TS+Vite model, and a summary here. If you have any other strange problems, please feel free to comment in the comments section.
Tips/questions summary
Volar plug-in
Recommend a VSCode plug-in, Volar is an official plug-in for the creation of Vue, in the fourth VueConf in yu Yu Creek has made a recommendation.
Lucky for those who use VSCode, it’s only around 21000 downloads now, but I think it will increase in the future. Because it is really very powerful, especially in Vue3 and some of Vue’s new RFC has a good fit and timely update.
The installation method is very simple, directly in vsCode plug-in market search Volar, and then click install can be, the specific use of their own experience slowly.
The TS type specification for props is provided in Vue3
It is very important to specify the data types required in a component, so that the component can be maintainable. Let’s try to specify the three common cases of objects, arrays, and functions.
Writing a
When using Vue3+TS to perform complex type validation for props, you can cast it directly with the PropType attribute provided by Vue:
Vue <script lang='ts'> import {defineComponent, PropType} from 'vue' interface IGoods {id: number; goodsName: string; } interface IFun {(): IGoods} export default defineComponent({props: {// object goods: {required: true, type: : // Array list: {required: true, type: Object as PropType<IGoods[]>}, // function getInfo: { required: true, type: Function as PropType<IFun> } } }) </script>Copy the code
Write two
It can also be written as a function:
Import {defineComponent} from 'vue' interface IGoods {id: number; goodsName: string; } interface IFun { (): IGoods } export default defineComponent({ props: { goods: { required: true, type: Object as () => IGoods }, list: { required: true, type: Array as () => IGoods[] }, getInfo: { required: true, type: Function as unknown as () => IFun } } }) </script>Copy the code
How do I mount global methods in Vue3
In the Vue2 project, we can often see scenes like this:
$dateFormat = () => {console.log(' date conversion method ')}; $dateFormat(); $dateFormat();Copy the code
Almost all Vue2 projects will have some global variables and methods directly mounted on the Vue prototype, which makes it easier to use this call. But there is no this in Vue3!! There is no this in Vue3!! There is no this in Vue3!! (Say important things three times)
globalProperties
Although Vue3 is compatible with Vue2, we can still use this, but only in the original Option API, not in the new Composition API. Vue3 is not recommended to work on the prototype, but in order to smooth the transition for users who want to upgrade Vue2 to Vue3, yuxi has also introduced the globalProperties solution instead of vue. prototype.
How to mount global methods:
// main.ts import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) App. Config. GlobalProperties $dateFormat = () = > {the console. The log (' date conversion method ')}; app.mount('#app')Copy the code
Specific use:
<script lang="ts"> import {defineComponent, onMounted, getCurrentInstance} from 'vue' export default defineComponent({ // Options API mounted() { this.$dateFormat() }, // Composition API setup() { const { proxy } = getCurrentInstance()! ; onMounted(() => { proxy.$dateFormat() }) return {} } }) </script>Copy the code
The above shows how the Option API and Composition API get global methods, respectively.
The getCurrentInstance() method is used to access the internal component instance, which has many methods attached to it. We can access the global methods mounted to it through its proxy property. There is also an alternative way to access globalProperties:
const { $dateFormat } = getCurrentInstance()! .appContext.config.globalProperties; $dateFormat();Copy the code
One thing to note here is that I’ve seen a lot of articles on the web that access something mounted on globalProperties in the form const {CTX} = getCurrentInstance(); ctx.$dateFormat(); However, this method can only be used in the development environment. CTX in the production environment will not have access to globalProperties. Yes, an error will be reported. Uncaught TypeError: CTX.$dateFormat is not a function Uncaught TypeError: CTX.$dateFormat is not a function
It is not recommended to use the globalProperties method as an alternative to the vue. prototype method in the Composition API. Check out this VUE/RFCS for details.
While Vue3 does not recommend how to mount some variables or methods, it does recommend using the provide() and inject() forms of dependency injection.
provide()/inject()
Bind dependencies using project() :
import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.provide('$dateFormat', () = > {the console. The log (' date conversion method ')}) app. Mount (' # app)Copy the code
Use inject() to obtain:
<script lang="ts">
import {defineComponent, inject} from 'vue'
export default defineComponent({
setup() {
const $dateFormat: (() => void) | undefined = inject('$dateFormat')
$dateFormat && $dateFormat()
return {}
}
})
</script>
Copy the code
Provide /inject is simple to use, but it is important to note that both can only be invoked during setup() of the current active instance. Am I
A plug-in for dynamic HTML content in Vite
In the project of building a use vue – cli, the default provide us with % > < % = htmlWebpackPlugin. The options. The title in the form of a dynamic insert content as HTML. The process is to use the HtmlWebpackPlugin provided by WebPack to replace the template variable with the actual title value when compiling.
In Vite, it’s very easy to do this, and we can easily do it with the help of v-plugin-html.
Installation:
npm install vite-plugin-html -D
Copy the code
Configuration:
// vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { injectHtml } from 'ite-plugin-html' export default defineConfig({plugins: [vue(), injectHtml({injectData: {title:' user management system '}}),})Copy the code
In particular, the dynamic variable syntax is much simpler:
// index.html <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" href="/favicon.ico" /> <meta name="viewport" content="width=device-width, Initial scale = 1.0 "/ > < title > < % = title % > < / title > < / head > < body > < div id =" app "> < / div > < script type =" module" src="/src/main.ts"></script> </body> </html>Copy the code
For more configuration details, check out the ite-plugin-html document. (a. ^ – ^ -)
Problem with configuring project alias “@” in Vite
Project alias configuration is now an essential part of the project, because the project uses Vite to build, Vite documentation also describes the alias configuration, we first according to the document to configure.
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
}
})
Copy the code
Simple, isn’t it? (^ ^) omega
Let’s assume that we introduce a CSS file and a TS file:
Uh… ????? The red! But the imported style works, and the methods in the imported TS file can be called as normal.
Because esLint is using esLint, we suspect that esLint does not recognize the project alias, so we should modify its configuration. There are a number of ways to resolve esLint’s failure to recognize project aliases, so let’s go ahead and select the most violent one and turn off its associated ESLint rules:
// .eslintrc.js module.exports = { env: { browser: true, es2021: true }, extends: ['plugin:vue/essential', 'airbnb-base', 'plugin:prettier/recommended'], parserOptions: { ecmaVersion: 12, parser: '@typescript-eslint/parser', sourceType: 'module' }, plugins: ['vue', '@typescript-eslint'], rules: {'import/no-unresolved': 'off', 'import/ no-extranillion-dependencies ': 'off', 'import/ no-extranillion-dependencies ': 'off', 'import/ no-extranillion-dependencies ': 'off'}}Copy the code
After modifying esLint’s configuration, we can see that the CSS files that were introduced are no longer reported in red, but the TS files are still reported in red. Why?
This should not be an ESLint problem, but probably a visual studio code editor review syntax problem. The VSCode syntax check and TSC compilation depend on the tsconfig.json file configuration, so let’s configure the TS alias again.
// tsconfig.json { "compilerOptions": { "target": "esnext", "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "esModuleInterop": true, "lib": [" esnext ", "dom"], "paths" : {" @ / * ": [". / SRC / *"], / / configuration ts alias}}, "include" : ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] }Copy the code
Tsconfig. json: tsconfig.json: tsconfig.json: tsconfig.json: tsconfig.json: tsconfig.json: tsconfig.json: tsconfig.json (a. ^ – ^ -)
CSS variables are introduced globally in Vite
Less variable
The installation
npm install less less-loader -D
Copy the code
configuration
// vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], css: { preprocessorOptions: { less: { modifyVars: { hack: `true; @import (reference) "${resolve('src/assets/lessVar.less')}"; ` }, javascriptEnabled: true } } } })Copy the code
The specific use
// lessVar.less
@primary: #43AFFF;
Copy the code
<style lang="less" scoped> h1 {color: @primary; } </style>Copy the code
Scss variable
The installation
NPM install sass sass-loader [email protected] -dCopy the code
configuration
// vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], css: { preprocessorOptions: { scss: { additionalData: '@import "src/assets/scssVar.scss"; '}}}})Copy the code
The specific use
// scssVar.less
$primary: #43AFFF;
Copy the code
<style lang=" SCSS "scoped> h1 {color: $primary; } </style>Copy the code
Stepping on two pits while using SCSS:
in
Vite
The use ofscss
Mandatory downloadsass
, or keep reporting errors.
I use the
win7
System, fornode-sass
Dependencies can only be installed for versions below 5, mainly becausenode-sass
对node
Version has requirements, requirementsnode15
Above, butnode
It has not been supported since around 14win7
Is installed.
Changes to the rewrite attribute of the proxy function in Vite
Configuring a custom proxy for the development server is also an old practice. Vite also provides a server.proxy to configure the proxy, which uses http-proxy as the underlying layer just like WebPack.
Many times when using WebPack we might do the following configuration:
Proxy: {'/ API ': {target: 'proxy service address ', secure: true, // Configure HTTPS changeOrigin: PathRewrite: {// ignore the prefix, that is, do not add/API layer '^/ API ': "}}}Copy the code
However, in a project built with Vite, this configuration is incorrect!!
The pathRewrite attribute is now renamed to rewrite and accepts a function form, correctly configured:
// vite.config.ts export default defineConfig({ plugins: [vue()], server: { proxy: { '/api': { target: Rewrite: (path) => path.replace(/^\/ API /, ")}}},})Copy the code
Environment variables in Vite
When using vue-cli, we often use the environment variable to determine the environment in which the program is running:
const BASE_URL = process.env.NODE_ENV === 'production' ? 'http://production.com' : 'http://development.com';
Copy the code
Vite
It also provides its ownThe environment variableWell, XDM learns and learns.
Vite uses import.meta. Env to access related environment variables. Let’s print import.meta first:
You can see that it contains a lot of things, but let’s focus on the env property, which has some environment variables built in:
import.meta.env.BASE_URL
: The value is string. It is the basic URL of the application deploymentThe base configuration itemsDecision.import.meta.env.DEV
: Boolean Specifies whether the application is running in the development environment (always withimport.meta.env.PROD
On the contrary).import.meta.env.MODE
: String. The mode in which the application is run. It is made up ofMode configuration itemsDecision.import.meta.env.PROD
: Boolean Indicates whether the application is running in the production environment.import.meta.env.SSR
: Boolean type, whether it is a SSR application,For more details.
Note that in a production environment, these environment variables are statically replaced at build time, so use completely static strings when referencing them. Dynamic keys cannot take effect. For example, the dynamic key value import.meta. Env [key] is invalid.
How do I create additional environment variables
We can load additional variables by creating configuration files in different modes. For example, we create.env.development and.env.production files in the project root directory.
//.env.development VITE_TITLE = 'orange someone-development environment' OTHER_TITLE = 'Other names-development environment'Copy the code
//.env.production VITE_TITLE = 'OTHER_TITLE =' other name - production environment 'Copy the code
The file content is as above, print import. Meta to check, and remember to restart.
We can see that we’ve already read these extra variables, since we started the project with the command NPM run dev, so we’ll be reading the contents of the.env.development file. If you run NPM run build, the.env.production file will be read.
In addition, Vite protects itself from accidentally leaking environment variables to the client by exposing only variables prefixed with vite_to Vite processed code.
Of course, we can not only create files for the development and Production modes. If you configure other modes, such as test mode, you can also create.env.test files to load additional variables.
Env.[mode] # Loads only in the specified mode, but is ignored by gitCopy the code
Vite uses globEager instead of require.context
In our vue-cli project, webpack provides us with require.context(), which makes it easy to import all the files in a folder. But this method is provided by Webpack, in Vite naturally can not be used, but do not worry, Vite for us to provide Glob mode module import, also can achieve the file import function.
Let’s take a look at the difference between the two to import all the files under the @/components/ file and register them as global components.
require.context
// main.js
const allCom = require.context('@/components/', true, /\.vue/);
allCom.keys().forEach(key => {
const fullName = key.substr(key.lastIndexOf('/') + 1)
const comName = fullName.split('.')[0].toUpperCase()
Vue.component(comName, allCom(key).default || allCom(key))
})
Copy the code
globEager
// main.ts const allCom = import.meta.globEager('./components/*.vue') Object.keys(allCom).forEach((key) => { const files = key.substr(key.lastIndexOf('/') + 1) const name = files.split('.')[0].toUpperCase() app.component(name, allCom[key].default) })Copy the code
The Glob pattern is treated as an import identifier: must be a relative path (starting with a./) or an absolute path (starting with a /, resolved relative to the project root), project aliases cannot be used
GlobEager is recommended instead of import.meta. Glob because it is lazy loading by default. And split into separate chunks at build time.
Common Eslint configurations
Eslint is a grinding goblin, loved and hated at the same time. While it makes us happy about the cleanliness and uniformity of the code it brings, it also makes us trapped in its clutches.
But a lot of times we choose it, for no other reason than, well, to have fun.
Remove the WARN alert for console
Use the Console method to print anything with a yellow line, ah, uncomfortable. (T_T)
Solution:
// .eslintrc.js module.exports = { ... Rules: {// the development environment does not review console' no-console': process.env.node_env === 'production'? 'warn' : 'off' } }Copy the code
Increment (‘++’) and decrement (‘–‘) symbols are allowed
In my opinion, it is very useful to increase and decrease the value. Many suggestions on the Internet can be written in the form of number. Value += 1.
Solution:
// .eslintrc.js module.exports = { ... Rules: {/ / allows you to use the increase since decreases symbols' no - plusplus: [' off '{allowForLoopAfterthoughts: true}]}}Copy the code
Remove the warn hint from alert()
Sometimes for convenience to directly use the system prompt box, this is also prompted yellow line.
Solution:
// .eslintrc.js module.exports = { ... Rules: {// call warn 'no-alert': 0}}Copy the code
Allows reassignment to function arguments
This is how I encapsulate the entire Axios from the previous part – separate API management, parameter serialization, cancel repeat request, Loading, status code… A problem with the article in TS form.
The general problem is that BY default, ESLint does not allow any further assignment to function arguments, otherwise it will send a red alert.
Doing assignments to variables in function arguments can be misleading, confusing, and can change arguments objects. This is a bit of a risky operation, but sometimes I just want to change (T_T). As I mentioned in the article above, I encapsulated a method to cancel repeated requests:
For convenience, I just want to change the cancelToken property in this addPending method. But reported red prompt, then is there any way to remove this prompt? The answer is yes, we need to configure the no-param-reassign rule.
Solution:
// .eslintrc.js module.exports = { ... Rules: {/ / allows modifying function into the parameter 'no - param - reassign: [' error' {props: true, ignorePropertyModificationsFor: [ 'config', ] } ], } }Copy the code
After configuration, the config is not submitted to the red, if more of the other parameters to configure, can continue to add the ignorePropertyModificationsFor attribute.
New component in ElementPlus – SelectV2 – virtual list selector
While I was writing this article, I happened to find a new component on the ElementPlus website. Here is a recommendation for you to update the latest version of the library.
The TS type of Loading component is used in ElementPlus
When we use TS to encapsulate ElementPlus components, it is easier to use its type.
<template> <div> < button@click ="clickEvent"> </button> </div> </template> <script lang="ts"> import {defineComponent } from 'vue' import { ElLoading } from 'element-plus' import { ILoadingOptions } from 'element-plus/lib/el-loading/src/loading.type' import 'element-plus/lib/theme-chalk/index.css' export default DefineComponent ({setup() {function openLoading(loadingOptions? : ILoadingOptions) { ElLoading.service(loadingOptions) } function clickEvent() { openLoading({ fullscreen: true }) } return { clickEvent } } }) </script>Copy the code
The type specification of other components is also imported by the corresponding type found in the source code.
Indexable types in TS
This is a feature that might be overlooked, but it does the same thing: you can use it to describe types that can be “indexed”, such as a[10] or ageMap[” Daniel “]. The document
This feature comes from seeing other members of the project write code that looks like this:
Interface Goods {goodsName: string} let Goods: Goods = {goodsName: '1'} Goods = {goodsName: '1'} Goods = {goodsName: string} 'Goods no. 2 ', aliasGoodsName:' asGoods';Copy the code
The above code bypasses editor inspection by adding an aliasGoodsName property to the Goods object through the AS assertion statement, but the Goods interface is not described, which can sometimes be confusing to other project members because the Goods object is specified using the Goods interface. All the properties should be clear, there should be no uncertainty.
The correct way to solve this problem is to use the optional attribute:
interface Goods { goodsName: string aliasGoodsName? : string} let goods: goods = {goodsName: 'goodsName'} goods = {goodsName: 'goodsName'};Copy the code
Optional attributes are good for this situation, but adding individual attributes is fine. If the uncertainty of the canonical object is very high, what’s ten? Twenty (in the extreme)? If we continue to use this approach, we will have to change the Goods interface every time, which will become troublesome.
Laziness is an important motivation to stimulate potential. Is there a way to do it once and for all? The answer, of course, is:
interface Goods { goodsName: string [proName: string]: any } let goods: Goods = { goodsName: } goods = {goodsName: 'goodname ', price: 100} goods = {goodsName:' goodname ', price: 100}Copy the code
With indexable type properties, we are able to implement arbitrary additions to the canonical type properties without having to worry about them anymore.
Uh, but!! Any is used here and did you suddenly feel that the entire interface type is a virtual diagram, not very meaningful?
Hahaha, I’m telling you…………….. That’s an illusion. Don’t worry about the details. Our first goal is to write code that runs, not code that doesn’t work.
I’ll share some of the temporary memories of Vue3+TS+Vite2+ElementPlus+Eslint project practices, but if there are others, I’ll add them later in this article. (= ^ del ^ =)
At this point, this article is finished, flower flower.
I hope this article has been helpful to you and look forward to your comments if you have any questions. Same old, like + comment = you got it, favorites = you got it.