<!--
* @Descripttion: Vue 3 + Typescript + Vite2.0 項目簡介
-->
# Vue 3 + Typescript + Vite + vant3 搭建移動端通用架子
pc 管理系統請參考移步:VUE VBEN ADMIN2.0 (vite2.0+vue3+ts+antd-design-vue) github 地址:git clone https://github.com/anncwb/vue-vben-admin.git vue-vben-admin-2.0 項目文檔:https://vvbin.cn/doc-next/ element-plus(支持 vue3) 文檔:https://element-plus.gitee.io/#/zh-CN/component/installation
vite2.0 中文文檔:https://cn.vitejs.dev/ vue3 官方文檔:https://v3.cn.vuejs.org/api/ Typescript 官方文檔:https://www.tslang.cn/docs/home.html vant3 官方文檔:https://vant-contrib.gitee.io/vant/v3/#/zh-CN/home
vue-i18n@next 國際化配置文檔:https://vue-i18n.intlify.dev/introduction.html ### 初始化項目 [yarn 和 npm 的區別不贅述]
npm init @vitejs/app or yarn create @vitejs/app ---> 輸入項目名稱 ---> 選擇 vue-ts [vue3+TS] ### 安裝依賴
npm i or cnpm i ### 啟動項目
cnpm run dev ### 安裝相關依賴 yarn 或者 cnpm npm 命令都行
yarn add xxx npm i vue-i18n@next -S or cnpm i vue-i18n@next -S npm i vue-router@4 -S or cnpm i vue-router@4 -S npm i vuex@next -S or cnpm i vuex@next -S ### 注意問題
node api 報錯 比如配置文件使用 require node.js 不是內置對象的一部分,如果想用 typescript 寫 Node.js,則需要引入第三方聲明文件 解決辦法:npm i @types/node -D or cnpm i @types/node -D tsconfig.json types 中配置 node 字段 ### 代碼規范
vscode 提示無法在只讀編輯器中編輯 json 文件 File → Preferences → Settings --> Eslint Eslint 官方文檔:https://eslint.org/docs/rules/ prettier 官方文檔:https://prettier.io/docs/en/configuration.html eslint-plugin-vue 官方文檔:https://eslint.vuejs.org/user-guide/#usage 自動修復 eslint 報錯
npm i eslint-plugin-vue -D or cnpm i eslint-plugin-vue -D vscode Vetur 插件 ---> vue 高亮插件 vscode ESlint 插件 ---> Eslint 插件用於根據工程目錄的.eslintrc.js 配置文件在編輯器中顯示一些錯誤提示,后面的自定格式化根據這里的錯誤提示進行格式化操作 如果是 vue-cli 創建的項目 創建的時候把 Linter/Formatter 選上(默認已選上) 下一步選擇 Eslint+Prettier --> Lint on save // eslint 配置項,保存時自動修復 "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, // 默認使用 prettier 格式化支持的文件 "editor.defaultFormatter": "esbenp.prettier-vscode", // 自動設定 eslint 工作區 "eslint.workingDirectories": [ { "mode": "auto" } ], "explorer.confirmDelete": false, "diffEditor.ignoreTrimWhitespace": true, "eslint.codeAction.showDocumentation": { "enable": true }, "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "eslint.format.enable": true, "eslint.validate": ["javascript", "vue", "html","jsx", "javascriptreact"], "editor.suggest.snippetsPreventQuickSuggestions": false, "files.associations": { "\*.vue": "html" }, "editor.formatOnSave": true //由於 prettier 不能格式化 vue 文件 template 所以使用 js-beautify-html 格式化 "vetur.format.defaultFormatter.html": "js-beautify-html", "vetur.format.defaultFormatterOptions": { "js-beautify-html": { "wrap*attributes": "force-aligned" //屬性強制折行對齊 } }, "prettier.singleQuote": true, //使用單引號而不是雙引號 "prettier.jsxBracketSameLine": true, //將>多行 JSX 元素放在最后一行的末尾,而不是單獨放在下一行 "prettier.printWidth": 120, // 超過最大值換行 "prettier.tabWidth": 2, // 縮進字節數 "prettier.useTabs": true, // 縮進使用 tab "prettier.semi": false, // 句尾添加分號 "prettier.singleQuote": true, // 使用單引號代替雙引號 "prettier.proseWrap": "preserve", // 默認值。因為使用了一些折行敏感型的渲染器(如 GitHub comment)而按照 markdown 文本樣式進行折行 "prettier.arrowParens": "avoid", // (x) => {} 箭頭函數參數只有一個時是否要有小括號。avoid:省略括號 "prettier.bracketSpacing": true, // 在對象,數組括號與文字之間加空格 "{ foo: bar }"
"prettier.endOfLine": "auto", // 結尾是 \n \r \n\r auto "prettier.htmlWhitespaceSensitivity": "ignore", "prettier.ignorePath": ".prettierignore", // 不使用 prettier 格式化的文件填寫在項目的.prettierignore 文件中 "prettier.requireConfig": false, // Require a "prettierconfig" to format prettier "prettier.trailingComma": "none", // 在對象或數組最后一個元素后面是否加逗號 /* 每種語言默認的格式化規則 \_/
"[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[scss]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, 安裝插件讓 ESLint 支持 TypeScript npm i typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin -D 當我們執行 npm run format 時還會報各種奇怪的錯誤 如:error: Delete ⏎ (prettier/prettier) at src/pages/xxx 等;這是因為 prettier 配置和 vscode 編輯器 prettier 配置沖突導致的 在 rules 中配置下覆蓋掉就可以了 出現了下面的警告:} expected css(css lcurlyexpected), 解決方案:settings.json 中配置如下 "files.associations": { "_.vue": "vue", "_.tpl": "html" }, ### git 提交代碼鈎子校驗
npm i husky lint-staged -D or cnpm i husky lint-staged -D ## package.json 中配置 GitHub 文檔:https://github.com/typicode/husky
"husky": { "hooks": { "pre-commit": "lint-staged", "pre-push": "lint-staged" } }, "lint-staged": { "\*.{js,jsx,md,html,css}": [ "prettier --write", "git add" ] } ### vm vw 布局適配方案 以及 css 預處理器 {這邊先選擇 less} UI 選型 {自己封裝常用的 or 選擇一種功能比較齊全的移動端 UI 庫}
cnpm i postcss-viewport-units postcss-px-to-viewport postcss-write-svg autoprefixer -D cnpm i less -D cnpm i vant@next -S cnpm i vite-plugin-imp -D // 按需加載 GitHub 文檔:https://github.com/onebay/vite-plugin-imp vant 官方網站:https://vant-contrib.gitee.io/vant/v3/#/zh-CN
其實在 Vite 中無須考慮按需引入的問題。Vite 在構建代碼時,會自動通過 Tree Shaking 移除未使用的 ESM 模塊。而 Vant 3.0 內部所有模塊都是基於 ESM 編寫的,天然具備按需引入的能力。現階段遺留的問題是,未使用的組件樣式無法被 Tree Shaking 識別並移除,后續 vant 團隊會考慮通過 Vite 插件的方式進行支持 ### 環境變量和打包命令配置
根目錄下新建文件 .env.development (開發) .env.test (測試) .env.production (生產) package.json 中配置打包命令 "build:dev": "vue-tsc --noEmit && vite build --mode development", "build:test": "vue-tsc --noEmit && vite build --mode test", "build:prod": "vue-tsc --noEmit && vite build --mode production" 打包命令 cnpm run build:dev // 本地包 cnpm run build:test // 測試包 cnpm run build:prod // 生產包 ### 使用 http-server 開啟一個本地服務器 預覽效果
npm install http-server -g cd dist http-server -c-1(只輸入 http-server 的話,更新了代碼后,頁面不會同步更新)ctrl + c 即可關閉 ### 調試工具
cnpm i vconsole -S 在 main.ts 引入 import Vconsole from 'vconsole'; new Vconsole(); ### PWA
參考文檔:https://github.com/antfu/vite-plugin-pwa cnpm i vite-plugin-pwa -D 配置 vite.config.ts 文件 import { VitePWA } from 'vite-plugin-pwa' plugins:[ VitePWA({ manifest: {}, workbox: { skipWaiting: true, clientsClaim: true } }) ] ### 組件樣式按需加載配置
參考文檔:https://github.com/anncwb/vite-plugin-style-import 配置 vite.config.ts 文件 cnpm i vite-plugin-style-import -D import styleImport from 'vite-plugin-style-import' css:{ preprocessorOptions:{ less:{ modifyVars:{}, javascriptEnabled: true } } }, plugins:[ styleImport({ libs:[ { libraryName: 'ant-design-vue', esModule: true, resolveStyle: name => `ant-design-vue/es/${name}/style/index` } ] }) ] ### 生產環境生成 .gz 文件.
[content-encoding:gzip] 壓縮代碼,在傳輸的時候用 gzip 壓縮,提高資源訪問速度。后端以 nginx 為例的話,在 nginx.conf 需要開啟 gizp 服務: gzip on; //開啟 gzip 壓縮功能 這樣你就可以在 network 查看到 content-encoding:gzip 這個選項 參考文檔:https://github.com/anncwb/vite-plugin-compression cnpm i vite-plugin-compression -D 配置 vite.config.ts 文件 import viteCompression from 'vite-plugin-compression' plugins:[ viteCompression({ verbose: true, disable: false, threshold: 10240, algorithm: 'gzip', ext: '.gz' }) ] ### 國際化配置
安裝 js-cookie cnpm i js-cookie -S cnpm i @types/js-cookie -D 參考文檔:https://www.npmjs.com/package/js-cookie cnpm i vue-i18n@next -S ### http 請求庫
cnpm i axios -S ### normalize.css 更好的 reset.css 方案
cnpm i normalize.css -S 參考文檔:https://github.com/necolas/normalize.css
項目環境以及打包命令配置
項目根目錄下創建 .env.test 【測試環境】 .env.development 【開發環境】 .env.production 【生產環境】
分別對應內容
NODE_ENV=test VITE_APP_BASE_URL='https://www.test.com/'
NODE_ENV=development VITE_APP_BASE_URL='api'
NODE_ENV=production VITE_APP_BASE_URL='https://www.prod.com/'
文件里獲取 console.log(import.meta.env.VITE_APP_BASE_URL, '環境變量')
package.json文件下面配置
"build:dev": "vue-tsc --noEmit && vite build --mode development", "build:test": "vue-tsc --noEmit && vite build --mode test", "build:prod": "vue-tsc --noEmit && vite build --mode production"
關於代碼規范:都可以自定義規則以下是自己簡單的配置規則(提供參考具體查看對應官方文檔配置屬性)
.eslintignore文件
*.sh node_modules *.md *.woff *.ttf .vscode .idea dist /public /docs .husky .local /bin Dockerfile
.eslintrc.js文件
/* * @Descripttion: eslint代碼規范 */ module.exports = { parser: 'vue-eslint-parser', parserOptions: { parser: '@typescript-eslint/parser', ecmaVersion: 2020, sourceType: 'module', ecmaFeatures: { jsx: true } }, extends: [ 'plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'prettier/@typescript-eslint', 'plugin:prettier/recommended' ], rules: { '@typescript-eslint/ban-ts-ignore': 'off', '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-empty-function': 'off', 'vue/custom-event-name-casing': 'off', 'no-use-before-define': 'off', // 'no-use-before-define': [
// 'error',
// {
// functions: false,
// classes: true,
// },
// ],
'@typescript-eslint/no-use-before-define': 'off', // '@typescript-eslint/no-use-before-define': [
// 'error',
// {
// functions: false,
// classes: true,
// },
// ],
'@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/ban-types': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^h$', varsIgnorePattern: '^h$' } ], 'no-unused-vars': [ 'error', { argsIgnorePattern: '^h$', varsIgnorePattern: '^h$' } ], 'space-before-function-paren': 'off', quotes: ['error', 'single'], 'comma-dangle': ['error', 'never'], "no-console": process.env.NODE_ENV === "production" ? "error" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" } }
.prettierignore文件
/dist/* .local .output.js /node_modules/**
**/*.svg **/*.sh /public/*
.prettierrc.js文件
/* * @Descripttion: prettier.config.js or .prettierrc.js package.json 中配置prettier屬性 */
// 如果vscode配置中有的這邊可以不用再配置
module.exports = { useTabs: false, vueIndentScriptAndStyle: true, quoteProps: 'as-needed', jsxSingleQuote: false, arrowParens: 'always', htmlWhitespaceSensitivity: 'strict', endOfLine: 'lf', printWidth: 200, // 換行字符串閾值
tabWidth: 2, // 設置工具每一個水平縮進的空格數
singleQuote: true, // 用單引號
semi: false, // 句末是否加分號
trailingComma: 'none', // 最后一個對象元素加逗號
bracketSpacing: true, // 對象,數組加空格
jsxBracketSameLine: false, // jsx > 是否另起一行
disableLanguages: ["vue"] // 不格式化vue文件,vue文件的格式化單獨設置
}
postcss.config.js文件
/* * @Descripttion: postcss.config.js */ module.exports = { plugins: { autoprefixer: { /* PostCSS plugin to parse CSS and add vendor prefixes to CSS rules */
/* 配置文檔鏈接:https://github.com/postcss/autoprefixer#options */ overrideBrowserslist: [ 'last 2 versions' // 最后兩個版本
] }, 'postcss-viewport-units': { /* vw兼容方案 */
/* 配置文檔鏈接:https://github.com/springuper/postcss-viewport-units#options */ }, 'postcss-px-to-viewport': { /* 將px單位轉換為視口單位的 (vw, vh, vmin, vmax) */
/* 配置文檔鏈接:https://github.com/evrone/postcss-px-to-viewport/blob/master/README_CN.md#%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0 */ viewportWidth: 375, viewportUnit: 'vw', unitPrecision: 3, minPixelValue: 1, // 小於或等於`1px`不轉換為視窗單位,你也可以設置為你想要的值
mediaQuery: false, // selectorBlackList: ['.vant'], // 以xxx開頭
include: [], // 包括
exclude: [] // 排除
}, 'postcss-write-svg': { /* 在retina屏繪制1px細線 */
/* 配置文檔鏈接:https://github.com/jonathantneal/postcss-write-svg#options */ }, } }
tsconfig.json文件
{ "compilerOptions": { "target": "esnext", "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "esModuleInterop": true, "lib": ["esnext", "dom", "ES2015.promise"], "types": ["vite/client", "node"], "typeRoots": ["./node_modules/@types/", "./src/types"], "paths": { "@": ["./src"] } }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "exclude": ["node_modules"] }
vite.config.ts配置
/* * @Descripttion: vite.config.ts vite2.0 */ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import viteCompression from 'vite-plugin-compression' const path = require('path') const resolve = (dir: string) => path.join(__dirname, dir) // https://vitejs.dev/config/
export default defineConfig({ base: process.env.NODE_ENV === 'production' ? './' : '/', plugins: [ vue(), // 默認情況下,小於1501字節的文件不會被壓縮
viteCompression({ // 是否在控制台輸出壓縮結果
verbose: true, // 是否禁用
disable: false, // 體積大於 threshold 才會被壓縮,單位 b
threshold: 10240, // 壓縮算法
algorithm: 'gzip', // 生成的壓縮包后綴
ext: '.gz', // 壓縮后是否刪除源文件
deleteOriginFile: false }) ], // 別名
resolve: { alias: { '@': resolve('src'), // 解決vue-i18n警告You are running the esm-bundler build of vue-i18n.
'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js' } }, // 代理解決dev模式跨域
server: { host: '0.0.0.0', // https: false,
port: 9999, //啟動端口
open: true, // 是否自動打開瀏覽器
cors: true, proxy: { // 如果是 /api 打頭,則訪問地址如下
'/api': { target: 'http://jsonplaceholder.typicode.com', changeOrigin: true, // ws: true,
rewrite: (path) => path.replace(/^\/api/, '') } } }, css: { preprocessorOptions: { less: { modifyVars: { // Used for global import to avoid the need to import each style file separately
// reference: Avoid repeated references
hack: `true; @import (reference) "${resolve('src/assets/style/index.less')}";` }, javascriptEnabled: true } } }, build: { target: 'es2015', outDir: 'dist', // 生產環境移除 console
terserOptions: { compress: { drop_console: process.env.NODE_ENV === 'production' ? true : false, drop_debugger: process.env.NODE_ENV === 'production' ? true : false } } } })
vscode setting json配置:
{ "workbench.colorTheme": "Atom One Dark", "workbench.iconTheme": "vscode-icons", "git.ignoreWindowsGit27Warning": true, "[html]": { "editor.defaultFormatter": "HookyQR.beautify" }, "[javascript]": { "editor.defaultFormatter": "HookyQR.beautify" }, "[json]": { "editor.defaultFormatter": "vscode.json-language-features" }, "fileheader.customMade": { "Descripttion": "", "version": "", "Author": "lhl", "Date": "Do not edit", "LastEditors": "lhl", "LastEditTime": "Do not Edit" }, "fileheader.cursorMode": { "name": "", "test": "test font", "msg": "", "param": "", "return": "" }, "explorer.confirmDelete": false, "diffEditor.ignoreTrimWhitespace": true, "eslint.codeAction.showDocumentation": { "enable": true }, "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "eslint.workingDirectories": [{ "mode": "auto" }], "editor.defaultFormatter": "esbenp.prettier-vscode", "eslint.format.enable": true, "eslint.validate": ["javascript", "vue", "html", "typescript"], "editor.suggest.snippetsPreventQuickSuggestions": false, "files.associations": { "*.vue": "vue", "*.tpl": "html" }, "vetur.format.defaultFormatter.html": "js-beautify-html", "vetur.format.defaultFormatterOptions": { "js-beautify-html": { "wrap_attributes": "force-aligned" } }, "prettier.singleQuote": true, "prettier.printWidth": 200, "prettier.tabWidth": 2, "prettier.useTabs": true, "prettier.semi": false, "prettier.proseWrap": "preserve", "prettier.arrowParens": "avoid", "prettier.bracketSpacing": true, "prettier.endOfLine": "auto", "prettier.htmlWhitespaceSensitivity": "ignore", "prettier.ignorePath": ".prettierignore", "prettier.requireConfig": false, "prettier.trailingComma": "none", "editor.formatOnSave": false, "[dart]": { "editor.formatOnSave": true, "editor.formatOnType": true, "editor.rulers": [ 80 ], "editor.selectionHighlight": false, "editor.suggest.snippetsPreventQuickSuggestions": false, "editor.suggestSelection": "first", "editor.tabCompletion": "onlySnippets", "editor.wordBasedSuggestions": false } }
package.json文件
{ "name": "vite-project", "version": "0.0.0", "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", "serve": "vite preview", "build:dev": "vue-tsc --noEmit && vite build --mode development", "build:test": "vue-tsc --noEmit && vite build --mode test", "build:prod": "vue-tsc --noEmit && vite build --mode production" }, "dependencies": { "@types/js-cookie": "^2.2.6", "@vant/area-data": "^1.0.0", "axios": "^0.21.1", "js-cookie": "^2.2.1", "normalize.css": "^8.0.1", "vant": "^3.0.12", "vconsole": "^3.4.0", "vue": "^3.0.5", "vue-i18n": "^9.0.0", "vue-router": "^4.0.5", "vuex": "^4.0.0" }, "devDependencies": { "@types/js-cookie": "^2.2.6", "@types/node": "^14.14.37", "@typescript-eslint/eslint-plugin": "^4.20.0", "@typescript-eslint/parser": "^4.20.0", "@vitejs/plugin-vue": "^1.2.1", "@vue/compiler-sfc": "^3.0.5", "autoprefixer": "^10.2.5", "eslint": "^7.23.0", "eslint-config-prettier": "^8.1.0", "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-vue": "^7.8.0", "husky": "^6.0.0", "less": "^4.1.1", "lint-staged": "^10.5.4", "postcss-px-to-viewport": "^1.1.1", "postcss-viewport-units": "^0.1.6", "postcss-write-svg": "^3.0.1", "prettier": "^2.2.1", "typescript": "^4.1.3", "vite": "^2.1.5", "vite-plugin-compression": "^0.2.4", "vite-plugin-imp": "^2.0.5", "vue-tsc": "^0.0.15" }, "husky": { "hooks": { "pre-commit": "lint-staged", "pre-push": "lint-staged" } }, "lint-staged": { "*.{js,jsx,md,html,css}": [ "prettier --write", "git add" ] } }
以上代碼純屬自己整理和測試,未經允許請勿隨意轉載,若有不正請及時告知!!
EditorConfig for Visual Studio Code (有喜愛的可以配置上這個下載vscode插件即可配置)
根目錄下創建 .editorconfig文件
配置參考:https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig