背景
将Vue2.0 + Ceium项目升级到Vue3.0,在此记录下整体升级的过程以及遇到的问题。
目标
用Vue3.0配套技术栈搭建项目框架并重构项目
技术栈:Vue2.0 + Webpack + JavaScript + Sass + Element ui + Vuex + Axios + Vue-router + Cesium
升级后:Vue3.0 + Vite + TypeScript + Sass + Element plus + Pinia + + Axios + Vue-router + Cesium
准备工作
-
升级node版本
由于Vite 需要 Node.js 版本 14.18+,16+。而且有些模板需要依赖更高的 Node 版本才能正常运行,包管理器可能会发出警告,请升级你的 Node 版本。推荐全局安装nvm对多个node版本进行管理,自行搜索教程,不多介绍了。
-
创建脚手架项目
通过 vite快速创建
npm create vite@latest
选择Vue 和 TypeScript
-
VSCode插件安装
安装volar插件支持vue3开发,同时禁用vetur。
安装ESLint插件
安装prettier插件
开发环境搭建
-
代码规范(ESlint + prettier)
随着前端得项目的规模越来越大,一个项目多人同时协作开发的场景越来越多,代码的规范都做统一约束,提高协作开发效率。我在项目中采用ESlint + prettier来规范代码风格。
-
安装ESlint
npm add -D eslint
初始化ESLint配置
npx eslint --init 根据自己的需求选择默认配置,初始化后根目录会生成一个.eslintrc.js文件,下面是我的基本配置
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:vue/vue3-essential"
],
"overrides": [
{
"env": {
"node": true
},
"files": [
".eslintrc.{js,cjs}"
],
"parserOptions": {
"sourceType": "script"
}
}
],
"parserOptions": {
"ecmaVersion": "latest",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"vue"
],
"rules": {
}
}
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:vue/vue3-essential"
],
"overrides": [
{
"env": {
"node": true
},
"files": [
".eslintrc.{js,cjs}"
],
"parserOptions": {
"sourceType": "script"
}
}
],
"parserOptions": {
"ecmaVersion": "latest",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"vue"
],
"rules": {
}
}
安装vite-plugin-eslint
npm add -D vite-plugin-eslint
安装eslint-parser
npm add -D @babel/core
npm add -D @babel/eslint-parser
配置vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import eslintPlugin from 'vite-plugin-eslint';
import { join } from 'path'
function resolve(dir: string) {
return join(__dirname, dir)
}
// https://vitejs.dev/config/
export default defineConfig({
base: './', // 打包路径
server: {
port: 8888, // 服务端口号
open: false, // 服务启动时是否自动打开浏览器
cors: true // 允许跨域
},
plugins: [
vue(),
eslintPlugin({
include: ['src/**/*.ts', 'src/**/*.vue', 'src/*.ts', 'src/*.vue'],
}),
],
resolve: {
// 配置路径别名
alias: {
'@': resolve('src')
},
}
});
问题:找不到path模块,设置别名无效
解决:安装@types/node模块
npm install @types/node --save-dev
在tsconfig.json中compilerOptions下添加配置
"paths": {
"@/*": ["./src/*"]
}
-
安装prettier
npm add -D prettier
npm add -D eslint-config-prettier 兼容eslint的插件
npm add -D eslint-plugin-prettier eslint的prettier
根目录下新建 .prettierrc.js 文件,下面是我的默认配置
module.exports = {
/**
* 换行宽度,当代码宽度达到多少时换行
* @default 150
* @type {number}
*/
printWidth: 150,
/**
* 缩进的空格数量
* @default 2
* @type {number}
*/
tabWidth: 2,
/**
* 是否使用制表符代替空格
* @default false
* @type {boolean}
*/
useTabs: false,
/**
* 是否在代码块结尾加上分号
* @default true
* @type {boolean}
*/
semi: true,
/**
* 是否使用单引号替代双引号
* @default false
* @type {boolean}
*/
singleQuote: true,
/**
* 对象属性的引号处理
* @default "as-needed"
* @type {"as-needed"|"consistent"|"preserve"}
*/
quoteProps: 'as-needed',
/**
* jsx中是否使用单引号替代双引号
* @default false
* @type {boolean}
*/
jsxSingleQuote: true,
/**
* 在jsx中使用是否单引号代替双引号
* @default false
* @type {boolean}
*/
/**
* 末尾是否加上逗号
* @default "es5"
* @type {"es5"|"none"|"all"}
*/
trailingComma: 'none',
/**
* 在对象,数组括号与文字之间加空格 "{ foo: bar }"
* @default true
* @type {boolean}
*/
bracketSpacing: true,
/**
* 把多行HTML (HTML, JSX, Vue, Angular)元素的>放在最后一行的末尾,而不是单独放在下一行(不适用于自关闭元素)。
* @default false
* @type {boolean}
*/
bracketSameLine: false,
/**
* 当箭头函数只有一个参数是否加括号
* @default "always"
* @type {"always"|"avoid"}
*/
arrowParens: 'always',
/**
* 为HTML、Vue、Angular和Handlebars指定全局空格敏感性
* @default "css"
* @type {"css"|"strict"|"ignore"}
*/
htmlWhitespaceSensitivity: 'ignore',
/**
* 是否缩进Vue文件中的<script>和<style>标记内的代码。有些人(比如Vue的创建者)不使用缩进来保存缩进级别,但这可能会破坏编辑器中的代码折叠。
* @default "always"
* @type {"always"|"avoid"}
*/
vueIndentScriptAndStyle: false,
/**
* 文件结束符
* @default "lf"
* @type {"lf"|"crlf"|"cr"|"auto"}
*/
endOfLine: 'crlf',
/**
* 因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
*/
proseWrap: 'never',
// 是否使用根目录下的EditorConfig配置文件
useEditorConfig: false,
/**
* HTML\VUE\JSX每行只有单个属性
* @default true
* @type {boolean}
*/
singleAttributePerLine: false,
disableLanguages: ['html']
}
-
引入Element Plus
安装 npm install element-plus --save
在main.ts中全局引入,如果需要按需引入,请参考官方文档
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
-
集成Vue-router
安装 npm install vue-router@4
创建src/router/index.ts文件
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
const routes: Array<RouteRecordRaw> = [
{
path: '/home',
name: 'Home',
component: () => import('@/components/HelloWorld.vue')
},
{
path: '/',
redirect: { name: 'Home' }
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router;
在main.ts中引入
import { createApp } from 'vue';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import './style.css';
import App from './App.vue';
import router from '@/router/index';
const app = createApp(App);
app.use(ElementPlus);
app.use(router);
app.mount('#app');
集成Pinia
安装 npm install pinia
创建src/store/index.ts文件
import { createPinia } from 'pinia';
const pinia = createPinia();
export default pinia;
在main.ts中引入
import { createApp } from 'vue';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import './style.css';
import App from './App.vue';
import router from '@/router/index';
import pinia from '@/store/index';
const app = createApp(App);
app.use(ElementPlus);
app.use(router);
app.use(pinia);
app.mount('#app');
集成Axios
安装 npm install axios
新建文件src/utils/service/request.js,创建axios拦截器,这里我暂时我用的JS,后续再改吧...
import axios from 'axios';
import qs from 'qs';
import { ElMessage } from 'element-plus';
// 创建axios实例
const service = axios.create({
baseURL: '',
timeout: 60000,
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
});
// 请求拦截器
service.interceptors.request.use(
(requestConfig) => {
// 防止GET请求缓存,追加时间戳
if (requestConfig.method?.toUpperCase() === 'GET') {
requestConfig.params = { ...requestConfig.params, t: new Date().getTime() / 1000 };
}
if (Object.values(requestConfig.headers).includes('application/x-www-form-urlencoded')) {
requestConfig.data = qs.stringify(requestConfig.data);
}
const token = sessionStorage.getItem("token"); // || projectConfig.accessToken;
if (token) {
requestConfig.headers.Authorization = "Bearer " + token;
}
return requestConfig;
},
error => {
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
response => {
if (response.status !== 200) {
return Promise.reject(new Error(response.statusText || 'Error'));
}
const resData = response.data;
if (resData.code === 200) {
return resData;
}
ElMessage.error(resData.message);
return Promise.reject(new Error(resData.message || 'Error'));
},
error => {
ElMessage.error(error.message);
return Promise.reject(error)
}
)
export default service;
挂载到全局
import { createApp } from 'vue';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import './style.css';
import App from './App.vue';
import router from '@/router/index';
import store from '@/store/index';
import service from '@/utils/service/request';
const app = createApp(App);
app.use(ElementPlus);
app.use(router);
app.use(store);
app.config.globalProperties.$axios = service;
app.mount('#app');
组件中引用
<template>
<h1>测试</h1>
</template>
<script setup lang="ts">
import { getCurrentInstance } from 'vue';
const currentInstance: any = getCurrentInstance();
const { proxy } = currentInstance;
const data = {}
proxy.$axios({
url: '',
method: 'post',
data
})
.then((res: any) => {
console.log(res);
});
proxy.$axios({
url: '',
method: 'get',
params: data
})
.then((res: any) => {
console.log(res);
});
</script>
<style lang="scss" scoped>
.read-the-docs {
color: #888;
}
</style>
集成CSS预编译器
我在项目中使用的是sass,Vite 已经集成好了相关的loader ,不需要再做额外的配置
安装 npm install sass -D
使用的话在style标签中添加 lang="scss"属性
<style lang="scss"></style>
集成Cesium
安装cesium
npm install cesium@1.67.0
在main.ts 定义全局变量 CESIUM_BASE_URL:
declare global {
interface Window {
CESIUM_BASE_URL: string
}
}
把 node_modules/cesium/Build/CesiumUnminified/
这个未压缩版本的文件夹下内容, Assets
、Widgets
、Workers
、ThirdParty
四个文件夹拷贝到 public/static/Cesium/
下
组件中使用
<template>
<div id="cesiumContainer" ref="viewerDivRef" class="viewer"></div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { TileMapServiceImageryProvider, Viewer, buildModuleUrl } from 'cesium'
import 'cesium/Build/CesiumUnminified/Widgets/widgets.css'
const viewerDivRef = ref();
window.CESIUM_BASE_URL = '/static/webgl/Cesium/'
onMounted(() => {
new Viewer(viewerDivRef.value, {
imageryProvider: new TileMapServiceImageryProvider({
url: '/static/webgl/Cesium/Assets/Textures/NaturalEarthII',
})
})
})
</script>
<style lang="scss" scoped>
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.viewer-main {
float: left;
width: 100%;
height: 100%;
position: relative;
}
</style>
效果
总结
以上就是从Vue2到Vue3+TypeScript+Element plus + Vue-router + Axios + Sass + Cesium的开发环境的准备工作,后续会继续记录用Vue3语法重构Vue2.0项目。