This series is too long to digest separately:

  • Front end framework: Vite2 + VUe3 +typescript+ AXIos + Vant
  • Front end framework: Vite2 + VUe3 +typescript+ AXIos + Vant
  • Front end framework: Vite2 + VUe3 +typescript+ AXIos + Vant
  • Front end framework: Vite2 + VUe3 +typescript+ AXIos + Vant

Resources to deal with

Referencing static resources

The official website of this piece is very clear, you can check: vitejs.cn/guide/asset…

  • Related: Common base paths
  • Related: assetsInclude configuration items

Reference in relative and absolute paths

We can refer to static resources in relative and absolute paths in template, style, and pure.css files in *.vue files.

<! PNG ="./assets/logo.png"> <! <img SRC ="/ SRC /assets/logo.png"> <style scoped> #app {background-image: url('./assets/logo.png'); } </style>Copy the code

Picture dynamic introduction

1, the import

<img :src="imgUrlVal"> <script lang="ts" setup> import { ref } from 'vue' import imgUrl from './img.png' const imgUrlVal  = ref(imgUrl) </script> <style scoped> #app { background-image: url('./assets/logo.png'); } </style>Copy the code

2, the new URL

Import.meta. url is a native ESM feature that exposes the URL of the current module. Using it in combination with the native URL constructor, we get a fully parsed static resource URL from relative paths in a JavaScript module:

Syntax for creating a new URL object:

new URL(url, [base])
Copy the code
  • Url – Full URL, or path only (if base is set),
  • Base — Optional Base URL: If this parameter is set and the parameter URL is only a path, the URL is generated from this base.

🍕 examples:

const imgUrl = new URL('./img.png', import.meta.url).href
​
document.getElementById('hero-img').src = imgUrl
Copy the code

PNG is the relative path, while import.meta.url is the base URL (root link).

This works natively in modern browsers – in fact, Vite doesn’t need to deal with this code during development!

This pattern also supports dynamic urls through string templates:

function getImageUrl(name) {
  return new URL(`./dir/${name}.png`, import.meta.url).href
}
Copy the code

At production build time, Vite does the necessary transformations to ensure that the URL still points to the correct address after packaging and resource hashing.

Note: Cannot be used in SSR

This mode is not supported if you are using Vite in server-side rendering mode because import.meta.url has different semantics in browsers and Node.js. The server artifacts also cannot predetermine the client host URL.

Aliases cannot be used in new URLS, but paths can be concatenated

publicdirectory

Resources that can be stored in the public directory referenced in the source code. They are left behind and the file name is not hashed.

These files are copied verbatim to the root of the distribution directory.

<img src="/logo.png">
Copy the code

🙋 Q: What kind of files should be placed in the public directory?

  • Not referenced by source code (e.grobots.txt)
  • Must keep the original file name (not hashed)
  • … Or maybe you just don’t want to import the resource in the first place to get the URL

The directory defaults to

/public, but can be configured with the publicDir option.

😈Pay attention to avoid pits:

  • The introduction ofpublicResources should always use the root absolute path – for example,public/icon.pngShould be referenced in source code as/icon.png.
  • publicResources in JavaScript/TS files should not be referenced by JavaScript/TS files.
  • You can place the resource in a specialpublicDirectory, which should be in your project root directory. Resources in this directory should be directly accessible at development time/Is accessed from the root directory, and is fully copied to the root directory of the destination directory when packaged.

usingjestand@vue/test-utilsThe test component

Install dependencies

"Jest" : "^ 24.0.0", "vue - jest" : "^ 5.0.0 - alpha. 3", "Babel - jest" : "^ 26.1.0", "@ Babel/preset - env" : "^ 7.10.4 @", "vue/test - utils" : "^ 2.0.0 - beta. 9"Copy the code

Configure the Babel. Config. Js

module.exports = {
  presets: [
    [
      "@babel/preset-env", { 
        targets: { 
          node: "current" 
        } 
      }
    ]
  ],
};
Copy the code

Configuration jest. Config. Js

module.exports = {
  testEnvironment: "jsdom",
  transform: {
    "^.+\.vue$": "vue-jest",
    "^.+\js$": "babel-jest",
  },
  moduleFileExtensions: ["vue", "js", "json", "jsx", "ts", "tsx", "node"],
  testMatch: ["**/tests/**/*.spec.js", "**/__tests__/**/*.spec.js"],
  moduleNameMapper: {
    "^main(.*)$": "<rootDir>/src$1",
  },
};
​
Copy the code

The startup script

"test": "jest --runInBand"
Copy the code

Test code, tests/example.spec.js

import HelloWorld from "main/components/HelloWorld.vue";
import { shallowMount } from "@vue/test-utils";
​
describe("aaa", () => {
  test("should ", () => {
    const wrapper = shallowMount(HelloWorld, {
      props: {
        msg: "hello,vue3",
      },
    });
    expect(wrapper.text()).toMatch("hello,vue3");
  });
});
Copy the code

Lint configuates to add the jEST environment, otherwise you will get an error message:

module.exports = {
  env: {
    jest: true
  },
}
Copy the code

Hook Lint, test, and git

npm i lint-staged yorkie -D

"gitHooks": {
  "pre-commit": "lint-staged",
  "pre-push": "npm run test"
},
"lint-staged": {
  "*.{js,vue}": "eslint"
},
Copy the code

Under normal circumstances submit hook yorkie automatically after installation If not submit hook can manually run the node node_modules/yorkie/bin/the js to install. Of course, you can run the node node_modules/yorkie/bin/uninstall. Js submitted to uninstall hooks.

Patterns and environment variables

Patterns and environment variables

Use mode to configure multiple environments. The default mode is Development for Vite serve and Production for Vite build.

When you need to deploy your application to production, simply run the vite build command. By default, it uses

/index.html as the build entry point and generates an application package suitable for static deployment. See deployment guidelines for deploying static sites to obtain common services.

Multi-environment configuration, which we actually created in the previous series

Env. Production // Production environment configuration fileCopy the code

It is placed in the root directory for easy reading by vite.config.ts

You can use

export default ({ command, mode }) => {
  return defineConfig({
    });
};
Copy the code

Instead of

export default defineConfig({
 });
​
Copy the code

✔ Create a configuration file. Env.development

VITE_BASE_API=/api
VITE_BASE_URL=./
VITE_APP_OUT_DIR = dist
Copy the code

Enroll. Production Create a configuration file

VITE_BASE_API=/api
VITE_BASE_URL=./
VITE_APP_OUT_DIR = dist
Copy the code

➤ Declare in env.d.ts (easy to configure for smart prompts and use without rechecking)

Interface ImportMetaEnv{VITE_BASE_API:string VITE_BASE_URL:string VITE_APP_OUT_DIR:string}Copy the code

✔ Click in the right ➤ code

import.meta.env.VITE_BASE_API
import.meta.env.VITE_BASE_URL
Copy the code

😈 Pay attention to avoid pits:

🙋1. Import.meta.env. XXx Variables defined in. Env [mode] cannot be accessed

Workaround: Use loadEnv instead

✔ modify vite. Config. Ts

import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import vueJsx from "@vitejs/plugin-vue-jsx"; import { resolve } from "path"; import styleImport, { VantResolve } from "vite-plugin-style-import"; import { viteMockServe } from "vite-plugin-mock"; import { loadEnv } from "vite"; export default ({ command, mode }) => { return defineConfig({ resolve: { alias: { "@": resolve(__dirname, "src"), comps: resolve(__dirname, "src/components"), apis: resolve(__dirname, "src/apis"), views: resolve(__dirname, "src/views"), utils: resolve(__dirname, "src/utils"), routes: resolve(__dirname, "src/routes"), styles: resolve(__dirname, "src/styles"), }, }, plugins: [ vue(), vueJsx(), styleImport({ resolves: [VantResolve()], }), viteMockServe({ mockPath: Mock ", // ↓ Parse the mock folder supportTs: false, // open the mock folder supportTs: false, // open the mock folder supportTs: false, // Open the mock folder supportTs: false, // Open the mock folder supportTs: false, // Open the mock folder supportTs: false, // Open the mock folder supportTs: false, // Open the mock folder supportTs: false, // Open the mock folder supportTs: false, // Open the mock folder supportTs: false. Network: use --host to expose // port: 4000, // proxy: {// "^/ API ": {// target: "https://baidu.com", // changeOrigin: true, // ws: true, // rewrite: PathStr = > pathStr. Replace (/ ^ \ / API /, ""), / /}, / /}, / / cors: true,}, * * * / services in the production of basic public path. * @default '/' */ base: "./", build: { //target: 'modules', / / build target format, modules by default, may also be esbuild configuration items, https://esbuild.github.io/api/#target outDir: LoadEnv (mode, process.cwd()).vite_app_out_dir, // build output path assetsDir:"static", // Static resources folder, same as outDir default assets sourcemap: False, // map file assetsInlineLimit: 4096, // KB, less than this value will be inline base64 format // rollupOptions: {// output: {// chunkFileNames: 'static/js1/[name]-[hash].js', // entryFileNames: 'static/js2/[name]-[hash].js', // assetFileNames: 'the static / [ext] / [name] - [hash] [ext]' / /}, / /}, / / brotliSize: false, / / / / no statistics minify: // terserOptions: {// compress: {// drop_console: true, //}, //},},}); };Copy the code

# # # 🛢 packaging

Use NPM run build to perform packaging

Custom build

The build process can be customized through a variety of build configuration options. In particular, you can directly adjust the underlying Rollup option == with build.rollupOptions:

Vite. Config. Ts

build: {
    rollupOptions: {
      // https://rollupjs.org/guide/en/#big-list-of-options
    }
  }
Copy the code

🍕 Example: 1. Multi-page application mode

Suppose you have the following project file structure

├── download.json ├─ ├─ index.html ├── ├.htm ├─ ├.htm ├─ ├.htm ├─ ├.htm ├─ ├.htm ├─ ├.htm ├─ ├.htm ├─ ├.htm ├─ ├.htm ├─ ├.htmCopy the code

In development, simply navigating or linking to /nested/ – will work as expected, just like a normal static file server.

In the build, all you need to do is specify multiple.html files as entry points:

Vite. Config. Ts

 build: {
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'index.html'),
        nested: resolve(__dirname, 'nested/index.html')
      }
    }
  }
Copy the code

🍕 Example: 2. Library mode

When you’re developing a browser-oriented library, you’ll probably spend most of your time on the library’s test/demo page. With Vite, you can use index.html.

Use the build.lib configuration when building your library for publishing. Be sure to externalize dependencies that you don’t want packaged into your library, such as vue or react:

Vite. Config. Ts

build: { lib: { entry: resolve(__dirname, 'lib/main.js'), name: 'MyLib' }, rollupOptions: External: ['vue'], output: {// Provide a global variable for these externalized dependencies in UMD build mode globals: {vue: 'vue'}}}}Copy the code

Question time

🙋问 : 1, vite cannot use require,require is not defined

Answer: Reason:

  • Node.js is not part of the built-in object. If you want to write Node.js in typescript, you need to import third-party declaration files
  • Vue cannot recognize require and browsers do not support CJS

How to handle it: If you are using typescript2. x, install the following packages

npm install @types/node --save-dev
Copy the code

1. Replace require with an import reference

🍕 for example: we want to introduce an image: require(‘./logo.png’) is an error

<template>
    <img :src="imgUrl" alt="">
    <img :src="imgUrl2" alt="">
</template>
<script setup lang="ts">
    import {ref, onMounted} from "vue";
    import imgUrl from './logo.png'
    const imgUrl2 = ref('');
    const handleImgSrc = async()=>{
        let m = await import('./logo.png');
        imgUrl2.value = m.default;
     };
    handleImgSrc()
</script>
Copy the code

2, the new URL

PNG) // equivalent to new URL('./assets/home.png', import.meta.url).hrefCopy the code

Require is not available in Vite

Import () is available in vite, but not in CSS in JS.

Use import.meta.globeager () or import.meta.glob

Note that the path must start with a./ or an absolute path (beginning with a /, resolved relative to the project root directory)

  • This is a Vite only feature, not a Web or ES standard
  • The Glob pattern is treated as an import identifier: it must be a relative path (to. /Start) or absolute path (with/Beginning, relative to project root resolution).
  • Glob matching is usedfast-globTo implement — read its documentation to look it upSupported Glob mode.
  • You should also note that the glob import does not accept variables; you should pass string patterns directly.
  • The glob pattern cannot contain the same quote string as the wrap quote (which includes'.".For example, if you want to implement‘/Tom’s files/ Effect, please use“/Tom’s files/“` instead.

Import.meta. glob is dynamically imported and will be separated into independent chunks during construction

Import.meta. globEager is a direct import

🍕 examples:

export function getAssetsImagesUrl(path:string) {
    return import.meta.globEager("/src/assets/images/*/*")[`/src/assets/images/${path}`].default
}
Copy the code

🍕 or a file in a folder

export function loadLottieApidataFile(path: string, meta: IdefaultObject) {
  return new Promise((resolve, reject) => {
    const modules = import.meta.glob(`/src/scripts/lottie/*/*.ts`);
    meta = meta || {};
    // 加载
    modules[`/src/${path}`]()
      .then(
        (data) => {
          meta = { ...meta, ...data.default };
          meta.reload = !meta.reload; // 添加重新绑定的开关
          resolve(data.default);
        },
        (err) => {
          reject(err);
        }
      )
      .catch((err) => {
        reject(err);
      });
  });
}
Copy the code

🍕 Dynamically import multiple VUE pages

import { App, Component } from 'vue' interface FileType { [key: string]: // Import all.vue files under globComponents const files: Record<string, FileType> = import.meta.globEager("/src/components/golbComponents/*.vue") export default (app: App): Keys (files).foreach ((c:).keys().foreach (c:).keys().keys().foreach (c:).keys().keys().foreach ().keys().keys().foreach ().keys().keys().foreach ().keys() string) => { const component = files[c]? .default // Mount global component.component.component.name as string, component})}Copy the code

If you use import.meta.glob directly, vscode will report that the attribute “glob” does not appear on the ImportMeta. You need to add vite/client to the tsconfig file

{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}
Copy the code

Exports: module.exports = {export default}

🙋 Q: 2. What should I do if the startup page is blank?

Answer: Possible reasons:

  • Check compatibility,
  • Note the entry file index.html, which needs to place the project root directory,
  • It’s still blank in the server, invite.config.tsFile to addbase:'./'(Because the default vue package path is the root path, and the configuration file in Vite is vite.config.ts)

🙋 Q: 3.viteNone in the environment by defaultprocess.envWhat to do?

A: You can define global variables to be used in vite.config.ts using define

Customize the global variable process.env

Used in vite.config.ts

define: {
  'process.env': {}
}
Copy the code

🙋 Q: 4. How do I set a special type for defineProps in a subcomponent

A: PropType is used

So let’s say I have a TitleScore component, and I want the scoreData information property, and I want to keep the ITitleScore interface.

1, the introduction of

import { PropType } from 'vue'
Copy the code

2. Define interfaces

Export interface ITitleScore {title: string score: number}Copy the code

3. Attribute verification

const { scoreData } = defineProps({
    scoreData: {
        type: Object as PropType<ITitleScore>
    }
}) 
Copy the code

🙋 Q: 5. How to set the default value of defineProps in the subcomponent

Answer: Use withDefaults

The withDefaults function is the API that binds default values to defineProps

For example, add the default value to question 4

The parent component

<template> <TitleScore :scoreData="{title: 'score', score: 98}" /> </template>Copy the code

Child components

<template> <! <div class="titlescore-container display-center-align-items"> <span Class = "titlescore - text" > {{scoreData. Title}}. </span> <div class="score-bg all-score" v-for="item in totalScore" :key="item"> <div v-if="scoreData.score >= item" class="score-bg current-score"></div> </div> </div> </template> <script setup lang="ts"> import { PropType } from 'vue';  interface ITitleScore { title: string score: DefineProps <ITitleScore>(),{title:' defineProps ', score:100 }) </script> <style lang="scss" scoped> .titlescore-container{ width: 100%; height: 15px; margin-bottom: 15px; .titlescore-text{ font-size: 15px; font-family: PingFangSC-Semibold, PingFang SC; font-weight: 600; color: #000000; } .score-bg{ background-image: url('.. /.. /assets/images/common/iconBg.png'); background-repeat: no-repeat; background-size: 180px auto; } .all-score{ width: 16px; height: 15px; background-position: -46px -163px; margin-right: 6px; position: relative; } .current-score{ width: 100%; height: 100%; background-position: -15px -163px; position: absolute; left: 0; top: 0; } } </style>Copy the code

Note: The default value is a reference type, need to wrap a function return out.

<script lang='ts' setup> interface Props { child: string|number, title? StrData: string, MSG? : string labels? : string[], obj? :{a:number} } const props = withDefaults(defineProps<Props>(), { msg: 'hello', labels: () => ['one', 'two'], obj: () => { return {a:2} } }) </script>Copy the code

🙋 Q: 6. A cross-domain error is reported when the index.html generated by packaging is opened directly in the browser

A: Vite’s default output is

Ps: Other issues are being summarized…