⛰️Vue2.7"Naruto"、Vue3"One Piece"——项目升级实践

533 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

本文将分为vue2.7和vue3两块进行项目整理。配置vscode成为前端开发利器!根据本人的开发做出的一些开发文档分享。欢迎大家一起探讨。

vue2.7

1、项目升级至vue2.7

在 Vue2.7 中,Vue3 的很多功能将会向后移植,以便于 Vue2 的很多项目可以使用 Vue3 的一些很好用的新特性,例如:

  1. Composition API (组合式 API)
  2. SFC <script setup>
  3. SFC CSS v-bind (单文件组件 CSS 中的 v-bind)

其他 API:

  1. defineComponent():具有改进的类型推断。
  2. h()、useSlot()、useAttrs()、useCssModules()...。
  3. set()、del()、nextTick() 在 ESM 构建中也作为命名导出提供。
  4. 支持 emits,但仅用作类型检查用途。Vue2.7"Naruto"详细内容

2、删除依赖

1.删除文件:node_modules、package-lock.json 2.删除依赖 vue-template-compiler

3、依赖版本升级

1.dependencies 将vue升级至2.7.8最新版

"dependencies": {
  "vue": "^2.7.8",
}

2.devDependencies 以下版本升级如下

"devDependencies": {
  "@vue/cli-plugin-babel": "^4.5.18",
  "@vue/cli-plugin-eslint": "^4.5.18",
  "@vue/cli-service": "~4.5.18",
  "vue-loader": "^15.10.0"
}

4、vue2.7语法变更

  1. /deep/、::v-deep、>>>更改为:deep()
    可以在vscode搜索里写如下
    输入/deep/(*.?)\{ 替换 :deep($1){

591660109494_.pic_hd.jpg

  1. <script setup>
<template>
  <div>
    <button @click="increment">Count is: {{ count }}</button>
    <span>{{ fullName }}</span>
    <!-- 在vue2.7中可以直接使用 ?. 和 ?? -->
    <p>{{ obj?.user?.name ?? '张三' }}</p>
    <p>{{ obj?.user?.age ?? 18 }}</p>
  </div>
</template>
<script setup>
import { ref, reactive, onBeforeMount, onMounted, computed } from 'vue';
console.log('1-开始创建组件-setup');
// const data = reactive({});
const count = ref(0);
function increment() {
  count.value++;
}

const obj = reactive({
  user: {
    name: '李四'
  }
});

const color = ref('#95bffe');

const firstName = ref('John');
const lastName = ref('Doe');

const fullName = computed({
  get() {
    return firstName.value + ' ' + lastName.value;
  },
  set(newValue) {
    [firstName.value, lastName.value] = newValue.split(' ');
  }
});

onBeforeMount(() => {
  console.log('2.组件挂载页面之前执行----onBeforeMount');
});
onMounted(() => {
  console.log('3.-组件挂载到页面之后执行-------onMounted');
  setTimeout(() => {
    color.value = '#4690ff';
  }, 5000);
});
// 当从组合式函数中返回响应式对象时,toRefs 相当有用。
// 使用它,消费者组件可以解构/展开返回的对象而不会失去响应性:
// ...toRefs(data)
</script>
<script>
export default {
  name: 'MainContent'
};
</script>
<style scoped lang="scss">
div {
  background-color: v-bind(color);
}
</style>

5、eslint的安装及使用

1、在vue2.6+的版本,应该安装eslint 6-7的版本,eslint8版本过高不适合vue2.x。可以在 www.npmjs.com/package/esl… 查看各个版本
通过命令行 npm i eslint@7.32.0 -D 指定版本。

2、eslint-plugin-vue、@vue/cli-plugin-eslint升级。 eslint-plugin-vue在vue2.7需要把它升级为9.x的版本,在2.6.x的版本安装8.x的版本即可。
命令行输入:

npm i eslint-plugin-vue@9.3.0 @vue/cli-plugin-eslint@4.5.18 -D

3、在vuecli根目录添加.eslintrc.js文件。详细规则 可以根据自己项目来制定各种规则。

module.exports = {
  env: {
    browser: true,
    es6: true, // 使用es6语法
    node: true // node环境编译
  },
  extends: [
    'plugin:vue/essential', // vue2语法插件
    'plugin:prettier/recommended' // 添加 prettier 插件
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly'
  },
  parserOptions: {
    ecmaVersion: 2018, // Es2018版本
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true
    },
    parser: 'babel-eslint' // 外部解析器
  },
  parser: 'vue-eslint-parser', // 内置解析器
  settings: {
    'import/resolver': {
      node: {
        paths: ['src']
      }
    }
  },
  rules: {
    'vue/singleline-html-element-content-newline': 'off',
    'vue/multiline-html-element-content-newline': 'off',
    // 'vue/name-property-casing': ['error', 'PascalCase'],
    'vue/no-v-html': 'off',
    'accessor-pairs': 2,
    'arrow-spacing': [
      2,
      {
        before: true,
        after: true
      }
    ],
    'block-spacing': [2, 'always'],
    'brace-style': [
      2,
      '1tbs',
      {
        allowSingleLine: true
      }
    ],
    camelcase: [
      0,
      {
        properties: 'always'
      }
    ],
    'comma-dangle': [2, 'never'],
    'comma-spacing': [
      2,
      {
        before: false,
        after: true
      }
    ],
    'comma-style': [2, 'last'],
    'constructor-super': 2,
    curly: [2, 'multi-line'],
    'dot-location': [2, 'property'],
    'eol-last': 2,
    eqeqeq: ['error', 'always', { null: 'ignore' }],
    'generator-star-spacing': [
      2,
      {
        before: true,
        after: true
      }
    ],
    'handle-callback-err': [2, '^(err|error)$'],
    indent: [
      0,
      2,
      {
        SwitchCase: 1,
        flatTernaryExpressions: true
      }
    ],
    'jsx-quotes': [2, 'prefer-double'],
    'key-spacing': [
      2,
      {
        beforeColon: false,
        afterColon: true
      }
    ],
    'keyword-spacing': [
      2,
      {
        before: true,
        after: true
      }
    ],
    'new-cap': [
      2,
      {
        newIsCap: true,
        capIsNew: false
      }
    ],
    'new-parens': 2,
    'no-array-constructor': 2,
    'no-caller': 2,
    'no-console': 'off',
    'no-class-assign': 2,
    'no-cond-assign': 2,
    'no-const-assign': 2,
    'no-control-regex': 0,
    'no-delete-var': 2,
    'no-dupe-args': 2,
    'no-dupe-class-members': 2,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-empty-character-class': 2,
    'no-empty-pattern': 2,
    'no-eval': 2,
    'no-ex-assign': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-extra-boolean-cast': 2,
    'no-extra-parens': [2, 'functions'],
    'no-fallthrough': 2,
    'no-floating-decimal': 2,
    'no-func-assign': 2,
    'no-implied-eval': 2,
    'no-inner-declarations': [2, 'functions'],
    'no-invalid-regexp': 2,
    'no-irregular-whitespace': 2,
    'no-iterator': 2,
    'no-label-var': 2,
    'no-labels': [
      2,
      {
        allowLoop: false,
        allowSwitch: false
      }
    ],
    'no-lone-blocks': 2,
    'no-mixed-spaces-and-tabs': 2,
    'no-multi-spaces': 2,
    'no-multi-str': 2,
    'no-multiple-empty-lines': [
      2,
      {
        max: 1
      }
    ],
    'no-native-reassign': 2,
    'no-negated-in-lhs': 2,
    'no-new-object': 2,
    'no-new-require': 2,
    'no-new-symbol': 2,
    'no-new-wrappers': 2,
    'no-obj-calls': 2,
    'no-octal': 2,
    'no-octal-escape': 2,
    'no-path-concat': 2,
    'no-proto': 2,
    'no-redeclare': 2,
    'no-regex-spaces': 2,
    'no-return-assign': [2, 'except-parens'],
    'no-self-assign': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-shadow-restricted-names': 2,
    'no-spaced-func': 2,
    'no-sparse-arrays': 2,
    'no-this-before-super': 2,
    'no-throw-literal': 2,
    'no-trailing-spaces': 2,
    'no-undef': 2,
    'no-undef-init': 2,
    'no-unexpected-multiline': 2,
    'no-unmodified-loop-condition': 2,
    'no-unneeded-ternary': [
      2,
      {
        defaultAssignment: false
      }
    ],
    'no-unreachable': 2,
    'no-unsafe-finally': 2,
    'no-unused-vars': [
      2,
      {
        vars: 'all',
        args: 'none'
      }
    ],
    'no-useless-call': 2,
    'no-useless-computed-key': 2,
    'no-useless-constructor': 2,
    'no-useless-escape': 0,
    'no-whitespace-before-property': 2,
    'no-with': 2,
    'one-var': [
      2,
      {
        initialized: 'never'
      }
    ],
    'operator-linebreak': [
      2,
      'after',
      {
        overrides: {
          '?': 'before',
          ':': 'before'
        }
      }
    ],
    'padded-blocks': [2, 'never'],
    quotes: [
      2,
      'single',
      {
        avoidEscape: true,
        allowTemplateLiterals: true
      }
    ],
    semi: [2, 'always'], // 语句强制分号结尾
    'semi-spacing': [0, { before: false, after: true }], // 分号前后空格
    'space-before-blocks': [2, 'always'],
    'space-before-function-paren': [
      'error',
      {
        anonymous: 'always',
        named: 'never',
        asyncArrow: 'always'
      }
    ],
    'space-in-parens': [2, 'never'],
    'space-infix-ops': 2,
    'space-unary-ops': [
      2,
      {
        words: true,
        nonwords: false
      }
    ],
    'spaced-comment': [
      2,
      'always',
      {
        markers: ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!']
      }
    ],
    'template-curly-spacing': [2, 'never'],
    'use-isnan': 2,
    'valid-typeof': 2,
    'wrap-iife': [2, 'any'],
    'yield-star-spacing': [2, 'both'],
    yoda: [2, 'never'],
    'prefer-const': 2,
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'object-curly-spacing': [
      2,
      'always',
      {
        objectsInObjects: true
      }
    ],
    'array-bracket-spacing': [2, 'never']
  }
};

4、可以在.eslintignore添加任意不被eslint语法提示文件。

build/*.js
public
dist
node_modules/**
**/node_modules/**
*.ts

5、vscode添加拓展程序eslint

6、通过设置命令行输入vue-cli-service lint即可检测出项目语法问题提示。--fix修复部分语法错误。

// "lint": "vue-cli-service lint"
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix"

npm run lint

6、Prettier的安装及使用

  1. 2.6.x -- 2.7.x版本中,安装prettier2.x版本即可npmjs prettier
    安装最新版 npm i prettier -D

2.在根目录添加 .prettierrc文件,并在.eslintrc.js --- extends中添加

plugin:prettier/recommended

3.添加prettier规则 prettier官网

在.prettierrc文件中不能有注释

{
  "eslintIntegration": true, // 让prettier使用eslint的代码格式进行校验
  "useTabs": false, // 是否使用tab进行缩进
  "tabWidth": 2, // 缩进字节数
  "printWidth": 90, // 代码行每行最多显示字节数,超过换行
  "singleQuote": true, // 使用单引号
  "trailingComma": "none", // 对象或数组最后一个元素后面是否加逗号
  "bracketSpacing": true, // 在对象,数组括号与文字之间加空格 例如: "{ foo: bar }"
  "semi": true, // 使用分号结尾
  "arrowParens": "avoid" // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid: 省略括号
}

7、解决Eslint与Prettier冲突

在安装eslint与prettier会发现,他们有语法格式冲突的问题,这时候需要安装插件解决。

安装插件 eslint-config-prettier、eslint-plugin-prettier(安装最新版) 即可。

npm i eslint-config-prettier eslint-plugin-prettier —D

prettier格式化命令:npx prettier --write src 在项目src文件夹下使用格式化命令

或者在package.json中添加

"format": "prettier --write \"./**/*.{html,vue,ts,js,json,md}\""

npm run format

8、安装插件 EditorConfig for VS Code

该插件使不同编辑器之间的代码格式保持统一,比如行尾序列、字符集编码、代码缩进等 配合.editorconfig文件使用。

# https://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
quote_type = single
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

9、设置vscode

以上依赖、插件安装好后。

  1. 配置默认格式化程序选择Prettier -Code formatter
  2. 在工作区.vscode文件夹下添加setting.json文件
{
  // 开启自动修复
  "editor.codeActionsOnSave": {
    "source.fixAll": false,
    "source.fixAll.eslint": true
  },
  // 保存的时候自动格式化
  "editor.formatOnSave": true,
  // 默认格式化工具选择prettier
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

然后在项目里保存代码即格式化~~~

  1. 安装 Vue Language Features (Volar)插件

    当前工作区禁用Vetur(vue2语法支持),如果使用vue2则需要把Volar禁用

10、vscode其他插件推荐

  1. Bracket Pair Colorizer 2(已弃用,可直接设置 Bracket Pair Colorization)
  2. One Dark Pro 主题
  3. vscode-icons 图标

vue3(3.2.x)

1、SFC <template>下支持多个标签

<template>
  <el-button size="large" :icon="Setting">作业设置</el-button>
  <el-button size="large" :icon="Refresh">刷新</el-button>
</template>

2、SFC 可以同时支持setup以及option Api写法

<template>
  <el-button size="large" :icon="Setting">作业设置</el-button>
  <el-button size="large" :icon="Refresh">刷新</el-button>
</template>
<script setup>
  import { Setting, Refresh } from '@element-plus/icons-vue';
</script>
export default {
  name: 'HomePage', // component name
  data() {}
}

3、eslint支持vue3语法

输入 npm i eslint eslint-plugin-vue -D 获取最新eslint支持

env: {
    browser: true,
    es2021: true, // script 版本
    node: true
  },
  extends: [
    'eslint:recommended', // eslint推荐语法
    'plugin:prettier/recommended', // 添加 prettier 插件
    'plugin:vue/vue3-essential', // 支持vue3 插件
    'plugin:@typescript-eslint/recommended' // typescript插件
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly'
  },
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true
    },
    parser: '@typescript-eslint/parser' // 如果已经使用了另外的解析器(例如"parser": "@typescript-eslint/parser"),则需要将其移至parseOptions,这样才不会与vue-eslint-parser冲突。
  },
  parser: 'vue-eslint-parser', //使用eslint解析器
  plugins: ['vue', '@typescript-eslint'],
  
  ...
  
}

4、支持typescript

vue3可在seteup函数中直接写ts代码

  1. 安装typescript、@typescript-eslint/parser、typescript-eslint/eslint-plugin

npm i typescript @typescript-eslint/parser typescript-eslint/eslint-plugin -D

2.在eslint添加插件 plugin:@typescript-eslint/recommended

3.在根目录上添加tsconfig.json

{
  "include": ["./src/components/**/*.ts"], //只编译的文件 如果没有可编译的文件eslint会报错
  "vueCompilerOptions": {
    // 模板上禁用了TypeScript intellisense
    "experimentalDisableTemplateSupport": true
  },
  "compilerOptions": {
    /* Language and Environment */
    "target": "esnext" /* 为发出的JavaScript设置JavaScript语言版本,并包含兼容的库声明 */,
    "lib": ["esnext", "dom"] /* 指定一组描述目标运行时环境的捆绑库声明文件 */,
    "useDefineForClassFields": true /* emit ECMAScript-符合标准的类字段。 */,
    /* Modules */
    "module": "esnext" /* 指定所生成的模块代码。 */,
    // "jsx": "preserve" /* 指定生成的JSX代码 */,
    // "rootDir": "./", /* 在源文件中指定根文件夹。 */
    "moduleResolution": "node" /* 指定TypeScript如何从给定的模块指定符中查找文件。 */
    "resolveJsonModule": true /* 启用导入.json文件 */
    "sourceMap": true /* 为发出的JavaScript文件创建源映射文件。 */,
    "esModuleInterop": true /* 发出额外的JavaScript,以简化对导入CommonJS模块的支持。这使得`允许合成默认导入`以实现类型兼容性。    */,
    "strict": true,
    "skipLibCheck": true /* 跳过类型检查所有。d.ts文件。 */
  }
}

5、使用scss

  1. 安装style-resources-loader

    vue add style-resources-loader 使用yarn命令

  2. 安装 node-sass、sass、sass-loader

    npm i node-sass sass sass-loader -D

3.在vue.config.js中添加

module.exports = {
  ...
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'scss',
      patterns: []
    }
  }
}

4.增加typescript/eslint规则

rules: {
  'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  '@typescript-eslint/no-explicit-any': ['off'], // 关闭any类型时的警告
  '@typescript-eslint/no-empty-function': ['off'], // 关闭空函数警告
  '@typescript-eslint/no-var-requires': [0],
  '@typescript-eslint/camelcase': ['off'], // 关闭词组下划线校验
  '@typescript-eslint/ban-ts-ignore': ['off'], // 允许使用ts-ignore
  'no-empty-function': ['off'],
  'no-empty': ['off'],
  'no-prototype-builtins': ['off'],
}

6、NVM安装

nodejs版本管理工具,用于切换各版本之间的版本。例如vue2项目 14.x 与vue3(vite)15.0+

  1. 安装 github.com/nvm-sh/nvm 选择Git install
$ git clone https://github.com/nvm-sh/nvm.git.nvm
$ cd .nvm
$ ./install.sh
$ sudo vim .bashrc
添加以下代码:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
$ source ~/.bashrc

2.### 安装node版本

nvm install 16
  1. 命令行
nvm ls :列出所有已安装的 node 版本
nvm list :列出所有已安装的 node 版本
nvm install [node版本号] :安装指定版本 node
nvm uninstall [node版本号] :删除已安装的指定版本
nvm use [node版本号] :切换到指定版本 node
nvm current :当前 node 版本

vue3 bug(目前3.2.x)

1、setup API与option API同时写在一个vue文件下。开发环境下没有错误,生产环境报错! github.com/vuejs/core/…

使用el-drawer的 v-model控制显示隐藏生产环境会出现以下bug!

ReferenceError: modelValue is not defined
  at HTMLInputElement.u.onUpdate:modelValue.l.<computed>.l.<computed>

2、keepalive包裹组件时出现热更新失败!github.com/vuejs/core/…

文章陆续更新中...